From 8af7814af47006dbd561c5150e30dbe1560adcb6 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Sun, 8 Dec 2024 15:28:57 +0500 Subject: [PATCH 01/57] fix: possible null reference --- zzre.core/math/WorldCollider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zzre.core/math/WorldCollider.cs b/zzre.core/math/WorldCollider.cs index 54036f32..a794aaa3 100644 --- a/zzre.core/math/WorldCollider.cs +++ b/zzre.core/math/WorldCollider.cs @@ -1,4 +1,4 @@ -using System.IO; +using System.IO; using System.Collections.Generic; using System.Linq; using zzio.rwbs; @@ -94,7 +94,7 @@ public static WorldCollider Create(RWWorld world) sectorType = RWPlaneSectionType.XPlane, leftValue = float.PositiveInfinity, rightValue = float.PositiveInfinity, - children = [rootAtomic, new RWString()] + children = [rootAtomic!, new RWString()] }; var splits = new CollisionSplit[splitCount]; From be81a7d9c10f874ec72a042a8709e9ec3a68dcf9 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 10 Dec 2024 15:30:37 +0500 Subject: [PATCH 02/57] feat: support text for neutral zzclass --- zzre/game/uibuilder/UIBuilder.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/zzre/game/uibuilder/UIBuilder.cs b/zzre/game/uibuilder/UIBuilder.cs index e8ee2035..71bad71f 100644 --- a/zzre/game/uibuilder/UIBuilder.cs +++ b/zzre/game/uibuilder/UIBuilder.cs @@ -166,6 +166,7 @@ public static string GetLightsIndicator(int value) ZZClass.Dark => GetDBText(new UID(0x8313DCA1)), // Dark ZZClass.Chaos => GetDBText(new UID(0xC659DCA1)), // Chaos ZZClass.Metal => GetDBText(new UID(0x3CE1DCA1)), // Metal + ZZClass.Neutral => GetDBText(new UID(0x8B6BDCA1)), // Neutral _ => throw new ArgumentException($"Unknown spell class: {zzClass}") }; } From 1631e7f466ea7a85b03bf7c46eb0af494c63bf93 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 10 Dec 2024 18:00:35 +0500 Subject: [PATCH 03/57] refactor: book menu --- zzre/game/components/ui/ScrBookMenu.cs | 3 - zzre/game/systems/ui/BaseScreen.cs | 1 + zzre/game/systems/ui/ScrBookMenu.cs | 153 ++++++++++++------------- 3 files changed, 76 insertions(+), 81 deletions(-) diff --git a/zzre/game/components/ui/ScrBookMenu.cs b/zzre/game/components/ui/ScrBookMenu.cs index e2db6d45..a7315456 100644 --- a/zzre/game/components/ui/ScrBookMenu.cs +++ b/zzre/game/components/ui/ScrBookMenu.cs @@ -1,13 +1,10 @@ -using System.Collections.Generic; using zzio.db; namespace zzre.game.components.ui; public struct ScrBookMenu { - public Inventory Inventory; public FairyRow[] Fairies; - public Dictionary FairyButtons; public DefaultEcs.Entity Sidebar; public DefaultEcs.Entity Crosshair; } diff --git a/zzre/game/systems/ui/BaseScreen.cs b/zzre/game/systems/ui/BaseScreen.cs index d8e41e91..977ea2a7 100644 --- a/zzre/game/systems/ui/BaseScreen.cs +++ b/zzre/game/systems/ui/BaseScreen.cs @@ -24,6 +24,7 @@ protected enum BlockFlags private readonly IDisposable removedSubscription; protected readonly IZanzarahContainer zzContainer; protected readonly Zanzarah zanzarah; + protected Inventory inventory => zanzarah.CurrentGame!.PlayerEntity.Get(); protected readonly UI ui; protected readonly DefaultEcs.World uiWorld;// necessary as Dialog UI is owned by the game and not by the UI. // Probably worth some cleanup but this would mean merging diff --git a/zzre/game/systems/ui/ScrBookMenu.cs b/zzre/game/systems/ui/ScrBookMenu.cs index d074d595..6ca54075 100644 --- a/zzre/game/systems/ui/ScrBookMenu.cs +++ b/zzre/game/systems/ui/ScrBookMenu.cs @@ -19,7 +19,10 @@ public partial class ScrBookMenu : BaseScreen(); if (!inventory.Contains(StdItemId.FairyBook)) return; - var entity = World.CreateEntity(); - entity.Set(); - ref var book = ref entity.Get(); - book.Inventory = inventory; - - preload.CreateFullBackOverlay(entity); - + var uiEntity = World.CreateEntity(); + uiEntity.Set(); + ref var book = ref uiEntity.Get(); book.Fairies = [.. db.Fairies.OrderBy(fairyRow => fairyRow.CardId.EntityId)]; - book.FairyButtons = []; book.Sidebar = default; book.Crosshair = default; - preload.CreateImage(entity) - .With(-new Vector2(320, 240)) + preload.CreateFullBackOverlay(uiEntity); + + // Draw Fairy Book background + preload.CreateImage(uiEntity) + .With(components.ui.FullAlignment.Center) .WithBitmap("col000") .WithRenderOrder(1) .Build(); - preload.CreateTooltipTarget(entity) - .With(new Vector2(-320 + 11, -240 + 11)) + preload.CreateTooltipTarget(uiEntity) + .With(Mid + new Vector2(11, 11)) .WithText("{205} - ") .Build(); - CreateTopButtons(preload, entity, inventory, IDOpenFairybook); - CreateFairyButtons(preload, entity, inventory, ref book); + CreateTopButtons(preload, uiEntity, inventory, IDOpenFairybook); + CreateFairyButtons(uiEntity, ref book); } - private static void CreateFairyButtons(UIBuilder preload, in DefaultEcs.Entity entity, Inventory inventory, ref components.ui.ScrBookMenu book) + private void CreateFairyButtons(in DefaultEcs.Entity entity, ref components.ui.ScrBookMenu book) { var fairies = book.Fairies; for (int i = 0; i < fairies.Length; i++) { if (inventory.Contains(fairies[i].CardId)) { - var element = new components.ui.ElementId(1 + i); + // Fairy icon var button = preload.CreateButton(entity) - .With(element) + .With(new components.ui.ElementId(i)) .With(Mid + FairyButtonPos(i)) .With(new components.ui.ButtonTiles(fairies[i].CardId.EntityId)) .With(UIPreloadAsset.Wiz000) .Build(); button.Set(button.Get().GrownBy(new Vector2(5, 5))); // No gaps button.Set(new components.ui.Silent()); - book.FairyButtons.Add(element, fairies[i]); // In the original engine, only the first fairy is checked for isInUse // This is an intentional bug fix - if (inventory.Fairies.Any(c => fairies[i].CardId == c.cardId && c.isInUse)) { + if (inventory.Fairies.Any(c => fairies[i].CardId == c.cardId && c.isInUse)) + { + // "Fairy is equipped" indicator preload.CreateImage(entity) .With(Mid + FairyButtonPos(i)) .With(UIPreloadAsset.Inf000, 16) @@ -91,24 +92,16 @@ private static void CreateFairyButtons(UIBuilder preload, in DefaultEcs.Entity e } } - private DefaultEcs.Entity CreateSidebar(UIBuilder preload, in DefaultEcs.Entity parent, FairyRow fairyRow, ref components.ui.ScrBookMenu book) + private DefaultEcs.Entity CreateSidebar(in DefaultEcs.Entity parent, ref components.ui.ScrBookMenu book, int fairyI) { var entity = World.CreateEntity(); entity.Set(new components.Parent(parent)); - var fairyI = Array.IndexOf(book.Fairies, fairyRow) + 1; - - var element = new components.ui.ElementId(0); - preload.CreateButton(entity) - .With(element) - .With(Mid + new Vector2(160, 218)) - .With(new components.ui.ButtonTiles(fairyRow.CardId.EntityId)) - .With(UIPreloadAsset.Wiz000) - .Build(); + var fairyRow = book.Fairies[fairyI]; preload.CreateLabel(entity) .With(Mid + new Vector2(21, 57)) - .WithText($"#{fairyI} {fairyRow.Name}") + .WithText($"#{fairyI + 1} {fairyRow.Name}") .With(UIPreloadAsset.Fnt000) .Build(); @@ -130,58 +123,59 @@ private DefaultEcs.Entity CreateSidebar(UIBuilder preload, in DefaultEcs.Entity .With(UIPreloadAsset.Fnt002) .Build(); - CreateStat(preload, entity, 0, Math.Min(500, fairyRow.MHP) / 100); - CreateStat(preload, entity, 1, fairyRow.MovSpeed + 1); - CreateStat(preload, entity, 2, fairyRow.JumpPower + 1); - CreateStat(preload, entity, 3, fairyRow.CriticalHit + 1); + preload.CreateImage(entity) + .With(Mid + new Vector2(160, 218)) + .With(UIPreloadAsset.Wiz000, fairyRow.CardId.EntityId) + .Build(); - const float MaxTextWidth = 190f; preload.CreateLabel(entity) - .With(Mid + new Vector2(21, 346)) - .WithText(fairyRow.Info) + .With(Mid + new Vector2(21, 271)) + .WithText(String.Join("\n", UIDStatNames.Select(uid => db.GetText(uid).Text))) + .WithLineHeight(17) .With(UIPreloadAsset.Fnt002) - .WithLineWrap(MaxTextWidth) .Build(); - return entity; - } - - private void CreateStat(UIBuilder preload, in DefaultEcs.Entity entity, int index, int value) - { preload.CreateLabel(entity) - .With(Mid + new Vector2(21, 271 + index*17)) - .WithText(db.GetText(UIDStatNames[index]).Text) - .With(UIPreloadAsset.Fnt002) + .With(Mid + new Vector2(111, 266)) + .WithText(StatsLights([ + Math.Min(500, fairyRow.MHP) / 100, + fairyRow.MovSpeed + 1, + fairyRow.JumpPower + 1, + fairyRow.CriticalHit + 1 + ])) + .WithLineHeight(17) + .With(UIPreloadAsset.Fnt001) .Build(); preload.CreateLabel(entity) - .With(Mid + new Vector2(111, 266 + index*17)) - .WithText(UIBuilder.GetLightsIndicator(value)) - .With(UIPreloadAsset.Fnt001) + .With(Mid + new Vector2(21, 346)) + .WithText(fairyRow.Info) + .With(UIPreloadAsset.Fnt002) + .WithLineWrap(190f) .Build(); - } - private static Vector2 FairyButtonPos(int fairyI) { - return new Vector2(226 + 45 * (fairyI % 9), 66 + 45 * (fairyI / 9)); + return entity; } - protected override void Update(float timeElapsed, in DefaultEcs.Entity entity, ref components.ui.ScrBookMenu bookMenu) - { - base.Update(timeElapsed, entity, ref bookMenu); - } + private static string StatsLights(int[] values) => + String.Join("\n", values.Select(value => UIBuilder.GetLightsIndicator(value))); - private void HandleElementDown(DefaultEcs.Entity entity, components.ui.ElementId id) - { - var bookMenuEntity = Set.GetEntities()[0]; - ref var book = ref bookMenuEntity.Get(); + private static Vector2 FairyButtonPos(int fairyI) => + new Vector2(226 + 45 * (fairyI % 9), 66 + 45 * (fairyI / 9)); - if (book.FairyButtons.TryGetValue(id, out var fairyRow)) + private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.ElementId id) + { + var uiEntity = Set.GetEntities()[0]; + ref var book = ref uiEntity.Get(); + var fairyI = id.Value; + var fairyRow = book.Fairies.ElementAtOrDefault(fairyI); + if (fairyRow != default) { book.Sidebar.Dispose(); - book.Sidebar = CreateSidebar(preload, entity, fairyRow, ref book); + book.Sidebar = CreateSidebar(uiEntity, ref book, fairyI); book.Crosshair.Dispose(); - book.Crosshair = preload.CreateImage(entity) - .With(Mid + new Vector2(-2, -2) + FairyButtonPos(book.Fairies.IndexOf(fairyRow))) + book.Crosshair = preload.CreateImage(uiEntity) + .With(Mid + new Vector2(-2, -2) + FairyButtonPos(fairyI)) .With(UIPreloadAsset.Dnd000, 0) .WithRenderOrder(-2) .Build(); @@ -189,40 +183,43 @@ private void HandleElementDown(DefaultEcs.Entity entity, components.ui.ElementId if (id == IDOpenDeck) { - bookMenuEntity.Dispose(); + uiEntity.Dispose(); zanzarah.UI.Publish(); } else if (id == IDOpenRunes) { - bookMenuEntity.Dispose(); + uiEntity.Dispose(); zanzarah.UI.Publish(); } else if (id == IDOpenMap) { - bookMenuEntity.Dispose(); + uiEntity.Dispose(); zanzarah.UI.Publish(); } else if (id == IDClose) - bookMenuEntity.Dispose(); + uiEntity.Dispose(); } protected override void HandleKeyDown(KeyCode key) { - var bookMenuEntity = Set.GetEntities()[0]; + var uiEntity = Set.GetEntities()[0]; base.HandleKeyDown(key); - if (key == KeyCode.KF2) { - bookMenuEntity.Dispose(); + if (key == KeyCode.KF2) + { + uiEntity.Dispose(); zanzarah.UI.Publish(); } - if (key == KeyCode.KF4) { - bookMenuEntity.Dispose(); + if (key == KeyCode.KF4) + { + uiEntity.Dispose(); zanzarah.UI.Publish(); } - if (key == KeyCode.KF5) { - bookMenuEntity.Dispose(); + if (key == KeyCode.KF5) + { + uiEntity.Dispose(); zanzarah.UI.Publish(); } - if (key == KeyCode.KReturn|| key == KeyCode.KEscape || key == KeyCode.KF3) + if (key == KeyCode.KReturn || key == KeyCode.KEscape || key == KeyCode.KF3) Set.DisposeAll(); } } From 71119a73e919f7ecb32f52544905c65ab1332428 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 10 Dec 2024 21:24:46 +0500 Subject: [PATCH 04/57] fix: improve handling of menu-tab switching * When using function keys, no longer exit the menu when trying to open a locked tab * Refactor to unify most (though not all) of tab handling * add sound to opening fairy book --- zzre/game/systems/player/OpenMenuKeys.cs | 25 ++++++-- zzre/game/systems/ui/InGameScreen.cs | 73 +++++++++++++++++++++--- zzre/game/systems/ui/ScrBookMenu.cs | 41 +------------ zzre/game/systems/ui/ScrDeck.cs | 37 +----------- zzre/game/systems/ui/ScrMapMenu.cs | 37 +----------- zzre/game/systems/ui/ScrRuneMenu.cs | 37 +----------- 6 files changed, 95 insertions(+), 155 deletions(-) diff --git a/zzre/game/systems/player/OpenMenuKeys.cs b/zzre/game/systems/player/OpenMenuKeys.cs index 9dac5711..4918cdd9 100644 --- a/zzre/game/systems/player/OpenMenuKeys.cs +++ b/zzre/game/systems/player/OpenMenuKeys.cs @@ -18,10 +18,12 @@ public class OpenMenuKeys : ISystem private readonly IZanzarahContainer zzContainer; private readonly PlayerControls playerControls; private readonly UI ui; + private readonly Zanzarah zanzarah; public OpenMenuKeys(ITagContainer diContainer) { ui = diContainer.GetTag(); + zanzarah = diContainer.GetTag(); playerControls = diContainer.GetTag(); zzContainer = diContainer.GetTag(); zzContainer.OnKeyDown += HandleKeyDown; @@ -34,15 +36,28 @@ public void Dispose() private void HandleKeyDown(KeyCode code) { + var inventory = zanzarah.CurrentGame!.PlayerEntity.Get(); if (!IsEnabled || playerControls.IsLocked) return; switch (code) { - case MenuKey: ui.Publish(); break; - case RuneMenuKey: ui.Publish(); break; - case BookMenuKey: ui.Publish(); break; - case MapMenuKey: ui.Publish(); break; - case DeckMenuKey: ui.Publish(); break; + case RuneMenuKey: + if (inventory.Contains(StdItemId.RuneFairyGarden)) + ui.Publish(); + break; + case BookMenuKey: + if (inventory.Contains(StdItemId.FairyBook)) + ui.Publish(); + break; + case MapMenuKey: + if (inventory.Contains(StdItemId.MapFairyGarden)) + ui.Publish(); + break; + case MenuKey: + case DeckMenuKey: + if (inventory.Contains(StdItemId.FairyBag)) + ui.Publish(); + break; } } diff --git a/zzre/game/systems/ui/InGameScreen.cs b/zzre/game/systems/ui/InGameScreen.cs index 44703d5c..86679dc4 100644 --- a/zzre/game/systems/ui/InGameScreen.cs +++ b/zzre/game/systems/ui/InGameScreen.cs @@ -1,5 +1,8 @@ -using System.Numerics; +using System.Collections.Generic; +using System.Numerics; +using System.Linq; using zzio; +using KeyCode = Silk.NET.SDL.KeyCode; namespace zzre.game.systems.ui; @@ -14,13 +17,13 @@ public static class InGameScreen public static readonly components.ui.ElementId IDOpenMap = new(1004); public static readonly components.ui.ElementId IDSaveGame = new(1005); - private record struct TabInfo(components.ui.ElementId Id, int PosX, int TileI, UID TooltipUID, StdItemId Item); - private static readonly TabInfo[] Tabs = + private record struct TabInfo(components.ui.ElementId Id, int PosX, int TileI, UID TooltipUID, KeyCode Key, StdItemId Item); + private static readonly List Tabs = [ - new(IDOpenDeck, PosX: 553, TileI: 21, TooltipUID: new(0x6659B4A1), StdItemId.FairyBag), - new(IDOpenRunes, PosX: 427, TileI: 12, TooltipUID: new(0x6636B4A1), StdItemId.RuneFairyGarden), - new(IDOpenFairybook, PosX: 469, TileI: 15, TooltipUID: new(0x8D1BBCA1), StdItemId.FairyBook), - new(IDOpenMap, PosX: 511, TileI: 18, TooltipUID: new(0xC51E6991), StdItemId.MapFairyGarden) + new(IDOpenDeck, PosX: 553, TileI: 21, TooltipUID: new(0x6659B4A1), KeyCode.KF5, StdItemId.FairyBag), + new(IDOpenRunes, PosX: 427, TileI: 12, TooltipUID: new(0x6636B4A1), KeyCode.KF2, StdItemId.RuneFairyGarden), + new(IDOpenFairybook, PosX: 469, TileI: 15, TooltipUID: new(0x8D1BBCA1), KeyCode.KF3, StdItemId.FairyBook), + new(IDOpenMap, PosX: 511, TileI: 18, TooltipUID: new(0xC51E6991), KeyCode.KF4, StdItemId.MapFairyGarden) ]; public static void CreateTopButtons(UIBuilder preload, in DefaultEcs.Entity parent, Inventory inventory, components.ui.ElementId curTab) @@ -60,4 +63,60 @@ public static void CreateTopButtons(UIBuilder preload, in DefaultEcs.Entity pare } } } + + public static void HandleNavClick(components.ui.ElementId id, Zanzarah zanzarah, DefaultEcs.Entity uiEntity, components.ui.ElementId curTab) + { + var tab = Tabs.FirstOrDefault(tab => tab.Id == id); + if (tab.Id == curTab) + { + // Ignore current tab + return; + } + if (tab != default) + TryOpenTab(tab, zanzarah, uiEntity, curTab); + if (id == IDClose) + uiEntity.Dispose(); + } + + public static void HandleNavKeyDown(KeyCode key, Zanzarah zanzarah, DefaultEcs.Entity uiEntity, components.ui.ElementId curTab) + { + var tab = Tabs.FirstOrDefault(tab => tab.Key == key); + if (tab.Id == curTab) + { + // Exit current tab + uiEntity.Dispose(); + return; + } + if (tab != default) + TryOpenTab(tab, zanzarah, uiEntity, curTab); + if (key == KeyCode.KReturn || key == KeyCode.KEscape) + uiEntity.Dispose(); + } + + private static void TryOpenTab(TabInfo tab, Zanzarah zanzarah, DefaultEcs.Entity uiEntity, components.ui.ElementId curTab) + { + var inventory = zanzarah.CurrentGame!.PlayerEntity.Get(); + if (!inventory.Contains(tab.Item)) return; + switch (tab.Key) + { + case KeyCode.KF2: + uiEntity.Dispose(); + zanzarah.UI.Publish(); + break; + case KeyCode.KF3: + uiEntity.Dispose(); + zanzarah.UI.Publish(); + break; + case KeyCode.KF4: + uiEntity.Dispose(); + zanzarah.UI.Publish(); + break; + case KeyCode.KF5: + uiEntity.Dispose(); + zanzarah.UI.Publish(); + break; + default: + break; + } + } } diff --git a/zzre/game/systems/ui/ScrBookMenu.cs b/zzre/game/systems/ui/ScrBookMenu.cs index 6ca54075..de7fe4e8 100644 --- a/zzre/game/systems/ui/ScrBookMenu.cs +++ b/zzre/game/systems/ui/ScrBookMenu.cs @@ -32,9 +32,7 @@ public ScrBookMenu(ITagContainer diContainer) : base(diContainer, BlockFlags.All protected override void HandleOpen(in messages.ui.OpenBookMenu message) { - if (!inventory.Contains(StdItemId.FairyBook)) - return; - + World.Publish(new messages.SpawnSample($"resources/audio/sfx/gui/_g006.wav")); var uiEntity = World.CreateEntity(); uiEntity.Set(); ref var book = ref uiEntity.Get(); @@ -180,46 +178,13 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El .WithRenderOrder(-2) .Build(); } - - if (id == IDOpenDeck) - { - uiEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDOpenRunes) - { - uiEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDOpenMap) - { - uiEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDClose) - uiEntity.Dispose(); + HandleNavClick(id, zanzarah, uiEntity, IDOpenFairybook); } protected override void HandleKeyDown(KeyCode key) { var uiEntity = Set.GetEntities()[0]; base.HandleKeyDown(key); - if (key == KeyCode.KF2) - { - uiEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KF4) - { - uiEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KF5) - { - uiEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KReturn || key == KeyCode.KEscape || key == KeyCode.KF3) - Set.DisposeAll(); + HandleNavKeyDown(key, zanzarah, uiEntity, IDOpenFairybook); } } diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 72a37937..991b1fc9 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -55,10 +55,6 @@ public ScrDeck(ITagContainer diContainer) : base(diContainer, BlockFlags.All) protected override void HandleOpen(in messages.ui.OpenDeck message) { - var inventory = zanzarah.CurrentGame!.PlayerEntity.Get(); - if (!inventory.Contains(StdItemId.FairyBag)) - return; - World.Publish(new messages.SpawnSample($"resources/audio/sfx/gui/_g006.wav")); var entity = World.CreateEntity(); entity.Set(); @@ -550,23 +546,7 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El UpdateSliderPosition(deck); FillList(ref deck); } - else if (id == IDOpenRunes) - { - deckEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDOpenFairybook) - { - deckEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDOpenMap) - { - deckEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDClose) - deckEntity.Dispose(); + else HandleNavClick(id, zanzarah, deckEntity, IDOpenDeck); } private void UpdateSliderPosition(in components.ui.ScrDeck deck) @@ -595,19 +575,6 @@ protected override void HandleKeyDown(KeyCode key) { var deckEntity = Set.GetEntities()[0]; base.HandleKeyDown(key); - if (key == KeyCode.KF2) { - deckEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KF3) { - deckEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KF4) { - deckEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KReturn || key == KeyCode.KEscape || key == KeyCode.KF3) - Set.DisposeAll(); + HandleNavKeyDown(key, zanzarah, deckEntity, IDOpenDeck); } } diff --git a/zzre/game/systems/ui/ScrMapMenu.cs b/zzre/game/systems/ui/ScrMapMenu.cs index c8996fa4..dcba80aa 100644 --- a/zzre/game/systems/ui/ScrMapMenu.cs +++ b/zzre/game/systems/ui/ScrMapMenu.cs @@ -18,10 +18,6 @@ public ScrMapMenu(ITagContainer diContainer) : base(diContainer, BlockFlags.All) protected override void HandleOpen(in messages.ui.OpenMapMenu message) { - var inventory = zanzarah.CurrentGame!.PlayerEntity.Get(); - if (!inventory.Contains(StdItemId.MapFairyGarden)) - return; - var entity = World.CreateEntity(); entity.Set(); ref var mapMenu = ref entity.Get(); @@ -67,42 +63,13 @@ protected override void Update(float timeElapsed, in DefaultEcs.Entity entity, r private void HandleElementDown(DefaultEcs.Entity entity, components.ui.ElementId id) { var mapMenuEntity = Set.GetEntities()[0]; - if (id == IDOpenDeck) - { - mapMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDOpenRunes) - { - mapMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDOpenFairybook) - { - mapMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDClose) - mapMenuEntity.Dispose(); + HandleNavClick(id, zanzarah, mapMenuEntity, IDOpenMap); } protected override void HandleKeyDown(KeyCode key) { var mapMenuEntity = Set.GetEntities()[0]; base.HandleKeyDown(key); - if (key == KeyCode.KF2) { - mapMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KF3) { - mapMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KF5) { - mapMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KReturn || key == KeyCode.KEscape || key == KeyCode.KF3) - Set.DisposeAll(); + HandleNavKeyDown(key, zanzarah, mapMenuEntity, IDOpenMap); } } diff --git a/zzre/game/systems/ui/ScrRuneMenu.cs b/zzre/game/systems/ui/ScrRuneMenu.cs index b7449621..d83e75ad 100644 --- a/zzre/game/systems/ui/ScrRuneMenu.cs +++ b/zzre/game/systems/ui/ScrRuneMenu.cs @@ -54,10 +54,6 @@ public ScrRuneMenu(ITagContainer diContainer) : base(diContainer, BlockFlags.All protected override void HandleOpen(in messages.ui.OpenRuneMenu message) { - var inventory = zanzarah.CurrentGame!.PlayerEntity.Get(); - if (!inventory.Contains(StdItemId.RuneFairyGarden)) - return; - var entity = World.CreateEntity(); entity.Set(); ref var runeMenu = ref entity.Get(); @@ -145,42 +141,13 @@ private void HandleElementDown(DefaultEcs.Entity entity, components.ui.ElementId runeMenuEntity.Dispose(); zanzarah.CurrentGame!.Publish(new messages.Teleport(runeInfo.scene, targetEntry: -1)); } - else if (id == IDOpenDeck) - { - runeMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDOpenFairybook) - { - runeMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDOpenMap) - { - runeMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - else if (id == IDClose) - runeMenuEntity.Dispose(); + else HandleNavClick(id, zanzarah, runeMenuEntity, IDOpenRunes); } protected override void HandleKeyDown(KeyCode key) { var runeMenuEntity = Set.GetEntities()[0]; base.HandleKeyDown(key); - if (key == KeyCode.KF3) { - runeMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KF4) { - runeMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KF5) { - runeMenuEntity.Dispose(); - zanzarah.UI.Publish(); - } - if (key == KeyCode.KReturn || key == KeyCode.KEscape || key == KeyCode.KF3) - Set.DisposeAll(); + HandleNavKeyDown(key, zanzarah, runeMenuEntity, IDOpenRunes); } } From 278ad8ea51c1120b8b2b9d28c18af0933299f348 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Wed, 11 Dec 2024 04:07:56 +0500 Subject: [PATCH 05/57] feat: deck pixie text & minor fixes * added pixie caught text in deck * moved save button by 1 pixel * use inherited BaseScreen.inventory in ScrDeck --- zzre/game/components/ui/ScrDeck.cs | 3 +-- zzre/game/systems/ui/InGameScreen.cs | 2 +- zzre/game/systems/ui/ScrDeck.cs | 37 +++++++++++++++------------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/zzre/game/components/ui/ScrDeck.cs b/zzre/game/components/ui/ScrDeck.cs index 9e9e20ea..99d4f0f3 100644 --- a/zzre/game/components/ui/ScrDeck.cs +++ b/zzre/game/components/ui/ScrDeck.cs @@ -1,4 +1,4 @@ -namespace zzre.game.components.ui; +namespace zzre.game.components.ui; public struct ScrDeck { @@ -14,7 +14,6 @@ public enum Tab public Tab ActiveTab; public bool IsGridMode; public int Scroll; - public Inventory Inventory; public DefaultEcs.Entity SummaryBackground; public DefaultEcs.Entity SpellBackground; public DefaultEcs.Entity ListSlider; diff --git a/zzre/game/systems/ui/InGameScreen.cs b/zzre/game/systems/ui/InGameScreen.cs index 86679dc4..7eb5e5db 100644 --- a/zzre/game/systems/ui/InGameScreen.cs +++ b/zzre/game/systems/ui/InGameScreen.cs @@ -38,7 +38,7 @@ public static void CreateTopButtons(UIBuilder preload, in DefaultEcs.Entity pare preload.CreateButton(parent) .With(IDSaveGame) - .With(Mid + new Vector2(384, 3)) + .With(Mid + new Vector2(385, 3)) .With(new components.ui.ButtonTiles(26, 27)) .With(UIPreloadAsset.Btn002) .WithTooltip(0x7113B8A1) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 991b1fc9..ed1336b6 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -59,7 +59,6 @@ protected override void HandleOpen(in messages.ui.OpenDeck message) var entity = World.CreateEntity(); entity.Set(); ref var deck = ref entity.Get(); - deck.Inventory = inventory; deck.DeckSlotParents = []; CreateBackgrounds(entity, ref deck); @@ -76,23 +75,23 @@ private void CreateBackgrounds(DefaultEcs.Entity entity, ref components.ui.ScrDe preload.CreateFullBackOverlay(entity); preload.CreateImage(entity) - .With(-new Vector2(52, 240)) + .With(Mid + new Vector2(268, 0)) .WithBitmap("dec000") .WithRenderOrder(1) .Build(); deck.SpellBackground = preload.CreateImage(entity) - .With(-new Vector2(320, 240)) + .With(Mid) .WithBitmap("dec001") .WithRenderOrder(1); deck.SummaryBackground = preload.CreateImage(entity) - .With(-new Vector2(320, 240)) + .With(Mid) .WithBitmap("dec002") .WithRenderOrder(1); preload.CreateTooltipTarget(entity) - .With(new Vector2(-320 + 11, -240 + 11)) + .With(Mid + new Vector2(11, 11)) .WithText("{205} - ") .Build(); } @@ -159,14 +158,18 @@ private void CreateListControls(DefaultEcs.Entity entity, ref components.ui.ScrD .WithTooltip(0xA086B911) .Build(); - // TODO: Add pixie count label + preload.CreateLabel(entity) + .With(Mid + new Vector2(337, 42)) + .With(UIPreloadAsset.Fnt002) + .WithText($"{zanzarah.OverworldGame!.GetTag().pixiesCatched}/30") + .Build(); } private void CreateFairySlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { for (int i = 0; i < Inventory.FairySlotCount; i++) { - var fairy = deck.Inventory.GetFairyAtSlot(i); + var fairy = inventory.GetFairyAtSlot(i); var fairyI = fairy?.cardId.EntityId ?? -1; preload.CreateButton(entity) .With(FirstFairySlot + i) @@ -211,10 +214,10 @@ private void CreateSpellSlots(DefaultEcs.Entity entity, ref components.ui.ScrDec var nextElementId = FirstSpellSlot; for (int fairyI = 0; fairyI < Inventory.FairySlotCount; fairyI++) { - var fairy = deck.Inventory.GetFairyAtSlot(fairyI); + var fairy = inventory.GetFairyAtSlot(fairyI); for (int spellI = 0; spellI < InventoryFairy.SpellSlotCount; spellI++) { - var spell = fairy == null ? null : deck.Inventory.GetSpellAtSlot(fairy, spellI); + var spell = fairy == null ? null : inventory.GetSpellAtSlot(fairy, spellI); preload.CreateButton(deck.DeckSlotParents[fairyI]) .With(nextElementId) .With(DeckSlotPos(fairyI, spellI)) @@ -261,7 +264,7 @@ private void CreateFairyInfo(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck.DeckSlotParents[fairyI].Dispose(); var slotParent = deck.DeckSlotParents[fairyI] = World.CreateEntity(); slotParent.Set(new components.Parent(entity)); - var fairy = deck.Inventory.GetFairyAtSlot(fairyI); + var fairy = inventory.GetFairyAtSlot(fairyI); if (fairy == null) return; @@ -273,7 +276,7 @@ private void CreateFairyInfo(DefaultEcs.Entity entity, ref components.ui.ScrDeck .WithTooltip(UIDFairyInfoDescriptions[slotI]) .Build(); - var spell = deck.Inventory.GetSpellAtSlot(fairy, slotI); + var spell = inventory.GetSpellAtSlot(fairy, slotI); if (spell == null) continue; preload.CreateLabel(slotParent) @@ -286,7 +289,7 @@ private void CreateFairyInfo(DefaultEcs.Entity entity, ref components.ui.ScrDeck preload.CreateLabel(slotParent) .With(DeckSlotPos(fairyI, 0)) .With(UIPreloadAsset.Fnt002) - .WithText(FormatSummary(deck.Inventory, fairy)) + .WithText(FormatSummary(inventory, fairy)) .Build(); } @@ -439,12 +442,12 @@ private void CreateGridList(DefaultEcs.Entity entity, ref components.ui.ScrDeck private IEnumerable AllCardsOfType(in components.ui.ScrDeck deck) => deck.ActiveTab switch { - Tab.Items => deck.Inventory.Items + Tab.Items => inventory.Items .OrderBy(c => mappedDB.GetItem(c.dbUID).Unknown switch { 1 => 0, 0 => 1, _ => 2 }) .ThenBy(c => c.cardId.EntityId), - Tab.Fairies => deck.Inventory.Fairies.OrderByDescending(c => c.level), - Tab.AttackSpells => deck.Inventory.AttackSpells.OrderBy(c => c.cardId.EntityId), - Tab.SupportSpells => deck.Inventory.SupportSpells.OrderBy(c => c.cardId.EntityId), + Tab.Fairies => inventory.Fairies.OrderByDescending(c => c.level), + Tab.AttackSpells => inventory.AttackSpells.OrderBy(c => c.cardId.EntityId), + Tab.SupportSpells => inventory.SupportSpells.OrderBy(c => c.cardId.EntityId), _ => [] }; @@ -482,7 +485,7 @@ private void FillList(ref components.ui.ScrDeck deck) { InventoryItem item => FormatSummary(item), InventorySpell spell => FormatSummary(spell), - InventoryFairy fairy => FormatSummary(deck.Inventory, fairy), + InventoryFairy fairy => FormatSummary(inventory, fairy), _ => throw new NotSupportedException("Unknown inventory card type") }; deck.ListSummaries[i].Set(new components.ui.Label(summary)); From 642592b0b2c9edba4ea1461e55b0ff569af1446c Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 12 Dec 2024 02:21:10 +0500 Subject: [PATCH 06/57] feat: deck stats on card hover --- zzre/game/components/ui/CardButton.cs | 5 + zzre/game/components/ui/ScrDeck.cs | 6 +- zzre/game/systems/ui/ScrDeck.cs | 129 +++++++++++++++++++++++++- 3 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 zzre/game/components/ui/CardButton.cs diff --git a/zzre/game/components/ui/CardButton.cs b/zzre/game/components/ui/CardButton.cs new file mode 100644 index 00000000..631dda6f --- /dev/null +++ b/zzre/game/components/ui/CardButton.cs @@ -0,0 +1,5 @@ +using zzio; + +namespace zzre.game.components.ui; + +public record struct CardButton(InventoryCard card); diff --git a/zzre/game/components/ui/ScrDeck.cs b/zzre/game/components/ui/ScrDeck.cs index 99d4f0f3..d0e480bd 100644 --- a/zzre/game/components/ui/ScrDeck.cs +++ b/zzre/game/components/ui/ScrDeck.cs @@ -17,10 +17,14 @@ public enum Tab public DefaultEcs.Entity SummaryBackground; public DefaultEcs.Entity SpellBackground; public DefaultEcs.Entity ListSlider; - public DefaultEcs.Entity FairyHoverSummary; public DefaultEcs.Entity[] ListTabs; public DefaultEcs.Entity[] ListButtons; public DefaultEcs.Entity[] ListUsedMarkers; public DefaultEcs.Entity[] ListSummaries; public DefaultEcs.Entity[] DeckSlotParents; + public DefaultEcs.Entity LastHovered; + public DefaultEcs.Entity StatsTitle; + public DefaultEcs.Entity StatsDescriptions; + public DefaultEcs.Entity StatsLights; + public DefaultEcs.Entity StatsLevel; } diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index ed1336b6..0383c255 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -30,6 +30,13 @@ public partial class ScrDeck : BaseScreen UIBuilder.GetLightsIndicator(stat))), + $"Level: {UIBuilder.GetSpellPrices(spellRow)}", + ]; + } + else + { + return [ + spellRow.Name, + $"{mappedDB.GetText(UIDStatNames[1]).Text}:\n{spellRow.Info}", + spellRow.Mana != 5 ? UIBuilder.GetLightsIndicator(spellRow.Mana + 1) : "-", + $"Level: {UIBuilder.GetSpellPrices(spellRow)}", + ]; + } + } + + private string[] FormatStats(InventoryCard card) + => card.cardId.Type switch + { + CardType.Item => FormatStats((InventoryItem)card), + CardType.Spell => FormatStats((InventorySpell)card), + CardType.Fairy => FormatStats((InventoryFairy)card), + _ => throw new ArgumentException($"Invalid inventory card type: {card.cardId.Type}") + }; + + private void CreateStats(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + { + ResetStats(ref deck); + var card = deck.LastHovered.Get().card; + var summary = FormatStats(card); + + deck.StatsTitle = preload.CreateLabel(entity) + .With(Mid + new Vector2(320, 350)) + .With(UIPreloadAsset.Fnt000) + .WithText(summary[0]) + .Build(); + deck.StatsDescriptions = preload.CreateLabel(entity) + .With(Mid + new Vector2(330, 379)) + .With(UIPreloadAsset.Fnt002) + .WithText(summary[1]) + .WithLineWrap(260f) + .Build(); + deck.StatsLights = preload.CreateLabel(entity) + .With(Mid + new Vector2(380, 379)) + .With(UIPreloadAsset.Fnt002) + .WithText(summary[2]) + .Build(); + deck.StatsLevel = preload.CreateLabel(entity) + .With(Mid + new Vector2(473, 379)) + .With(UIPreloadAsset.Fnt002) + .WithText(summary[3]) + .Build(); + } + private static bool IsInfoTab(Tab tab) => tab == Tab.Fairies || tab == Tab.Items; private static bool IsSpellTab(Tab tab) => tab == Tab.AttackSpells || tab == Tab.SupportSpells; @@ -572,6 +683,22 @@ protected override void Update( deck.Scroll = newScrollI; FillList(ref deck); } + + var curHovered = World.Has() + ? World.Get() + : default; + if (curHovered.Entity == deck.LastHovered) + return; + if (deck.LastHovered != default) + { + deck.LastHovered = default; + ResetStats(ref deck); + } + if (deck.ListButtons.Contains(curHovered.Entity)) + { + deck.LastHovered = curHovered.Entity; + CreateStats(entity, ref deck); + } } protected override void HandleKeyDown(KeyCode key) From 930961cea878e6fe02b94fd38cab6e9b2d30204b Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 12 Dec 2024 03:37:25 +0500 Subject: [PATCH 07/57] fix: deck list mode switch button position --- zzre/game/systems/ui/ScrDeck.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 0383c255..07e0120f 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -159,7 +159,7 @@ private void CreateListControls(DefaultEcs.Entity entity, ref components.ui.ScrD preload.CreateButton(entity) .With(IDSwitchListMode) - .With(tabButtonRect.Min + new Vector2(15, 261)) + .With(tabButtonRect.Min + new Vector2(16, 261)) .With(new components.ui.ButtonTiles(28, 29)) .With(UIPreloadAsset.Btn002) .WithTooltip(0xA086B911) From 76929851f1d3c921eba5318e4e02d6e2c1987231 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 12 Dec 2024 14:11:45 +0500 Subject: [PATCH 08/57] fix: stats for blank buttons --- zzre/game/components/ui/CardButton.cs | 2 +- zzre/game/systems/ui/ScrDeck.cs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/zzre/game/components/ui/CardButton.cs b/zzre/game/components/ui/CardButton.cs index 631dda6f..38fe0d05 100644 --- a/zzre/game/components/ui/CardButton.cs +++ b/zzre/game/components/ui/CardButton.cs @@ -2,4 +2,4 @@ namespace zzre.game.components.ui; -public record struct CardButton(InventoryCard card); +public record struct CardButton(InventoryCard? card); diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 07e0120f..f8769406 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -482,6 +482,7 @@ private void FillList(ref components.ui.ScrDeck deck) for (; i < deck.ListButtons.Length; i++) { deck.ListButtons[i].Set(components.Visibility.Invisible); + deck.ListButtons[i].Set(new components.ui.CardButton()); deck.ListUsedMarkers[i].Set(components.Visibility.Invisible); } @@ -589,6 +590,9 @@ private void CreateStats(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec { ResetStats(ref deck); var card = deck.LastHovered.Get().card; + // Show empty stats for blank buttons + if (card == default) + return; var summary = FormatStats(card); deck.StatsTitle = preload.CreateLabel(entity) From 0089601159a0c346d9cc22bfd80f4dc1c4e70614 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 12 Dec 2024 15:22:17 +0500 Subject: [PATCH 09/57] feat: card tooltips --- zzre/game/systems/ui/ScrDeck.cs | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index f8769406..10bd3010 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -457,6 +457,31 @@ private void CreateGridList(DefaultEcs.Entity entity, ref components.ui.ScrDeck _ => [] }; + private components.ui.TooltipUID CardTooltip(InventoryItem item) + => mappedDB.GetItem(item.dbUID).Script.Length == 0 + ? new UID(0x8F4510A1) // item cannot be used + : new UID(0x75F10CA1); // select item + + private static components.ui.TooltipUID CardTooltip(InventoryFairy fairy) + => fairy.isInUse + ? new UID(0x9054EAB1) // fairy is in use + : new UID(0x00B500A1); // select fairy + + private components.ui.TooltipUID CardTooltip(InventorySpell spell) + => spell.isInUse + ? new UID(0x6B46EEB1) // spell is in use + : mappedDB.GetSpell(spell.dbUID).Type == 0 + ? new UID(0xDA2B08A1) // select offensive spell + : new UID(0x93840CA1); // select passive spell + + private components.ui.TooltipUID CardTooltip(InventoryCard card) => card.cardId.Type switch + { + CardType.Item => CardTooltip((InventoryItem)card), + CardType.Spell => CardTooltip((InventorySpell)card), + CardType.Fairy => CardTooltip((InventoryFairy)card), + _ => throw new ArgumentException($"Invalid inventory card type: {card.cardId.Type}") + }; + private void FillList(ref components.ui.ScrDeck deck) { var allCardsOfType = AllCardsOfType(deck); @@ -475,7 +500,8 @@ private void FillList(ref components.ui.ScrDeck deck) deck.ListButtons[i].Set(ListTileSheet(deck)); deck.ListButtons[i].Set(new components.ui.ButtonTiles(shownCards[i].cardId.EntityId)); deck.ListButtons[i].Set(new components.ui.CardButton(shownCards[i])); - deck.ListUsedMarkers[i].Set(shownCards[i].isInUse + deck.ListButtons[i].Set(CardTooltip(shownCards[i])); + deck.ListUsedMarkers[i].Set(shownCards[i].isInUse || shownCards[i].cardId.Type == CardType.Item && mappedDB.GetItem(shownCards[i].dbUID).Script.Length == 0 ? components.Visibility.Visible : components.Visibility.Invisible); } @@ -483,6 +509,8 @@ private void FillList(ref components.ui.ScrDeck deck) { deck.ListButtons[i].Set(components.Visibility.Invisible); deck.ListButtons[i].Set(new components.ui.CardButton()); + if (deck.ListButtons[i].Has()) + deck.ListButtons[i].Remove(); deck.ListUsedMarkers[i].Set(components.Visibility.Invisible); } From ee19acf8e47fc77fcd70d5452dfb8430ef2d2f6a Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 12 Dec 2024 20:24:16 +0500 Subject: [PATCH 10/57] feat: card dragging --- zzre/game/components/ui/ScrDeck.cs | 2 ++ zzre/game/systems/ui/ScrDeck.cs | 56 +++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 5 deletions(-) diff --git a/zzre/game/components/ui/ScrDeck.cs b/zzre/game/components/ui/ScrDeck.cs index d0e480bd..51f4c044 100644 --- a/zzre/game/components/ui/ScrDeck.cs +++ b/zzre/game/components/ui/ScrDeck.cs @@ -27,4 +27,6 @@ public enum Tab public DefaultEcs.Entity StatsDescriptions; public DefaultEcs.Entity StatsLights; public DefaultEcs.Entity StatsLevel; + public DefaultEcs.Entity DraggedCard; + public DefaultEcs.Entity DraggedOverlay; } diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 10bd3010..a1ce68e8 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -457,18 +457,26 @@ private void CreateGridList(DefaultEcs.Entity entity, ref components.ui.ScrDeck _ => [] }; + private bool IsClickable(InventoryCard card) => card.cardId.Type switch + { + CardType.Item => mappedDB.GetItem(card.dbUID).Script.Length != 0, + CardType.Spell => !card.isInUse, + CardType.Fairy => !card.isInUse, + _ => throw new ArgumentException($"Invalid inventory card type: {card.cardId.Type}") + }; + private components.ui.TooltipUID CardTooltip(InventoryItem item) - => mappedDB.GetItem(item.dbUID).Script.Length == 0 + => !IsClickable(item) ? new UID(0x8F4510A1) // item cannot be used : new UID(0x75F10CA1); // select item - private static components.ui.TooltipUID CardTooltip(InventoryFairy fairy) - => fairy.isInUse + private components.ui.TooltipUID CardTooltip(InventoryFairy fairy) + => !IsClickable(fairy) ? new UID(0x9054EAB1) // fairy is in use : new UID(0x00B500A1); // select fairy private components.ui.TooltipUID CardTooltip(InventorySpell spell) - => spell.isInUse + => !IsClickable(spell) ? new UID(0x6B46EEB1) // spell is in use : mappedDB.GetSpell(spell.dbUID).Type == 0 ? new UID(0xDA2B08A1) // select offensive spell @@ -501,7 +509,7 @@ private void FillList(ref components.ui.ScrDeck deck) deck.ListButtons[i].Set(new components.ui.ButtonTiles(shownCards[i].cardId.EntityId)); deck.ListButtons[i].Set(new components.ui.CardButton(shownCards[i])); deck.ListButtons[i].Set(CardTooltip(shownCards[i])); - deck.ListUsedMarkers[i].Set(shownCards[i].isInUse || shownCards[i].cardId.Type == CardType.Item && mappedDB.GetItem(shownCards[i].dbUID).Script.Length == 0 + deck.ListUsedMarkers[i].Set(!IsClickable(shownCards[i]) ? components.Visibility.Visible : components.Visibility.Invisible); } @@ -692,6 +700,32 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El UpdateSliderPosition(deck); FillList(ref deck); } + else if (id >= FirstListCell && id < FirstListCell + deck.ListButtons.Length) + { + if (clickedEntity.TryGet(out components.ui.CardButton cardButton)) + { + if (cardButton.card != default && IsClickable(cardButton.card)) + { + var buttonTileSheet = ListTileSheet(deck); + if (deck.DraggedCard != default) deck.DraggedCard.Dispose(); + deck.DraggedCard = preload.CreateImage(deckEntity) + .With(Mid) + .With(cardButton.card.cardId) + .WithRenderOrder(-2) + .Build(); + deck.DraggedCard.Set(new components.ui.CardButton(cardButton.card)); + deck.DraggedCard.Set(components.ui.UIOffset.GameUpperLeft); + + if (deck.DraggedOverlay != default) deck.DraggedOverlay.Dispose(); + deck.DraggedOverlay = preload.CreateImage(deckEntity) + .With(Mid) + .With(UIPreloadAsset.Dnd000, 0) + .WithRenderOrder(-3) + .Build(); + deck.DraggedOverlay.Set(components.ui.UIOffset.GameUpperLeft); + } + } + } else HandleNavClick(id, zanzarah, deckEntity, IDOpenDeck); } @@ -702,6 +736,12 @@ private void UpdateSliderPosition(in components.ui.ScrDeck deck) slider = slider with { Current = Vector2.UnitY * Math.Clamp(deck.Scroll / (allCardsCount - 1f), 0, 1f) }; } + private void Drag(DefaultEcs.Entity entity) + { + var tiles = entity.Get(); + tiles[0].Rect = tiles[0].Rect with { Center = ui.CursorEntity.Get().Center }; + } + protected override void Update( float elapsedTime, in DefaultEcs.Entity entity, @@ -716,6 +756,12 @@ protected override void Update( FillList(ref deck); } + if (deck.DraggedCard != default) + { + Drag(deck.DraggedCard); + Drag(deck.DraggedOverlay); + } + var curHovered = World.Has() ? World.Get() : default; From e541342e7e580f61b744a3b7b5e73d1a12c8ce82 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 12 Dec 2024 21:10:21 +0500 Subject: [PATCH 11/57] refactor: drag card --- zzre/game/systems/ui/ScrDeck.cs | 57 +++++++++++++++++---------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index a1ce68e8..6452bdeb 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -457,7 +457,7 @@ private void CreateGridList(DefaultEcs.Entity entity, ref components.ui.ScrDeck _ => [] }; - private bool IsClickable(InventoryCard card) => card.cardId.Type switch + private bool IsDraggable(InventoryCard card) => card.cardId.Type switch { CardType.Item => mappedDB.GetItem(card.dbUID).Script.Length != 0, CardType.Spell => !card.isInUse, @@ -466,17 +466,17 @@ private void CreateGridList(DefaultEcs.Entity entity, ref components.ui.ScrDeck }; private components.ui.TooltipUID CardTooltip(InventoryItem item) - => !IsClickable(item) + => !IsDraggable(item) ? new UID(0x8F4510A1) // item cannot be used : new UID(0x75F10CA1); // select item private components.ui.TooltipUID CardTooltip(InventoryFairy fairy) - => !IsClickable(fairy) + => !IsDraggable(fairy) ? new UID(0x9054EAB1) // fairy is in use : new UID(0x00B500A1); // select fairy private components.ui.TooltipUID CardTooltip(InventorySpell spell) - => !IsClickable(spell) + => !IsDraggable(spell) ? new UID(0x6B46EEB1) // spell is in use : mappedDB.GetSpell(spell.dbUID).Type == 0 ? new UID(0xDA2B08A1) // select offensive spell @@ -509,7 +509,7 @@ private void FillList(ref components.ui.ScrDeck deck) deck.ListButtons[i].Set(new components.ui.ButtonTiles(shownCards[i].cardId.EntityId)); deck.ListButtons[i].Set(new components.ui.CardButton(shownCards[i])); deck.ListButtons[i].Set(CardTooltip(shownCards[i])); - deck.ListUsedMarkers[i].Set(!IsClickable(shownCards[i]) + deck.ListUsedMarkers[i].Set(!IsDraggable(shownCards[i]) ? components.Visibility.Visible : components.Visibility.Invisible); } @@ -674,6 +674,29 @@ private void OpenTab(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, T RecreateList(entity, ref deck); } + private void TryDragCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, InventoryCard card) + { + if (!IsDraggable(card)) return; + + var buttonTileSheet = ListTileSheet(deck); + if (deck.DraggedCard != default) deck.DraggedCard.Dispose(); + deck.DraggedCard = preload.CreateImage(entity) + .With(Mid) + .With(card.cardId) + .WithRenderOrder(-2) + .Build(); + deck.DraggedCard.Set(new components.ui.CardButton(card)); + deck.DraggedCard.Set(components.ui.UIOffset.GameUpperLeft); + + if (deck.DraggedOverlay != default) deck.DraggedOverlay.Dispose(); + deck.DraggedOverlay = preload.CreateImage(entity) + .With(Mid) + .With(UIPreloadAsset.Dnd000, 0) + .WithRenderOrder(-3) + .Build(); + deck.DraggedOverlay.Set(components.ui.UIOffset.GameUpperLeft); + } + private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.ElementId id) { var deckEntity = Set.GetEntities()[0]; @@ -703,28 +726,8 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El else if (id >= FirstListCell && id < FirstListCell + deck.ListButtons.Length) { if (clickedEntity.TryGet(out components.ui.CardButton cardButton)) - { - if (cardButton.card != default && IsClickable(cardButton.card)) - { - var buttonTileSheet = ListTileSheet(deck); - if (deck.DraggedCard != default) deck.DraggedCard.Dispose(); - deck.DraggedCard = preload.CreateImage(deckEntity) - .With(Mid) - .With(cardButton.card.cardId) - .WithRenderOrder(-2) - .Build(); - deck.DraggedCard.Set(new components.ui.CardButton(cardButton.card)); - deck.DraggedCard.Set(components.ui.UIOffset.GameUpperLeft); - - if (deck.DraggedOverlay != default) deck.DraggedOverlay.Dispose(); - deck.DraggedOverlay = preload.CreateImage(deckEntity) - .With(Mid) - .With(UIPreloadAsset.Dnd000, 0) - .WithRenderOrder(-3) - .Build(); - deck.DraggedOverlay.Set(components.ui.UIOffset.GameUpperLeft); - } - } + if (cardButton.card != default) + TryDragCard(deckEntity, ref deck, cardButton.card); } else HandleNavClick(id, zanzarah, deckEntity, IDOpenDeck); } From e32c25161999deb9ac7ba147d0c80122f20c4bb4 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 16 Dec 2024 03:26:12 +0500 Subject: [PATCH 12/57] refactor: deck: clean up Update --- zzre/game/systems/ui/ScrDeck.cs | 44 +++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 6452bdeb..4b847509 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -745,26 +745,8 @@ private void Drag(DefaultEcs.Entity entity) tiles[0].Rect = tiles[0].Rect with { Center = ui.CursorEntity.Get().Center }; } - protected override void Update( - float elapsedTime, - in DefaultEcs.Entity entity, - ref components.ui.ScrDeck deck) + private void TryStartDragging(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { - var slider = deck.ListSlider.Get(); - var allCardsCount = AllCardsOfType(deck).Count(); - var newScrollI = (int)MathF.Round(slider.Current.Y * (allCardsCount - 1) * (deck.IsGridMode ? ListRows : 1)); - if (newScrollI != deck.Scroll) - { - deck.Scroll = newScrollI; - FillList(ref deck); - } - - if (deck.DraggedCard != default) - { - Drag(deck.DraggedCard); - Drag(deck.DraggedOverlay); - } - var curHovered = World.Has() ? World.Get() : default; @@ -782,6 +764,30 @@ protected override void Update( } } + private void UpdateScroll(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + { + var slider = deck.ListSlider.Get(); + var allCardsCount = AllCardsOfType(deck).Count(); + var newScrollI = (int)MathF.Round(slider.Current.Y * (allCardsCount - 1) * (deck.IsGridMode ? ListRows : 1)); + if (newScrollI != deck.Scroll) + { + deck.Scroll = newScrollI; + FillList(ref deck); + } + } + + protected override void Update(float elapsedTime, in DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + { + TryStartDragging(entity, ref deck); + UpdateScroll(entity, ref deck); + + if (deck.DraggedCard != default) + { + Drag(deck.DraggedCard); + Drag(deck.DraggedOverlay); + } + } + protected override void HandleKeyDown(KeyCode key) { var deckEntity = Set.GetEntities()[0]; From 77bf2b81e370b158a53b475fb4bc88064f08bbbc Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 16 Dec 2024 17:45:34 +0500 Subject: [PATCH 13/57] refactor: ScrDeck by child entity --- zzre/game/components/ui/Card.cs | 15 + zzre/game/components/ui/CardButton.cs | 5 - zzre/game/components/ui/DraggedCard.cs | 5 + zzre/game/components/ui/ScrDeck.cs | 13 +- zzre/game/components/ui/SpellSlot.cs | 12 + zzre/game/systems/ui/ScrDeck.BaseCard.cs | 141 ++++++ zzre/game/systems/ui/ScrDeck.DeckCard.cs | 60 +++ zzre/game/systems/ui/ScrDeck.ListCard.cs | 71 +++ zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 112 +++++ zzre/game/systems/ui/ScrDeck.Summary.cs | 124 +++++ zzre/game/systems/ui/ScrDeck.cs | 561 +++------------------- 11 files changed, 618 insertions(+), 501 deletions(-) create mode 100644 zzre/game/components/ui/Card.cs delete mode 100644 zzre/game/components/ui/CardButton.cs create mode 100644 zzre/game/components/ui/DraggedCard.cs create mode 100644 zzre/game/components/ui/SpellSlot.cs create mode 100644 zzre/game/systems/ui/ScrDeck.BaseCard.cs create mode 100644 zzre/game/systems/ui/ScrDeck.DeckCard.cs create mode 100644 zzre/game/systems/ui/ScrDeck.ListCard.cs create mode 100644 zzre/game/systems/ui/ScrDeck.SpellSlot.cs create mode 100644 zzre/game/systems/ui/ScrDeck.Summary.cs diff --git a/zzre/game/components/ui/Card.cs b/zzre/game/components/ui/Card.cs new file mode 100644 index 00000000..b0425be6 --- /dev/null +++ b/zzre/game/components/ui/Card.cs @@ -0,0 +1,15 @@ +using zzio; + +namespace zzre.game.components.ui; + +public record struct Card +{ + public enum Type { DeckCard, ListCard } + public Type type; + public InventoryCard? card; + public DefaultEcs.Entity button; + public components.ui.ElementId buttonId; + public DefaultEcs.Entity usedMarker; + public DefaultEcs.Entity summary; + public DefaultEcs.Entity[] spellSlots; +}; diff --git a/zzre/game/components/ui/CardButton.cs b/zzre/game/components/ui/CardButton.cs deleted file mode 100644 index 38fe0d05..00000000 --- a/zzre/game/components/ui/CardButton.cs +++ /dev/null @@ -1,5 +0,0 @@ -using zzio; - -namespace zzre.game.components.ui; - -public record struct CardButton(InventoryCard? card); diff --git a/zzre/game/components/ui/DraggedCard.cs b/zzre/game/components/ui/DraggedCard.cs new file mode 100644 index 00000000..9166a59f --- /dev/null +++ b/zzre/game/components/ui/DraggedCard.cs @@ -0,0 +1,5 @@ +using zzio; + +namespace zzre.game.components.ui; + +public record struct DraggedCard(InventoryCard card); diff --git a/zzre/game/components/ui/ScrDeck.cs b/zzre/game/components/ui/ScrDeck.cs index 51f4c044..f03285aa 100644 --- a/zzre/game/components/ui/ScrDeck.cs +++ b/zzre/game/components/ui/ScrDeck.cs @@ -16,17 +16,18 @@ public enum Tab public int Scroll; public DefaultEcs.Entity SummaryBackground; public DefaultEcs.Entity SpellBackground; + + public DefaultEcs.Entity[] DeckCards; + public DefaultEcs.Entity[] TabButtons; + public DefaultEcs.Entity[] ListCards; public DefaultEcs.Entity ListSlider; - public DefaultEcs.Entity[] ListTabs; - public DefaultEcs.Entity[] ListButtons; - public DefaultEcs.Entity[] ListUsedMarkers; - public DefaultEcs.Entity[] ListSummaries; - public DefaultEcs.Entity[] DeckSlotParents; - public DefaultEcs.Entity LastHovered; + public DefaultEcs.Entity StatsTitle; public DefaultEcs.Entity StatsDescriptions; public DefaultEcs.Entity StatsLights; public DefaultEcs.Entity StatsLevel; + + public DefaultEcs.Entity LastHovered; public DefaultEcs.Entity DraggedCard; public DefaultEcs.Entity DraggedOverlay; } diff --git a/zzre/game/components/ui/SpellSlot.cs b/zzre/game/components/ui/SpellSlot.cs new file mode 100644 index 00000000..25da5a1d --- /dev/null +++ b/zzre/game/components/ui/SpellSlot.cs @@ -0,0 +1,12 @@ +using zzio; + +namespace zzre.game.components.ui; + +public record struct SpellSlot +{ + public InventorySpell? spell; + public int index; + public DefaultEcs.Entity button; + public DefaultEcs.Entity summary; + public DefaultEcs.Entity req; +}; diff --git a/zzre/game/systems/ui/ScrDeck.BaseCard.cs b/zzre/game/systems/ui/ScrDeck.BaseCard.cs new file mode 100644 index 00000000..1b521863 --- /dev/null +++ b/zzre/game/systems/ui/ScrDeck.BaseCard.cs @@ -0,0 +1,141 @@ +using System; +using System.Numerics; +using zzio; + +namespace zzre.game.systems.ui; + +public partial class ScrDeck +{ + private DefaultEcs.Entity CreateBaseCard( + DefaultEcs.Entity parent, + Vector2 pos, + components.ui.ElementId id + ) + { + var entity = World.CreateEntity(); + entity.Set(new components.Parent(parent)); + entity.Set(new components.ui.Card()); + ref var card = ref entity.Get(); + + card.buttonId = id; + card.button = preload.CreateButton(entity) + .With(id) + .With(pos) + .With(new components.ui.ButtonTiles(-1)) + .With(UIPreloadAsset.Wiz000) + .Build(); + + UnsetCard(ref card); + return entity; + } + + private void CreateCardSummary(DefaultEcs.Entity entity, Vector2 offset) + { + ref var card = ref entity.Get(); + card.summary = preload.CreateLabel(entity) + .With(card.button.Get().Min + offset) + .With(UIPreloadAsset.Fnt002); + } + + private static UITileSheetAsset.Info TileSheet(CardId cardId) => cardId.Type switch + { + CardType.Fairy => UIPreloadAsset.Wiz000, + CardType.Item => UIPreloadAsset.Itm000, + CardType.Spell => UIPreloadAsset.Spl000, + _ => throw new NotSupportedException("Unknown inventory card type") + }; + + private void ChangeTileSheet(DefaultEcs.Entity entity, UITileSheetAsset.Info tileSheetInfo) + { + // This is probably highly inefficient? + preload.UI.GetTag().LoadUITileSheet(entity, tileSheetInfo); + } + + private void SetCard(ref components.ui.Card card, InventoryCard invCard) + { + card.card = invCard; + card.button.Set(components.Visibility.Visible); + ChangeTileSheet(card.button, TileSheet(invCard.cardId)); + card.button.Set(new components.ui.ButtonTiles(invCard.cardId.EntityId)); + card.button.Set(CardTooltip(invCard)); + + if (card.summary != default) + card.summary.Set(new components.ui.Label(card.card switch + { + InventoryItem item => FormatSummary(item), + InventorySpell spell => FormatSummary(spell), + InventoryFairy fairy => FormatSummary(fairy), + _ => throw new NotSupportedException("Unknown inventory card type") + })); + } + + private static void UnsetCard(ref components.ui.Card card) + { + card.card = default; + card.button.Set(components.Visibility.Invisible); + if (card.button.Has()) + card.button.Remove(); + if (card.usedMarker != default) + card.usedMarker.Set(components.Visibility.Invisible); + if (card.summary != default) + card.summary.Set(new components.ui.Label("")); + } + + private string FormatSummary(InventoryFairy fairy) + { + var builder = new System.Text.StringBuilder(); + builder.Append(fairy.name); + builder.Append(' '); + + builder.Append(fairy.status switch + { + ZZPermSpellStatus.Poisoned => "{110}", + ZZPermSpellStatus.Cursed => "{111}", + ZZPermSpellStatus.Burned => "{115}", + ZZPermSpellStatus.Frozen => "{114}", + ZZPermSpellStatus.Silenced => "{112}", + _ => "" + }); + builder.Append('\n'); + + builder.Append("{100}"); + builder.Append(fairy.currentMHP); + builder.Append('/'); + builder.Append(fairy.maxMHP); + if (fairy.currentMHP < 100) + builder.Append(' '); + if (fairy.currentMHP < 10) + builder.Append(' '); + if (fairy.maxMHP < 100) + builder.Append(' '); + // no second space for maxMHP + + builder.Append(" L-"); + builder.Append(fairy.level); + if (fairy.level < 10) + builder.Append(' '); + + builder.Append(" {101}"); + builder.Append(fairy.xp); + var levelupXP = inventory.GetLevelupXP(fairy); + if (levelupXP.HasValue) + { + builder.Append("{105}"); + builder.Append(levelupXP.Value + 1); + } + + return builder.ToString(); + } + + private string FormatSummary(InventoryItem item) => item.amount > 1 + ? $"{item.amount} x {mappedDB.GetItem(item.dbUID).Name}" + : mappedDB.GetItem(item.dbUID).Name; + + private string FormatSummary(InventorySpell spell) + { + var dbSpell = mappedDB.GetSpell(spell.dbUID); + var mana = dbSpell.Mana == 5 ? "-/-" : $"{spell.mana}/{dbSpell.MaxMana}"; + return $"{dbSpell.Name}\n{{104}}{mana} {UIBuilder.GetSpellPrices(dbSpell)}"; + } + +} diff --git a/zzre/game/systems/ui/ScrDeck.DeckCard.cs b/zzre/game/systems/ui/ScrDeck.DeckCard.cs new file mode 100644 index 00000000..1497af98 --- /dev/null +++ b/zzre/game/systems/ui/ScrDeck.DeckCard.cs @@ -0,0 +1,60 @@ +using System; +using System.Numerics; +using zzio; + +namespace zzre.game.systems.ui; + +public partial class ScrDeck +{ + private static readonly UID UIDSelectFairy = new(0x41912581); + private static readonly UID UIDPlaceFairy = new(0x41912581); + private static readonly UID UIDReplaceFairy = new(0x41912581); + private static readonly UID UIDUseItemOnFairy = new(0x41912581); + + private DefaultEcs.Entity CreateDeckCard( + DefaultEcs.Entity parent, + Vector2 pos, + components.ui.ElementId id + ) + { + var entity = CreateBaseCard(parent, pos, id); + ref var card = ref entity.Get(); + + CreateCardSummary(entity, new(48, 4)); + + card.spellSlots = new DefaultEcs.Entity[4]; + for (int i = 0; i < InventoryFairy.SpellSlotCount; i++) + card.spellSlots[i] = CreateSpellSlot(entity, ref card, i); + + return entity; + } + + private void SetDeckCard(DefaultEcs.Entity entity, InventoryCard invCard) + { + ref var card = ref entity.Get(); + SetCard(ref card, invCard); + card.button.Set(new components.ui.TooltipUID(UIDSelectFairy)); + } + + private void InfoMode(ref components.ui.Card card) + { + if (card.card != default) + card.summary.Set(new components.ui.Label(card.card switch + { + InventoryItem item => FormatSummary(item), + InventorySpell spell => FormatSummary(spell), + InventoryFairy fairy => FormatSummary(fairy), + _ => throw new NotSupportedException("Unknown inventory card type") + })); + foreach (var slot in card.spellSlots) + InfoMode(ref slot.Get()); + } + + private static void SpellMode(ref components.ui.Card card) + { + card.summary.Set(new components.ui.Label("")); + foreach (var slot in card.spellSlots) + SpellMode(ref slot.Get()); + } + +} diff --git a/zzre/game/systems/ui/ScrDeck.ListCard.cs b/zzre/game/systems/ui/ScrDeck.ListCard.cs new file mode 100644 index 00000000..4b0b6557 --- /dev/null +++ b/zzre/game/systems/ui/ScrDeck.ListCard.cs @@ -0,0 +1,71 @@ +using System; +using System.Numerics; +using zzio; + +namespace zzre.game.systems.ui; + +public partial class ScrDeck +{ + + private DefaultEcs.Entity CreateListCard( + DefaultEcs.Entity parent, + Vector2 pos, + components.ui.ElementId id + ) + { + var entity = CreateBaseCard(parent, pos, id); + ref var card = ref entity.Get(); + + card.usedMarker = preload.CreateImage(entity) + .With(pos) + .With(UIPreloadAsset.Inf000, 16) + .WithRenderOrder(-1) + .Invisible() + .Build(); + + return entity; + } + + private void SetListCard(DefaultEcs.Entity entity, InventoryCard invCard) + { + ref var card = ref entity.Get(); + SetCard(ref card, invCard); + card.usedMarker.Set(!IsDraggable(invCard) + ? components.Visibility.Visible + : components.Visibility.Invisible); + card.button.Set(CardTooltip(invCard)); + } + + private bool IsDraggable(InventoryCard card) => card.cardId.Type switch + { + CardType.Item => mappedDB.GetItem(card.dbUID).Script.Length != 0, + CardType.Spell => !card.isInUse, + CardType.Fairy => !card.isInUse, + _ => throw new ArgumentException($"Invalid inventory card type: {card.cardId.Type}") + }; + + private components.ui.TooltipUID CardTooltip(InventoryItem item) + => !IsDraggable(item) + ? new UID(0x8F4510A1) // item cannot be used + : new UID(0x75F10CA1); // select item + + private components.ui.TooltipUID CardTooltip(InventoryFairy fairy) + => !IsDraggable(fairy) + ? new UID(0x9054EAB1) // fairy is in use + : new UID(0x00B500A1); // select fairy + + private components.ui.TooltipUID CardTooltip(InventorySpell spell) + => !IsDraggable(spell) + ? new UID(0x6B46EEB1) // spell is in use + : mappedDB.GetSpell(spell.dbUID).Type == 0 + ? new UID(0xDA2B08A1) // select offensive spell + : new UID(0x93840CA1); // select passive spell + + private components.ui.TooltipUID CardTooltip(InventoryCard card) => card.cardId.Type switch + { + CardType.Item => CardTooltip((InventoryItem)card), + CardType.Spell => CardTooltip((InventorySpell)card), + CardType.Fairy => CardTooltip((InventoryFairy)card), + _ => throw new ArgumentException($"Invalid inventory card type: {card.cardId.Type}") + }; +} diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs new file mode 100644 index 00000000..47321b1a --- /dev/null +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -0,0 +1,112 @@ +using System.Numerics; +using System.Linq; +using zzio; + +namespace zzre.game.systems.ui; + +public partial class ScrDeck +{ + private static readonly UID[] UIDSpellSlotNames = + [ + new(0x37697321), // First offensive slot + new(0x8A717321), // First defensive slot + new(0x0F207721), // Second offensive slot + new(0x5C577721) // Second defensive slot + ]; + + private static readonly UID[] UIDFairyInfoDescriptions = + [ + new(0x45B032A1), // Current and max HP + new(0xE58236A1), // Level of your fairy + new(0xB26B36A1), // XP, current and necessary for next level + new(0xB26B36A1) + ]; + + private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref components.ui.Card card, int index) + { + var entity = World.CreateEntity(); + entity.Set(new components.Parent(parent)); + entity.Set(new components.ui.SpellSlot()); + ref var spell = ref entity.Get(); + spell.index = index; + + spell.button = preload.CreateButton(entity) + .With(card.buttonId + index + 1) + .With(card.button.Get().Min + new Vector2(81 + 46 * spell.index)) + .With(new components.ui.ButtonTiles(-1)) + .With(UIPreloadAsset.Spl000) + // .WithTooltip(UIDSpellSlotNames[i]) + .Build(); + + InfoMode(ref spell); + + return entity; + } + + public void SetSpell(DefaultEcs.Entity entity, ref components.ui.SpellSlot spell, InventorySpell invSpell) + { + spell.spell = invSpell; + spell.button.Set(new components.ui.ButtonTiles(invSpell.cardId.EntityId)); + if (spell.summary != default) spell.summary.Dispose(); + spell.summary = preload.CreateLabel(entity) + .With(spell.button.Get().Min + new Vector2(0, 44)) + .With(UIPreloadAsset.Fnt002) + .WithText(FormatManaAmount(spell.spell)) + .Build(); + if (spell.req != default) spell.req.Dispose(); + spell.req = CreateSpellReq( + entity, + ((InventoryFairy)(entity.Get().Entity.Get().card!)).spellReqs[spell.index], + (spell.index % 2) == 0, + spell.button.Get().Min + new Vector2(2, 45) + ); + } + + public static void InfoMode(ref components.ui.SpellSlot spell) + { + spell.button.Set(components.Visibility.Invisible); + spell.button.Set(new components.ui.TooltipUID(UIDFairyInfoDescriptions[spell.index])); + if (spell.summary != default) + spell.summary.Set(components.Visibility.Visible); + if (spell.req != default) + spell.req.Set(components.Visibility.Invisible); + } + + public static void SpellMode(ref components.ui.SpellSlot spell) + { + spell.button.Set(components.Visibility.Visible); + spell.button.Set(new components.ui.TooltipUID(UIDSpellSlotNames[spell.index])); + if (spell.summary != default) + spell.summary.Set(components.Visibility.Invisible); + if (spell.req != default) + spell.req.Set(components.Visibility.Visible); + } + + private DefaultEcs.Entity CreateSpellReq(DefaultEcs.Entity parent, SpellReq spellReq, bool isAttack, Vector2 pos) + { + var entity = World.CreateEntity(); + entity.Set(new components.Parent(parent)); + entity.Set(components.Visibility.Visible); + entity.Set(components.ui.UIOffset.Center); + entity.Set(IColor.White); + assetRegistry.LoadUITileSheet(entity, isAttack ? UIPreloadAsset.Cls001 : UIPreloadAsset.Cls000); + + var tileSize = entity.Get().GetPixelSize(0); + entity.Set(Rect.FromTopLeftSize(pos, tileSize * 3)); + entity.Set(spellReq.Select((req, i) => new components.ui.Tile( + TileId: (int)req, + Rect: Rect.FromTopLeftSize(pos + i * new Vector2(8, 5), tileSize))) + .ToArray()); + + return entity; + } + + private string FormatManaAmount(InventorySpell spell) + { + var dbSpell = mappedDB.GetSpell(spell.dbUID); + return dbSpell.MaxMana == 5 + ? "{104}-" + : $"{{104}}{spell.mana}/{dbSpell.MaxMana}"; + } + +} diff --git a/zzre/game/systems/ui/ScrDeck.Summary.cs b/zzre/game/systems/ui/ScrDeck.Summary.cs new file mode 100644 index 00000000..b4408b85 --- /dev/null +++ b/zzre/game/systems/ui/ScrDeck.Summary.cs @@ -0,0 +1,124 @@ +using System; +using System.Numerics; +using System.Linq; +using zzio; +using static zzre.game.systems.ui.InGameScreen; + +namespace zzre.game.systems.ui; + +public partial class ScrDeck +{ + private static readonly UID[] UIDStatNames = + [ + new(0xE946ECA1), // Damage + new(0x238A3981), // Mana + new(0x04211121), // Fire Rate + ]; + + private void CreateStats(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + { + ResetStats(ref deck); + var card = deck.LastHovered.Get().card; + // Show empty stats for blank buttons + if (card == default) + return; + var summary = FormatStats(card); + + deck.StatsTitle = preload.CreateLabel(entity) + .With(Mid + new Vector2(320, 350)) + .With(UIPreloadAsset.Fnt000) + .WithText(summary[0]) + .Build(); + deck.StatsDescriptions = preload.CreateLabel(entity) + .With(Mid + new Vector2(330, 379)) + .With(UIPreloadAsset.Fnt002) + .WithText(summary[1]) + .WithLineWrap(260f) + .Build(); + deck.StatsLights = preload.CreateLabel(entity) + .With(Mid + new Vector2(380, 379)) + .With(UIPreloadAsset.Fnt002) + .WithText(summary[2]) + .Build(); + deck.StatsLevel = preload.CreateLabel(entity) + .With(Mid + new Vector2(473, 379)) + .With(UIPreloadAsset.Fnt002) + .WithText(summary[3]) + .Build(); + } + + private static void ResetStats(ref components.ui.ScrDeck deck) + { + var allEntities = new[] + { + deck.StatsTitle, + deck.StatsDescriptions, + deck.StatsLights, + deck.StatsLevel + }; + foreach (var entity in allEntities) + if (entity != default) + entity.Dispose(); + deck.StatsTitle = + deck.StatsDescriptions = + deck.StatsLights = + deck.StatsLevel = default; + } + + private string[] FormatStats(InventoryFairy fairy) + { + var fairyRow = mappedDB.GetFairy(fairy.dbUID); + return [fairy.name, fairyRow.Info, "", ""]; + } + + private string[] FormatStats(InventoryItem item) + { + var itemRow = mappedDB.GetItem(item.dbUID); + var count = item.amount != 1 ? $"{{5*x{item.amount}}}" : ""; + return [$"{itemRow.Name} {count}", itemRow.Info, "", ""]; + } + + private string[] FormatStats(InventorySpell spell) + { + var spellRow = mappedDB.GetSpell(spell.dbUID); + if (spellRow.Type == 0) + { + var stats = new[] { + spellRow.Damage + 1, + spellRow.Mana + 1, + spellRow.Loadup + 1, + }; + var descs = new[] { + mappedDB.GetText(UIDStatNames[0]).Text, + mappedDB.GetText(UIDStatNames[1]).Text, + mappedDB.GetText(UIDStatNames[2]).Text, + spellRow.Info, + }; + return [ + spellRow.Name, + String.Join(":\n", descs), + String.Join("\n", stats.Select(stat => UIBuilder.GetLightsIndicator(stat))), + $"Level: {UIBuilder.GetSpellPrices(spellRow)}", + ]; + } + else + { + return [ + spellRow.Name, + $"{mappedDB.GetText(UIDStatNames[1]).Text}:\n{spellRow.Info}", + spellRow.Mana != 5 ? UIBuilder.GetLightsIndicator(spellRow.Mana + 1) : "-", + $"Level: {UIBuilder.GetSpellPrices(spellRow)}", + ]; + } + } + + private string[] FormatStats(InventoryCard card) + => card.cardId.Type switch + { + CardType.Item => FormatStats((InventoryItem)card), + CardType.Spell => FormatStats((InventorySpell)card), + CardType.Fairy => FormatStats((InventoryFairy)card), + _ => throw new ArgumentException($"Invalid inventory card type: {card.cardId.Type}") + }; + +} diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 4b847509..b5b331ce 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Numerics; using System.Collections.Generic; using System.Linq; @@ -14,29 +14,6 @@ public partial class ScrDeck : BaseScreen Tabs = + [ + new(Tab.Fairies, IDTabFairies, PosY: 79, TileNormal: 0, TileHovered: 1, TileActive: 2, TooltipUID: new(0x7DB4EEB1)), + new(Tab.Items, IDTabItems, PosY: 123, TileNormal: 3, TileHovered: 4, TileActive: 5, TooltipUID: new(0x93530331)), + new(Tab.AttackSpells, IDTabAttackSpells, PosY: 167, TileNormal: 6, TileHovered: 7, TileActive: 8, TooltipUID: new(0xB5E80331)), + new(Tab.SupportSpells, IDTabSupportSpells, PosY: 211, TileNormal: 9, TileHovered: 10, TileActive: 11, TooltipUID: new(0x9D0DAD11)), + ]; + private readonly IAssetRegistry assetRegistry; private readonly zzio.db.MappedDB mappedDB; @@ -66,12 +58,11 @@ protected override void HandleOpen(in messages.ui.OpenDeck message) var entity = World.CreateEntity(); entity.Set(); ref var deck = ref entity.Get(); - deck.DeckSlotParents = []; CreateBackgrounds(entity, ref deck); CreateListControls(entity, ref deck); CreateTopButtons(preload, entity, inventory, IDOpenDeck); - CreateFairySlots(entity, ref deck); + CreateDeckCards(entity, ref deck); if (deck.ActiveTab == Tab.None) OpenTab(entity, ref deck, Tab.Fairies); @@ -101,6 +92,12 @@ private void CreateBackgrounds(DefaultEcs.Entity entity, ref components.ui.ScrDe .With(Mid + new Vector2(11, 11)) .WithText("{205} - ") .Build(); + + preload.CreateLabel(entity) + .With(Mid + new Vector2(337, 42)) + .With(UIPreloadAsset.Fnt002) + .WithText($"{zanzarah.OverworldGame!.GetTag().pixiesCatched}/30") + .Build(); } private void CreateListControls(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) @@ -126,36 +123,16 @@ private void CreateListControls(DefaultEcs.Entity entity, ref components.ui.ScrD .With(UIPreloadAsset.Btn001); deck.ListSlider.Set(components.ui.Slider.Vertical); - deck.ListTabs = new DefaultEcs.Entity[4]; + deck.TabButtons = new DefaultEcs.Entity[4]; var tabButtonRect = Rect.FromTopLeftSize(Mid + new Vector2(281, 0f), new Vector2(35, 35)); - deck.ListTabs[(int)Tab.Fairies - 1] = preload.CreateButton(entity) - .With(IDTabFairies) - .With(tabButtonRect.OffsettedBy(0, 79)) - .With(new components.ui.ButtonTiles(0, 1, 2)) - .With(UIPreloadAsset.Btn002) - .WithTooltip(0x7DB4EEB1); - - deck.ListTabs[(int)Tab.Items - 1] = preload.CreateButton(entity) - .With(IDTabItems) - .With(tabButtonRect.OffsettedBy(0, 123)) - .With(new components.ui.ButtonTiles(3, 4, 5)) - .With(UIPreloadAsset.Btn002) - .WithTooltip(0x93530331); - - deck.ListTabs[(int)Tab.AttackSpells - 1] = preload.CreateButton(entity) - .With(IDTabAttackSpells) - .With(tabButtonRect.OffsettedBy(0, 167)) - .With(new components.ui.ButtonTiles(6, 7, 8)) - .With(UIPreloadAsset.Btn002) - .WithTooltip(0xB5E80331); - - deck.ListTabs[(int)Tab.SupportSpells - 1] = preload.CreateButton(entity) - .With(IDTabSupportSpells) - .With(tabButtonRect.OffsettedBy(0, 211)) - .With(new components.ui.ButtonTiles(9, 10, 11)) - .With(UIPreloadAsset.Btn002) - .WithTooltip(0x9D0DAD11); + foreach (var tab in Tabs) + deck.TabButtons[(int)tab.Type - 1] = preload.CreateButton(entity) + .With(tab.Id) + .With(tabButtonRect.OffsettedBy(0, tab.PosY)) + .With(new components.ui.ButtonTiles(tab.TileNormal, tab.TileHovered, tab.TileActive)) + .With(UIPreloadAsset.Btn002) + .WithTooltip(tab.TooltipUID); preload.CreateButton(entity) .With(IDSwitchListMode) @@ -164,288 +141,65 @@ private void CreateListControls(DefaultEcs.Entity entity, ref components.ui.ScrD .With(UIPreloadAsset.Btn002) .WithTooltip(0xA086B911) .Build(); - - preload.CreateLabel(entity) - .With(Mid + new Vector2(337, 42)) - .With(UIPreloadAsset.Fnt002) - .WithText($"{zanzarah.OverworldGame!.GetTag().pixiesCatched}/30") - .Build(); } - private void CreateFairySlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + private void CreateDeckCards(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { + deck.DeckCards = new DefaultEcs.Entity[Inventory.FairySlotCount]; for (int i = 0; i < Inventory.FairySlotCount; i++) { + deck.DeckCards[i] = CreateDeckCard(entity, Mid + new Vector2(31, 60 + 79 * i), FirstFairySlot + i); var fairy = inventory.GetFairyAtSlot(i); - var fairyI = fairy?.cardId.EntityId ?? -1; - preload.CreateButton(entity) - .With(FirstFairySlot + i) - .With(Mid + new Vector2(31, 60 + 79 * i)) - .With(new components.ui.ButtonTiles(fairyI)) - .With(UIPreloadAsset.Wiz000) - .WithTooltip(UIDChooseFairyToSwap) - .Build(); + if (fairy != default) + SetDeckCard(deck.DeckCards[i], fairy); } } - private void ResetDeckSlotParents(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, bool createNewEntities) - { - foreach (var oldParent in deck.DeckSlotParents) - oldParent.Dispose(); - - if (createNewEntities) - { - deck.DeckSlotParents = Enumerable - .Repeat(0, Inventory.FairySlotCount) - .Select(_ => - { - var slotParent = World.CreateEntity(); - slotParent.Set(new components.Parent(entity)); - return slotParent; - }) - .ToArray(); - } - else - deck.DeckSlotParents = new DefaultEcs.Entity[Inventory.FairySlotCount]; - } - - private static Vector2 DeckSlotPos(int fairyI, int slotI) => + private static Vector2 DeckCardPos(int fairyI, int slotI) => Mid + new Vector2(81 + 46 * slotI, 60 + 79 * fairyI); - private void CreateSpellSlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + private static void SpellMode(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { deck.SpellBackground.Set(components.Visibility.Visible); deck.SummaryBackground.Set(components.Visibility.Invisible); - - ResetDeckSlotParents(entity, ref deck, createNewEntities: true); - var nextElementId = FirstSpellSlot; - for (int fairyI = 0; fairyI < Inventory.FairySlotCount; fairyI++) - { - var fairy = inventory.GetFairyAtSlot(fairyI); - for (int spellI = 0; spellI < InventoryFairy.SpellSlotCount; spellI++) - { - var spell = fairy == null ? null : inventory.GetSpellAtSlot(fairy, spellI); - preload.CreateButton(deck.DeckSlotParents[fairyI]) - .With(nextElementId) - .With(DeckSlotPos(fairyI, spellI)) - .With(new components.ui.ButtonTiles(spell?.cardId.EntityId ?? -1)) - .With(UIPreloadAsset.Spl000) - .WithTooltip(UIDSpellSlotNames[spellI]) - .Build(); - nextElementId += 1; - - var spellReq = fairy == null ? default : fairy.spellReqs[spellI]; - if (spellReq != default) - CreateSpellReq( - deck.DeckSlotParents[fairyI], - spellReq, - isAttack: (spellI % 2) == 0, - DeckSlotPos(fairyI, spellI) + new Vector2(2, 45)); - } - } - } - - private DefaultEcs.Entity CreateSpellReq(DefaultEcs.Entity parent, SpellReq spellReq, bool isAttack, Vector2 pos, int renderOrder = 0) - { - var entity = World.CreateEntity(); - entity.Set(new components.Parent(parent)); - entity.Set(components.Visibility.Visible); - entity.Set(components.ui.UIOffset.Center); - entity.Set(new components.ui.RenderOrder(renderOrder)); - entity.Set(IColor.White); - assetRegistry.LoadUITileSheet(entity, isAttack ? UIPreloadAsset.Cls001 : UIPreloadAsset.Cls000); - - var tileSize = entity.Get().GetPixelSize(0); - entity.Set(Rect.FromTopLeftSize(pos, tileSize * 3)); - entity.Set(spellReq.Select((req, i) => new components.ui.Tile( - TileId: (int)req, - Rect: Rect.FromTopLeftSize(pos + i * new Vector2(8, 5), tileSize))) - .ToArray()); - - return entity; - } - - private void CreateFairyInfo(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, int fairyI) - { - if (deck.DeckSlotParents[fairyI] != default) - deck.DeckSlotParents[fairyI].Dispose(); - var slotParent = deck.DeckSlotParents[fairyI] = World.CreateEntity(); - slotParent.Set(new components.Parent(entity)); - var fairy = inventory.GetFairyAtSlot(fairyI); - if (fairy == null) - return; - - for (int slotI = 0; slotI < InventoryFairy.SpellSlotCount; slotI++) - { - preload.CreateTooltipArea(slotParent) - .With(FirstSpellSlot + fairyI * InventoryFairy.SpellSlotCount + slotI) - .With(Rect.FromTopLeftSize(DeckSlotPos(fairyI, slotI), Vector2.One * 40)) - .WithTooltip(UIDFairyInfoDescriptions[slotI]) - .Build(); - - var spell = inventory.GetSpellAtSlot(fairy, slotI); - if (spell == null) - continue; - preload.CreateLabel(slotParent) - .With(DeckSlotPos(fairyI, slotI) + new Vector2(0, 44)) - .With(UIPreloadAsset.Fnt002) - .WithText(FormatManaAmount(spell)) - .Build(); - } - - preload.CreateLabel(slotParent) - .With(DeckSlotPos(fairyI, 0)) - .With(UIPreloadAsset.Fnt002) - .WithText(FormatSummary(inventory, fairy)) - .Build(); - } - - private string FormatManaAmount(InventorySpell spell) - { - var dbSpell = mappedDB.GetSpell(spell.dbUID); - return dbSpell.MaxMana == 5 - ? "{104}-" - : $"{{104}}{spell.mana}/{dbSpell.MaxMana}"; - } - - private static string FormatSummary(Inventory inv, InventoryFairy fairy) - { - var builder = new System.Text.StringBuilder(); - builder.Append(fairy.name); - builder.Append(' '); - - builder.Append(fairy.status switch - { - ZZPermSpellStatus.Poisoned => "{110}", - ZZPermSpellStatus.Cursed => "{111}", - ZZPermSpellStatus.Burned => "{115}", - ZZPermSpellStatus.Frozen => "{114}", - ZZPermSpellStatus.Silenced => "{112}", - _ => "" - }); - builder.Append('\n'); - - builder.Append("{100}"); - builder.Append(fairy.currentMHP); - builder.Append('/'); - builder.Append(fairy.maxMHP); - if (fairy.currentMHP < 100) - builder.Append(' '); - if (fairy.currentMHP < 10) - builder.Append(' '); - if (fairy.maxMHP < 100) - builder.Append(' '); - // no second space for maxMHP - - builder.Append(" L-"); - builder.Append(fairy.level); - if (fairy.level < 10) - builder.Append(' '); - - builder.Append(" {101}"); - builder.Append(fairy.xp); - var levelupXP = inv.GetLevelupXP(fairy); - if (levelupXP.HasValue) - { - builder.Append("{105}"); - builder.Append(levelupXP.Value + 1); - } - - return builder.ToString(); - } - - private string FormatSummary(InventoryItem item) => item.amount > 1 - ? $"{item.amount} x {mappedDB.GetItem(item.dbUID).Name}" - : mappedDB.GetItem(item.dbUID).Name; - - private string FormatSummary(InventorySpell spell) - { - var dbSpell = mappedDB.GetSpell(spell.dbUID); - var mana = dbSpell.Mana == 5 ? "-/-" : $"{spell.mana}/{dbSpell.MaxMana}"; - return $"{dbSpell.Name}\n{{104}}{mana} {UIBuilder.GetSpellPrices(dbSpell)}"; + foreach (var deckCard in deck.DeckCards) + SpellMode(ref deckCard.Get()); } - private void CreateFairyInfos(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + private void InfoMode(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { deck.SpellBackground.Set(components.Visibility.Invisible); deck.SummaryBackground.Set(components.Visibility.Visible); - - ResetDeckSlotParents(entity, ref deck, createNewEntities: false); - for (int i = 0; i < Inventory.FairySlotCount; i++) - CreateFairyInfo(entity, ref deck, i); + foreach (var deckCard in deck.DeckCards) + InfoMode(ref deckCard.Get()); } private static void ResetList(ref components.ui.ScrDeck deck) { - var allEntities = new[] - { - deck.ListButtons, - deck.ListSummaries, - deck.ListUsedMarkers - }.NotNull().SelectMany(); - foreach (var entity in allEntities) - entity.Dispose(); - deck.ListButtons = deck.ListSummaries = deck.ListUsedMarkers = - []; + if (deck.ListCards != default) + foreach (var entity in deck.ListCards) + entity.Dispose(); + deck.ListCards = []; } - private static Vector2 ListCellPos(int column, int row) => + private static Vector2 ListCardPos(int column, int row) => Mid + new Vector2(322 + column * 42, 70 + row * 43); - private static UITileSheetAsset.Info ListTileSheet(in components.ui.ScrDeck deck) => deck.ActiveTab switch + private void CreateListCards(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, int columns, int rows = ListRows) { - Tab.Fairies => UIPreloadAsset.Wiz000, - Tab.Items => UIPreloadAsset.Itm000, - Tab.SupportSpells => UIPreloadAsset.Spl000, - Tab.AttackSpells => UIPreloadAsset.Spl000, - _ => UIPreloadAsset.Wiz000 - }; - - private void CreateListCells(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, int columns, int rows = ListRows) - { - var buttonTileSheet = ListTileSheet(deck); - deck.ListButtons = new DefaultEcs.Entity[rows * columns]; - deck.ListUsedMarkers = new DefaultEcs.Entity[rows * columns]; + deck.ListCards = new DefaultEcs.Entity[rows * columns]; for (int y = 0; y < rows; y++) { for (int x = 0; x < columns; x++) { var i = y * columns + x; - deck.ListButtons[i] = preload.CreateButton(entity) - .With(FirstListCell + i) - .With(ListCellPos(x, y)) - .With(new components.ui.ButtonTiles(-1)) - .With(buttonTileSheet); - - deck.ListUsedMarkers[i] = preload.CreateImage(entity) - .With(ListCellPos(x, y)) - .With(UIPreloadAsset.Inf000, 16) - .WithRenderOrder(-1) - .Invisible(); + deck.ListCards[i] = CreateListCard(entity, ListCardPos(x, y), FirstListCell + i); + if (columns == 1) + CreateCardSummary(deck.ListCards[i], new(42, 9)); } } } - private void CreateRowList(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) - { - ResetList(ref deck); - CreateListCells(entity, ref deck, columns: 1); - var summaryOffset = new Vector2(42, deck.ActiveTab == Tab.Items ? 14 : 5); - deck.ListSummaries = new DefaultEcs.Entity[ListRows]; - for (int i = 0; i < ListRows; i++) - { - deck.ListSummaries[i % ListRows] = preload.CreateLabel(entity) - .With(ListCellPos(column: 0, row: i) + summaryOffset) - .With(UIPreloadAsset.Fnt002); - } - } - - private void CreateGridList(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) - { - ResetList(ref deck); - CreateListCells(entity, ref deck, columns: 6); - } - private IEnumerable AllCardsOfType(in components.ui.ScrDeck deck) => deck.ActiveTab switch { Tab.Items => inventory.Items @@ -457,39 +211,6 @@ private void CreateGridList(DefaultEcs.Entity entity, ref components.ui.ScrDeck _ => [] }; - private bool IsDraggable(InventoryCard card) => card.cardId.Type switch - { - CardType.Item => mappedDB.GetItem(card.dbUID).Script.Length != 0, - CardType.Spell => !card.isInUse, - CardType.Fairy => !card.isInUse, - _ => throw new ArgumentException($"Invalid inventory card type: {card.cardId.Type}") - }; - - private components.ui.TooltipUID CardTooltip(InventoryItem item) - => !IsDraggable(item) - ? new UID(0x8F4510A1) // item cannot be used - : new UID(0x75F10CA1); // select item - - private components.ui.TooltipUID CardTooltip(InventoryFairy fairy) - => !IsDraggable(fairy) - ? new UID(0x9054EAB1) // fairy is in use - : new UID(0x00B500A1); // select fairy - - private components.ui.TooltipUID CardTooltip(InventorySpell spell) - => !IsDraggable(spell) - ? new UID(0x6B46EEB1) // spell is in use - : mappedDB.GetSpell(spell.dbUID).Type == 0 - ? new UID(0xDA2B08A1) // select offensive spell - : new UID(0x93840CA1); // select passive spell - - private components.ui.TooltipUID CardTooltip(InventoryCard card) => card.cardId.Type switch - { - CardType.Item => CardTooltip((InventoryItem)card), - CardType.Spell => CardTooltip((InventorySpell)card), - CardType.Fairy => CardTooltip((InventoryFairy)card), - _ => throw new ArgumentException($"Invalid inventory card type: {card.cardId.Type}") - }; - private void FillList(ref components.ui.ScrDeck deck) { var allCardsOfType = AllCardsOfType(deck); @@ -497,163 +218,24 @@ private void FillList(ref components.ui.ScrDeck deck) deck.Scroll = Math.Clamp(deck.Scroll, 0, Math.Max(0, count - 1)); var shownCards = allCardsOfType .Skip(deck.Scroll) - .Take(deck.ListButtons.Length) - .ToArray(); + .Take(deck.ListCards.Length); - int i; - - for (i = 0; i < shownCards.Length; i++) - { - deck.ListButtons[i].Set(components.Visibility.Visible); - deck.ListButtons[i].Set(ListTileSheet(deck)); - deck.ListButtons[i].Set(new components.ui.ButtonTiles(shownCards[i].cardId.EntityId)); - deck.ListButtons[i].Set(new components.ui.CardButton(shownCards[i])); - deck.ListButtons[i].Set(CardTooltip(shownCards[i])); - deck.ListUsedMarkers[i].Set(!IsDraggable(shownCards[i]) - ? components.Visibility.Visible - : components.Visibility.Invisible); - } - for (; i < deck.ListButtons.Length; i++) - { - deck.ListButtons[i].Set(components.Visibility.Invisible); - deck.ListButtons[i].Set(new components.ui.CardButton()); - if (deck.ListButtons[i].Has()) - deck.ListButtons[i].Remove(); - deck.ListUsedMarkers[i].Set(components.Visibility.Invisible); - } - - if (deck.IsGridMode) - return; - for (i = 0; i < shownCards.Length; i++) + for (var i = 0; i < deck.ListCards.Length; i++) { - var summary = shownCards[i] switch - { - InventoryItem item => FormatSummary(item), - InventorySpell spell => FormatSummary(spell), - InventoryFairy fairy => FormatSummary(inventory, fairy), - _ => throw new NotSupportedException("Unknown inventory card type") - }; - deck.ListSummaries[i].Set(new components.ui.Label(summary)); + var shownCard = shownCards.ElementAtOrDefault(i); + if (shownCard != default) + SetListCard(deck.ListCards[i], shownCard); + else UnsetCard(ref deck.ListCards[i].Get()); } - for (; i < deck.ListButtons.Length; i++) - deck.ListSummaries[i].Set(new components.ui.Label("")); } private void RecreateList(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { - if (deck.IsGridMode) - CreateGridList(entity, ref deck); - else - CreateRowList(entity, ref deck); + ResetList(ref deck); + CreateListCards(entity, ref deck, columns: deck.IsGridMode ? 6 : 1); FillList(ref deck); } - private static void ResetStats(ref components.ui.ScrDeck deck) - { - var allEntities = new[] - { - deck.StatsTitle, - deck.StatsDescriptions, - deck.StatsLights, - deck.StatsLevel - }; - foreach (var entity in allEntities) - if (entity != default) - entity.Dispose(); - deck.StatsTitle = - deck.StatsDescriptions = - deck.StatsLights = - deck.StatsLevel = default; - } - - private string[] FormatStats(InventoryFairy fairy) - { - var fairyRow = mappedDB.GetFairy(fairy.dbUID); - return [fairy.name, fairyRow.Info, "", ""]; - } - - private string[] FormatStats(InventoryItem item) - { - var itemRow = mappedDB.GetItem(item.dbUID); - var count = item.amount != 1 ? $"{{5*x{item.amount}}}" : ""; - return [$"{itemRow.Name} {count}", itemRow.Info, "", ""]; - } - - private string[] FormatStats(InventorySpell spell) - { - var spellRow = mappedDB.GetSpell(spell.dbUID); - if (spellRow.Type == 0) - { - var stats = new[] { - spellRow.Damage + 1, - spellRow.Mana + 1, - spellRow.Loadup + 1, - }; - var descs = new[] { - mappedDB.GetText(UIDStatNames[0]).Text, - mappedDB.GetText(UIDStatNames[1]).Text, - mappedDB.GetText(UIDStatNames[2]).Text, - spellRow.Info, - }; - return [ - spellRow.Name, - String.Join(":\n", descs), - String.Join("\n", stats.Select(stat => UIBuilder.GetLightsIndicator(stat))), - $"Level: {UIBuilder.GetSpellPrices(spellRow)}", - ]; - } - else - { - return [ - spellRow.Name, - $"{mappedDB.GetText(UIDStatNames[1]).Text}:\n{spellRow.Info}", - spellRow.Mana != 5 ? UIBuilder.GetLightsIndicator(spellRow.Mana + 1) : "-", - $"Level: {UIBuilder.GetSpellPrices(spellRow)}", - ]; - } - } - - private string[] FormatStats(InventoryCard card) - => card.cardId.Type switch - { - CardType.Item => FormatStats((InventoryItem)card), - CardType.Spell => FormatStats((InventorySpell)card), - CardType.Fairy => FormatStats((InventoryFairy)card), - _ => throw new ArgumentException($"Invalid inventory card type: {card.cardId.Type}") - }; - - private void CreateStats(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) - { - ResetStats(ref deck); - var card = deck.LastHovered.Get().card; - // Show empty stats for blank buttons - if (card == default) - return; - var summary = FormatStats(card); - - deck.StatsTitle = preload.CreateLabel(entity) - .With(Mid + new Vector2(320, 350)) - .With(UIPreloadAsset.Fnt000) - .WithText(summary[0]) - .Build(); - deck.StatsDescriptions = preload.CreateLabel(entity) - .With(Mid + new Vector2(330, 379)) - .With(UIPreloadAsset.Fnt002) - .WithText(summary[1]) - .WithLineWrap(260f) - .Build(); - deck.StatsLights = preload.CreateLabel(entity) - .With(Mid + new Vector2(380, 379)) - .With(UIPreloadAsset.Fnt002) - .WithText(summary[2]) - .Build(); - deck.StatsLevel = preload.CreateLabel(entity) - .With(Mid + new Vector2(473, 379)) - .With(UIPreloadAsset.Fnt002) - .WithText(summary[3]) - .Build(); - } - private static bool IsInfoTab(Tab tab) => tab == Tab.Fairies || tab == Tab.Items; private static bool IsSpellTab(Tab tab) => tab == Tab.AttackSpells || tab == Tab.SupportSpells; @@ -663,13 +245,13 @@ private void OpenTab(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, T deck.ActiveTab = newTab; if (oldTab != Tab.None) - deck.ListTabs[(int)oldTab - 1].Remove(); - deck.ListTabs[(int)newTab - 1].Set(); + deck.TabButtons[(int)oldTab - 1].Remove(); + deck.TabButtons[(int)newTab - 1].Set(); if (IsInfoTab(newTab) && !IsInfoTab(oldTab)) - CreateFairyInfos(entity, ref deck); + InfoMode(entity, ref deck); if (IsSpellTab(newTab) && !IsSpellTab(oldTab)) - CreateSpellSlots(entity, ref deck); + SpellMode(entity, ref deck); RecreateList(entity, ref deck); } @@ -678,14 +260,13 @@ private void TryDragCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec { if (!IsDraggable(card)) return; - var buttonTileSheet = ListTileSheet(deck); if (deck.DraggedCard != default) deck.DraggedCard.Dispose(); deck.DraggedCard = preload.CreateImage(entity) .With(Mid) .With(card.cardId) .WithRenderOrder(-2) .Build(); - deck.DraggedCard.Set(new components.ui.CardButton(card)); + deck.DraggedCard.Set(new components.ui.DraggedCard(card)); deck.DraggedCard.Set(components.ui.UIOffset.GameUpperLeft); if (deck.DraggedOverlay != default) deck.DraggedOverlay.Dispose(); @@ -723,11 +304,11 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El UpdateSliderPosition(deck); FillList(ref deck); } - else if (id >= FirstListCell && id < FirstListCell + deck.ListButtons.Length) + else if (id >= FirstListCell && id < FirstListCell + deck.ListCards.Length) { - if (clickedEntity.TryGet(out components.ui.CardButton cardButton)) - if (cardButton.card != default) - TryDragCard(deckEntity, ref deck, cardButton.card); + if (clickedEntity.TryGet(out components.ui.DraggedCard card)) + if (card.card != default) + TryDragCard(deckEntity, ref deck, card.card); } else HandleNavClick(id, zanzarah, deckEntity, IDOpenDeck); } @@ -757,7 +338,7 @@ private void TryStartDragging(DefaultEcs.Entity entity, ref components.ui.ScrDec deck.LastHovered = default; ResetStats(ref deck); } - if (deck.ListButtons.Contains(curHovered.Entity)) + if (deck.ListCards.Contains(curHovered.Entity)) { deck.LastHovered = curHovered.Entity; CreateStats(entity, ref deck); From 9ad42325fa5975a7b7a8c8966a4b6a4fff98e3a5 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 16 Dec 2024 18:17:09 +0500 Subject: [PATCH 14/57] refactor: rename card entities to slots --- zzre/game/components/ui/ScrDeck.cs | 5 +- zzre/game/components/ui/{Card.cs => Slot.cs} | 4 +- ...crDeck.BaseCard.cs => ScrDeck.BaseSlot.cs} | 69 +++++++++---------- zzre/game/systems/ui/ScrDeck.DeckCard.cs | 60 ---------------- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 59 ++++++++++++++++ ...crDeck.ListCard.cs => ScrDeck.ListSlot.cs} | 18 ++--- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 67 +++++++++--------- zzre/game/systems/ui/ScrDeck.Summary.cs | 2 +- zzre/game/systems/ui/ScrDeck.cs | 56 +++++++-------- 9 files changed, 166 insertions(+), 174 deletions(-) rename zzre/game/components/ui/{Card.cs => Slot.cs} (81%) rename zzre/game/systems/ui/{ScrDeck.BaseCard.cs => ScrDeck.BaseSlot.cs} (62%) delete mode 100644 zzre/game/systems/ui/ScrDeck.DeckCard.cs create mode 100644 zzre/game/systems/ui/ScrDeck.DeckSlot.cs rename zzre/game/systems/ui/{ScrDeck.ListCard.cs => ScrDeck.ListSlot.cs} (80%) diff --git a/zzre/game/components/ui/ScrDeck.cs b/zzre/game/components/ui/ScrDeck.cs index f03285aa..6985773b 100644 --- a/zzre/game/components/ui/ScrDeck.cs +++ b/zzre/game/components/ui/ScrDeck.cs @@ -17,11 +17,12 @@ public enum Tab public DefaultEcs.Entity SummaryBackground; public DefaultEcs.Entity SpellBackground; - public DefaultEcs.Entity[] DeckCards; public DefaultEcs.Entity[] TabButtons; - public DefaultEcs.Entity[] ListCards; public DefaultEcs.Entity ListSlider; + public DefaultEcs.Entity[] DeckSlots; + public DefaultEcs.Entity[] ListSlots; + public DefaultEcs.Entity StatsTitle; public DefaultEcs.Entity StatsDescriptions; public DefaultEcs.Entity StatsLights; diff --git a/zzre/game/components/ui/Card.cs b/zzre/game/components/ui/Slot.cs similarity index 81% rename from zzre/game/components/ui/Card.cs rename to zzre/game/components/ui/Slot.cs index b0425be6..16dd991f 100644 --- a/zzre/game/components/ui/Card.cs +++ b/zzre/game/components/ui/Slot.cs @@ -2,9 +2,9 @@ namespace zzre.game.components.ui; -public record struct Card +public record struct Slot { - public enum Type { DeckCard, ListCard } + public enum Type { DeckSlot, ListSlot } public Type type; public InventoryCard? card; public DefaultEcs.Entity button; diff --git a/zzre/game/systems/ui/ScrDeck.BaseCard.cs b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs similarity index 62% rename from zzre/game/systems/ui/ScrDeck.BaseCard.cs rename to zzre/game/systems/ui/ScrDeck.BaseSlot.cs index 1b521863..663ae2bb 100644 --- a/zzre/game/systems/ui/ScrDeck.BaseCard.cs +++ b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs @@ -6,7 +6,7 @@ namespace zzre.game.systems.ui; public partial class ScrDeck { - private DefaultEcs.Entity CreateBaseCard( + private DefaultEcs.Entity CreateBaseSlot( DefaultEcs.Entity parent, Vector2 pos, components.ui.ElementId id @@ -14,26 +14,26 @@ components.ui.ElementId id { var entity = World.CreateEntity(); entity.Set(new components.Parent(parent)); - entity.Set(new components.ui.Card()); - ref var card = ref entity.Get(); + entity.Set(new components.ui.Slot()); + ref var slot = ref entity.Get(); - card.buttonId = id; - card.button = preload.CreateButton(entity) + slot.buttonId = id; + slot.button = preload.CreateButton(entity) .With(id) .With(pos) .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Wiz000) .Build(); - UnsetCard(ref card); + UnsetSlot(ref slot); return entity; } - private void CreateCardSummary(DefaultEcs.Entity entity, Vector2 offset) + private void CreateSlotSummary(DefaultEcs.Entity entity, Vector2 offset) { - ref var card = ref entity.Get(); - card.summary = preload.CreateLabel(entity) - .With(card.button.Get().Min + offset) + ref var slot = ref entity.Get(); + slot.summary = preload.CreateLabel(entity) + .With(slot.button.Get().Min + offset) .With(UIPreloadAsset.Fnt002); } @@ -51,37 +51,37 @@ private void ChangeTileSheet(DefaultEcs.Entity entity, UITileSheetAsset.Info til preload.UI.GetTag().LoadUITileSheet(entity, tileSheetInfo); } - private void SetCard(ref components.ui.Card card, InventoryCard invCard) + private void SetSlot(ref components.ui.Slot slot, InventoryCard card) { - card.card = invCard; - card.button.Set(components.Visibility.Visible); - ChangeTileSheet(card.button, TileSheet(invCard.cardId)); - card.button.Set(new components.ui.ButtonTiles(invCard.cardId.EntityId)); - card.button.Set(CardTooltip(invCard)); - - if (card.summary != default) - card.summary.Set(new components.ui.Label(card.card switch + slot.card = card; + slot.button.Set(components.Visibility.Visible); + ChangeTileSheet(slot.button, TileSheet(card.cardId)); + slot.button.Set(new components.ui.ButtonTiles(card.cardId.EntityId)); + slot.button.Set(CardTooltip(card)); + + if (slot.summary != default) + slot.summary.Set(new components.ui.Label(slot.card switch { - InventoryItem item => FormatSummary(item), - InventorySpell spell => FormatSummary(spell), - InventoryFairy fairy => FormatSummary(fairy), + InventoryItem item => FormatSlotSummary(item), + InventorySpell spell => FormatSlotSummary(spell), + InventoryFairy fairy => FormatSlotSummary(fairy), _ => throw new NotSupportedException("Unknown inventory card type") })); } - private static void UnsetCard(ref components.ui.Card card) + private static void UnsetSlot(ref components.ui.Slot slot) { - card.card = default; - card.button.Set(components.Visibility.Invisible); - if (card.button.Has()) - card.button.Remove(); - if (card.usedMarker != default) - card.usedMarker.Set(components.Visibility.Invisible); - if (card.summary != default) - card.summary.Set(new components.ui.Label("")); + slot.card = default; + slot.button.Set(components.Visibility.Invisible); + if (slot.button.Has()) + slot.button.Remove(); + if (slot.usedMarker != default) + slot.usedMarker.Set(components.Visibility.Invisible); + if (slot.summary != default) + slot.summary.Set(new components.ui.Label("")); } - private string FormatSummary(InventoryFairy fairy) + private string FormatSlotSummary(InventoryFairy fairy) { var builder = new System.Text.StringBuilder(); builder.Append(fairy.name); @@ -127,15 +127,14 @@ private string FormatSummary(InventoryFairy fairy) return builder.ToString(); } - private string FormatSummary(InventoryItem item) => item.amount > 1 + private string FormatSlotSummary(InventoryItem item) => item.amount > 1 ? $"{item.amount} x {mappedDB.GetItem(item.dbUID).Name}" : mappedDB.GetItem(item.dbUID).Name; - private string FormatSummary(InventorySpell spell) + private string FormatSlotSummary(InventorySpell spell) { var dbSpell = mappedDB.GetSpell(spell.dbUID); var mana = dbSpell.Mana == 5 ? "-/-" : $"{spell.mana}/{dbSpell.MaxMana}"; return $"{dbSpell.Name}\n{{104}}{mana} {UIBuilder.GetSpellPrices(dbSpell)}"; } - } diff --git a/zzre/game/systems/ui/ScrDeck.DeckCard.cs b/zzre/game/systems/ui/ScrDeck.DeckCard.cs deleted file mode 100644 index 1497af98..00000000 --- a/zzre/game/systems/ui/ScrDeck.DeckCard.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Numerics; -using zzio; - -namespace zzre.game.systems.ui; - -public partial class ScrDeck -{ - private static readonly UID UIDSelectFairy = new(0x41912581); - private static readonly UID UIDPlaceFairy = new(0x41912581); - private static readonly UID UIDReplaceFairy = new(0x41912581); - private static readonly UID UIDUseItemOnFairy = new(0x41912581); - - private DefaultEcs.Entity CreateDeckCard( - DefaultEcs.Entity parent, - Vector2 pos, - components.ui.ElementId id - ) - { - var entity = CreateBaseCard(parent, pos, id); - ref var card = ref entity.Get(); - - CreateCardSummary(entity, new(48, 4)); - - card.spellSlots = new DefaultEcs.Entity[4]; - for (int i = 0; i < InventoryFairy.SpellSlotCount; i++) - card.spellSlots[i] = CreateSpellSlot(entity, ref card, i); - - return entity; - } - - private void SetDeckCard(DefaultEcs.Entity entity, InventoryCard invCard) - { - ref var card = ref entity.Get(); - SetCard(ref card, invCard); - card.button.Set(new components.ui.TooltipUID(UIDSelectFairy)); - } - - private void InfoMode(ref components.ui.Card card) - { - if (card.card != default) - card.summary.Set(new components.ui.Label(card.card switch - { - InventoryItem item => FormatSummary(item), - InventorySpell spell => FormatSummary(spell), - InventoryFairy fairy => FormatSummary(fairy), - _ => throw new NotSupportedException("Unknown inventory card type") - })); - foreach (var slot in card.spellSlots) - InfoMode(ref slot.Get()); - } - - private static void SpellMode(ref components.ui.Card card) - { - card.summary.Set(new components.ui.Label("")); - foreach (var slot in card.spellSlots) - SpellMode(ref slot.Get()); - } - -} diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs new file mode 100644 index 00000000..08fbbe29 --- /dev/null +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -0,0 +1,59 @@ +using System; +using System.Numerics; +using zzio; + +namespace zzre.game.systems.ui; + +public partial class ScrDeck +{ + private static readonly UID UIDSelectFairy = new(0x41912581); + private static readonly UID UIDPlaceFairy = new(0x41912581); + private static readonly UID UIDReplaceFairy = new(0x41912581); + private static readonly UID UIDUseItemOnFairy = new(0x41912581); + + private DefaultEcs.Entity CreateDeckSlot( + DefaultEcs.Entity parent, + Vector2 pos, + components.ui.ElementId id + ) + { + var entity = CreateBaseSlot(parent, pos, id); + ref var slot = ref entity.Get(); + + CreateSlotSummary(entity, new(48, 4)); + + slot.spellSlots = new DefaultEcs.Entity[4]; + for (int i = 0; i < InventoryFairy.SpellSlotCount; i++) + slot.spellSlots[i] = CreateSpellSlot(entity, ref slot, i); + + return entity; + } + + private void SetDeckSlot(DefaultEcs.Entity entity, InventoryCard card) + { + ref var slot = ref entity.Get(); + SetSlot(ref slot, card); + slot.button.Set(new components.ui.TooltipUID(UIDSelectFairy)); + } + + private void InfoMode(ref components.ui.Slot slot) + { + if (slot.card != default) + slot.summary.Set(new components.ui.Label(slot.card switch + { + InventoryItem item => FormatSlotSummary(item), + InventorySpell spell => FormatSlotSummary(spell), + InventoryFairy fairy => FormatSlotSummary(fairy), + _ => throw new NotSupportedException("Unknown inventory card type") + })); + foreach (var spellSlot in slot.spellSlots) + InfoMode(ref spellSlot.Get()); + } + + private static void SpellMode(ref components.ui.Slot slot) + { + slot.summary.Set(new components.ui.Label("")); + foreach (var spellSlot in slot.spellSlots) + SpellMode(ref spellSlot.Get()); + } +} diff --git a/zzre/game/systems/ui/ScrDeck.ListCard.cs b/zzre/game/systems/ui/ScrDeck.ListSlot.cs similarity index 80% rename from zzre/game/systems/ui/ScrDeck.ListCard.cs rename to zzre/game/systems/ui/ScrDeck.ListSlot.cs index 4b0b6557..f5d5f6a3 100644 --- a/zzre/game/systems/ui/ScrDeck.ListCard.cs +++ b/zzre/game/systems/ui/ScrDeck.ListSlot.cs @@ -7,16 +7,16 @@ namespace zzre.game.systems.ui; public partial class ScrDeck { - private DefaultEcs.Entity CreateListCard( + private DefaultEcs.Entity CreateListSlot( DefaultEcs.Entity parent, Vector2 pos, components.ui.ElementId id ) { - var entity = CreateBaseCard(parent, pos, id); - ref var card = ref entity.Get(); + var entity = CreateBaseSlot(parent, pos, id); + ref var slot = ref entity.Get(); - card.usedMarker = preload.CreateImage(entity) + slot.usedMarker = preload.CreateImage(entity) .With(pos) .With(UIPreloadAsset.Inf000, 16) .WithRenderOrder(-1) @@ -26,14 +26,14 @@ components.ui.ElementId id return entity; } - private void SetListCard(DefaultEcs.Entity entity, InventoryCard invCard) + private void SetListSlot(DefaultEcs.Entity entity, InventoryCard card) { - ref var card = ref entity.Get(); - SetCard(ref card, invCard); - card.usedMarker.Set(!IsDraggable(invCard) + ref var slot = ref entity.Get(); + SetSlot(ref slot, card); + slot.usedMarker.Set(!IsDraggable(card) ? components.Visibility.Visible : components.Visibility.Invisible); - card.button.Set(CardTooltip(invCard)); + slot.button.Set(CardTooltip(card)); } private bool IsDraggable(InventoryCard card) => card.cardId.Type switch diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 47321b1a..89d4256f 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -22,64 +22,64 @@ public partial class ScrDeck new(0xB26B36A1) ]; - private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref components.ui.Card card, int index) + private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref components.ui.Slot slot, int index) { var entity = World.CreateEntity(); entity.Set(new components.Parent(parent)); entity.Set(new components.ui.SpellSlot()); - ref var spell = ref entity.Get(); - spell.index = index; + ref var spellSlot = ref entity.Get(); + spellSlot.index = index; - spell.button = preload.CreateButton(entity) - .With(card.buttonId + index + 1) - .With(card.button.Get().Min + new Vector2(81 + 46 * spell.index)) + spellSlot.button = preload.CreateButton(entity) + .With(slot.buttonId + index + 1) + .With(slot.button.Get().Min + new Vector2(81 + 46 * spellSlot.index)) .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Spl000) // .WithTooltip(UIDSpellSlotNames[i]) .Build(); - InfoMode(ref spell); + InfoMode(ref spellSlot); return entity; } - public void SetSpell(DefaultEcs.Entity entity, ref components.ui.SpellSlot spell, InventorySpell invSpell) + public void SetSpell(DefaultEcs.Entity entity, ref components.ui.SpellSlot spellSlot, InventorySpell invSpell) { - spell.spell = invSpell; - spell.button.Set(new components.ui.ButtonTiles(invSpell.cardId.EntityId)); - if (spell.summary != default) spell.summary.Dispose(); - spell.summary = preload.CreateLabel(entity) - .With(spell.button.Get().Min + new Vector2(0, 44)) + spellSlot.spell = invSpell; + spellSlot.button.Set(new components.ui.ButtonTiles(invSpell.cardId.EntityId)); + if (spellSlot.summary != default) spellSlot.summary.Dispose(); + spellSlot.summary = preload.CreateLabel(entity) + .With(spellSlot.button.Get().Min + new Vector2(0, 44)) .With(UIPreloadAsset.Fnt002) - .WithText(FormatManaAmount(spell.spell)) + .WithText(FormatManaAmount(spellSlot.spell)) .Build(); - if (spell.req != default) spell.req.Dispose(); - spell.req = CreateSpellReq( + if (spellSlot.req != default) spellSlot.req.Dispose(); + spellSlot.req = CreateSpellReq( entity, - ((InventoryFairy)(entity.Get().Entity.Get().card!)).spellReqs[spell.index], - (spell.index % 2) == 0, - spell.button.Get().Min + new Vector2(2, 45) + ((InventoryFairy)(entity.Get().Entity.Get().card!)).spellReqs[spellSlot.index], + (spellSlot.index % 2) == 0, + spellSlot.button.Get().Min + new Vector2(2, 45) ); } - public static void InfoMode(ref components.ui.SpellSlot spell) + public static void InfoMode(ref components.ui.SpellSlot spellSlot) { - spell.button.Set(components.Visibility.Invisible); - spell.button.Set(new components.ui.TooltipUID(UIDFairyInfoDescriptions[spell.index])); - if (spell.summary != default) - spell.summary.Set(components.Visibility.Visible); - if (spell.req != default) - spell.req.Set(components.Visibility.Invisible); + spellSlot.button.Set(components.Visibility.Invisible); + spellSlot.button.Set(new components.ui.TooltipUID(UIDFairyInfoDescriptions[spellSlot.index])); + if (spellSlot.summary != default) + spellSlot.summary.Set(components.Visibility.Visible); + if (spellSlot.req != default) + spellSlot.req.Set(components.Visibility.Invisible); } - public static void SpellMode(ref components.ui.SpellSlot spell) + public static void SpellMode(ref components.ui.SpellSlot spellSlot) { - spell.button.Set(components.Visibility.Visible); - spell.button.Set(new components.ui.TooltipUID(UIDSpellSlotNames[spell.index])); - if (spell.summary != default) - spell.summary.Set(components.Visibility.Invisible); - if (spell.req != default) - spell.req.Set(components.Visibility.Visible); + spellSlot.button.Set(components.Visibility.Visible); + spellSlot.button.Set(new components.ui.TooltipUID(UIDSpellSlotNames[spellSlot.index])); + if (spellSlot.summary != default) + spellSlot.summary.Set(components.Visibility.Invisible); + if (spellSlot.req != default) + spellSlot.req.Set(components.Visibility.Visible); } private DefaultEcs.Entity CreateSpellReq(DefaultEcs.Entity parent, SpellReq spellReq, bool isAttack, Vector2 pos) @@ -108,5 +108,4 @@ private string FormatManaAmount(InventorySpell spell) ? "{104}-" : $"{{104}}{spell.mana}/{dbSpell.MaxMana}"; } - } diff --git a/zzre/game/systems/ui/ScrDeck.Summary.cs b/zzre/game/systems/ui/ScrDeck.Summary.cs index b4408b85..d6ce5a79 100644 --- a/zzre/game/systems/ui/ScrDeck.Summary.cs +++ b/zzre/game/systems/ui/ScrDeck.Summary.cs @@ -18,7 +18,7 @@ public partial class ScrDeck private void CreateStats(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { ResetStats(ref deck); - var card = deck.LastHovered.Get().card; + var card = deck.LastHovered.Get().card; // Show empty stats for blank buttons if (card == default) return; diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index b5b331ce..eaf49cca 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -62,7 +62,7 @@ protected override void HandleOpen(in messages.ui.OpenDeck message) CreateBackgrounds(entity, ref deck); CreateListControls(entity, ref deck); CreateTopButtons(preload, entity, inventory, IDOpenDeck); - CreateDeckCards(entity, ref deck); + CreateDeckSlots(entity, ref deck); if (deck.ActiveTab == Tab.None) OpenTab(entity, ref deck, Tab.Fairies); @@ -143,59 +143,54 @@ private void CreateListControls(DefaultEcs.Entity entity, ref components.ui.ScrD .Build(); } - private void CreateDeckCards(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + private void CreateDeckSlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { - deck.DeckCards = new DefaultEcs.Entity[Inventory.FairySlotCount]; + deck.DeckSlots = new DefaultEcs.Entity[Inventory.FairySlotCount]; for (int i = 0; i < Inventory.FairySlotCount; i++) { - deck.DeckCards[i] = CreateDeckCard(entity, Mid + new Vector2(31, 60 + 79 * i), FirstFairySlot + i); + deck.DeckSlots[i] = CreateDeckSlot(entity, Mid + new Vector2(31, 60 + 79 * i), FirstFairySlot + i); var fairy = inventory.GetFairyAtSlot(i); if (fairy != default) - SetDeckCard(deck.DeckCards[i], fairy); + SetDeckSlot(deck.DeckSlots[i], fairy); } } - private static Vector2 DeckCardPos(int fairyI, int slotI) => + private static Vector2 DeckSlotPos(int fairyI, int slotI) => Mid + new Vector2(81 + 46 * slotI, 60 + 79 * fairyI); private static void SpellMode(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { deck.SpellBackground.Set(components.Visibility.Visible); deck.SummaryBackground.Set(components.Visibility.Invisible); - foreach (var deckCard in deck.DeckCards) - SpellMode(ref deckCard.Get()); + foreach (var deckCard in deck.DeckSlots) + SpellMode(ref deckCard.Get()); } private void InfoMode(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { deck.SpellBackground.Set(components.Visibility.Invisible); deck.SummaryBackground.Set(components.Visibility.Visible); - foreach (var deckCard in deck.DeckCards) - InfoMode(ref deckCard.Get()); + foreach (var deckCard in deck.DeckSlots) + InfoMode(ref deckCard.Get()); } - private static void ResetList(ref components.ui.ScrDeck deck) - { - if (deck.ListCards != default) - foreach (var entity in deck.ListCards) - entity.Dispose(); - deck.ListCards = []; - } - - private static Vector2 ListCardPos(int column, int row) => + private static Vector2 ListSlotPos(int column, int row) => Mid + new Vector2(322 + column * 42, 70 + row * 43); - private void CreateListCards(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, int columns, int rows = ListRows) + private void CreateListSlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, int columns, int rows = ListRows) { - deck.ListCards = new DefaultEcs.Entity[rows * columns]; + if (deck.ListSlots != default) + foreach (var listSlot in deck.ListSlots) + listSlot.Dispose(); + deck.ListSlots = new DefaultEcs.Entity[rows * columns]; for (int y = 0; y < rows; y++) { for (int x = 0; x < columns; x++) { var i = y * columns + x; - deck.ListCards[i] = CreateListCard(entity, ListCardPos(x, y), FirstListCell + i); + deck.ListSlots[i] = CreateListSlot(entity, ListSlotPos(x, y), FirstListCell + i); if (columns == 1) - CreateCardSummary(deck.ListCards[i], new(42, 9)); + CreateSlotSummary(deck.ListSlots[i], new(42, 9)); } } } @@ -218,21 +213,20 @@ private void FillList(ref components.ui.ScrDeck deck) deck.Scroll = Math.Clamp(deck.Scroll, 0, Math.Max(0, count - 1)); var shownCards = allCardsOfType .Skip(deck.Scroll) - .Take(deck.ListCards.Length); + .Take(deck.ListSlots.Length); - for (var i = 0; i < deck.ListCards.Length; i++) + for (var i = 0; i < deck.ListSlots.Length; i++) { var shownCard = shownCards.ElementAtOrDefault(i); if (shownCard != default) - SetListCard(deck.ListCards[i], shownCard); - else UnsetCard(ref deck.ListCards[i].Get()); + SetListSlot(deck.ListSlots[i], shownCard); + else UnsetSlot(ref deck.ListSlots[i].Get()); } } private void RecreateList(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { - ResetList(ref deck); - CreateListCards(entity, ref deck, columns: deck.IsGridMode ? 6 : 1); + CreateListSlots(entity, ref deck, columns: deck.IsGridMode ? 6 : 1); FillList(ref deck); } @@ -304,7 +298,7 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El UpdateSliderPosition(deck); FillList(ref deck); } - else if (id >= FirstListCell && id < FirstListCell + deck.ListCards.Length) + else if (id >= FirstListCell && id < FirstListCell + deck.ListSlots.Length) { if (clickedEntity.TryGet(out components.ui.DraggedCard card)) if (card.card != default) @@ -338,7 +332,7 @@ private void TryStartDragging(DefaultEcs.Entity entity, ref components.ui.ScrDec deck.LastHovered = default; ResetStats(ref deck); } - if (deck.ListCards.Contains(curHovered.Entity)) + if (deck.ListSlots.Contains(curHovered.Entity)) { deck.LastHovered = curHovered.Entity; CreateStats(entity, ref deck); From 60805ea6a796637ef3a40f12f0382f59b268e7e5 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 16 Dec 2024 19:08:58 +0500 Subject: [PATCH 15/57] fix: create spell slots --- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 11 +++ zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 74 +++++++++++-------- .../tools/ECSExplorer/ECSExplorer.Standard.cs | 2 + 3 files changed, 56 insertions(+), 31 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index 08fbbe29..f88e3b30 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -34,6 +34,17 @@ private void SetDeckSlot(DefaultEcs.Entity entity, InventoryCard card) ref var slot = ref entity.Get(); SetSlot(ref slot, card); slot.button.Set(new components.ui.TooltipUID(UIDSelectFairy)); + + for (int i = 0; i < InventoryFairy.SpellSlotCount; i++) + { + var spell = slot.card == null + ? null + : inventory.GetSpellAtSlot((InventoryFairy)slot.card, i); + if (spell != default) + SetSpellSlot(slot.spellSlots[i], spell); + else + UnsetSpellSlot(slot.spellSlots[i]); + } } private void InfoMode(ref components.ui.Slot slot) diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 89d4256f..b7e0a0f7 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -32,7 +32,7 @@ private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref componen spellSlot.button = preload.CreateButton(entity) .With(slot.buttonId + index + 1) - .With(slot.button.Get().Min + new Vector2(81 + 46 * spellSlot.index)) + .With(slot.button.Get().Min + new Vector2(50 + 46 * spellSlot.index, 0)) .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Spl000) // .WithTooltip(UIDSpellSlotNames[i]) @@ -43,31 +43,28 @@ private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref componen return entity; } - public void SetSpell(DefaultEcs.Entity entity, ref components.ui.SpellSlot spellSlot, InventorySpell invSpell) + public void SetSpellSlot(DefaultEcs.Entity entity, InventorySpell invSpell) { + ref var spellSlot = ref entity.Get(); spellSlot.spell = invSpell; spellSlot.button.Set(new components.ui.ButtonTiles(invSpell.cardId.EntityId)); - if (spellSlot.summary != default) spellSlot.summary.Dispose(); - spellSlot.summary = preload.CreateLabel(entity) - .With(spellSlot.button.Get().Min + new Vector2(0, 44)) - .With(UIPreloadAsset.Fnt002) - .WithText(FormatManaAmount(spellSlot.spell)) - .Build(); - if (spellSlot.req != default) spellSlot.req.Dispose(); - spellSlot.req = CreateSpellReq( - entity, - ((InventoryFairy)(entity.Get().Entity.Get().card!)).spellReqs[spellSlot.index], - (spellSlot.index % 2) == 0, - spellSlot.button.Get().Min + new Vector2(2, 45) - ); + CreateSpellSummary(entity); + CreateSpellReq(entity); } - public static void InfoMode(ref components.ui.SpellSlot spellSlot) + public void UnsetSpellSlot(DefaultEcs.Entity entity) + { + CreateSpellReq(entity); + } + + public void InfoMode(ref components.ui.SpellSlot spellSlot) { spellSlot.button.Set(components.Visibility.Invisible); spellSlot.button.Set(new components.ui.TooltipUID(UIDFairyInfoDescriptions[spellSlot.index])); if (spellSlot.summary != default) - spellSlot.summary.Set(components.Visibility.Visible); + spellSlot.summary.Set(spellSlot.spell != default + ? new components.ui.Label(FormatManaAmount(spellSlot.spell)) + : new components.ui.Label("")); if (spellSlot.req != default) spellSlot.req.Set(components.Visibility.Invisible); } @@ -77,28 +74,43 @@ public static void SpellMode(ref components.ui.SpellSlot spellSlot) spellSlot.button.Set(components.Visibility.Visible); spellSlot.button.Set(new components.ui.TooltipUID(UIDSpellSlotNames[spellSlot.index])); if (spellSlot.summary != default) - spellSlot.summary.Set(components.Visibility.Invisible); + spellSlot.summary.Set(new components.ui.Label("")); if (spellSlot.req != default) spellSlot.req.Set(components.Visibility.Visible); } - private DefaultEcs.Entity CreateSpellReq(DefaultEcs.Entity parent, SpellReq spellReq, bool isAttack, Vector2 pos) + private void CreateSpellSummary(DefaultEcs.Entity entity) { - var entity = World.CreateEntity(); - entity.Set(new components.Parent(parent)); - entity.Set(components.Visibility.Visible); - entity.Set(components.ui.UIOffset.Center); - entity.Set(IColor.White); - assetRegistry.LoadUITileSheet(entity, isAttack ? UIPreloadAsset.Cls001 : UIPreloadAsset.Cls000); - - var tileSize = entity.Get().GetPixelSize(0); - entity.Set(Rect.FromTopLeftSize(pos, tileSize * 3)); - entity.Set(spellReq.Select((req, i) => new components.ui.Tile( + ref var spellSlot = ref entity.Get(); + if (spellSlot.summary != default) spellSlot.summary.Dispose(); + spellSlot.summary = preload.CreateLabel(entity) + .With(spellSlot.button.Get().Min + new Vector2(0, 44)) + .With(UIPreloadAsset.Fnt002) + .Build(); + } + + private void CreateSpellReq(DefaultEcs.Entity entity) + { + ref var spellSlot = ref entity.Get(); + var spellReq = ((InventoryFairy)(entity.Get().Entity.Get().card!)).spellReqs[spellSlot.index]; + var isAttack = spellSlot.index % 2 == 0; + var pos = spellSlot.button.Get().Min + new Vector2(2, 45); + + if (spellSlot.req != default) spellSlot.req.Dispose(); + spellSlot.req = World.CreateEntity(); + spellSlot.req.Set(new components.Parent(entity)); + spellSlot.req.Set(components.Visibility.Visible); + spellSlot.req.Set(components.ui.UIOffset.Center); + spellSlot.req.Set(new components.ui.RenderOrder(0)); + spellSlot.req.Set(IColor.White); + assetRegistry.LoadUITileSheet(spellSlot.req, isAttack ? UIPreloadAsset.Cls001 : UIPreloadAsset.Cls000); + + var tileSize = spellSlot.req.Get().GetPixelSize(0); + spellSlot.req.Set(Rect.FromTopLeftSize(pos, tileSize * 3)); + spellSlot.req.Set(spellReq.Select((req, i) => new components.ui.Tile( TileId: (int)req, Rect: Rect.FromTopLeftSize(pos + i * new Vector2(8, 5), tileSize))) .ToArray()); - - return entity; } private string FormatManaAmount(InventorySpell spell) diff --git a/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs b/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs index fc1d35bf..093786e9 100644 --- a/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs +++ b/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs @@ -69,6 +69,8 @@ private static void AddStandardEntityNaming() AddEntityNamerByComponent(High, e => $"Tooltip Target {e}"); AddEntityNamerByComponent(High, e => $"Fade {e}"); AddEntityNamerByComponent(High, e => $"Slider #{e.TryGet().GetValueOrDefault(default).Value} {e}"); + AddEntityNamerByComponent(High, e => $"Slot {e}"); + AddEntityNamerByComponent(High, e => $"SpellSlot #{e.TryGet().GetValueOrDefault(default).index} {e}"); AddEntityNamerByComponent(High, (in AnimatedLabel label) => $"Anim. Label \"{Sanitize(label.FullText)}\""); AddEntityNamerByComponent(Def, (in Label label) => $"Label \"{Sanitize(label.Text)}\""); AddEntityNamerByComponent(Low, e => $"Visuals {e}"); From 0c848b6bbe187a988a36d11690fa521e88fb2e75 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 16 Dec 2024 20:05:52 +0500 Subject: [PATCH 16/57] fix: give all buttons a size --- zzre/game/systems/ui/ScrDeck.BaseSlot.cs | 5 ++++- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 1 + zzre/game/systems/ui/ScrDeck.ListSlot.cs | 1 + zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 8 ++++---- zzre/tools/ECSExplorer/ECSExplorer.Standard.cs | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs index 663ae2bb..78af34d3 100644 --- a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs @@ -6,6 +6,9 @@ namespace zzre.game.systems.ui; public partial class ScrDeck { + // Provide a size for buttons, including unset ones. + public Vector2 SlotButtonSize = Vector2.One * 38; + private DefaultEcs.Entity CreateBaseSlot( DefaultEcs.Entity parent, Vector2 pos, @@ -20,7 +23,7 @@ components.ui.ElementId id slot.buttonId = id; slot.button = preload.CreateButton(entity) .With(id) - .With(pos) + .With(Rect.FromTopLeftSize(pos, SlotButtonSize)) .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Wiz000) .Build(); diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index f88e3b30..3ff72d21 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -19,6 +19,7 @@ components.ui.ElementId id { var entity = CreateBaseSlot(parent, pos, id); ref var slot = ref entity.Get(); + slot.type = components.ui.Slot.Type.DeckSlot; CreateSlotSummary(entity, new(48, 4)); diff --git a/zzre/game/systems/ui/ScrDeck.ListSlot.cs b/zzre/game/systems/ui/ScrDeck.ListSlot.cs index f5d5f6a3..d9480807 100644 --- a/zzre/game/systems/ui/ScrDeck.ListSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.ListSlot.cs @@ -15,6 +15,7 @@ components.ui.ElementId id { var entity = CreateBaseSlot(parent, pos, id); ref var slot = ref entity.Get(); + slot.type = components.ui.Slot.Type.ListSlot; slot.usedMarker = preload.CreateImage(entity) .With(pos) diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index b7e0a0f7..871ee52e 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -32,10 +32,9 @@ private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref componen spellSlot.button = preload.CreateButton(entity) .With(slot.buttonId + index + 1) - .With(slot.button.Get().Min + new Vector2(50 + 46 * spellSlot.index, 0)) + .With(slot.button.Get().OffsettedBy(50 + 46 * spellSlot.index, 0)) .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Spl000) - // .WithTooltip(UIDSpellSlotNames[i]) .Build(); InfoMode(ref spellSlot); @@ -71,7 +70,8 @@ public void InfoMode(ref components.ui.SpellSlot spellSlot) public static void SpellMode(ref components.ui.SpellSlot spellSlot) { - spellSlot.button.Set(components.Visibility.Visible); + if (spellSlot.button.Get().Normal != -1) + spellSlot.button.Set(components.Visibility.Visible); spellSlot.button.Set(new components.ui.TooltipUID(UIDSpellSlotNames[spellSlot.index])); if (spellSlot.summary != default) spellSlot.summary.Set(new components.ui.Label("")); @@ -84,7 +84,7 @@ private void CreateSpellSummary(DefaultEcs.Entity entity) ref var spellSlot = ref entity.Get(); if (spellSlot.summary != default) spellSlot.summary.Dispose(); spellSlot.summary = preload.CreateLabel(entity) - .With(spellSlot.button.Get().Min + new Vector2(0, 44)) + .With(spellSlot.button.Get().Min + new Vector2(0, 47)) .With(UIPreloadAsset.Fnt002) .Build(); } diff --git a/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs b/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs index 093786e9..c4ceed9b 100644 --- a/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs +++ b/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs @@ -69,7 +69,7 @@ private static void AddStandardEntityNaming() AddEntityNamerByComponent(High, e => $"Tooltip Target {e}"); AddEntityNamerByComponent(High, e => $"Fade {e}"); AddEntityNamerByComponent(High, e => $"Slider #{e.TryGet().GetValueOrDefault(default).Value} {e}"); - AddEntityNamerByComponent(High, e => $"Slot {e}"); + AddEntityNamerByComponent(High, e => $"{e.TryGet().GetValueOrDefault(default).type} {e}"); AddEntityNamerByComponent(High, e => $"SpellSlot #{e.TryGet().GetValueOrDefault(default).index} {e}"); AddEntityNamerByComponent(High, (in AnimatedLabel label) => $"Anim. Label \"{Sanitize(label.FullText)}\""); AddEntityNamerByComponent(Def, (in Label label) => $"Label \"{Sanitize(label.Text)}\""); From 3b566ff033e44d27b7f4476ce85b5fedd0a9509e Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 16 Dec 2024 22:48:54 +0500 Subject: [PATCH 17/57] fix: button and summary offsets --- zzre/game/systems/ui/ScrDeck.BaseSlot.cs | 20 +++++++++++++++++++- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 3 ++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs index 78af34d3..f971b042 100644 --- a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs @@ -23,7 +23,7 @@ components.ui.ElementId id slot.buttonId = id; slot.button = preload.CreateButton(entity) .With(id) - .With(Rect.FromTopLeftSize(pos, SlotButtonSize)) + .With(pos) .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Wiz000) .Build(); @@ -54,6 +54,21 @@ private void ChangeTileSheet(DefaultEcs.Entity entity, UITileSheetAsset.Info til preload.UI.GetTag().LoadUITileSheet(entity, tileSheetInfo); } + private void SetSummaryOffset(ref components.ui.Slot slot) + { + var min = slot.button.Get().Min + SummaryOffset(ref slot); + slot.summary.Set(Rect.FromMinMax(min, min)); + } + + private Vector2 SummaryOffset(ref components.ui.Slot slot) + { + if (slot.type == components.ui.Slot.Type.DeckSlot) + return new(48, 4); + if (slot.card!.cardId.Type == CardType.Item) + return new(42, 18); + return new(42, 9); + } + private void SetSlot(ref components.ui.Slot slot, InventoryCard card) { slot.card = card; @@ -63,6 +78,7 @@ private void SetSlot(ref components.ui.Slot slot, InventoryCard card) slot.button.Set(CardTooltip(card)); if (slot.summary != default) + { slot.summary.Set(new components.ui.Label(slot.card switch { InventoryItem item => FormatSlotSummary(item), @@ -70,6 +86,8 @@ private void SetSlot(ref components.ui.Slot slot, InventoryCard card) InventoryFairy fairy => FormatSlotSummary(fairy), _ => throw new NotSupportedException("Unknown inventory card type") })); + SetSummaryOffset(ref slot); + } } private static void UnsetSlot(ref components.ui.Slot slot) diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 871ee52e..7625fe38 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -6,6 +6,7 @@ namespace zzre.game.systems.ui; public partial class ScrDeck { + public Vector2 SpellSlotSize = new(38, 38); private static readonly UID[] UIDSpellSlotNames = [ new(0x37697321), // First offensive slot @@ -32,7 +33,7 @@ private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref componen spellSlot.button = preload.CreateButton(entity) .With(slot.buttonId + index + 1) - .With(slot.button.Get().OffsettedBy(50 + 46 * spellSlot.index, 0)) + .With(Rect.FromTopLeftSize(slot.button.Get().Min + new Vector2(50 + 46 * spellSlot.index, 0), SpellSlotSize)) .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Spl000) .Build(); From c413ded9b208108cde88c6b40e6580ef89ca585d Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 16 Dec 2024 23:00:42 +0500 Subject: [PATCH 18/57] fix: tab and pixie offset --- zzre/game/systems/ui/ScrDeck.BaseSlot.cs | 4 ++-- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 2 +- zzre/game/systems/ui/ScrDeck.cs | 8 +++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs index f971b042..d7f533fb 100644 --- a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs @@ -54,13 +54,13 @@ private void ChangeTileSheet(DefaultEcs.Entity entity, UITileSheetAsset.Info til preload.UI.GetTag().LoadUITileSheet(entity, tileSheetInfo); } - private void SetSummaryOffset(ref components.ui.Slot slot) + private static void SetSummaryOffset(ref components.ui.Slot slot) { var min = slot.button.Get().Min + SummaryOffset(ref slot); slot.summary.Set(Rect.FromMinMax(min, min)); } - private Vector2 SummaryOffset(ref components.ui.Slot slot) + private static Vector2 SummaryOffset(ref components.ui.Slot slot) { if (slot.type == components.ui.Slot.Type.DeckSlot) return new(48, 4); diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 7625fe38..24b1a64f 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -85,7 +85,7 @@ private void CreateSpellSummary(DefaultEcs.Entity entity) ref var spellSlot = ref entity.Get(); if (spellSlot.summary != default) spellSlot.summary.Dispose(); spellSlot.summary = preload.CreateLabel(entity) - .With(spellSlot.button.Get().Min + new Vector2(0, 47)) + .With(spellSlot.button.Get().Min + new Vector2(0, 48)) .With(UIPreloadAsset.Fnt002) .Build(); } diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index eaf49cca..7439949f 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -94,7 +94,7 @@ private void CreateBackgrounds(DefaultEcs.Entity entity, ref components.ui.ScrDe .Build(); preload.CreateLabel(entity) - .With(Mid + new Vector2(337, 42)) + .With(Mid + new Vector2(337, 44)) .With(UIPreloadAsset.Fnt002) .WithText($"{zanzarah.OverworldGame!.GetTag().pixiesCatched}/30") .Build(); @@ -124,19 +124,17 @@ private void CreateListControls(DefaultEcs.Entity entity, ref components.ui.ScrD deck.ListSlider.Set(components.ui.Slider.Vertical); deck.TabButtons = new DefaultEcs.Entity[4]; - var tabButtonRect = Rect.FromTopLeftSize(Mid + new Vector2(281, 0f), new Vector2(35, 35)); - foreach (var tab in Tabs) deck.TabButtons[(int)tab.Type - 1] = preload.CreateButton(entity) .With(tab.Id) - .With(tabButtonRect.OffsettedBy(0, tab.PosY)) + .With(Mid + new Vector2(282, tab.PosY)) .With(new components.ui.ButtonTiles(tab.TileNormal, tab.TileHovered, tab.TileActive)) .With(UIPreloadAsset.Btn002) .WithTooltip(tab.TooltipUID); preload.CreateButton(entity) .With(IDSwitchListMode) - .With(tabButtonRect.Min + new Vector2(16, 261)) + .With(Mid + new Vector2(297, 261)) .With(new components.ui.ButtonTiles(28, 29)) .With(UIPreloadAsset.Btn002) .WithTooltip(0xA086B911) From 59f6fc90aaacfd65743d5ec74a45641e5ee98437 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 17 Dec 2024 14:07:07 +0500 Subject: [PATCH 19/57] fix: summary --- zzre/game/components/ui/ScrDeck.cs | 7 +- zzre/game/components/ui/Slot.cs | 8 +- zzre/game/components/ui/SlotButton.cs | 3 + zzre/game/components/ui/SpellSlot.cs | 12 --- zzre/game/systems/ui/ScrDeck.BaseSlot.cs | 1 + zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 4 +- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 91 ++++++++++--------- zzre/game/systems/ui/ScrDeck.Summary.cs | 59 +++++++----- zzre/game/systems/ui/ScrDeck.cs | 33 ++++--- .../tools/ECSExplorer/ECSExplorer.Standard.cs | 5 +- 10 files changed, 120 insertions(+), 103 deletions(-) create mode 100644 zzre/game/components/ui/SlotButton.cs delete mode 100644 zzre/game/components/ui/SpellSlot.cs diff --git a/zzre/game/components/ui/ScrDeck.cs b/zzre/game/components/ui/ScrDeck.cs index 6985773b..588eb7a6 100644 --- a/zzre/game/components/ui/ScrDeck.cs +++ b/zzre/game/components/ui/ScrDeck.cs @@ -1,3 +1,5 @@ +using zzio; + namespace zzre.game.components.ui; public struct ScrDeck @@ -29,6 +31,9 @@ public enum Tab public DefaultEcs.Entity StatsLevel; public DefaultEcs.Entity LastHovered; - public DefaultEcs.Entity DraggedCard; + + public int VacatedDeckSlot; + public InventoryCard? DraggedCard; + public DefaultEcs.Entity DraggedCardImage; public DefaultEcs.Entity DraggedOverlay; } diff --git a/zzre/game/components/ui/Slot.cs b/zzre/game/components/ui/Slot.cs index 16dd991f..23391f26 100644 --- a/zzre/game/components/ui/Slot.cs +++ b/zzre/game/components/ui/Slot.cs @@ -4,12 +4,14 @@ namespace zzre.game.components.ui; public record struct Slot { - public enum Type { DeckSlot, ListSlot } + public enum Type { DeckSlot, ListSlot, SpellSlot } public Type type; + public int index; public InventoryCard? card; public DefaultEcs.Entity button; public components.ui.ElementId buttonId; - public DefaultEcs.Entity usedMarker; + public DefaultEcs.Entity usedMarker; // ListSlot only public DefaultEcs.Entity summary; - public DefaultEcs.Entity[] spellSlots; + public DefaultEcs.Entity req; // SpellSlot only + public DefaultEcs.Entity[] spellSlots; // DeckSlot only }; diff --git a/zzre/game/components/ui/SlotButton.cs b/zzre/game/components/ui/SlotButton.cs new file mode 100644 index 00000000..f50f9a7f --- /dev/null +++ b/zzre/game/components/ui/SlotButton.cs @@ -0,0 +1,3 @@ +namespace zzre.game.components.ui; + +public record struct SlotButton; diff --git a/zzre/game/components/ui/SpellSlot.cs b/zzre/game/components/ui/SpellSlot.cs deleted file mode 100644 index 25da5a1d..00000000 --- a/zzre/game/components/ui/SpellSlot.cs +++ /dev/null @@ -1,12 +0,0 @@ -using zzio; - -namespace zzre.game.components.ui; - -public record struct SpellSlot -{ - public InventorySpell? spell; - public int index; - public DefaultEcs.Entity button; - public DefaultEcs.Entity summary; - public DefaultEcs.Entity req; -}; diff --git a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs index d7f533fb..dce0596a 100644 --- a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs @@ -27,6 +27,7 @@ components.ui.ElementId id .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Wiz000) .Build(); + slot.button.Set(new components.ui.SlotButton()); UnsetSlot(ref slot); return entity; diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index 3ff72d21..75fb28dc 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -59,13 +59,13 @@ private void InfoMode(ref components.ui.Slot slot) _ => throw new NotSupportedException("Unknown inventory card type") })); foreach (var spellSlot in slot.spellSlots) - InfoMode(ref spellSlot.Get()); + InfoModeSpell(ref spellSlot.Get()); } private static void SpellMode(ref components.ui.Slot slot) { slot.summary.Set(new components.ui.Label("")); foreach (var spellSlot in slot.spellSlots) - SpellMode(ref spellSlot.Get()); + SpellModeSpell(ref spellSlot.Get()); } } diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 24b1a64f..61550623 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -23,31 +23,32 @@ public partial class ScrDeck new(0xB26B36A1) ]; - private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref components.ui.Slot slot, int index) + private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref components.ui.Slot parentSlot, int index) { var entity = World.CreateEntity(); entity.Set(new components.Parent(parent)); - entity.Set(new components.ui.SpellSlot()); - ref var spellSlot = ref entity.Get(); - spellSlot.index = index; + entity.Set(new components.ui.Slot()); + ref var slot = ref entity.Get(); + slot.index = index; - spellSlot.button = preload.CreateButton(entity) - .With(slot.buttonId + index + 1) - .With(Rect.FromTopLeftSize(slot.button.Get().Min + new Vector2(50 + 46 * spellSlot.index, 0), SpellSlotSize)) + slot.button = preload.CreateButton(entity) + .With(parentSlot.buttonId + index + 1) + .With(Rect.FromTopLeftSize(parentSlot.button.Get().Min + new Vector2(50 + 46 * slot.index, 0), SpellSlotSize)) .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Spl000) .Build(); + slot.button.Set(new components.ui.SlotButton()); - InfoMode(ref spellSlot); + InfoModeSpell(ref slot); return entity; } public void SetSpellSlot(DefaultEcs.Entity entity, InventorySpell invSpell) { - ref var spellSlot = ref entity.Get(); - spellSlot.spell = invSpell; - spellSlot.button.Set(new components.ui.ButtonTiles(invSpell.cardId.EntityId)); + ref var slot = ref entity.Get(); + slot.card = invSpell; + slot.button.Set(new components.ui.ButtonTiles(invSpell.cardId.EntityId)); CreateSpellSummary(entity); CreateSpellReq(entity); } @@ -57,32 +58,32 @@ public void UnsetSpellSlot(DefaultEcs.Entity entity) CreateSpellReq(entity); } - public void InfoMode(ref components.ui.SpellSlot spellSlot) + public void InfoModeSpell(ref components.ui.Slot slot) { - spellSlot.button.Set(components.Visibility.Invisible); - spellSlot.button.Set(new components.ui.TooltipUID(UIDFairyInfoDescriptions[spellSlot.index])); - if (spellSlot.summary != default) - spellSlot.summary.Set(spellSlot.spell != default - ? new components.ui.Label(FormatManaAmount(spellSlot.spell)) + slot.button.Set(components.Visibility.Invisible); + slot.button.Set(new components.ui.TooltipUID(UIDFairyInfoDescriptions[slot.index])); + if (slot.summary != default) + slot.summary.Set(slot.card != default + ? new components.ui.Label(FormatManaAmount((InventorySpell)slot.card)) : new components.ui.Label("")); - if (spellSlot.req != default) - spellSlot.req.Set(components.Visibility.Invisible); + if (slot.req != default) + slot.req.Set(components.Visibility.Invisible); } - public static void SpellMode(ref components.ui.SpellSlot spellSlot) + public static void SpellModeSpell(ref components.ui.Slot slot) { - if (spellSlot.button.Get().Normal != -1) - spellSlot.button.Set(components.Visibility.Visible); - spellSlot.button.Set(new components.ui.TooltipUID(UIDSpellSlotNames[spellSlot.index])); - if (spellSlot.summary != default) - spellSlot.summary.Set(new components.ui.Label("")); - if (spellSlot.req != default) - spellSlot.req.Set(components.Visibility.Visible); + if (slot.button.Get().Normal != -1) + slot.button.Set(components.Visibility.Visible); + slot.button.Set(new components.ui.TooltipUID(UIDSpellSlotNames[slot.index])); + if (slot.summary != default) + slot.summary.Set(new components.ui.Label("")); + if (slot.req != default) + slot.req.Set(components.Visibility.Visible); } private void CreateSpellSummary(DefaultEcs.Entity entity) { - ref var spellSlot = ref entity.Get(); + ref var spellSlot = ref entity.Get(); if (spellSlot.summary != default) spellSlot.summary.Dispose(); spellSlot.summary = preload.CreateLabel(entity) .With(spellSlot.button.Get().Min + new Vector2(0, 48)) @@ -92,23 +93,23 @@ private void CreateSpellSummary(DefaultEcs.Entity entity) private void CreateSpellReq(DefaultEcs.Entity entity) { - ref var spellSlot = ref entity.Get(); - var spellReq = ((InventoryFairy)(entity.Get().Entity.Get().card!)).spellReqs[spellSlot.index]; - var isAttack = spellSlot.index % 2 == 0; - var pos = spellSlot.button.Get().Min + new Vector2(2, 45); - - if (spellSlot.req != default) spellSlot.req.Dispose(); - spellSlot.req = World.CreateEntity(); - spellSlot.req.Set(new components.Parent(entity)); - spellSlot.req.Set(components.Visibility.Visible); - spellSlot.req.Set(components.ui.UIOffset.Center); - spellSlot.req.Set(new components.ui.RenderOrder(0)); - spellSlot.req.Set(IColor.White); - assetRegistry.LoadUITileSheet(spellSlot.req, isAttack ? UIPreloadAsset.Cls001 : UIPreloadAsset.Cls000); - - var tileSize = spellSlot.req.Get().GetPixelSize(0); - spellSlot.req.Set(Rect.FromTopLeftSize(pos, tileSize * 3)); - spellSlot.req.Set(spellReq.Select((req, i) => new components.ui.Tile( + ref var slot = ref entity.Get(); + var spellReq = ((InventoryFairy)(entity.Get().Entity.Get().card!)).spellReqs[slot.index]; + var isAttack = slot.index % 2 == 0; + var pos = slot.button.Get().Min + new Vector2(2, 45); + + if (slot.req != default) slot.req.Dispose(); + slot.req = World.CreateEntity(); + slot.req.Set(new components.Parent(entity)); + slot.req.Set(components.Visibility.Visible); + slot.req.Set(components.ui.UIOffset.Center); + slot.req.Set(new components.ui.RenderOrder(0)); + slot.req.Set(IColor.White); + assetRegistry.LoadUITileSheet(slot.req, isAttack ? UIPreloadAsset.Cls001 : UIPreloadAsset.Cls000); + + var tileSize = slot.req.Get().GetPixelSize(0); + slot.req.Set(Rect.FromTopLeftSize(pos, tileSize * 3)); + slot.req.Set(spellReq.Select((req, i) => new components.ui.Tile( TileId: (int)req, Rect: Rect.FromTopLeftSize(pos + i * new Vector2(8, 5), tileSize))) .ToArray()); diff --git a/zzre/game/systems/ui/ScrDeck.Summary.cs b/zzre/game/systems/ui/ScrDeck.Summary.cs index d6ce5a79..caeeda24 100644 --- a/zzre/game/systems/ui/ScrDeck.Summary.cs +++ b/zzre/game/systems/ui/ScrDeck.Summary.cs @@ -14,32 +14,33 @@ public partial class ScrDeck new(0x238A3981), // Mana new(0x04211121), // Fire Rate ]; + private static readonly UID numCollectedFairies = new(0xA3EC01B1); private void CreateStats(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { - ResetStats(ref deck); - var card = deck.LastHovered.Get().card; - // Show empty stats for blank buttons - if (card == default) - return; - var summary = FormatStats(card); + var card = GetHoveredCard(entity, ref deck); + var summary = card == default ? GetDefaultSummary(ref deck) : FormatStats(card); + if (deck.StatsTitle != default) deck.StatsTitle.Dispose(); deck.StatsTitle = preload.CreateLabel(entity) .With(Mid + new Vector2(320, 350)) .With(UIPreloadAsset.Fnt000) .WithText(summary[0]) .Build(); + if (deck.StatsDescriptions != default) deck.StatsDescriptions.Dispose(); deck.StatsDescriptions = preload.CreateLabel(entity) .With(Mid + new Vector2(330, 379)) .With(UIPreloadAsset.Fnt002) .WithText(summary[1]) .WithLineWrap(260f) .Build(); + if (deck.StatsLights != default) deck.StatsLights.Dispose(); deck.StatsLights = preload.CreateLabel(entity) .With(Mid + new Vector2(380, 379)) .With(UIPreloadAsset.Fnt002) .WithText(summary[2]) .Build(); + if (deck.StatsLevel != default) deck.StatsLevel.Dispose(); deck.StatsLevel = preload.CreateLabel(entity) .With(Mid + new Vector2(473, 379)) .With(UIPreloadAsset.Fnt002) @@ -47,22 +48,37 @@ private void CreateStats(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec .Build(); } - private static void ResetStats(ref components.ui.ScrDeck deck) + private InventoryCard? GetHoveredCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { - var allEntities = new[] - { - deck.StatsTitle, - deck.StatsDescriptions, - deck.StatsLights, - deck.StatsLevel - }; - foreach (var entity in allEntities) - if (entity != default) - entity.Dispose(); - deck.StatsTitle = - deck.StatsDescriptions = - deck.StatsLights = - deck.StatsLevel = default; + // Hovering over a non-slot entity + if (!deck.LastHovered.Has()) return default; + + ref var slot = ref deck.LastHovered.Get().Entity.Get(); + + // Hovering over an empty slot entity + if (slot.card == default) + return default; + + // Hovering over deck slot while in fairy tab (get "faery count" instead) + if (deck.ActiveTab == components.ui.ScrDeck.Tab.Fairies && slot.type == components.ui.Slot.Type.DeckSlot) + return default; + + // Dragging fairy over non-deck slot + if (deck.DraggedCard?.cardId.Type == CardType.Fairy && slot.type != components.ui.Slot.Type.DeckSlot) + return default; + + // Dragging spell over non-spell slot + if (deck.DraggedCard?.cardId.Type == CardType.Spell && slot.type != components.ui.Slot.Type.SpellSlot) + return default; + + return slot.card; + } + + private string[] GetDefaultSummary(ref components.ui.ScrDeck deck) + { + if (deck.ActiveTab == components.ui.ScrDeck.Tab.Fairies) + return ["", $"{mappedDB.GetText(numCollectedFairies).Text} {inventory.Fairies.Count()}", "", ""]; + return ["", "", "", ""]; } private string[] FormatStats(InventoryFairy fairy) @@ -120,5 +136,4 @@ private string[] FormatStats(InventoryCard card) CardType.Fairy => FormatStats((InventoryFairy)card), _ => throw new ArgumentException($"Invalid inventory card type: {card.cardId.Type}") }; - } diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 7439949f..c76f83ed 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -252,14 +252,14 @@ private void TryDragCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec { if (!IsDraggable(card)) return; - if (deck.DraggedCard != default) deck.DraggedCard.Dispose(); - deck.DraggedCard = preload.CreateImage(entity) + if (deck.DraggedCardImage != default) deck.DraggedCardImage.Dispose(); + deck.DraggedCardImage = preload.CreateImage(entity) .With(Mid) .With(card.cardId) .WithRenderOrder(-2) .Build(); - deck.DraggedCard.Set(new components.ui.DraggedCard(card)); - deck.DraggedCard.Set(components.ui.UIOffset.GameUpperLeft); + deck.DraggedCardImage.Set(new components.ui.DraggedCard(card)); + deck.DraggedCardImage.Set(components.ui.UIOffset.GameUpperLeft); if (deck.DraggedOverlay != default) deck.DraggedOverlay.Dispose(); deck.DraggedOverlay = preload.CreateImage(entity) @@ -318,23 +318,26 @@ private void Drag(DefaultEcs.Entity entity) tiles[0].Rect = tiles[0].Rect with { Center = ui.CursorEntity.Get().Center }; } - private void TryStartDragging(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + private void HandleHover(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { var curHovered = World.Has() ? World.Get() : default; - if (curHovered.Entity == deck.LastHovered) - return; + + // Still hovering over the same entity + if (curHovered.Entity == deck.LastHovered) return; + + // Unhovered an entity if (deck.LastHovered != default) { deck.LastHovered = default; - ResetStats(ref deck); - } - if (deck.ListSlots.Contains(curHovered.Entity)) - { - deck.LastHovered = curHovered.Entity; CreateStats(entity, ref deck); + return; } + + // Hovered an entity + deck.LastHovered = curHovered.Entity; + CreateStats(entity, ref deck); } private void UpdateScroll(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) @@ -351,12 +354,12 @@ private void UpdateScroll(DefaultEcs.Entity entity, ref components.ui.ScrDeck de protected override void Update(float elapsedTime, in DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { - TryStartDragging(entity, ref deck); + HandleHover(entity, ref deck); UpdateScroll(entity, ref deck); - if (deck.DraggedCard != default) + if (deck.DraggedCardImage != default) { - Drag(deck.DraggedCard); + Drag(deck.DraggedCardImage); Drag(deck.DraggedOverlay); } } diff --git a/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs b/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs index c4ceed9b..676bda32 100644 --- a/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs +++ b/zzre/tools/ECSExplorer/ECSExplorer.Standard.cs @@ -1,4 +1,4 @@ -using System; +using System; using zzre.game.components; using zzre.game.components.ui; using zzre.materials; @@ -69,8 +69,7 @@ private static void AddStandardEntityNaming() AddEntityNamerByComponent(High, e => $"Tooltip Target {e}"); AddEntityNamerByComponent(High, e => $"Fade {e}"); AddEntityNamerByComponent(High, e => $"Slider #{e.TryGet().GetValueOrDefault(default).Value} {e}"); - AddEntityNamerByComponent(High, e => $"{e.TryGet().GetValueOrDefault(default).type} {e}"); - AddEntityNamerByComponent(High, e => $"SpellSlot #{e.TryGet().GetValueOrDefault(default).index} {e}"); + AddEntityNamerByComponent(High, e => $"{e.TryGet().GetValueOrDefault(default).type} #{e.TryGet().GetValueOrDefault(default).index} {e}"); AddEntityNamerByComponent(High, (in AnimatedLabel label) => $"Anim. Label \"{Sanitize(label.FullText)}\""); AddEntityNamerByComponent(Def, (in Label label) => $"Label \"{Sanitize(label.Text)}\""); AddEntityNamerByComponent(Low, e => $"Visuals {e}"); From efffe133bf72480029ace1d773ad08d8c099acce Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 17 Dec 2024 14:38:11 +0500 Subject: [PATCH 20/57] fix: basic dragging --- zzre/game/components/ui/ScrDeck.cs | 3 +-- zzre/game/systems/ui/ScrDeck.cs | 27 ++++++++++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/zzre/game/components/ui/ScrDeck.cs b/zzre/game/components/ui/ScrDeck.cs index 588eb7a6..6ea5117c 100644 --- a/zzre/game/components/ui/ScrDeck.cs +++ b/zzre/game/components/ui/ScrDeck.cs @@ -25,13 +25,12 @@ public enum Tab public DefaultEcs.Entity[] DeckSlots; public DefaultEcs.Entity[] ListSlots; + public DefaultEcs.Entity LastHovered; public DefaultEcs.Entity StatsTitle; public DefaultEcs.Entity StatsDescriptions; public DefaultEcs.Entity StatsLights; public DefaultEcs.Entity StatsLevel; - public DefaultEcs.Entity LastHovered; - public int VacatedDeckSlot; public InventoryCard? DraggedCard; public DefaultEcs.Entity DraggedCardImage; diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index c76f83ed..269789f4 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -275,6 +275,23 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El var deckEntity = Set.GetEntities()[0]; ref var deck = ref deckEntity.Get(); + if (clickedEntity.Has()) + { + ref var slot = ref deck.LastHovered.Get().Entity.Get(); + if (slot.card != default) + TryDragCard(deckEntity, ref deck, slot.card); + } + + // if (id >= FirstListCell && id < FirstListCell + deck.ListSlots.Length) + // { + // if (clickedEntity.TryGet(out components.ui.DraggedCard card)) + // if (card.card != default) + // TryDragCard(deckEntity, ref deck, card.card); + // } + + if (deck.VacatedDeckSlot != default) + return; + if (id == IDSwitchListMode) { deck.IsGridMode = !deck.IsGridMode; @@ -296,12 +313,6 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El UpdateSliderPosition(deck); FillList(ref deck); } - else if (id >= FirstListCell && id < FirstListCell + deck.ListSlots.Length) - { - if (clickedEntity.TryGet(out components.ui.DraggedCard card)) - if (card.card != default) - TryDragCard(deckEntity, ref deck, card.card); - } else HandleNavClick(id, zanzarah, deckEntity, IDOpenDeck); } @@ -367,7 +378,9 @@ protected override void Update(float elapsedTime, in DefaultEcs.Entity entity, r protected override void HandleKeyDown(KeyCode key) { var deckEntity = Set.GetEntities()[0]; + ref var deck = ref deckEntity.Get(); base.HandleKeyDown(key); - HandleNavKeyDown(key, zanzarah, deckEntity, IDOpenDeck); + if (deck.DraggedCardImage == default) + HandleNavKeyDown(key, zanzarah, deckEntity, IDOpenDeck); } } From a2e7771634ed70c2b0998557705489a39c449e58 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 17 Dec 2024 15:30:03 +0500 Subject: [PATCH 21/57] fix: restrict dragging on slot type --- zzre/game/components/ui/Slot.cs | 2 +- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 1 + zzre/game/systems/ui/ScrDeck.Summary.cs | 2 +- zzre/game/systems/ui/ScrDeck.cs | 43 +++++++++++++++-------- 4 files changed, 31 insertions(+), 17 deletions(-) diff --git a/zzre/game/components/ui/Slot.cs b/zzre/game/components/ui/Slot.cs index 23391f26..4693e887 100644 --- a/zzre/game/components/ui/Slot.cs +++ b/zzre/game/components/ui/Slot.cs @@ -4,7 +4,7 @@ namespace zzre.game.components.ui; public record struct Slot { - public enum Type { DeckSlot, ListSlot, SpellSlot } + public enum Type { None, DeckSlot, ListSlot, SpellSlot } public Type type; public int index; public InventoryCard? card; diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 61550623..9431c0e3 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -29,6 +29,7 @@ private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref componen entity.Set(new components.Parent(parent)); entity.Set(new components.ui.Slot()); ref var slot = ref entity.Get(); + slot.type = components.ui.Slot.Type.SpellSlot; slot.index = index; slot.button = preload.CreateButton(entity) diff --git a/zzre/game/systems/ui/ScrDeck.Summary.cs b/zzre/game/systems/ui/ScrDeck.Summary.cs index caeeda24..3243ba91 100644 --- a/zzre/game/systems/ui/ScrDeck.Summary.cs +++ b/zzre/game/systems/ui/ScrDeck.Summary.cs @@ -48,7 +48,7 @@ private void CreateStats(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec .Build(); } - private InventoryCard? GetHoveredCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + private static InventoryCard? GetHoveredCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { // Hovering over a non-slot entity if (!deck.LastHovered.Has()) return default; diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 269789f4..9c794b89 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -248,9 +248,9 @@ private void OpenTab(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, T RecreateList(entity, ref deck); } - private void TryDragCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, InventoryCard card) + private void DragCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, InventoryCard card) { - if (!IsDraggable(card)) return; + // if (!IsDraggable(card)) return; if (deck.DraggedCardImage != default) deck.DraggedCardImage.Dispose(); deck.DraggedCardImage = preload.CreateImage(entity) @@ -270,24 +270,33 @@ private void TryDragCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec deck.DraggedOverlay.Set(components.ui.UIOffset.GameUpperLeft); } + private void HandleSlotDown(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) + { + ref var slot = ref slotEntity.Get(); + if (slot.card == default) return; + switch (slot.type) + { + case components.ui.Slot.Type.DeckSlot: + DragCard(deckEntity, ref deck, slot.card); + break; + case components.ui.Slot.Type.ListSlot: + if (IsDraggable(slot.card)) + DragCard(deckEntity, ref deck, slot.card); + break; + case components.ui.Slot.Type.SpellSlot: + break; + default: + throw new ArgumentException($"Invalid slot type: {slot.type}"); + } + } + private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.ElementId id) { var deckEntity = Set.GetEntities()[0]; ref var deck = ref deckEntity.Get(); if (clickedEntity.Has()) - { - ref var slot = ref deck.LastHovered.Get().Entity.Get(); - if (slot.card != default) - TryDragCard(deckEntity, ref deck, slot.card); - } - - // if (id >= FirstListCell && id < FirstListCell + deck.ListSlots.Length) - // { - // if (clickedEntity.TryGet(out components.ui.DraggedCard card)) - // if (card.card != default) - // TryDragCard(deckEntity, ref deck, card.card); - // } + HandleSlotDown(deckEntity, ref deck, clickedEntity.Get().Entity); if (deck.VacatedDeckSlot != default) return; @@ -313,7 +322,11 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El UpdateSliderPosition(deck); FillList(ref deck); } - else HandleNavClick(id, zanzarah, deckEntity, IDOpenDeck); + + if (deck.DraggedCardImage != default) + return; + + HandleNavClick(id, zanzarah, deckEntity, IDOpenDeck); } private void UpdateSliderPosition(in components.ui.ScrDeck deck) From ec3d206dfc2d00aa27c53ff43b59b33e96b8dbce Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 17 Dec 2024 17:09:17 +0500 Subject: [PATCH 22/57] fix: assign indices to slots --- zzre/game/systems/ui/ScrDeck.BaseSlot.cs | 5 +++-- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 9 +++++---- zzre/game/systems/ui/ScrDeck.ListSlot.cs | 5 +++-- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 10 +++++++--- zzre/game/systems/ui/ScrDeck.cs | 4 ++-- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs index dce0596a..0ff48c80 100644 --- a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs @@ -12,14 +12,15 @@ public partial class ScrDeck private DefaultEcs.Entity CreateBaseSlot( DefaultEcs.Entity parent, Vector2 pos, - components.ui.ElementId id + components.ui.ElementId id, + int index ) { var entity = World.CreateEntity(); entity.Set(new components.Parent(parent)); entity.Set(new components.ui.Slot()); ref var slot = ref entity.Get(); - + slot.index = index; slot.buttonId = id; slot.button = preload.CreateButton(entity) .With(id) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index 75fb28dc..6865264a 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -12,12 +12,13 @@ public partial class ScrDeck private static readonly UID UIDUseItemOnFairy = new(0x41912581); private DefaultEcs.Entity CreateDeckSlot( - DefaultEcs.Entity parent, - Vector2 pos, - components.ui.ElementId id + DefaultEcs.Entity parent, + Vector2 pos, + components.ui.ElementId id, + int index ) { - var entity = CreateBaseSlot(parent, pos, id); + var entity = CreateBaseSlot(parent, pos, id, index); ref var slot = ref entity.Get(); slot.type = components.ui.Slot.Type.DeckSlot; diff --git a/zzre/game/systems/ui/ScrDeck.ListSlot.cs b/zzre/game/systems/ui/ScrDeck.ListSlot.cs index d9480807..452cd0db 100644 --- a/zzre/game/systems/ui/ScrDeck.ListSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.ListSlot.cs @@ -10,10 +10,11 @@ public partial class ScrDeck private DefaultEcs.Entity CreateListSlot( DefaultEcs.Entity parent, Vector2 pos, - components.ui.ElementId id + components.ui.ElementId id, + int index ) { - var entity = CreateBaseSlot(parent, pos, id); + var entity = CreateBaseSlot(parent, pos, id, index); ref var slot = ref entity.Get(); slot.type = components.ui.Slot.Type.ListSlot; diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 9431c0e3..1c4abc6c 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -23,7 +23,11 @@ public partial class ScrDeck new(0xB26B36A1) ]; - private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref components.ui.Slot parentSlot, int index) + private DefaultEcs.Entity CreateSpellSlot( + DefaultEcs.Entity parent, + ref components.ui.Slot parentSlot, + int index + ) { var entity = World.CreateEntity(); entity.Set(new components.Parent(parent)); @@ -31,9 +35,9 @@ private DefaultEcs.Entity CreateSpellSlot(DefaultEcs.Entity parent, ref componen ref var slot = ref entity.Get(); slot.type = components.ui.Slot.Type.SpellSlot; slot.index = index; - + slot.buttonId = parentSlot.buttonId + index + 1; slot.button = preload.CreateButton(entity) - .With(parentSlot.buttonId + index + 1) + .With(slot.buttonId) .With(Rect.FromTopLeftSize(parentSlot.button.Get().Min + new Vector2(50 + 46 * slot.index, 0), SpellSlotSize)) .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Spl000) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 9c794b89..ca1e107f 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -146,7 +146,7 @@ private void CreateDeckSlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck.DeckSlots = new DefaultEcs.Entity[Inventory.FairySlotCount]; for (int i = 0; i < Inventory.FairySlotCount; i++) { - deck.DeckSlots[i] = CreateDeckSlot(entity, Mid + new Vector2(31, 60 + 79 * i), FirstFairySlot + i); + deck.DeckSlots[i] = CreateDeckSlot(entity, Mid + new Vector2(31, 60 + 79 * i), FirstFairySlot + i, i); var fairy = inventory.GetFairyAtSlot(i); if (fairy != default) SetDeckSlot(deck.DeckSlots[i], fairy); @@ -186,7 +186,7 @@ private void CreateListSlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck for (int x = 0; x < columns; x++) { var i = y * columns + x; - deck.ListSlots[i] = CreateListSlot(entity, ListSlotPos(x, y), FirstListCell + i); + deck.ListSlots[i] = CreateListSlot(entity, ListSlotPos(x, y), FirstListCell + i, i); if (columns == 1) CreateSlotSummary(deck.ListSlots[i], new(42, 9)); } From 34746dd833e039fa42ecb897ba810420715fb3c4 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 17 Dec 2024 17:57:07 +0500 Subject: [PATCH 23/57] feat: add drop --- zzre/game/systems/ui/BaseScreen.cs | 9 ++++- zzre/game/systems/ui/ScrDeck.Drag.cs | 53 ++++++++++++++++++++++++++++ zzre/game/systems/ui/ScrDeck.cs | 46 +++++++----------------- 3 files changed, 73 insertions(+), 35 deletions(-) create mode 100644 zzre/game/systems/ui/ScrDeck.Drag.cs diff --git a/zzre/game/systems/ui/BaseScreen.cs b/zzre/game/systems/ui/BaseScreen.cs index 977ea2a7..0720a90d 100644 --- a/zzre/game/systems/ui/BaseScreen.cs +++ b/zzre/game/systems/ui/BaseScreen.cs @@ -32,6 +32,7 @@ protected enum BlockFlags protected readonly UIBuilder preload; protected event Action? OnElementDown; protected event Action? OnElementUp; + protected event Action? OnRightClick; protected Vector2 ScreenCenter => ui.LogicalScreen.Center; @@ -90,6 +91,12 @@ protected virtual void HandleRemoved(in DefaultEcs.Entity entity, in TComponent private void HandleMouseUp(MouseButton button, Vector2 pos) => HandleMouse(button, pos, isDown: false); private void HandleMouse(MouseButton button, Vector2 pos, bool isDown) { + if (button == MouseButton.Right) + { + if (isDown) + OnRightClick?.Invoke(); + return; + } if (button != MouseButton.Left) return; @@ -112,4 +119,4 @@ protected virtual void HandleKeyDown(KeyCode key) [Update] protected virtual void Update(float timeElapsed, in DefaultEcs.Entity entity, ref TComponent component) { } -} \ No newline at end of file +} diff --git a/zzre/game/systems/ui/ScrDeck.Drag.cs b/zzre/game/systems/ui/ScrDeck.Drag.cs new file mode 100644 index 00000000..2fb2b974 --- /dev/null +++ b/zzre/game/systems/ui/ScrDeck.Drag.cs @@ -0,0 +1,53 @@ +using zzio; + +using static zzre.game.systems.ui.InGameScreen; +namespace zzre.game.systems.ui; + +public partial class ScrDeck : BaseScreen +{ + private void DragCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, InventoryCard card) + { + deck.DraggedCard = card; + + if (deck.DraggedCardImage != default) deck.DraggedCardImage.Dispose(); + deck.DraggedCardImage = preload.CreateImage(entity) + .With(Mid) + .With(card.cardId) + .WithRenderOrder(-2) + .Build(); + deck.DraggedCardImage.Set(new components.ui.DraggedCard(card)); + deck.DraggedCardImage.Set(components.ui.UIOffset.GameUpperLeft); + + if (deck.DraggedOverlay != default) deck.DraggedOverlay.Dispose(); + deck.DraggedOverlay = preload.CreateImage(entity) + .With(Mid) + .With(UIPreloadAsset.Dnd000, 0) + .WithRenderOrder(-3) + .Build(); + deck.DraggedOverlay.Set(components.ui.UIOffset.GameUpperLeft); + } + + private static void DropCard(ref components.ui.ScrDeck deck) + { + deck.DraggedCard = default; + deck.DraggedCardImage.Dispose(); + deck.DraggedCardImage = default; + deck.DraggedOverlay.Dispose(); + deck.DraggedOverlay = default; + } + + private void Drag(ref components.ui.ScrDeck deck) + { + if (deck.DraggedCardImage != default) + { + DragImage(deck.DraggedCardImage); + DragImage(deck.DraggedOverlay); + } + } + + private void DragImage(DefaultEcs.Entity entity) + { + var tiles = entity.Get(); + tiles[0].Rect = tiles[0].Rect with { Center = ui.CursorEntity.Get().Center }; + } +} diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index ca1e107f..82098072 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -50,6 +50,7 @@ public ScrDeck(ITagContainer diContainer) : base(diContainer, BlockFlags.All) assetRegistry = diContainer.GetTag(); mappedDB = diContainer.GetTag(); OnElementDown += HandleElementDown; + OnRightClick += HandleRightClick; } protected override void HandleOpen(in messages.ui.OpenDeck message) @@ -248,28 +249,6 @@ private void OpenTab(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, T RecreateList(entity, ref deck); } - private void DragCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, InventoryCard card) - { - // if (!IsDraggable(card)) return; - - if (deck.DraggedCardImage != default) deck.DraggedCardImage.Dispose(); - deck.DraggedCardImage = preload.CreateImage(entity) - .With(Mid) - .With(card.cardId) - .WithRenderOrder(-2) - .Build(); - deck.DraggedCardImage.Set(new components.ui.DraggedCard(card)); - deck.DraggedCardImage.Set(components.ui.UIOffset.GameUpperLeft); - - if (deck.DraggedOverlay != default) deck.DraggedOverlay.Dispose(); - deck.DraggedOverlay = preload.CreateImage(entity) - .With(Mid) - .With(UIPreloadAsset.Dnd000, 0) - .WithRenderOrder(-3) - .Build(); - deck.DraggedOverlay.Set(components.ui.UIOffset.GameUpperLeft); - } - private void HandleSlotDown(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) { ref var slot = ref slotEntity.Get(); @@ -336,12 +315,6 @@ private void UpdateSliderPosition(in components.ui.ScrDeck deck) slider = slider with { Current = Vector2.UnitY * Math.Clamp(deck.Scroll / (allCardsCount - 1f), 0, 1f) }; } - private void Drag(DefaultEcs.Entity entity) - { - var tiles = entity.Get(); - tiles[0].Rect = tiles[0].Rect with { Center = ui.CursorEntity.Get().Center }; - } - private void HandleHover(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { var curHovered = World.Has() @@ -380,12 +353,7 @@ protected override void Update(float elapsedTime, in DefaultEcs.Entity entity, r { HandleHover(entity, ref deck); UpdateScroll(entity, ref deck); - - if (deck.DraggedCardImage != default) - { - Drag(deck.DraggedCardImage); - Drag(deck.DraggedOverlay); - } + Drag(ref deck); } protected override void HandleKeyDown(KeyCode key) @@ -396,4 +364,14 @@ protected override void HandleKeyDown(KeyCode key) if (deck.DraggedCardImage == default) HandleNavKeyDown(key, zanzarah, deckEntity, IDOpenDeck); } + + protected void HandleRightClick() + { + Console.WriteLine("Right click"); + var deckEntity = Set.GetEntities()[0]; + ref var deck = ref deckEntity.Get(); + if (deck.DraggedCard == default) + return; + DropCard(ref deck); + } } From cfd17072871adde2ddc12184b6cddcd7154a4134 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 17 Dec 2024 20:32:44 +0500 Subject: [PATCH 24/57] fix: deck slot control flow --- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 4 +- zzre/game/systems/ui/ScrDeck.Drag.cs | 4 +- zzre/game/systems/ui/ScrDeck.cs | 60 ++++++++++++++++-------- 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index 6865264a..f8128ee4 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -31,7 +31,7 @@ int index return entity; } - private void SetDeckSlot(DefaultEcs.Entity entity, InventoryCard card) + private void SetDeckSlot(DefaultEcs.Entity entity, InventoryCard card, ref components.ui.ScrDeck deck) { ref var slot = ref entity.Get(); SetSlot(ref slot, card); @@ -47,6 +47,8 @@ private void SetDeckSlot(DefaultEcs.Entity entity, InventoryCard card) else UnsetSpellSlot(slot.spellSlots[i]); } + if (IsInfoTab(deck.ActiveTab)) InfoMode(ref slot); + else SpellMode(ref slot); } private void InfoMode(ref components.ui.Slot slot) diff --git a/zzre/game/systems/ui/ScrDeck.Drag.cs b/zzre/game/systems/ui/ScrDeck.Drag.cs index 2fb2b974..71fa730e 100644 --- a/zzre/game/systems/ui/ScrDeck.Drag.cs +++ b/zzre/game/systems/ui/ScrDeck.Drag.cs @@ -27,13 +27,15 @@ private void DragCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, deck.DraggedOverlay.Set(components.ui.UIOffset.GameUpperLeft); } - private static void DropCard(ref components.ui.ScrDeck deck) + private void DropCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { deck.DraggedCard = default; deck.DraggedCardImage.Dispose(); deck.DraggedCardImage = default; deck.DraggedOverlay.Dispose(); deck.DraggedOverlay = default; + SetListSlots(ref deck); + SetDeckSlots(ref deck); } private void Drag(ref components.ui.ScrDeck deck) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 82098072..ab41fbd6 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -146,11 +146,17 @@ private void CreateDeckSlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck { deck.DeckSlots = new DefaultEcs.Entity[Inventory.FairySlotCount]; for (int i = 0; i < Inventory.FairySlotCount; i++) - { deck.DeckSlots[i] = CreateDeckSlot(entity, Mid + new Vector2(31, 60 + 79 * i), FirstFairySlot + i, i); + SetDeckSlots(ref deck); + } + + private void SetDeckSlots(ref components.ui.ScrDeck deck) + { + for (int i = 0; i < Inventory.FairySlotCount; i++) + { var fairy = inventory.GetFairyAtSlot(i); if (fairy != default) - SetDeckSlot(deck.DeckSlots[i], fairy); + SetDeckSlot(deck.DeckSlots[i], fairy, ref deck); } } @@ -178,9 +184,6 @@ private static Vector2 ListSlotPos(int column, int row) => private void CreateListSlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, int columns, int rows = ListRows) { - if (deck.ListSlots != default) - foreach (var listSlot in deck.ListSlots) - listSlot.Dispose(); deck.ListSlots = new DefaultEcs.Entity[rows * columns]; for (int y = 0; y < rows; y++) { @@ -205,7 +208,7 @@ private void CreateListSlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck _ => [] }; - private void FillList(ref components.ui.ScrDeck deck) + private void SetListSlots(ref components.ui.ScrDeck deck) { var allCardsOfType = AllCardsOfType(deck); var count = allCardsOfType.Count(); @@ -225,8 +228,11 @@ private void FillList(ref components.ui.ScrDeck deck) private void RecreateList(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { + if (deck.ListSlots != default) + foreach (var listSlot in deck.ListSlots) + listSlot.Dispose(); CreateListSlots(entity, ref deck, columns: deck.IsGridMode ? 6 : 1); - FillList(ref deck); + SetListSlots(ref deck); } private static bool IsInfoTab(Tab tab) => tab == Tab.Fairies || tab == Tab.Items; @@ -249,18 +255,31 @@ private void OpenTab(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, T RecreateList(entity, ref deck); } - private void HandleSlotDown(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) + private void HandleTryDragSlot(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) + { + ref var slot = ref slotEntity.Get(); + var card = slot.card; + if (card == default) return; + if (slot.type == components.ui.Slot.Type.DeckSlot) + { + UnsetSlot(ref slot); + DragCard(deckEntity, ref deck, card); + } + else if (slot.type == components.ui.Slot.Type.ListSlot && IsDraggable(card)) + { + UnsetSlot(ref slot); + DragCard(deckEntity, ref deck, card); + } + } + + private void HandleTryDropSlot(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) { ref var slot = ref slotEntity.Get(); - if (slot.card == default) return; switch (slot.type) { case components.ui.Slot.Type.DeckSlot: - DragCard(deckEntity, ref deck, slot.card); break; case components.ui.Slot.Type.ListSlot: - if (IsDraggable(slot.card)) - DragCard(deckEntity, ref deck, slot.card); break; case components.ui.Slot.Type.SpellSlot: break; @@ -275,8 +294,12 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El ref var deck = ref deckEntity.Get(); if (clickedEntity.Has()) - HandleSlotDown(deckEntity, ref deck, clickedEntity.Get().Entity); - + { + if (deck.DraggedCard == default) + HandleTryDragSlot(deckEntity, ref deck, clickedEntity.Get().Entity); + else + HandleTryDropSlot(deckEntity, ref deck, clickedEntity.Get().Entity); + } if (deck.VacatedDeckSlot != default) return; @@ -293,13 +316,13 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El { deck.Scroll += deck.IsGridMode ? ListRows : 1; UpdateSliderPosition(deck); - FillList(ref deck); + SetListSlots(ref deck); } else if (id == IDSliderUp) { deck.Scroll -= deck.IsGridMode ? ListRows : 1; UpdateSliderPosition(deck); - FillList(ref deck); + SetListSlots(ref deck); } if (deck.DraggedCardImage != default) @@ -345,7 +368,7 @@ private void UpdateScroll(DefaultEcs.Entity entity, ref components.ui.ScrDeck de if (newScrollI != deck.Scroll) { deck.Scroll = newScrollI; - FillList(ref deck); + SetListSlots(ref deck); } } @@ -367,11 +390,10 @@ protected override void HandleKeyDown(KeyCode key) protected void HandleRightClick() { - Console.WriteLine("Right click"); var deckEntity = Set.GetEntities()[0]; ref var deck = ref deckEntity.Get(); if (deck.DraggedCard == default) return; - DropCard(ref deck); + DropCard(deckEntity, ref deck); } } From daa33ab36bbb9508ec96bb8c2e38160ac4453922 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 17 Dec 2024 21:15:21 +0500 Subject: [PATCH 25/57] feat: apply dragged card to slot --- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 9 +++- zzre/game/systems/ui/ScrDeck.Drag.cs | 6 +-- zzre/game/systems/ui/ScrDeck.cs | 67 +++++++++++++++++------- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index f8128ee4..8d94d2f3 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -31,9 +31,16 @@ int index return entity; } - private void SetDeckSlot(DefaultEcs.Entity entity, InventoryCard card, ref components.ui.ScrDeck deck) + private void SetDeckSlot(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { ref var slot = ref entity.Get(); + var card = inventory.GetFairyAtSlot(slot.index); + if (card == default) + { + UnsetSlot(ref slot); + return; + }; + SetSlot(ref slot, card); slot.button.Set(new components.ui.TooltipUID(UIDSelectFairy)); diff --git a/zzre/game/systems/ui/ScrDeck.Drag.cs b/zzre/game/systems/ui/ScrDeck.Drag.cs index 71fa730e..68b6fc0b 100644 --- a/zzre/game/systems/ui/ScrDeck.Drag.cs +++ b/zzre/game/systems/ui/ScrDeck.Drag.cs @@ -5,12 +5,12 @@ namespace zzre.game.systems.ui; public partial class ScrDeck : BaseScreen { - private void DragCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, InventoryCard card) + private void DragCard(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, InventoryCard card) { deck.DraggedCard = card; if (deck.DraggedCardImage != default) deck.DraggedCardImage.Dispose(); - deck.DraggedCardImage = preload.CreateImage(entity) + deck.DraggedCardImage = preload.CreateImage(deckEntity) .With(Mid) .With(card.cardId) .WithRenderOrder(-2) @@ -19,7 +19,7 @@ private void DragCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, deck.DraggedCardImage.Set(components.ui.UIOffset.GameUpperLeft); if (deck.DraggedOverlay != default) deck.DraggedOverlay.Dispose(); - deck.DraggedOverlay = preload.CreateImage(entity) + deck.DraggedOverlay = preload.CreateImage(deckEntity) .With(Mid) .With(UIPreloadAsset.Dnd000, 0) .WithRenderOrder(-3) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index ab41fbd6..d3188ade 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -153,11 +153,7 @@ private void CreateDeckSlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck private void SetDeckSlots(ref components.ui.ScrDeck deck) { for (int i = 0; i < Inventory.FairySlotCount; i++) - { - var fairy = inventory.GetFairyAtSlot(i); - if (fairy != default) - SetDeckSlot(deck.DeckSlots[i], fairy, ref deck); - } + SetDeckSlot(deck.DeckSlots[i], ref deck); } private static Vector2 DeckSlotPos(int fairyI, int slotI) => @@ -255,33 +251,67 @@ private void OpenTab(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, T RecreateList(entity, ref deck); } - private void HandleTryDragSlot(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) + private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) { - ref var slot = ref slotEntity.Get(); - var card = slot.card; - if (card == default) return; - if (slot.type == components.ui.Slot.Type.DeckSlot) + if (deck.DraggedCard == default) { - UnsetSlot(ref slot); - DragCard(deckEntity, ref deck, card); + // Clicking on an empty slot with an empty hand + if (slot.card == default) + return; + // Picking up a card + DragCard(deckEntity, ref deck, slot.card); + SetDeckSlot(slotEntity, ref deck); + return; } - else if (slot.type == components.ui.Slot.Type.ListSlot && IsDraggable(card)) + + // Applying a card + if (deck.DraggedCard.cardId.Type == CardType.Spell) + return; + if (deck.DraggedCard.cardId.Type == CardType.Fairy) { - UnsetSlot(ref slot); - DragCard(deckEntity, ref deck, card); + // Swap fairies + var oldDrag = deck.DraggedCard; + var newDrag = slot.card; + inventory.SetSlot((InventoryFairy)oldDrag, slot.index); + if (newDrag != default) + { + DragCard(deckEntity, ref deck, newDrag); + } + SetDeckSlot(slotEntity, ref deck); + return; + } + else if (deck.DraggedCard.cardId.Type == CardType.Item) + { + Console.WriteLine("Apply item {deck.DraggedCard.cardId} to fairy {slotEntity}"); } } - private void HandleTryDropSlot(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) + private void HandleListSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) + { + if (deck.DraggedCard != default) return; + if (slot.card == default) return; + DragCard(deckEntity, ref deck, slot.card); + } + + private void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) + { + if (deck.DraggedCard == default) return; + if (deck.DraggedCard.cardId.Type != CardType.Spell) return; + Console.WriteLine("Apply spell {deck.DraggedCard.cardId} to spell {slotEntity}"); + } + private void HandleSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) { ref var slot = ref slotEntity.Get(); switch (slot.type) { case components.ui.Slot.Type.DeckSlot: + HandleDeckSlotClick(deckEntity, ref deck, slotEntity, ref slot); break; case components.ui.Slot.Type.ListSlot: + HandleListSlotClick(deckEntity, ref deck, slotEntity, ref slot); break; case components.ui.Slot.Type.SpellSlot: + HandleSpellSlotClick(deckEntity, ref deck, slotEntity, ref slot); break; default: throw new ArgumentException($"Invalid slot type: {slot.type}"); @@ -295,10 +325,7 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El if (clickedEntity.Has()) { - if (deck.DraggedCard == default) - HandleTryDragSlot(deckEntity, ref deck, clickedEntity.Get().Entity); - else - HandleTryDropSlot(deckEntity, ref deck, clickedEntity.Get().Entity); + HandleSlotClick(deckEntity, ref deck, clickedEntity.Get().Entity); } if (deck.VacatedDeckSlot != default) return; From 3788c094d0b0cb19da4ca9cbb46a9e166c26086e Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 17 Dec 2024 21:25:08 +0500 Subject: [PATCH 26/57] refactor: move click handlers to each slot --- zzre/game/systems/ui/ScrDeck.BaseSlot.cs | 19 +++++++ zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 35 ++++++++++++ zzre/game/systems/ui/ScrDeck.ListSlot.cs | 8 +++ zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 8 +++ zzre/game/systems/ui/ScrDeck.cs | 67 ----------------------- 5 files changed, 70 insertions(+), 67 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs index 0ff48c80..b33c6a9b 100644 --- a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs @@ -104,6 +104,25 @@ private static void UnsetSlot(ref components.ui.Slot slot) slot.summary.Set(new components.ui.Label("")); } + private void HandleSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) + { + ref var slot = ref slotEntity.Get(); + switch (slot.type) + { + case components.ui.Slot.Type.DeckSlot: + HandleDeckSlotClick(deckEntity, ref deck, slotEntity, ref slot); + break; + case components.ui.Slot.Type.ListSlot: + HandleListSlotClick(deckEntity, ref deck, slotEntity, ref slot); + break; + case components.ui.Slot.Type.SpellSlot: + HandleSpellSlotClick(deckEntity, ref deck, slotEntity, ref slot); + break; + default: + throw new ArgumentException($"Invalid slot type: {slot.type}"); + } + } + private string FormatSlotSummary(InventoryFairy fairy) { var builder = new System.Text.StringBuilder(); diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index 8d94d2f3..a3e6e2bb 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -78,4 +78,39 @@ private static void SpellMode(ref components.ui.Slot slot) foreach (var spellSlot in slot.spellSlots) SpellModeSpell(ref spellSlot.Get()); } + + private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) + { + if (deck.DraggedCard == default) + { + // Clicking on an empty slot with an empty hand + if (slot.card == default) + return; + // Picking up a card + DragCard(deckEntity, ref deck, slot.card); + SetDeckSlot(slotEntity, ref deck); + return; + } + + // Applying a card + if (deck.DraggedCard.cardId.Type == CardType.Spell) + return; + if (deck.DraggedCard.cardId.Type == CardType.Fairy) + { + // Swap fairies + var oldDrag = deck.DraggedCard; + var newDrag = slot.card; + inventory.SetSlot((InventoryFairy)oldDrag, slot.index); + if (newDrag != default) + { + DragCard(deckEntity, ref deck, newDrag); + } + SetDeckSlot(slotEntity, ref deck); + return; + } + else if (deck.DraggedCard.cardId.Type == CardType.Item) + { + Console.WriteLine("Apply item {deck.DraggedCard.cardId} to fairy {slotEntity}"); + } + } } diff --git a/zzre/game/systems/ui/ScrDeck.ListSlot.cs b/zzre/game/systems/ui/ScrDeck.ListSlot.cs index 452cd0db..63c3ee7c 100644 --- a/zzre/game/systems/ui/ScrDeck.ListSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.ListSlot.cs @@ -46,6 +46,14 @@ private void SetListSlot(DefaultEcs.Entity entity, InventoryCard card) _ => throw new ArgumentException($"Invalid inventory card type: {card.cardId.Type}") }; + private void HandleListSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) + { + if (deck.DraggedCard != default) return; + if (slot.card == default) return; + if (!IsDraggable(slot.card)) return; + DragCard(deckEntity, ref deck, slot.card); + } + private components.ui.TooltipUID CardTooltip(InventoryItem item) => !IsDraggable(item) ? new UID(0x8F4510A1) // item cannot be used diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 1c4abc6c..421c4f82 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -1,3 +1,4 @@ +using System; using System.Numerics; using System.Linq; using zzio; @@ -86,6 +87,13 @@ public static void SpellModeSpell(ref components.ui.Slot slot) slot.req.Set(components.Visibility.Visible); } + private void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) + { + if (deck.DraggedCard == default) return; + if (deck.DraggedCard.cardId.Type != CardType.Spell) return; + Console.WriteLine("Apply spell {deck.DraggedCard.cardId} to spell {slotEntity}"); + } + private void CreateSpellSummary(DefaultEcs.Entity entity) { ref var spellSlot = ref entity.Get(); diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index d3188ade..e3a68218 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -251,73 +251,6 @@ private void OpenTab(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck, T RecreateList(entity, ref deck); } - private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) - { - if (deck.DraggedCard == default) - { - // Clicking on an empty slot with an empty hand - if (slot.card == default) - return; - // Picking up a card - DragCard(deckEntity, ref deck, slot.card); - SetDeckSlot(slotEntity, ref deck); - return; - } - - // Applying a card - if (deck.DraggedCard.cardId.Type == CardType.Spell) - return; - if (deck.DraggedCard.cardId.Type == CardType.Fairy) - { - // Swap fairies - var oldDrag = deck.DraggedCard; - var newDrag = slot.card; - inventory.SetSlot((InventoryFairy)oldDrag, slot.index); - if (newDrag != default) - { - DragCard(deckEntity, ref deck, newDrag); - } - SetDeckSlot(slotEntity, ref deck); - return; - } - else if (deck.DraggedCard.cardId.Type == CardType.Item) - { - Console.WriteLine("Apply item {deck.DraggedCard.cardId} to fairy {slotEntity}"); - } - } - - private void HandleListSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) - { - if (deck.DraggedCard != default) return; - if (slot.card == default) return; - DragCard(deckEntity, ref deck, slot.card); - } - - private void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) - { - if (deck.DraggedCard == default) return; - if (deck.DraggedCard.cardId.Type != CardType.Spell) return; - Console.WriteLine("Apply spell {deck.DraggedCard.cardId} to spell {slotEntity}"); - } - private void HandleSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) - { - ref var slot = ref slotEntity.Get(); - switch (slot.type) - { - case components.ui.Slot.Type.DeckSlot: - HandleDeckSlotClick(deckEntity, ref deck, slotEntity, ref slot); - break; - case components.ui.Slot.Type.ListSlot: - HandleListSlotClick(deckEntity, ref deck, slotEntity, ref slot); - break; - case components.ui.Slot.Type.SpellSlot: - HandleSpellSlotClick(deckEntity, ref deck, slotEntity, ref slot); - break; - default: - throw new ArgumentException($"Invalid slot type: {slot.type}"); - } - } - private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.ElementId id) { var deckEntity = Set.GetEntities()[0]; From 5c54f135ed881ae8674c15031c0a2c27590d7f70 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 17 Dec 2024 21:56:15 +0500 Subject: [PATCH 27/57] feat: add mousewheel decklist scrolling --- zzre/game/Zanzarah.cs | 1 + zzre/game/systems/ui/BaseScreen.cs | 6 +++++- zzre/game/systems/ui/ScrDeck.cs | 13 +++++++++++++ zzre/tools/ZanzarahWindow.cs | 6 ++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/zzre/game/Zanzarah.cs b/zzre/game/Zanzarah.cs index 986ce00a..0091d673 100644 --- a/zzre/game/Zanzarah.cs +++ b/zzre/game/Zanzarah.cs @@ -24,6 +24,7 @@ public interface IZanzarahContainer event Action OnMouseDown; event Action OnMouseUp; event Action OnMouseMove; + event Action OnScroll; } public class Zanzarah : ITagContainer diff --git a/zzre/game/systems/ui/BaseScreen.cs b/zzre/game/systems/ui/BaseScreen.cs index 0720a90d..a84ea460 100644 --- a/zzre/game/systems/ui/BaseScreen.cs +++ b/zzre/game/systems/ui/BaseScreen.cs @@ -64,6 +64,7 @@ protected virtual void HandleAdded(in DefaultEcs.Entity entity, in TComponent _) zzContainer.OnMouseDown += HandleMouseDown; zzContainer.OnMouseUp += HandleMouseUp; zzContainer.OnKeyDown += HandleKeyDown; + zzContainer.OnScroll += HandleScroll; if (zanzarah.CurrentGame != null && blockFlags.HasFlag(BlockFlags.DisableGameUpdate)) zanzarah.CurrentGame.IsUpdateEnabled = false; @@ -78,6 +79,7 @@ protected virtual void HandleRemoved(in DefaultEcs.Entity entity, in TComponent zzContainer.OnMouseDown -= HandleMouseDown; zzContainer.OnMouseUp -= HandleMouseUp; zzContainer.OnKeyDown -= HandleKeyDown; + zzContainer.OnScroll -= HandleScroll; if (zanzarah.CurrentGame != null && blockFlags.HasFlag(BlockFlags.DisableGameUpdate)) zanzarah.CurrentGame.IsUpdateEnabled = true; @@ -113,7 +115,9 @@ private void HandleMouse(MouseButton button, Vector2 pos, bool isDown) protected virtual void HandleKeyDown(KeyCode key) { } - + protected virtual void HandleScroll(float scrollAmount) + { + } protected abstract void HandleOpen(in TMessage message); [Update] diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index e3a68218..14526cf4 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -356,4 +356,17 @@ protected void HandleRightClick() return; DropCard(deckEntity, ref deck); } + + protected override void HandleScroll(float scrollAmount) + { + var deckEntity = Set.GetEntities()[0]; + ref var deck = ref deckEntity.Get(); + + if (scrollAmount < 0) + deck.Scroll += deck.IsGridMode ? ListRows : 1; + else + deck.Scroll -= deck.IsGridMode ? ListRows : 1; + UpdateSliderPosition(deck); + SetListSlots(ref deck); + } } diff --git a/zzre/tools/ZanzarahWindow.cs b/zzre/tools/ZanzarahWindow.cs index a3db16a7..7ff19c0b 100644 --- a/zzre/tools/ZanzarahWindow.cs +++ b/zzre/tools/ZanzarahWindow.cs @@ -73,6 +73,12 @@ public event Action OnMouseUp remove => mouseArea.OnButtonUp -= value; } + public event Action OnScroll + { + add => mouseArea.OnScroll += value; + remove => mouseArea.OnScroll -= value; + } + public event Action OnMouseMove { add => onMouseMove += value; From 92167bab624fb331d0da50bb32d11a39fce702d2 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 17 Dec 2024 22:04:40 +0500 Subject: [PATCH 28/57] fix: temporarily undo the grid mode slider bug While the (deck.IsGridMode ? ListRows : 1)) solution worked for dragging the slider, it also broke buttons (and now the mousewheel). Ill reintroduce the bug when I know how to do it properly. --- zzre/game/systems/ui/ScrDeck.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 14526cf4..53c47db3 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -324,7 +324,7 @@ private void UpdateScroll(DefaultEcs.Entity entity, ref components.ui.ScrDeck de { var slider = deck.ListSlider.Get(); var allCardsCount = AllCardsOfType(deck).Count(); - var newScrollI = (int)MathF.Round(slider.Current.Y * (allCardsCount - 1) * (deck.IsGridMode ? ListRows : 1)); + var newScrollI = (int)MathF.Round(slider.Current.Y * (allCardsCount - 1)); if (newScrollI != deck.Scroll) { deck.Scroll = newScrollI; From 1446e99e1b012cecef628810807f404dec6dcdcc Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Wed, 18 Dec 2024 06:16:25 +0500 Subject: [PATCH 29/57] feat: drag and drop deck slots --- zzre/game/systems/ui/ScrDeck.BaseSlot.cs | 5 +++- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 30 +++++++++++++++++++++-- zzre/game/systems/ui/ScrDeck.Drag.cs | 5 +++- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 19 +++++++++++--- zzre/game/systems/ui/ScrDeck.cs | 6 +++-- 5 files changed, 56 insertions(+), 9 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs index b33c6a9b..fc0d8d39 100644 --- a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs @@ -92,7 +92,7 @@ private void SetSlot(ref components.ui.Slot slot, InventoryCard card) } } - private static void UnsetSlot(ref components.ui.Slot slot) + private void UnsetSlot(ref components.ui.Slot slot) { slot.card = default; slot.button.Set(components.Visibility.Invisible); @@ -102,6 +102,9 @@ private static void UnsetSlot(ref components.ui.Slot slot) slot.usedMarker.Set(components.Visibility.Invisible); if (slot.summary != default) slot.summary.Set(new components.ui.Label("")); + if (slot.spellSlots != default) + foreach (var spellSlot in slot.spellSlots) + UnsetSpellSlot(spellSlot); } private void HandleSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index a3e6e2bb..d51468c2 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -18,8 +18,19 @@ private DefaultEcs.Entity CreateDeckSlot( int index ) { - var entity = CreateBaseSlot(parent, pos, id, index); + var entity = World.CreateEntity(); + entity.Set(new components.Parent(parent)); + entity.Set(new components.ui.Slot()); ref var slot = ref entity.Get(); + slot.index = index; + slot.buttonId = id; + slot.button = preload.CreateButton(entity) + .With(id) + .With(Rect.FromTopLeftSize(pos, new Vector2(38, 38))) + .With(new components.ui.ButtonTiles(-1)) + .With(UIPreloadAsset.Wiz000) + .Build(); + slot.button.Set(new components.ui.SlotButton()); slot.type = components.ui.Slot.Type.DeckSlot; CreateSlotSummary(entity, new(48, 4)); @@ -28,6 +39,8 @@ int index for (int i = 0; i < InventoryFairy.SpellSlotCount; i++) slot.spellSlots[i] = CreateSpellSlot(entity, ref slot, i); + UnsetSlot(ref slot); + return entity; } @@ -87,6 +100,8 @@ private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui if (slot.card == default) return; // Picking up a card + inventory.SetSlot((InventoryFairy)slot.card, -1); + deck.VacatedDeckSlot = slot.index; DragCard(deckEntity, ref deck, slot.card); SetDeckSlot(slotEntity, ref deck); return; @@ -97,13 +112,24 @@ private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui return; if (deck.DraggedCard.cardId.Type == CardType.Fairy) { - // Swap fairies var oldDrag = deck.DraggedCard; var newDrag = slot.card; inventory.SetSlot((InventoryFairy)oldDrag, slot.index); + // Swap fairies if (newDrag != default) { DragCard(deckEntity, ref deck, newDrag); + if (newDrag.isInUse) + { + inventory.SetSlot((InventoryFairy)newDrag, -1); + deck.VacatedDeckSlot = slot.index; + } + } + else + { + // Drop off fairy + deck.VacatedDeckSlot = -1; + DropCard(ref deck); } SetDeckSlot(slotEntity, ref deck); return; diff --git a/zzre/game/systems/ui/ScrDeck.Drag.cs b/zzre/game/systems/ui/ScrDeck.Drag.cs index 68b6fc0b..338dff87 100644 --- a/zzre/game/systems/ui/ScrDeck.Drag.cs +++ b/zzre/game/systems/ui/ScrDeck.Drag.cs @@ -27,8 +27,11 @@ private void DragCard(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck de deck.DraggedOverlay.Set(components.ui.UIOffset.GameUpperLeft); } - private void DropCard(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + private void DropCard(ref components.ui.ScrDeck deck) { + if (deck.VacatedDeckSlot != -1) + inventory.SetSlot((InventoryFairy)deck.DraggedCard!, deck.VacatedDeckSlot); + deck.VacatedDeckSlot = -1; deck.DraggedCard = default; deck.DraggedCardImage.Dispose(); deck.DraggedCardImage = default; diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 421c4f82..681b3621 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -54,6 +54,7 @@ public void SetSpellSlot(DefaultEcs.Entity entity, InventorySpell invSpell) { ref var slot = ref entity.Get(); slot.card = invSpell; + slot.button.Set(components.Visibility.Visible); slot.button.Set(new components.ui.ButtonTiles(invSpell.cardId.EntityId)); CreateSpellSummary(entity); CreateSpellReq(entity); @@ -61,6 +62,10 @@ public void SetSpellSlot(DefaultEcs.Entity entity, InventorySpell invSpell) public void UnsetSpellSlot(DefaultEcs.Entity entity) { + ref var slot = ref entity.Get(); + slot.button.Set(components.Visibility.Invisible); + slot.button.Set(new components.ui.ButtonTiles(-1)); + CreateSpellSummary(entity); CreateSpellReq(entity); } @@ -87,7 +92,7 @@ public static void SpellModeSpell(ref components.ui.Slot slot) slot.req.Set(components.Visibility.Visible); } - private void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) + private static void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) { if (deck.DraggedCard == default) return; if (deck.DraggedCard.cardId.Type != CardType.Spell) return; @@ -107,11 +112,19 @@ private void CreateSpellSummary(DefaultEcs.Entity entity) private void CreateSpellReq(DefaultEcs.Entity entity) { ref var slot = ref entity.Get(); - var spellReq = ((InventoryFairy)(entity.Get().Entity.Get().card!)).spellReqs[slot.index]; + if (slot.req != default) + { + slot.req.Dispose(); + slot.req = default; + }; + + ref var deckSlot = ref entity.Get().Entity.Get(); + if (deckSlot.card == default) return; + + var spellReq = ((InventoryFairy)deckSlot.card).spellReqs[slot.index]; var isAttack = slot.index % 2 == 0; var pos = slot.button.Get().Min + new Vector2(2, 45); - if (slot.req != default) slot.req.Dispose(); slot.req = World.CreateEntity(); slot.req.Set(new components.Parent(entity)); slot.req.Set(components.Visibility.Visible); diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 53c47db3..d496a915 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -67,6 +67,8 @@ protected override void HandleOpen(in messages.ui.OpenDeck message) if (deck.ActiveTab == Tab.None) OpenTab(entity, ref deck, Tab.Fairies); + + deck.VacatedDeckSlot = -1; } private void CreateBackgrounds(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) @@ -260,7 +262,7 @@ private void HandleElementDown(DefaultEcs.Entity clickedEntity, components.ui.El { HandleSlotClick(deckEntity, ref deck, clickedEntity.Get().Entity); } - if (deck.VacatedDeckSlot != default) + if (deck.VacatedDeckSlot != -1) return; if (id == IDSwitchListMode) @@ -354,7 +356,7 @@ protected void HandleRightClick() ref var deck = ref deckEntity.Get(); if (deck.DraggedCard == default) return; - DropCard(deckEntity, ref deck); + DropCard(ref deck); } protected override void HandleScroll(float scrollAmount) From 152feb0d159405d3541703fb174252a5d79eac5d Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Wed, 18 Dec 2024 06:20:07 +0500 Subject: [PATCH 30/57] fix: update list slot markers when swapping --- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index d51468c2..ab360bda 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -119,6 +119,7 @@ private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui if (newDrag != default) { DragCard(deckEntity, ref deck, newDrag); + SetListSlots(ref deck); if (newDrag.isInUse) { inventory.SetSlot((InventoryFairy)newDrag, -1); From 83568107f30ebbd0d8f596ce953aad572681802c Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Wed, 18 Dec 2024 18:35:14 +0500 Subject: [PATCH 31/57] refactor: deck slots --- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 29 +++++++++++------------- zzre/game/systems/ui/ScrDeck.cs | 9 +++----- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index ab360bda..cb06b169 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -1,6 +1,7 @@ using System; using System.Numerics; using zzio; +using static zzre.game.systems.ui.InGameScreen; namespace zzre.game.systems.ui; @@ -13,7 +14,6 @@ public partial class ScrDeck private DefaultEcs.Entity CreateDeckSlot( DefaultEcs.Entity parent, - Vector2 pos, components.ui.ElementId id, int index ) @@ -26,7 +26,7 @@ int index slot.buttonId = id; slot.button = preload.CreateButton(entity) .With(id) - .With(Rect.FromTopLeftSize(pos, new Vector2(38, 38))) + .With(Rect.FromTopLeftSize(Mid + new Vector2(31, 60 + 79 * slot.index), new Vector2(40, 40))) .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Wiz000) .Build(); @@ -39,23 +39,25 @@ int index for (int i = 0; i < InventoryFairy.SpellSlotCount; i++) slot.spellSlots[i] = CreateSpellSlot(entity, ref slot, i); - UnsetSlot(ref slot); - return entity; } - private void SetDeckSlot(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) + private void SetDeckSlot(DefaultEcs.Entity slotEntity, ref components.ui.ScrDeck deck) { - ref var slot = ref entity.Get(); + ref var slot = ref slotEntity.Get(); var card = inventory.GetFairyAtSlot(slot.index); if (card == default) { UnsetSlot(ref slot); return; - }; + } - SetSlot(ref slot, card); + slot.card = card; + slot.button.Set(components.Visibility.Visible); + slot.button.Set(new components.ui.ButtonTiles(card.cardId.EntityId)); slot.button.Set(new components.ui.TooltipUID(UIDSelectFairy)); + slot.summary.Set(new components.ui.Label(FormatSlotSummary(card))); + SetSummaryOffset(ref slot); for (int i = 0; i < InventoryFairy.SpellSlotCount; i++) { @@ -74,13 +76,7 @@ private void SetDeckSlot(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec private void InfoMode(ref components.ui.Slot slot) { if (slot.card != default) - slot.summary.Set(new components.ui.Label(slot.card switch - { - InventoryItem item => FormatSlotSummary(item), - InventorySpell spell => FormatSlotSummary(spell), - InventoryFairy fairy => FormatSlotSummary(fairy), - _ => throw new NotSupportedException("Unknown inventory card type") - })); + slot.summary.Set(new components.ui.Label(FormatSlotSummary((InventoryFairy)(slot.card)))); foreach (var spellSlot in slot.spellSlots) InfoModeSpell(ref spellSlot.Get()); } @@ -103,7 +99,8 @@ private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui inventory.SetSlot((InventoryFairy)slot.card, -1); deck.VacatedDeckSlot = slot.index; DragCard(deckEntity, ref deck, slot.card); - SetDeckSlot(slotEntity, ref deck); + UnsetSlot(ref slot); + SetListSlots(ref deck); return; } diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index d496a915..9a50d8ff 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -148,19 +148,16 @@ private void CreateDeckSlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck { deck.DeckSlots = new DefaultEcs.Entity[Inventory.FairySlotCount]; for (int i = 0; i < Inventory.FairySlotCount; i++) - deck.DeckSlots[i] = CreateDeckSlot(entity, Mid + new Vector2(31, 60 + 79 * i), FirstFairySlot + i, i); + deck.DeckSlots[i] = CreateDeckSlot(entity, FirstFairySlot + i, i); SetDeckSlots(ref deck); } private void SetDeckSlots(ref components.ui.ScrDeck deck) { - for (int i = 0; i < Inventory.FairySlotCount; i++) - SetDeckSlot(deck.DeckSlots[i], ref deck); + foreach (var deckSlot in deck.DeckSlots) + SetDeckSlot(deckSlot, ref deck); } - private static Vector2 DeckSlotPos(int fairyI, int slotI) => - Mid + new Vector2(81 + 46 * slotI, 60 + 79 * fairyI); - private static void SpellMode(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) { deck.SpellBackground.Set(components.Visibility.Visible); From 099245040de587d630b8d03d312f94ce63c9398f Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Wed, 18 Dec 2024 20:33:37 +0500 Subject: [PATCH 32/57] fix: spell slot unsetting --- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 681b3621..581104ce 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -63,7 +63,7 @@ public void SetSpellSlot(DefaultEcs.Entity entity, InventorySpell invSpell) public void UnsetSpellSlot(DefaultEcs.Entity entity) { ref var slot = ref entity.Get(); - slot.button.Set(components.Visibility.Invisible); + UnsetSlot(ref slot); slot.button.Set(new components.ui.ButtonTiles(-1)); CreateSpellSummary(entity); CreateSpellReq(entity); From 037770901d22206edad0b9afdc864816b7306451 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 19 Dec 2024 02:05:52 +0500 Subject: [PATCH 33/57] fix: reduce visual updates on drop card --- zzre/game/systems/ui/ScrDeck.Drag.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zzre/game/systems/ui/ScrDeck.Drag.cs b/zzre/game/systems/ui/ScrDeck.Drag.cs index 338dff87..7736a0db 100644 --- a/zzre/game/systems/ui/ScrDeck.Drag.cs +++ b/zzre/game/systems/ui/ScrDeck.Drag.cs @@ -30,7 +30,10 @@ private void DragCard(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck de private void DropCard(ref components.ui.ScrDeck deck) { if (deck.VacatedDeckSlot != -1) + { inventory.SetSlot((InventoryFairy)deck.DraggedCard!, deck.VacatedDeckSlot); + SetDeckSlot(deck.DeckSlots[deck.VacatedDeckSlot], ref deck); + } deck.VacatedDeckSlot = -1; deck.DraggedCard = default; deck.DraggedCardImage.Dispose(); @@ -38,7 +41,6 @@ private void DropCard(ref components.ui.ScrDeck deck) deck.DraggedOverlay.Dispose(); deck.DraggedOverlay = default; SetListSlots(ref deck); - SetDeckSlots(ref deck); } private void Drag(ref components.ui.ScrDeck deck) From 9751899649aa6b4ec1bdea60aa4681d79d836ea3 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 19 Dec 2024 02:29:49 +0500 Subject: [PATCH 34/57] feat: spell assignment --- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 28 ++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 581104ce..ea3f79cb 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -92,11 +92,37 @@ public static void SpellModeSpell(ref components.ui.Slot slot) slot.req.Set(components.Visibility.Visible); } - private static void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) + private void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) { if (deck.DraggedCard == default) return; if (deck.DraggedCard.cardId.Type != CardType.Spell) return; Console.WriteLine("Apply spell {deck.DraggedCard.cardId} to spell {slotEntity}"); + + var fairyEntity = slotEntity.Get().Entity; + ref var fairySlot = ref fairyEntity.Get(); + + if (fairySlot.card == default) return; + + var oldDrag = deck.DraggedCard; + var newDrag = slot.card; + + inventory.SetSpellSlot((InventoryFairy)fairySlot.card, (InventorySpell)oldDrag, slot.index); + + // Swap spells + if (newDrag != default) + { + newDrag.isInUse = false; // Is this never handled in Inventory.GameLogic? + DragCard(deckEntity, ref deck, newDrag); + SetListSlots(ref deck); + } + else + { + // Drop off spell + DropCard(ref deck); + } + // Update the slot visual + SetDeckSlot(fairyEntity, ref deck); + return; } private void CreateSpellSummary(DefaultEcs.Entity entity) From 963fb556ced324ff285fd378328aeea986cbe6a2 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 19 Dec 2024 02:51:12 +0500 Subject: [PATCH 35/57] feat: throw notif on incompatible spell slots --- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index ea3f79cb..743b9707 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -1,4 +1,3 @@ -using System; using System.Numerics; using System.Linq; using zzio; @@ -96,13 +95,21 @@ private void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.u { if (deck.DraggedCard == default) return; if (deck.DraggedCard.cardId.Type != CardType.Spell) return; - Console.WriteLine("Apply spell {deck.DraggedCard.cardId} to spell {slotEntity}"); var fairyEntity = slotEntity.Get().Entity; ref var fairySlot = ref fairyEntity.Get(); if (fairySlot.card == default) return; + if (mappedDB.GetSpell(deck.DraggedCard.dbUID).Type == 0 && slot.index % 2 != 0 || + mappedDB.GetSpell(deck.DraggedCard.dbUID).Type != 0 && slot.index % 2 == 0 + ) + { + var note = slot.index % 2 == 0 ? new UID(0xC18D4C31) : new UID(0x9CD74C31); + ui.Publish(new messages.ui.Notification(mappedDB.GetText(note).Text)); + return; + } + var oldDrag = deck.DraggedCard; var newDrag = slot.card; From 5ef3fc7175cf41346d845e4f78588e2a651cb355 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 19 Dec 2024 03:50:13 +0500 Subject: [PATCH 36/57] feat: check spell for skills compatibility --- zzio/InventoryCard.cs | 21 +++++++++++++++++++++ zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 6 ++++++ 2 files changed, 27 insertions(+) diff --git a/zzio/InventoryCard.cs b/zzio/InventoryCard.cs index 3a937ea3..0589a0cc 100644 --- a/zzio/InventoryCard.cs +++ b/zzio/InventoryCard.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; +using System.Linq; namespace zzio; @@ -155,6 +156,26 @@ public IEnumerator GetEnumerator() if (class2 != ZZClass.None) yield return class2; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public bool IsCompatible(zzio.db.SpellRow spell) + { + var zzclasses = Enum.GetValues().Where(s => s != ZZClass.None); + List skills = [class0, class1, class2]; + List reqs = [spell.PriceA, spell.PriceB, spell.PriceC]; + + var neutralsNeeded = 0; + foreach (var zzclass in zzclasses) + { + var skillHad = skills.Where(s => s == zzclass).Count(); + var skillNeeded = reqs.Where(s => s == zzclass).Count(); + var skillDeficit = skillNeeded - skillHad; + if (skillDeficit > 0) + neutralsNeeded += skillDeficit; + } + if (skills.Where(s => s == ZZClass.Neutral).Count() - neutralsNeeded < 0) + return false; + return true; + } } public enum ZZPermSpellStatus diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 743b9707..c9d2e309 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -109,6 +109,12 @@ private void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.u ui.Publish(new messages.ui.Notification(mappedDB.GetText(note).Text)); return; } + if (!((InventoryFairy)fairySlot.card).spellReqs[slot.index].IsCompatible(mappedDB.GetSpell(((InventorySpell)deck.DraggedCard).dbUID))) + { + // Not enough skills to use spell + ui.Publish(new messages.ui.Notification(mappedDB.GetText(new UID(0x79C75031)).Text)); + return; + } var oldDrag = deck.DraggedCard; var newDrag = slot.card; From b6363075ead91fa06e41f6c90916f7d900bc8526 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 19 Dec 2024 03:53:18 +0500 Subject: [PATCH 37/57] fix: code style --- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 6 +++--- zzre/game/systems/ui/ScrDeck.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index cb06b169..cbf40627 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -8,9 +8,9 @@ namespace zzre.game.systems.ui; public partial class ScrDeck { private static readonly UID UIDSelectFairy = new(0x41912581); - private static readonly UID UIDPlaceFairy = new(0x41912581); - private static readonly UID UIDReplaceFairy = new(0x41912581); - private static readonly UID UIDUseItemOnFairy = new(0x41912581); + // private static readonly UID UIDPlaceFairy = new(0x41912581); + // private static readonly UID UIDReplaceFairy = new(0x41912581); + // private static readonly UID UIDUseItemOnFairy = new(0x41912581); private DefaultEcs.Entity CreateDeckSlot( DefaultEcs.Entity parent, diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 9a50d8ff..afae0f64 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -24,7 +24,7 @@ public partial class ScrDeck : BaseScreen Date: Thu, 19 Dec 2024 05:02:24 +0500 Subject: [PATCH 38/57] feat: dummy uiscript --- zzre/game/UI.cs | 1 + zzre/game/messages/ui/ExecuteUIScript.cs | 3 ++ zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 5 +- zzre/game/systems/ui/UIScript.Execute.cs | 25 +++++++++ zzre/game/systems/ui/UIScript.cs | 65 ++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 zzre/game/messages/ui/ExecuteUIScript.cs create mode 100644 zzre/game/systems/ui/UIScript.Execute.cs create mode 100644 zzre/game/systems/ui/UIScript.cs diff --git a/zzre/game/UI.cs b/zzre/game/UI.cs index 533cefa1..47b5abe8 100644 --- a/zzre/game/UI.cs +++ b/zzre/game/UI.cs @@ -81,6 +81,7 @@ public UI(ITagContainer diContainer) new systems.ui.Tooltip(this), new systems.ui.CorrectRenderOrder(this), new systems.ui.Fade(this), + new systems.ui.UIScript(this), new systems.Reaper(this), new systems.ParentReaper(this)); diff --git a/zzre/game/messages/ui/ExecuteUIScript.cs b/zzre/game/messages/ui/ExecuteUIScript.cs new file mode 100644 index 00000000..360c6a1b --- /dev/null +++ b/zzre/game/messages/ui/ExecuteUIScript.cs @@ -0,0 +1,3 @@ +namespace zzre.game.messages.ui; + +public readonly record struct ExecuteUIScript(zzio.InventoryItem item); diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index cbf40627..4a4e0860 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -1,4 +1,3 @@ -using System; using System.Numerics; using zzio; using static zzre.game.systems.ui.InGameScreen; @@ -134,7 +133,9 @@ private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui } else if (deck.DraggedCard.cardId.Type == CardType.Item) { - Console.WriteLine("Apply item {deck.DraggedCard.cardId} to fairy {slotEntity}"); + if (slot.card == default) + return; + World.Publish(new messages.ui.ExecuteUIScript((InventoryItem)deck.DraggedCard)); } } } diff --git a/zzre/game/systems/ui/UIScript.Execute.cs b/zzre/game/systems/ui/UIScript.Execute.cs new file mode 100644 index 00000000..73289e12 --- /dev/null +++ b/zzre/game/systems/ui/UIScript.Execute.cs @@ -0,0 +1,25 @@ +using System.Linq; +using zzio.script; + +namespace zzre.game.systems.ui; + +partial class UIScript +{ + private const string CmdModifyWizform = ";"; + private const string CmdIfIsWizform = "D"; + + protected override OpReturn Execute(in DefaultEcs.Entity entity, ref components.ScriptExecution script, RawInstruction instruction) + { + var args = instruction.Arguments; + switch (instruction.Command) + { + case CmdModifyWizform: + ModifyWizform(entity, (ModifyWizformType)int.Parse(args[0]), int.Parse(args[1])); + return OpReturn.Continue; + case CmdIfIsWizform: + return IfIsWizform(entity, int.Parse(args.Single())) ? OpReturn.Continue : OpReturn.ConditionalSkip; + default: + return OpReturn.UnknownInstruction; + } + } +} diff --git a/zzre/game/systems/ui/UIScript.cs b/zzre/game/systems/ui/UIScript.cs new file mode 100644 index 00000000..557dddc9 --- /dev/null +++ b/zzre/game/systems/ui/UIScript.cs @@ -0,0 +1,65 @@ +using System; +using DefaultEcs.System; +using DefaultEcs.Command; +using zzio.db; + +namespace zzre.game.systems.ui; + +public partial class UIScript : BaseScript +{ + private readonly MappedDB db; + private readonly EntityCommandRecorder recorder; + private readonly IDisposable executeUIScriptDisposable; + + public enum ModifyWizformType + { + Heal = 0, + AddXP = 1, + ClearStatusEffects = 2, + Transform = 7, + AddNearLevelXP = 8, + // 9-13: Set Unknown + // 14: Add Unknown + Revive = 16, + FillMana = 17, + Rename = 18, + } + + public UIScript(ITagContainer diContainer) : base(diContainer, CreateEntityContainer) + { + db = diContainer.GetTag(); + recorder = diContainer.GetTag(); + executeUIScriptDisposable = World.Subscribe(HandleExecuteUIScript); + } + + public override void Dispose() + { + base.Dispose(); + executeUIScriptDisposable.Dispose(); + } + + private static void ModifyWizform(DefaultEcs.Entity scriptEntity, ModifyWizformType type, int value) + { + Console.WriteLine($"Not implemented: ModifyWizform, {scriptEntity}, {type}, {value}"); + } + + private static bool IfIsWizform(DefaultEcs.Entity scriptEntity, int fairyI) // presumably? + { + Console.WriteLine($"Not implemented: IfIsWizform, {scriptEntity}, {fairyI}"); + return false; + } + + private void HandleExecuteUIScript(in messages.ui.ExecuteUIScript message) + { + var scriptEntity = World.CreateEntity(); + var scriptEntityRecord = recorder.Record(scriptEntity); + scriptEntityRecord.Set(new components.ScriptExecution(db.GetItem(message.item.dbUID).Script)); + } + + [Update] + private void Update(in DefaultEcs.Entity scriptEntity, ref components.ScriptExecution execution) + { + Continue(scriptEntity, ref execution); + scriptEntity.Dispose(); + } +} From 8652f3a79b1883569d5d25e897496e688568f2a9 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 19 Dec 2024 05:18:35 +0500 Subject: [PATCH 39/57] feat: implement IfIsWizform --- zzre/game/components/ui/UIScript.cs | 3 +++ zzre/game/messages/ui/ExecuteUIScript.cs | 5 ++++- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 2 +- zzre/game/systems/ui/UIScript.cs | 13 ++++++++++--- 4 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 zzre/game/components/ui/UIScript.cs diff --git a/zzre/game/components/ui/UIScript.cs b/zzre/game/components/ui/UIScript.cs new file mode 100644 index 00000000..867542b6 --- /dev/null +++ b/zzre/game/components/ui/UIScript.cs @@ -0,0 +1,3 @@ +namespace zzre.game.components.ui; + +public record struct UIScript(DefaultEcs.Entity DeckSlotEntity); diff --git a/zzre/game/messages/ui/ExecuteUIScript.cs b/zzre/game/messages/ui/ExecuteUIScript.cs index 360c6a1b..4a065437 100644 --- a/zzre/game/messages/ui/ExecuteUIScript.cs +++ b/zzre/game/messages/ui/ExecuteUIScript.cs @@ -1,3 +1,6 @@ namespace zzre.game.messages.ui; -public readonly record struct ExecuteUIScript(zzio.InventoryItem item); +public readonly record struct ExecuteUIScript( + zzio.InventoryItem Item, + DefaultEcs.Entity DeckSlotEntity +); diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index 4a4e0860..39b4d528 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -135,7 +135,7 @@ private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui { if (slot.card == default) return; - World.Publish(new messages.ui.ExecuteUIScript((InventoryItem)deck.DraggedCard)); + World.Publish(new messages.ui.ExecuteUIScript((InventoryItem)deck.DraggedCard, slotEntity)); } } } diff --git a/zzre/game/systems/ui/UIScript.cs b/zzre/game/systems/ui/UIScript.cs index 557dddc9..63ff2fcf 100644 --- a/zzre/game/systems/ui/UIScript.cs +++ b/zzre/game/systems/ui/UIScript.cs @@ -40,20 +40,27 @@ public override void Dispose() private static void ModifyWizform(DefaultEcs.Entity scriptEntity, ModifyWizformType type, int value) { + ref var script = ref scriptEntity.Get(); + ref var slot = ref script.DeckSlotEntity.Get(); + Console.WriteLine($"Not implemented: ModifyWizform, {scriptEntity}, {type}, {value}"); } - private static bool IfIsWizform(DefaultEcs.Entity scriptEntity, int fairyI) // presumably? + private static bool IfIsWizform(DefaultEcs.Entity scriptEntity, int fairyI) { - Console.WriteLine($"Not implemented: IfIsWizform, {scriptEntity}, {fairyI}"); + ref var script = ref scriptEntity.Get(); + ref var slot = ref script.DeckSlotEntity.Get(); + if (slot.card!.cardId.EntityId == fairyI) + return true; return false; } private void HandleExecuteUIScript(in messages.ui.ExecuteUIScript message) { var scriptEntity = World.CreateEntity(); + scriptEntity.Set(new components.ui.UIScript(message.DeckSlotEntity)); var scriptEntityRecord = recorder.Record(scriptEntity); - scriptEntityRecord.Set(new components.ScriptExecution(db.GetItem(message.item.dbUID).Script)); + scriptEntityRecord.Set(new components.ScriptExecution(db.GetItem(message.Item.dbUID).Script)); } [Update] From c7bca663baf599d643c120aebe54556b91af9432 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Thu, 19 Dec 2024 06:19:05 +0500 Subject: [PATCH 40/57] feat: implement ModifyWizform --- zzre/game/components/ui/UIScript.cs | 5 ++- zzre/game/messages/ui/UIScriptFinished.cs | 6 +++ zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 12 ++++++ zzre/game/systems/ui/ScrDeck.cs | 2 + zzre/game/systems/ui/UIScript.Execute.cs | 3 +- zzre/game/systems/ui/UIScript.cs | 50 +++++++++++++++++++++-- 6 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 zzre/game/messages/ui/UIScriptFinished.cs diff --git a/zzre/game/components/ui/UIScript.cs b/zzre/game/components/ui/UIScript.cs index 867542b6..0172e6b1 100644 --- a/zzre/game/components/ui/UIScript.cs +++ b/zzre/game/components/ui/UIScript.cs @@ -1,3 +1,6 @@ namespace zzre.game.components.ui; -public record struct UIScript(DefaultEcs.Entity DeckSlotEntity); +public record struct UIScript( + DefaultEcs.Entity DeckSlotEntity, + bool ItemConsumed +); diff --git a/zzre/game/messages/ui/UIScriptFinished.cs b/zzre/game/messages/ui/UIScriptFinished.cs new file mode 100644 index 00000000..d3417040 --- /dev/null +++ b/zzre/game/messages/ui/UIScriptFinished.cs @@ -0,0 +1,6 @@ +namespace zzre.game.messages.ui; + +public readonly record struct UIScriptFinished( + DefaultEcs.Entity DeckSlotEntity, + bool ItemConsumed +); diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index 39b4d528..6410a12e 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -138,4 +138,16 @@ private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui World.Publish(new messages.ui.ExecuteUIScript((InventoryItem)deck.DraggedCard, slotEntity)); } } + + protected void HandleUIScriptFinished(in messages.ui.UIScriptFinished message) + { + ref var deck = ref message.DeckSlotEntity.Get().Entity.Get(); + + SetDeckSlot(message.DeckSlotEntity, ref deck); + if (message.ItemConsumed) + { + inventory.RemoveCards(deck.DraggedCard!.cardId, 1); + DropCard(ref deck); + } + } } diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index afae0f64..b3867adc 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -44,6 +44,7 @@ UID TooltipUID private readonly IAssetRegistry assetRegistry; private readonly zzio.db.MappedDB mappedDB; + private readonly IDisposable OnUIScriptFinished; public ScrDeck(ITagContainer diContainer) : base(diContainer, BlockFlags.All) { @@ -51,6 +52,7 @@ public ScrDeck(ITagContainer diContainer) : base(diContainer, BlockFlags.All) mappedDB = diContainer.GetTag(); OnElementDown += HandleElementDown; OnRightClick += HandleRightClick; + OnUIScriptFinished = World.Subscribe(HandleUIScriptFinished); } protected override void HandleOpen(in messages.ui.OpenDeck message) diff --git a/zzre/game/systems/ui/UIScript.Execute.cs b/zzre/game/systems/ui/UIScript.Execute.cs index 73289e12..c92b1353 100644 --- a/zzre/game/systems/ui/UIScript.Execute.cs +++ b/zzre/game/systems/ui/UIScript.Execute.cs @@ -11,10 +11,11 @@ partial class UIScript protected override OpReturn Execute(in DefaultEcs.Entity entity, ref components.ScriptExecution script, RawInstruction instruction) { var args = instruction.Arguments; + ref var uiScript = ref entity.Get(); switch (instruction.Command) { case CmdModifyWizform: - ModifyWizform(entity, (ModifyWizformType)int.Parse(args[0]), int.Parse(args[1])); + uiScript.ItemConsumed = ModifyWizform(entity, (ModifyWizformType)int.Parse(args[0]), int.Parse(args[1])); return OpReturn.Continue; case CmdIfIsWizform: return IfIsWizform(entity, int.Parse(args.Single())) ? OpReturn.Continue : OpReturn.ConditionalSkip; diff --git a/zzre/game/systems/ui/UIScript.cs b/zzre/game/systems/ui/UIScript.cs index 63ff2fcf..4476da73 100644 --- a/zzre/game/systems/ui/UIScript.cs +++ b/zzre/game/systems/ui/UIScript.cs @@ -2,6 +2,7 @@ using DefaultEcs.System; using DefaultEcs.Command; using zzio.db; +using zzio; namespace zzre.game.systems.ui; @@ -10,6 +11,8 @@ public partial class UIScript : BaseScript private readonly MappedDB db; private readonly EntityCommandRecorder recorder; private readonly IDisposable executeUIScriptDisposable; + protected readonly Zanzarah zanzarah; + protected Inventory inventory => zanzarah.CurrentGame!.PlayerEntity.Get(); public enum ModifyWizformType { @@ -28,6 +31,7 @@ public enum ModifyWizformType public UIScript(ITagContainer diContainer) : base(diContainer, CreateEntityContainer) { db = diContainer.GetTag(); + zanzarah = diContainer.GetTag(); recorder = diContainer.GetTag(); executeUIScriptDisposable = World.Subscribe(HandleExecuteUIScript); } @@ -38,12 +42,50 @@ public override void Dispose() executeUIScriptDisposable.Dispose(); } - private static void ModifyWizform(DefaultEcs.Entity scriptEntity, ModifyWizformType type, int value) + private bool ModifyWizform(DefaultEcs.Entity scriptEntity, ModifyWizformType type, int value) { ref var script = ref scriptEntity.Get(); ref var slot = ref script.DeckSlotEntity.Get(); + var fairy = (InventoryFairy)slot.card!; - Console.WriteLine($"Not implemented: ModifyWizform, {scriptEntity}, {type}, {value}"); + switch (type) + { + case ModifyWizformType.Heal: + fairy.currentMHP += (uint)value; + if (fairy.currentMHP > fairy.maxMHP) + fairy.currentMHP = fairy.maxMHP; + return true; + case ModifyWizformType.AddXP: + inventory.AddXP(fairy, (uint)value); + return true; + case ModifyWizformType.ClearStatusEffects: + fairy.status = ZZPermSpellStatus.None; + return true; + case ModifyWizformType.Transform: + fairy.cardId = new CardId(CardType.Fairy, value); + fairy.dbUID = db.GetFairy(value).Uid; + // TODO: correctly handle evolution, including name, fairy stats + return true; + case ModifyWizformType.AddNearLevelXP: + var nearLevel = inventory.GetLevelupXP(fairy) - fairy.xp + 1; + if (nearLevel != null) + inventory.AddXP(fairy, (uint)nearLevel); + // TODO: investigate golden carrot behaviour on level 59 & 60 + return true; + case ModifyWizformType.Revive: + if (fairy.currentMHP != 0) return false; + // TODO: Determine the correct revive hp factor + fairy.currentMHP = (uint)(fairy.maxMHP * 0.5); + return true; + case ModifyWizformType.FillMana: + inventory.FillMana(fairy); + return true; + case ModifyWizformType.Rename: + Console.WriteLine($"Not implemented: ModifyWizform: Rename"); + return false; + default: + throw new NotImplementedException($"Unimplemented ModifyWizformType: {type}"); + } } private static bool IfIsWizform(DefaultEcs.Entity scriptEntity, int fairyI) @@ -58,7 +100,7 @@ private static bool IfIsWizform(DefaultEcs.Entity scriptEntity, int fairyI) private void HandleExecuteUIScript(in messages.ui.ExecuteUIScript message) { var scriptEntity = World.CreateEntity(); - scriptEntity.Set(new components.ui.UIScript(message.DeckSlotEntity)); + scriptEntity.Set(new components.ui.UIScript(message.DeckSlotEntity, false)); var scriptEntityRecord = recorder.Record(scriptEntity); scriptEntityRecord.Set(new components.ScriptExecution(db.GetItem(message.Item.dbUID).Script)); } @@ -67,6 +109,8 @@ private void HandleExecuteUIScript(in messages.ui.ExecuteUIScript message) private void Update(in DefaultEcs.Entity scriptEntity, ref components.ScriptExecution execution) { Continue(scriptEntity, ref execution); + ref var script = ref scriptEntity.Get(); + World.Publish(new messages.ui.UIScriptFinished(script.DeckSlotEntity, script.ItemConsumed)); scriptEntity.Dispose(); } } From 590a74fee27dad60368d8cca3757c3bfa3c26740 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 23 Dec 2024 21:55:34 +0500 Subject: [PATCH 41/57] feat: add interaction sounds --- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 8 ++++++++ zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 1 + zzre/game/systems/ui/UIScript.cs | 20 +++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index 6410a12e..0355aa29 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -110,7 +110,10 @@ private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui { var oldDrag = deck.DraggedCard; var newDrag = slot.card; + + World.Publish(new messages.SpawnSample("resources/audio/sfx/gui/_g012.wav")); inventory.SetSlot((InventoryFairy)oldDrag, slot.index); + // Swap fairies if (newDrag != default) { @@ -149,5 +152,10 @@ protected void HandleUIScriptFinished(in messages.ui.UIScriptFinished message) inventory.RemoveCards(deck.DraggedCard!.cardId, 1); DropCard(ref deck); } + else + { + World.Publish(new messages.SpawnSample("resources/audio/sfx/gui/_g013.wav")); + ui.Publish(new messages.ui.Notification(mappedDB.GetText(new UID(0xB5E90B81)).Text)); + } } } diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index c9d2e309..935da49b 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -119,6 +119,7 @@ private void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.u var oldDrag = deck.DraggedCard; var newDrag = slot.card; + World.Publish(new messages.SpawnSample("resources/audio/sfx/gui/_g008.wav")); inventory.SetSpellSlot((InventoryFairy)fairySlot.card, (InventorySpell)oldDrag, slot.index); // Swap spells diff --git a/zzre/game/systems/ui/UIScript.cs b/zzre/game/systems/ui/UIScript.cs index 4476da73..9e3f6a99 100644 --- a/zzre/game/systems/ui/UIScript.cs +++ b/zzre/game/systems/ui/UIScript.cs @@ -12,6 +12,7 @@ public partial class UIScript : BaseScript private readonly EntityCommandRecorder recorder; private readonly IDisposable executeUIScriptDisposable; protected readonly Zanzarah zanzarah; + protected readonly UI ui; protected Inventory inventory => zanzarah.CurrentGame!.PlayerEntity.Get(); public enum ModifyWizformType @@ -28,10 +29,16 @@ public enum ModifyWizformType Rename = 18, } + private void PlayChime() + { + World.Publish(new messages.SpawnSample("resources/audio/sfx/specials/_s021.wav")); + } + public UIScript(ITagContainer diContainer) : base(diContainer, CreateEntityContainer) { db = diContainer.GetTag(); zanzarah = diContainer.GetTag(); + ui = diContainer.GetTag(); recorder = diContainer.GetTag(); executeUIScriptDisposable = World.Subscribe(HandleExecuteUIScript); } @@ -51,14 +58,18 @@ private bool ModifyWizform(DefaultEcs.Entity scriptEntity, ModifyWizformType typ switch (type) { case ModifyWizformType.Heal: + if (fairy.currentMHP == fairy.maxMHP) return false; + PlayChime(); fairy.currentMHP += (uint)value; if (fairy.currentMHP > fairy.maxMHP) fairy.currentMHP = fairy.maxMHP; return true; case ModifyWizformType.AddXP: + // TODO: is there a chime? inventory.AddXP(fairy, (uint)value); return true; case ModifyWizformType.ClearStatusEffects: + PlayChime(); fairy.status = ZZPermSpellStatus.None; return true; case ModifyWizformType.Transform: @@ -67,17 +78,24 @@ private bool ModifyWizform(DefaultEcs.Entity scriptEntity, ModifyWizformType typ // TODO: correctly handle evolution, including name, fairy stats return true; case ModifyWizformType.AddNearLevelXP: + // TODO: is there a chime? var nearLevel = inventory.GetLevelupXP(fairy) - fairy.xp + 1; if (nearLevel != null) inventory.AddXP(fairy, (uint)nearLevel); // TODO: investigate golden carrot behaviour on level 59 & 60 return true; case ModifyWizformType.Revive: - if (fairy.currentMHP != 0) return false; + if (fairy.currentMHP != 0) + { + ui.Publish(new messages.ui.Notification(db.GetText(new UID(0x3D422781)).Text)); + return false; + } + // TODO: is there a chime? // TODO: Determine the correct revive hp factor fairy.currentMHP = (uint)(fairy.maxMHP * 0.5); return true; case ModifyWizformType.FillMana: + PlayChime(); inventory.FillMana(fairy); return true; case ModifyWizformType.Rename: From ee172d24fa10b4e7e8e03425ba597d3ec29b40bb Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 23 Dec 2024 22:01:19 +0500 Subject: [PATCH 42/57] fix: golden carrots make a chime --- zzre/game/systems/ui/UIScript.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zzre/game/systems/ui/UIScript.cs b/zzre/game/systems/ui/UIScript.cs index 9e3f6a99..f858e4f3 100644 --- a/zzre/game/systems/ui/UIScript.cs +++ b/zzre/game/systems/ui/UIScript.cs @@ -78,7 +78,7 @@ private bool ModifyWizform(DefaultEcs.Entity scriptEntity, ModifyWizformType typ // TODO: correctly handle evolution, including name, fairy stats return true; case ModifyWizformType.AddNearLevelXP: - // TODO: is there a chime? + PlayChime(); var nearLevel = inventory.GetLevelupXP(fairy) - fairy.xp + 1; if (nearLevel != null) inventory.AddXP(fairy, (uint)nearLevel); From ba72a2fb166a1bcce6099f7a268383b8f2e3b02f Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 23 Dec 2024 22:09:12 +0500 Subject: [PATCH 43/57] fix: max mana spell summary is hyphen --- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 935da49b..2bc19ede 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -184,7 +184,7 @@ private void CreateSpellReq(DefaultEcs.Entity entity) private string FormatManaAmount(InventorySpell spell) { var dbSpell = mappedDB.GetSpell(spell.dbUID); - return dbSpell.MaxMana == 5 + return dbSpell.Mana == 5 ? "{104}-" : $"{{104}}{spell.mana}/{dbSpell.MaxMana}"; } From 97f518153941a5824e661ff30b9f3d285a3a926c Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 23 Dec 2024 22:13:48 +0500 Subject: [PATCH 44/57] fix: golden carrot behaviour --- zzre/game/systems/ui/UIScript.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zzre/game/systems/ui/UIScript.cs b/zzre/game/systems/ui/UIScript.cs index f858e4f3..263866ff 100644 --- a/zzre/game/systems/ui/UIScript.cs +++ b/zzre/game/systems/ui/UIScript.cs @@ -79,7 +79,7 @@ private bool ModifyWizform(DefaultEcs.Entity scriptEntity, ModifyWizformType typ return true; case ModifyWizformType.AddNearLevelXP: PlayChime(); - var nearLevel = inventory.GetLevelupXP(fairy) - fairy.xp + 1; + var nearLevel = inventory.GetLevelupXP(fairy) - fairy.xp; if (nearLevel != null) inventory.AddXP(fairy, (uint)nearLevel); // TODO: investigate golden carrot behaviour on level 59 & 60 From 5840ecb284792f4acb4b77123ace65ebd24a077f Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Mon, 23 Dec 2024 22:37:55 +0500 Subject: [PATCH 45/57] fix: avoid overlapping notifications --- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 5 ----- zzre/game/systems/ui/UIScript.cs | 9 +++++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index 0355aa29..89015ea0 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -152,10 +152,5 @@ protected void HandleUIScriptFinished(in messages.ui.UIScriptFinished message) inventory.RemoveCards(deck.DraggedCard!.cardId, 1); DropCard(ref deck); } - else - { - World.Publish(new messages.SpawnSample("resources/audio/sfx/gui/_g013.wav")); - ui.Publish(new messages.ui.Notification(mappedDB.GetText(new UID(0xB5E90B81)).Text)); - } } } diff --git a/zzre/game/systems/ui/UIScript.cs b/zzre/game/systems/ui/UIScript.cs index 263866ff..12de4da1 100644 --- a/zzre/game/systems/ui/UIScript.cs +++ b/zzre/game/systems/ui/UIScript.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using DefaultEcs.System; using DefaultEcs.Command; using zzio.db; @@ -128,6 +129,14 @@ private void Update(in DefaultEcs.Entity scriptEntity, ref components.ScriptExec { Continue(scriptEntity, ref execution); ref var script = ref scriptEntity.Get(); + + if (!script.ItemConsumed) + { + World.Publish(new messages.SpawnSample("resources/audio/sfx/gui/_g013.wav")); + if (World.GetEntities().AsEnumerable().All(entity => !entity.Has())) + // Default failure notification if no notification was thrown during script execution + ui.Publish(new messages.ui.Notification(db.GetText(new UID(0xB5E90B81)).Text)); + } World.Publish(new messages.ui.UIScriptFinished(script.DeckSlotEntity, script.ItemConsumed)); scriptEntity.Dispose(); } From add494e9ba2ffc35bc77dfad87bd19d72f4b4274 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 00:49:37 +0500 Subject: [PATCH 46/57] fix: fairy count summary positioning --- zzre/game/systems/ui/ScrDeck.Summary.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zzre/game/systems/ui/ScrDeck.Summary.cs b/zzre/game/systems/ui/ScrDeck.Summary.cs index 3243ba91..35e355d1 100644 --- a/zzre/game/systems/ui/ScrDeck.Summary.cs +++ b/zzre/game/systems/ui/ScrDeck.Summary.cs @@ -77,7 +77,7 @@ private void CreateStats(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec private string[] GetDefaultSummary(ref components.ui.ScrDeck deck) { if (deck.ActiveTab == components.ui.ScrDeck.Tab.Fairies) - return ["", $"{mappedDB.GetText(numCollectedFairies).Text} {inventory.Fairies.Count()}", "", ""]; + return ["", $"\n\n{mappedDB.GetText(numCollectedFairies).Text} {inventory.Fairies.Count()}", "", ""]; return ["", "", "", ""]; } From 3ffa23b175ec43ed4a9dcd250760ac7a7b5f6d4a Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 01:32:46 +0500 Subject: [PATCH 47/57] fix: deck system disposal --- zzre/game/systems/ui/ScrDeck.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index b3867adc..2846ee9f 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -44,7 +44,7 @@ UID TooltipUID private readonly IAssetRegistry assetRegistry; private readonly zzio.db.MappedDB mappedDB; - private readonly IDisposable OnUIScriptFinished; + private readonly IDisposable OnUIScriptFinishedDisposable; public ScrDeck(ITagContainer diContainer) : base(diContainer, BlockFlags.All) { @@ -52,7 +52,15 @@ public ScrDeck(ITagContainer diContainer) : base(diContainer, BlockFlags.All) mappedDB = diContainer.GetTag(); OnElementDown += HandleElementDown; OnRightClick += HandleRightClick; - OnUIScriptFinished = World.Subscribe(HandleUIScriptFinished); + OnUIScriptFinishedDisposable = World.Subscribe(HandleUIScriptFinished); + } + + public override void Dispose() + { + base.Dispose(); + OnElementDown -= HandleElementDown; + OnRightClick -= HandleRightClick; + OnUIScriptFinishedDisposable.Dispose(); } protected override void HandleOpen(in messages.ui.OpenDeck message) From ecafdd83874626a84c7e97d5dcfdebead119ed2c Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 02:47:23 +0500 Subject: [PATCH 48/57] refactor: create list slot --- zzre/game/systems/ui/ScrDeck.BaseSlot.cs | 25 ------------------------ zzre/game/systems/ui/ScrDeck.ListSlot.cs | 14 ++++++++++++- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs index fc0d8d39..ca50f5f0 100644 --- a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs @@ -9,31 +9,6 @@ public partial class ScrDeck // Provide a size for buttons, including unset ones. public Vector2 SlotButtonSize = Vector2.One * 38; - private DefaultEcs.Entity CreateBaseSlot( - DefaultEcs.Entity parent, - Vector2 pos, - components.ui.ElementId id, - int index - ) - { - var entity = World.CreateEntity(); - entity.Set(new components.Parent(parent)); - entity.Set(new components.ui.Slot()); - ref var slot = ref entity.Get(); - slot.index = index; - slot.buttonId = id; - slot.button = preload.CreateButton(entity) - .With(id) - .With(pos) - .With(new components.ui.ButtonTiles(-1)) - .With(UIPreloadAsset.Wiz000) - .Build(); - slot.button.Set(new components.ui.SlotButton()); - - UnsetSlot(ref slot); - return entity; - } - private void CreateSlotSummary(DefaultEcs.Entity entity, Vector2 offset) { ref var slot = ref entity.Get(); diff --git a/zzre/game/systems/ui/ScrDeck.ListSlot.cs b/zzre/game/systems/ui/ScrDeck.ListSlot.cs index 63c3ee7c..427287b8 100644 --- a/zzre/game/systems/ui/ScrDeck.ListSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.ListSlot.cs @@ -14,9 +14,20 @@ private DefaultEcs.Entity CreateListSlot( int index ) { - var entity = CreateBaseSlot(parent, pos, id, index); + var entity = World.CreateEntity(); + entity.Set(new components.Parent(parent)); + entity.Set(new components.ui.Slot()); ref var slot = ref entity.Get(); slot.type = components.ui.Slot.Type.ListSlot; + slot.index = index; + slot.buttonId = id; + slot.button = preload.CreateButton(entity) + .With(id) + .With(pos) + .With(new components.ui.ButtonTiles(-1)) + .With(UIPreloadAsset.Wiz000) + .Build(); + slot.button.Set(new components.ui.SlotButton()); slot.usedMarker = preload.CreateImage(entity) .With(pos) @@ -25,6 +36,7 @@ int index .Invisible() .Build(); + UnsetSlot(ref slot); return entity; } From 26c31a65ab4571d32bd99132e571e2038fb95285 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 02:56:25 +0500 Subject: [PATCH 49/57] refactor: remove buttonId from component --- zzre/game/components/ui/Slot.cs | 1 - zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 1 - zzre/game/systems/ui/ScrDeck.ListSlot.cs | 1 - zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 3 +-- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/zzre/game/components/ui/Slot.cs b/zzre/game/components/ui/Slot.cs index 4693e887..48af90b5 100644 --- a/zzre/game/components/ui/Slot.cs +++ b/zzre/game/components/ui/Slot.cs @@ -9,7 +9,6 @@ public enum Type { None, DeckSlot, ListSlot, SpellSlot } public int index; public InventoryCard? card; public DefaultEcs.Entity button; - public components.ui.ElementId buttonId; public DefaultEcs.Entity usedMarker; // ListSlot only public DefaultEcs.Entity summary; public DefaultEcs.Entity req; // SpellSlot only diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index 89015ea0..f1dcb9f3 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -22,7 +22,6 @@ int index entity.Set(new components.ui.Slot()); ref var slot = ref entity.Get(); slot.index = index; - slot.buttonId = id; slot.button = preload.CreateButton(entity) .With(id) .With(Rect.FromTopLeftSize(Mid + new Vector2(31, 60 + 79 * slot.index), new Vector2(40, 40))) diff --git a/zzre/game/systems/ui/ScrDeck.ListSlot.cs b/zzre/game/systems/ui/ScrDeck.ListSlot.cs index 427287b8..b2d802cd 100644 --- a/zzre/game/systems/ui/ScrDeck.ListSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.ListSlot.cs @@ -20,7 +20,6 @@ int index ref var slot = ref entity.Get(); slot.type = components.ui.Slot.Type.ListSlot; slot.index = index; - slot.buttonId = id; slot.button = preload.CreateButton(entity) .With(id) .With(pos) diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 2bc19ede..72d55418 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -35,9 +35,8 @@ int index ref var slot = ref entity.Get(); slot.type = components.ui.Slot.Type.SpellSlot; slot.index = index; - slot.buttonId = parentSlot.buttonId + index + 1; slot.button = preload.CreateButton(entity) - .With(slot.buttonId) + .With(parentSlot.button.Get() + index + 1) .With(Rect.FromTopLeftSize(parentSlot.button.Get().Min + new Vector2(50 + 46 * slot.index, 0), SpellSlotSize)) .With(new components.ui.ButtonTiles(-1)) .With(UIPreloadAsset.Spl000) From 9843e93eeb8ff3ce82f232062559033c0a0c22a2 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 05:10:30 +0500 Subject: [PATCH 50/57] feat: fairy spells on list slot hover --- zzre/game/components/ui/Slot.cs | 2 + zzre/game/systems/ui/ScrDeck.BaseSlot.cs | 2 + zzre/game/systems/ui/ScrDeck.Drag.cs | 2 + zzre/game/systems/ui/ScrDeck.ListSlot.cs | 81 ++++++++++++++++++++++++ zzre/game/systems/ui/ScrDeck.cs | 22 +++++++ 5 files changed, 109 insertions(+) diff --git a/zzre/game/components/ui/Slot.cs b/zzre/game/components/ui/Slot.cs index 48af90b5..5a641f61 100644 --- a/zzre/game/components/ui/Slot.cs +++ b/zzre/game/components/ui/Slot.cs @@ -10,6 +10,8 @@ public enum Type { None, DeckSlot, ListSlot, SpellSlot } public InventoryCard? card; public DefaultEcs.Entity button; public DefaultEcs.Entity usedMarker; // ListSlot only + public DefaultEcs.Entity[] spellImages; // ListSlot only + public bool showSpells; // ListSlot only public DefaultEcs.Entity summary; public DefaultEcs.Entity req; // SpellSlot only public DefaultEcs.Entity[] spellSlots; // DeckSlot only diff --git a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs index ca50f5f0..307cabfb 100644 --- a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs @@ -80,6 +80,8 @@ private void UnsetSlot(ref components.ui.Slot slot) if (slot.spellSlots != default) foreach (var spellSlot in slot.spellSlots) UnsetSpellSlot(spellSlot); + if (slot.spellImages != default) + UnsetSpellImages(ref slot); } private void HandleSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) diff --git a/zzre/game/systems/ui/ScrDeck.Drag.cs b/zzre/game/systems/ui/ScrDeck.Drag.cs index 7736a0db..73d4978b 100644 --- a/zzre/game/systems/ui/ScrDeck.Drag.cs +++ b/zzre/game/systems/ui/ScrDeck.Drag.cs @@ -34,6 +34,8 @@ private void DropCard(ref components.ui.ScrDeck deck) inventory.SetSlot((InventoryFairy)deck.DraggedCard!, deck.VacatedDeckSlot); SetDeckSlot(deck.DeckSlots[deck.VacatedDeckSlot], ref deck); } + foreach (var slotEntity in deck.ListSlots) + UnsetHoverMode(slotEntity); deck.VacatedDeckSlot = -1; deck.DraggedCard = default; deck.DraggedCardImage.Dispose(); diff --git a/zzre/game/systems/ui/ScrDeck.ListSlot.cs b/zzre/game/systems/ui/ScrDeck.ListSlot.cs index b2d802cd..9f0bd6af 100644 --- a/zzre/game/systems/ui/ScrDeck.ListSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.ListSlot.cs @@ -47,6 +47,12 @@ private void SetListSlot(DefaultEcs.Entity entity, InventoryCard card) ? components.Visibility.Visible : components.Visibility.Invisible); slot.button.Set(CardTooltip(card)); + + if (slot.spellImages != default) + if (slot.showSpells) + SetSpellImages(entity); + else + UnsetSpellImages(ref slot); } private bool IsDraggable(InventoryCard card) => card.cardId.Type switch @@ -65,6 +71,81 @@ private void HandleListSlotClick(DefaultEcs.Entity deckEntity, ref components.ui DragCard(deckEntity, ref deck, slot.card); } + private void CreateSpellImages(DefaultEcs.Entity entity) + { + ref var slot = ref entity.Get(); + slot.spellImages = new DefaultEcs.Entity[4]; + for (var i = 0; i < slot.spellImages.Length; i++) + { + slot.spellImages[i] = preload.CreateImage(entity) + .With(slot.button.Get().Min + new Vector2(42 + 40 * i, 0)) + .With(UIPreloadAsset.Spl000) + .Build(); + } + UnsetSpellImages(ref slot); + } + + private void SetHoverMode(DefaultEcs.Entity entity) + { + ref var slot = ref entity.Get(); + if (slot.summary == default) return; + slot.showSpells = true; + SetSpellImages(entity); + } + private void UnsetHoverMode(DefaultEcs.Entity entity) + { + ref var slot = ref entity.Get(); + if (slot.summary == default) return; + slot.showSpells = false; + UnsetSpellImages(ref slot); + } + + private void SetSpellImages(DefaultEcs.Entity entity) + { + ref var slot = ref entity.Get(); + if (slot.card == default || slot.card.cardId.Type != CardType.Fairy) + { + UnsetSpellImages(ref slot); + return; + } + for (var i = 0; i < slot.spellImages.Length; i++) + { + var spell = inventory.GetSpellAtSlot((InventoryFairy)slot.card, i); + if (spell != default) + { + slot.spellImages[i].Set(components.Visibility.Visible); + slot.spellImages[i].Set(new components.ui.ButtonTiles(spell.cardId.EntityId)); + } + else UnsetSpellImage(slot.spellImages[i]); + } + if (slot.summary != default) + slot.summary.Set(new components.ui.Label("")); + } + + private void UnsetSpellImages(ref components.ui.Slot slot) + { + foreach (var spellImage in slot.spellImages) + UnsetSpellImage(spellImage); + + if (slot.summary != default && slot.card != default) + { + slot.summary.Set(new components.ui.Label(slot.card switch + { + InventoryItem item => FormatSlotSummary(item), + InventorySpell spell => FormatSlotSummary(spell), + InventoryFairy fairy => FormatSlotSummary(fairy), + _ => throw new NotSupportedException("Unknown inventory card type") + })); + SetSummaryOffset(ref slot); + } + } + + private void UnsetSpellImage(DefaultEcs.Entity spellImage) + { + spellImage.Set(components.Visibility.Invisible); + spellImage.Set(new components.ui.ButtonTiles(-1)); + } + private components.ui.TooltipUID CardTooltip(InventoryItem item) => !IsDraggable(item) ? new UID(0x8F4510A1) // item cannot be used diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 2846ee9f..c9d7248c 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -197,7 +197,10 @@ private void CreateListSlots(DefaultEcs.Entity entity, ref components.ui.ScrDeck var i = y * columns + x; deck.ListSlots[i] = CreateListSlot(entity, ListSlotPos(x, y), FirstListCell + i, i); if (columns == 1) + { CreateSlotSummary(deck.ListSlots[i], new(42, 9)); + CreateSpellImages(deck.ListSlots[i]); + } } } } @@ -319,6 +322,15 @@ private void HandleHover(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec // Unhovered an entity if (deck.LastHovered != default) { + if (deck.DraggedCard == default) + if (deck.LastHovered.Has()) + { + var slotEntity = deck.LastHovered.Get().Entity; + ref var slot = ref slotEntity.Get(); + if (slot.type == components.ui.Slot.Type.ListSlot) + UnsetHoverMode(slotEntity); + } + deck.LastHovered = default; CreateStats(entity, ref deck); return; @@ -326,6 +338,16 @@ private void HandleHover(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec // Hovered an entity deck.LastHovered = curHovered.Entity; + + if (deck.DraggedCard == default) + if (deck.LastHovered.Has()) + { + var slotEntity = deck.LastHovered.Get().Entity; + ref var slot = ref slotEntity.Get(); + if (slot.type == components.ui.Slot.Type.ListSlot) + SetHoverMode(slotEntity); + } + CreateStats(entity, ref deck); } From 37f7aed524ec1432d7bfc9ccd77bed18d26a8584 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 05:18:40 +0500 Subject: [PATCH 51/57] refactor: slot summary setting --- zzre/game/systems/ui/ScrDeck.BaseSlot.cs | 39 ++++++++++++++++-------- zzre/game/systems/ui/ScrDeck.ListSlot.cs | 18 ++--------- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs index 307cabfb..ecbc491f 100644 --- a/zzre/game/systems/ui/ScrDeck.BaseSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.BaseSlot.cs @@ -54,17 +54,7 @@ private void SetSlot(ref components.ui.Slot slot, InventoryCard card) slot.button.Set(new components.ui.ButtonTiles(card.cardId.EntityId)); slot.button.Set(CardTooltip(card)); - if (slot.summary != default) - { - slot.summary.Set(new components.ui.Label(slot.card switch - { - InventoryItem item => FormatSlotSummary(item), - InventorySpell spell => FormatSlotSummary(spell), - InventoryFairy fairy => FormatSlotSummary(fairy), - _ => throw new NotSupportedException("Unknown inventory card type") - })); - SetSummaryOffset(ref slot); - } + SetSlotSummary(ref slot); } private void UnsetSlot(ref components.ui.Slot slot) @@ -75,8 +65,7 @@ private void UnsetSlot(ref components.ui.Slot slot) slot.button.Remove(); if (slot.usedMarker != default) slot.usedMarker.Set(components.Visibility.Invisible); - if (slot.summary != default) - slot.summary.Set(new components.ui.Label("")); + UnsetSlotSummary(ref slot); if (slot.spellSlots != default) foreach (var spellSlot in slot.spellSlots) UnsetSpellSlot(spellSlot); @@ -84,6 +73,30 @@ private void UnsetSlot(ref components.ui.Slot slot) UnsetSpellImages(ref slot); } + private void SetSlotSummary(ref components.ui.Slot slot) + { + if (slot.summary == default) return; + if (slot.card == default) + { + UnsetSlotSummary(ref slot); + return; + } + slot.summary.Set(new components.ui.Label(slot.card switch + { + InventoryItem item => FormatSlotSummary(item), + InventorySpell spell => FormatSlotSummary(spell), + InventoryFairy fairy => FormatSlotSummary(fairy), + _ => throw new NotSupportedException("Unknown inventory card type") + })); + SetSummaryOffset(ref slot); + } + + private static void UnsetSlotSummary(ref components.ui.Slot slot) + { + if (slot.summary == default) return; + slot.summary.Set(new components.ui.Label("")); + } + private void HandleSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity) { ref var slot = ref slotEntity.Get(); diff --git a/zzre/game/systems/ui/ScrDeck.ListSlot.cs b/zzre/game/systems/ui/ScrDeck.ListSlot.cs index 9f0bd6af..0b7d7604 100644 --- a/zzre/game/systems/ui/ScrDeck.ListSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.ListSlot.cs @@ -118,29 +118,17 @@ private void SetSpellImages(DefaultEcs.Entity entity) } else UnsetSpellImage(slot.spellImages[i]); } - if (slot.summary != default) - slot.summary.Set(new components.ui.Label("")); + UnsetSlotSummary(ref slot); } private void UnsetSpellImages(ref components.ui.Slot slot) { foreach (var spellImage in slot.spellImages) UnsetSpellImage(spellImage); - - if (slot.summary != default && slot.card != default) - { - slot.summary.Set(new components.ui.Label(slot.card switch - { - InventoryItem item => FormatSlotSummary(item), - InventorySpell spell => FormatSlotSummary(spell), - InventoryFairy fairy => FormatSlotSummary(fairy), - _ => throw new NotSupportedException("Unknown inventory card type") - })); - SetSummaryOffset(ref slot); - } + SetSlotSummary(ref slot); } - private void UnsetSpellImage(DefaultEcs.Entity spellImage) + private static void UnsetSpellImage(DefaultEcs.Entity spellImage) { spellImage.Set(components.Visibility.Invisible); spellImage.Set(new components.ui.ButtonTiles(-1)); From e50803361909ca0c05dabade64aabb53e58c9970 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 08:37:31 +0500 Subject: [PATCH 52/57] feat: only allow fairy changes in london --- zzre/game/Game.cs | 1 + zzre/game/systems/ui/ScrDeck.ListSlot.cs | 9 ++++++++- zzre/game/systems/ui/ScrDeck.cs | 6 ++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/zzre/game/Game.cs b/zzre/game/Game.cs index e938cea1..8348c4aa 100644 --- a/zzre/game/Game.cs +++ b/zzre/game/Game.cs @@ -128,6 +128,7 @@ protected void LoadScene(string sceneName) clearColor = (scene.misc.clearColor.ToFColor() with { a = 1f }).ToVeldrid(); ecsWorld.Publish(new messages.SceneLoaded(scene, GetTag())); + ui.World.Publish(new messages.SceneLoaded(scene, GetTag())); } private void DisposeUnusedAssets(in messages.SceneLoaded _) diff --git a/zzre/game/systems/ui/ScrDeck.ListSlot.cs b/zzre/game/systems/ui/ScrDeck.ListSlot.cs index 0b7d7604..0f996dfe 100644 --- a/zzre/game/systems/ui/ScrDeck.ListSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.ListSlot.cs @@ -68,6 +68,11 @@ private void HandleListSlotClick(DefaultEcs.Entity deckEntity, ref components.ui if (deck.DraggedCard != default) return; if (slot.card == default) return; if (!IsDraggable(slot.card)) return; + if (!scene.dataset.canChangeDeck && slot.card.cardId.Type == CardType.Fairy) + { + ui.Publish(new messages.ui.Notification(mappedDB.GetText(new UID(0xC21C5531)).Text)); + return; + } DragCard(deckEntity, ref deck, slot.card); } @@ -142,7 +147,9 @@ private components.ui.TooltipUID CardTooltip(InventoryItem item) private components.ui.TooltipUID CardTooltip(InventoryFairy fairy) => !IsDraggable(fairy) ? new UID(0x9054EAB1) // fairy is in use - : new UID(0x00B500A1); // select fairy + : scene.dataset.canChangeDeck + ? new UID(0x00B500A1) // select fairy + : new UID(0x4D1B04A1); // can only be changed in London private components.ui.TooltipUID CardTooltip(InventorySpell spell) => !IsDraggable(spell) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index c9d7248c..ff3dab3b 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -44,6 +44,8 @@ UID TooltipUID private readonly IAssetRegistry assetRegistry; private readonly zzio.db.MappedDB mappedDB; + private zzio.scn.Scene scene = null!; + private readonly IDisposable SceneLoadedDisposable; private readonly IDisposable OnUIScriptFinishedDisposable; public ScrDeck(ITagContainer diContainer) : base(diContainer, BlockFlags.All) @@ -52,6 +54,7 @@ public ScrDeck(ITagContainer diContainer) : base(diContainer, BlockFlags.All) mappedDB = diContainer.GetTag(); OnElementDown += HandleElementDown; OnRightClick += HandleRightClick; + SceneLoadedDisposable = World.Subscribe(HandleSceneLoaded); OnUIScriptFinishedDisposable = World.Subscribe(HandleUIScriptFinished); } @@ -60,9 +63,12 @@ public override void Dispose() base.Dispose(); OnElementDown -= HandleElementDown; OnRightClick -= HandleRightClick; + SceneLoadedDisposable.Dispose(); OnUIScriptFinishedDisposable.Dispose(); } + protected void HandleSceneLoaded(in messages.SceneLoaded message) => scene = message.Scene; + protected override void HandleOpen(in messages.ui.OpenDeck message) { World.Publish(new messages.SpawnSample($"resources/audio/sfx/gui/_g006.wav")); From ef28f0e4e7d28c21edffe894b626d21c902e058f Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 10:17:13 +0500 Subject: [PATCH 53/57] fix: correct deck slot tooltips --- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 46 ++++++++++++++++++++++-- zzre/game/systems/ui/ScrDeck.Drag.cs | 12 +++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index f1dcb9f3..37d55a53 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -1,3 +1,4 @@ +using System; using System.Numerics; using zzio; using static zzre.game.systems.ui.InGameScreen; @@ -46,14 +47,14 @@ private void SetDeckSlot(DefaultEcs.Entity slotEntity, ref components.ui.ScrDeck var card = inventory.GetFairyAtSlot(slot.index); if (card == default) { - UnsetSlot(ref slot); + UnsetDeckSlot(ref deck, ref slot); return; } slot.card = card; slot.button.Set(components.Visibility.Visible); slot.button.Set(new components.ui.ButtonTiles(card.cardId.EntityId)); - slot.button.Set(new components.ui.TooltipUID(UIDSelectFairy)); + SetDeckSlotTooltip(ref deck, ref slot); slot.summary.Set(new components.ui.Label(FormatSlotSummary(card))); SetSummaryOffset(ref slot); @@ -71,6 +72,45 @@ private void SetDeckSlot(DefaultEcs.Entity slotEntity, ref components.ui.ScrDeck else SpellMode(ref slot); } + private void UnsetDeckSlot(ref components.ui.ScrDeck deck, ref components.ui.Slot slot) + { + slot.card = default; + slot.button.Set(components.Visibility.Invisible); + SetDeckSlotTooltip(ref deck, ref slot); + UnsetSlotSummary(ref slot); + foreach (var spellSlot in slot.spellSlots) + UnsetSpellSlot(spellSlot); + } + + private static void SetDeckSlotTooltip(ref components.ui.ScrDeck deck, ref components.ui.Slot slot) + { + var tooltip = DeckCardTooltip(ref deck, ref slot); + if (tooltip != null) + slot.button.Set(new components.ui.TooltipUID(tooltip.Value)); + else if (slot.button.Has()) + slot.button.Remove(); + } + + private static UID? DeckCardTooltip(ref components.ui.ScrDeck deck, ref components.ui.Slot slot) + { + if (deck.DraggedCard == default) + return slot.card != default + ? new UID(0x41912581) // select fairy + : null; + + if (deck.DraggedCard.cardId.Type == CardType.Fairy) + return slot.card != default + ? new UID(0x5B971D81) // replace fairy + : new UID(0xD66A2581); // place fairy + + if (deck.DraggedCard.cardId.Type == CardType.Item) + return slot.card != default + ? new UID(0x89A21981) // press key 1 + : new UID(0xD66A2581); // place fairy (?!) + + return null; // no tooltip for dragged spells + } + private void InfoMode(ref components.ui.Slot slot) { if (slot.card != default) @@ -97,7 +137,7 @@ private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui inventory.SetSlot((InventoryFairy)slot.card, -1); deck.VacatedDeckSlot = slot.index; DragCard(deckEntity, ref deck, slot.card); - UnsetSlot(ref slot); + UnsetDeckSlot(ref deck, ref slot); SetListSlots(ref deck); return; } diff --git a/zzre/game/systems/ui/ScrDeck.Drag.cs b/zzre/game/systems/ui/ScrDeck.Drag.cs index 73d4978b..84d2f95d 100644 --- a/zzre/game/systems/ui/ScrDeck.Drag.cs +++ b/zzre/game/systems/ui/ScrDeck.Drag.cs @@ -25,6 +25,12 @@ private void DragCard(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck de .WithRenderOrder(-3) .Build(); deck.DraggedOverlay.Set(components.ui.UIOffset.GameUpperLeft); + + foreach (var slotEntity in deck.DeckSlots) + { + ref var slot = ref slotEntity.Get(); + SetDeckSlotTooltip(ref deck, ref slot); + } } private void DropCard(ref components.ui.ScrDeck deck) @@ -43,6 +49,12 @@ private void DropCard(ref components.ui.ScrDeck deck) deck.DraggedOverlay.Dispose(); deck.DraggedOverlay = default; SetListSlots(ref deck); + + foreach (var slotEntity in deck.DeckSlots) + { + ref var slot = ref slotEntity.Get(); + SetDeckSlotTooltip(ref deck, ref slot); + } } private void Drag(ref components.ui.ScrDeck deck) From e6c2e8f22482ddce27585b4bc6cc789266f7ca7c Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 10:39:22 +0500 Subject: [PATCH 54/57] feat: spell slot tooltips --- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 13 +++++---- zzre/game/systems/ui/ScrDeck.Drag.cs | 16 ++++++----- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 33 +++++++++++++++++++---- zzre/game/systems/ui/ScrDeck.cs | 4 +-- 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index 37d55a53..b65b6e38 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -1,4 +1,3 @@ -using System; using System.Numerics; using zzio; using static zzre.game.systems.ui.InGameScreen; @@ -68,8 +67,8 @@ private void SetDeckSlot(DefaultEcs.Entity slotEntity, ref components.ui.ScrDeck else UnsetSpellSlot(slot.spellSlots[i]); } - if (IsInfoTab(deck.ActiveTab)) InfoMode(ref slot); - else SpellMode(ref slot); + if (IsInfoTab(deck.ActiveTab)) InfoMode(ref deck, ref slot); + else SpellMode(ref deck, ref slot); } private void UnsetDeckSlot(ref components.ui.ScrDeck deck, ref components.ui.Slot slot) @@ -111,19 +110,19 @@ private static void SetDeckSlotTooltip(ref components.ui.ScrDeck deck, ref compo return null; // no tooltip for dragged spells } - private void InfoMode(ref components.ui.Slot slot) + private void InfoMode(ref components.ui.ScrDeck deck, ref components.ui.Slot slot) { if (slot.card != default) slot.summary.Set(new components.ui.Label(FormatSlotSummary((InventoryFairy)(slot.card)))); foreach (var spellSlot in slot.spellSlots) - InfoModeSpell(ref spellSlot.Get()); + InfoModeSpell(ref deck, ref slot, ref spellSlot.Get()); } - private static void SpellMode(ref components.ui.Slot slot) + private static void SpellMode(ref components.ui.ScrDeck deck, ref components.ui.Slot slot) { slot.summary.Set(new components.ui.Label("")); foreach (var spellSlot in slot.spellSlots) - SpellModeSpell(ref spellSlot.Get()); + SpellModeSpell(ref deck, ref slot, ref spellSlot.Get()); } private void HandleDeckSlotClick(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck deck, DefaultEcs.Entity slotEntity, ref components.ui.Slot slot) diff --git a/zzre/game/systems/ui/ScrDeck.Drag.cs b/zzre/game/systems/ui/ScrDeck.Drag.cs index 84d2f95d..07092dff 100644 --- a/zzre/game/systems/ui/ScrDeck.Drag.cs +++ b/zzre/game/systems/ui/ScrDeck.Drag.cs @@ -25,12 +25,7 @@ private void DragCard(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck de .WithRenderOrder(-3) .Build(); deck.DraggedOverlay.Set(components.ui.UIOffset.GameUpperLeft); - - foreach (var slotEntity in deck.DeckSlots) - { - ref var slot = ref slotEntity.Get(); - SetDeckSlotTooltip(ref deck, ref slot); - } + RefreshTooltips(ref deck); } private void DropCard(ref components.ui.ScrDeck deck) @@ -49,11 +44,20 @@ private void DropCard(ref components.ui.ScrDeck deck) deck.DraggedOverlay.Dispose(); deck.DraggedOverlay = default; SetListSlots(ref deck); + RefreshTooltips(ref deck); + } + private static void RefreshTooltips(ref components.ui.ScrDeck deck) + { foreach (var slotEntity in deck.DeckSlots) { ref var slot = ref slotEntity.Get(); SetDeckSlotTooltip(ref deck, ref slot); + foreach (var spellSlotEntity in slot.spellSlots) + { + ref var spellSlot = ref spellSlotEntity.Get(); + SetSpellSlotTooltip(ref deck, ref slot, ref spellSlot); + } } } diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index 72d55418..c2d21b18 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -43,7 +43,7 @@ int index .Build(); slot.button.Set(new components.ui.SlotButton()); - InfoModeSpell(ref slot); + InfoModeSpell(ref parent.Get().Entity.Get(), ref parentSlot, ref slot); return entity; } @@ -67,10 +67,33 @@ public void UnsetSpellSlot(DefaultEcs.Entity entity) CreateSpellReq(entity); } - public void InfoModeSpell(ref components.ui.Slot slot) + private static void SetSpellSlotTooltip(ref components.ui.ScrDeck deck, ref components.ui.Slot fairySlot, ref components.ui.Slot slot) + { + var tooltip = SpellSlotTooltip(ref deck, ref fairySlot, ref slot); + if (tooltip != null) + slot.button.Set(new components.ui.TooltipUID(tooltip.Value)); + else if (slot.button.Has()) + slot.button.Remove(); + } + + private static UID? SpellSlotTooltip(ref components.ui.ScrDeck deck, ref components.ui.Slot fairySlot, ref components.ui.Slot slot) + { + if (fairySlot.card == default) return null; + if (deck.DraggedCard == default) + return IsInfoTab(deck.ActiveTab) + ? UIDFairyInfoDescriptions[slot.index] + : UIDSpellSlotNames[slot.index]; + if (deck.DraggedCard.cardId.Type == CardType.Spell) + return slot.card == default + ? new UID(0x3B46CC81) // deploy spell + : new UID(0x0A05D081); // overwrite spell + return null; + } + + public void InfoModeSpell(ref components.ui.ScrDeck deck, ref components.ui.Slot fairySlot, ref components.ui.Slot slot) { slot.button.Set(components.Visibility.Invisible); - slot.button.Set(new components.ui.TooltipUID(UIDFairyInfoDescriptions[slot.index])); + SetSpellSlotTooltip(ref deck, ref fairySlot, ref slot); if (slot.summary != default) slot.summary.Set(slot.card != default ? new components.ui.Label(FormatManaAmount((InventorySpell)slot.card)) @@ -79,11 +102,11 @@ public void InfoModeSpell(ref components.ui.Slot slot) slot.req.Set(components.Visibility.Invisible); } - public static void SpellModeSpell(ref components.ui.Slot slot) + public static void SpellModeSpell(ref components.ui.ScrDeck deck, ref components.ui.Slot fairySlot, ref components.ui.Slot slot) { if (slot.button.Get().Normal != -1) slot.button.Set(components.Visibility.Visible); - slot.button.Set(new components.ui.TooltipUID(UIDSpellSlotNames[slot.index])); + SetSpellSlotTooltip(ref deck, ref fairySlot, ref slot); if (slot.summary != default) slot.summary.Set(new components.ui.Label("")); if (slot.req != default) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index ff3dab3b..31c59589 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -179,7 +179,7 @@ private static void SpellMode(DefaultEcs.Entity entity, ref components.ui.ScrDec deck.SpellBackground.Set(components.Visibility.Visible); deck.SummaryBackground.Set(components.Visibility.Invisible); foreach (var deckCard in deck.DeckSlots) - SpellMode(ref deckCard.Get()); + SpellMode(ref deck, ref deckCard.Get()); } private void InfoMode(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) @@ -187,7 +187,7 @@ private void InfoMode(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck) deck.SpellBackground.Set(components.Visibility.Invisible); deck.SummaryBackground.Set(components.Visibility.Visible); foreach (var deckCard in deck.DeckSlots) - InfoMode(ref deckCard.Get()); + InfoMode(ref deck, ref deckCard.Get()); } private static Vector2 ListSlotPos(int column, int row) => From ee8100b9cd4be30403a1cb092edc96ab16c279a5 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 10:45:08 +0500 Subject: [PATCH 55/57] fix: accessing dead top buttons --- zzre/game/systems/ui/ScrDeck.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 31c59589..9ceda9c7 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -329,7 +329,7 @@ private void HandleHover(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec if (deck.LastHovered != default) { if (deck.DraggedCard == default) - if (deck.LastHovered.Has()) + if (deck.LastHovered.IsAlive && deck.LastHovered.Has()) { var slotEntity = deck.LastHovered.Get().Entity; ref var slot = ref slotEntity.Get(); @@ -346,7 +346,7 @@ private void HandleHover(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec deck.LastHovered = curHovered.Entity; if (deck.DraggedCard == default) - if (deck.LastHovered.Has()) + if (deck.LastHovered.IsAlive && deck.LastHovered.Has()) { var slotEntity = deck.LastHovered.Get().Entity; ref var slot = ref slotEntity.Get(); From 48e9bacb0b823e7f33fdb7f87616447222269287 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 10:46:25 +0500 Subject: [PATCH 56/57] fix: remove unused UIDs --- zzre/game/systems/ui/ScrDeck.DeckSlot.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs index b65b6e38..39544201 100644 --- a/zzre/game/systems/ui/ScrDeck.DeckSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.DeckSlot.cs @@ -6,11 +6,6 @@ namespace zzre.game.systems.ui; public partial class ScrDeck { - private static readonly UID UIDSelectFairy = new(0x41912581); - // private static readonly UID UIDPlaceFairy = new(0x41912581); - // private static readonly UID UIDReplaceFairy = new(0x41912581); - // private static readonly UID UIDUseItemOnFairy = new(0x41912581); - private DefaultEcs.Entity CreateDeckSlot( DefaultEcs.Entity parent, components.ui.ElementId id, From 5ccd0235d12dce72c911464c5fbc09dbc0c93600 Mon Sep 17 00:00:00 2001 From: AcipenserSturio Date: Tue, 24 Dec 2024 20:36:32 +0500 Subject: [PATCH 57/57] feat: update drag overlay tile --- zzre/game/systems/ui/ScrDeck.Drag.cs | 22 +++++++++++++++++++++- zzre/game/systems/ui/ScrDeck.SpellSlot.cs | 7 ++++--- zzre/game/systems/ui/ScrDeck.cs | 2 ++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/zzre/game/systems/ui/ScrDeck.Drag.cs b/zzre/game/systems/ui/ScrDeck.Drag.cs index 07092dff..3edf7afb 100644 --- a/zzre/game/systems/ui/ScrDeck.Drag.cs +++ b/zzre/game/systems/ui/ScrDeck.Drag.cs @@ -21,10 +21,11 @@ private void DragCard(DefaultEcs.Entity deckEntity, ref components.ui.ScrDeck de if (deck.DraggedOverlay != default) deck.DraggedOverlay.Dispose(); deck.DraggedOverlay = preload.CreateImage(deckEntity) .With(Mid) - .With(UIPreloadAsset.Dnd000, 0) + .With(UIPreloadAsset.Dnd000) .WithRenderOrder(-3) .Build(); deck.DraggedOverlay.Set(components.ui.UIOffset.GameUpperLeft); + SetDragOverlayTile(ref deck); RefreshTooltips(ref deck); } @@ -61,6 +62,25 @@ private static void RefreshTooltips(ref components.ui.ScrDeck deck) } } + private void SetDragOverlayTile(ref components.ui.ScrDeck deck) + { + if (deck.DraggedCard == default) return; + deck.DraggedOverlay.Set(new components.ui.ButtonTiles(DragOverlayTile(ref deck))); + } + + private int DragOverlayTile(ref components.ui.ScrDeck deck) + { + if (deck.LastHovered == default) return 1; + if (!deck.LastHovered.Has()) return 1; + var slotEntity = deck.LastHovered.Get().Entity; + ref var slot = ref slotEntity.Get(); + if (slot.type == components.ui.Slot.Type.DeckSlot && deck.DraggedCard!.cardId.Type != CardType.Spell) + return 0; + if (slot.type == components.ui.Slot.Type.SpellSlot && deck.DraggedCard!.cardId.Type == CardType.Spell && IsOfMatchingSpellType(ref slot, deck.DraggedCard!)) + return 0; + return 1; + } + private void Drag(ref components.ui.ScrDeck deck) { if (deck.DraggedCardImage != default) diff --git a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs index c2d21b18..4c083876 100644 --- a/zzre/game/systems/ui/ScrDeck.SpellSlot.cs +++ b/zzre/game/systems/ui/ScrDeck.SpellSlot.cs @@ -123,9 +123,7 @@ private void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.u if (fairySlot.card == default) return; - if (mappedDB.GetSpell(deck.DraggedCard.dbUID).Type == 0 && slot.index % 2 != 0 || - mappedDB.GetSpell(deck.DraggedCard.dbUID).Type != 0 && slot.index % 2 == 0 - ) + if (!IsOfMatchingSpellType(ref slot, deck.DraggedCard)) { var note = slot.index % 2 == 0 ? new UID(0xC18D4C31) : new UID(0x9CD74C31); ui.Publish(new messages.ui.Notification(mappedDB.GetText(note).Text)); @@ -161,6 +159,9 @@ private void HandleSpellSlotClick(DefaultEcs.Entity deckEntity, ref components.u return; } + private bool IsOfMatchingSpellType(ref components.ui.Slot slot, InventoryCard card) => + mappedDB.GetSpell(card.dbUID).Type == slot.index % 2; + private void CreateSpellSummary(DefaultEcs.Entity entity) { ref var spellSlot = ref entity.Get(); diff --git a/zzre/game/systems/ui/ScrDeck.cs b/zzre/game/systems/ui/ScrDeck.cs index 9ceda9c7..134f53a7 100644 --- a/zzre/game/systems/ui/ScrDeck.cs +++ b/zzre/game/systems/ui/ScrDeck.cs @@ -339,6 +339,7 @@ private void HandleHover(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec deck.LastHovered = default; CreateStats(entity, ref deck); + SetDragOverlayTile(ref deck); return; } @@ -355,6 +356,7 @@ private void HandleHover(DefaultEcs.Entity entity, ref components.ui.ScrDeck dec } CreateStats(entity, ref deck); + SetDragOverlayTile(ref deck); } private void UpdateScroll(DefaultEcs.Entity entity, ref components.ui.ScrDeck deck)