From f5b7f3e2d8c6008c00e0b961f57478be0562ad3f Mon Sep 17 00:00:00 2001 From: MpakobecEx Date: Thu, 22 Oct 2026 01:40:29 +0500 Subject: [PATCH] Improve battle cards, mulligan and damage zone --- .../Assets/Vanguard/Runtime/UI/BattleView.cs | 323 ++++++++++++++---- .../Vanguard/Tests/Editor/ClientSmokeTests.cs | 6 + .../src/Vanguard.Rules/Engine/GameEngine.cs | 88 ++++- .../src/Vanguard.Rules/Engine/GameModels.cs | 11 + .../Vanguard.Rules.Tests/GameEngineTests.cs | 50 ++- 5 files changed, 399 insertions(+), 79 deletions(-) diff --git a/client/Assets/Vanguard/Runtime/UI/BattleView.cs b/client/Assets/Vanguard/Runtime/UI/BattleView.cs index fc92be9..e9f2ae1 100644 --- a/client/Assets/Vanguard/Runtime/UI/BattleView.cs +++ b/client/Assets/Vanguard/Runtime/UI/BattleView.cs @@ -71,6 +71,7 @@ namespace Vanguard.UI private readonly HashSet _highlightKeys = new HashSet(StringComparer.Ordinal); private int _pendingBoosterSlot = -1; private int? _triggerPowerSlot; + private readonly HashSet _mulliganSelected = new HashSet(); private readonly Dictionary _cardPanels = new Dictionary(StringComparer.Ordinal); private readonly List _cardAnimations = new List(); @@ -205,6 +206,7 @@ namespace Vanguard.UI _result.gameObject.SetActive(false); _pendingIntents.Clear(); _highlightKeys.Clear(); + _mulliganSelected.Clear(); _pendingBoosterSlot = -1; _triggerPowerSlot = null; _showAllIntents = false; @@ -1181,16 +1183,123 @@ namespace Vanguard.UI { var column = UiKit.CreatePanel(parent, "DamageColumn", new Color(0f, 0f, 0f, 0f)); var element = column.gameObject.AddComponent(); - element.preferredWidth = 88f; - element.minWidth = 80f; + element.preferredWidth = 174f; + element.minWidth = 158f; element.flexibleWidth = 0f; - UiKit.AddVerticalLayout(column, 0, 5); + UiKit.AddVerticalLayout(column, 0, 4); - AddPile(column, "УРОН", - player.FaceDownDamage + player.FaceUpDamage.Count, - new Color(0.48f, 0.12f, 0.12f), 118f); + AddDamageZone(column, player); AddPile(column, "SOUL", player.Soul.Count, - new Color(0.26f, 0.18f, 0.42f), 96f); + new Color(0.26f, 0.18f, 0.42f), 78f); + } + + private void AddDamageZone(Transform parent, PlayerView player) + { + var count = player.FaceDownDamage + player.FaceUpDamage.Count; + var zone = UiKit.CreatePanel( + parent, "DamageZone", new Color(0.16f, 0.05f, 0.06f, 0.9f)); + var element = zone.gameObject.AddComponent(); + element.preferredHeight = 206f; + element.flexibleWidth = 1f; + UiKit.AddVerticalLayout(zone, 4, 2); + + var title = UiKit.CreateText( + zone, "Title", "УРОН · " + count, 11, + new Color(1f, 0.78f, 0.72f), TextAnchor.MiddleCenter); + title.fontStyle = FontStyle.Bold; + UiKit.SetPreferredHeight(title, 18f); + + var grid = UiKit.CreatePanel(zone, "DamageCards", new Color(0f, 0f, 0f, 0f)); + var gridElement = grid.gameObject.AddComponent(); + gridElement.flexibleHeight = 1f; + gridElement.preferredHeight = 176f; + + var damageChoice = IsDamageChoice(); + var displayIndex = 0; + + for (var i = 0; i < player.FaceDownDamage; i++, displayIndex++) + { + AddDamageCard(grid, displayIndex, null, false, damageChoice); + } + + foreach (var card in player.FaceUpDamage) + { + AddDamageCard(grid, displayIndex, card, true, damageChoice); + displayIndex++; + } + } + + private void AddDamageCard( + RectTransform parent, + int displayIndex, + CardView card, + bool faceUp, + bool damageChoice) + { + var panel = UiKit.CreatePanel(parent, "Damage_" + displayIndex, Color.white); + var rect = panel; + rect.anchorMin = new Vector2(0.5f, 0.5f); + rect.anchorMax = new Vector2(0.5f, 0.5f); + rect.pivot = new Vector2(0.5f, 0.5f); + rect.sizeDelta = new Vector2(58f, 78f); + rect.anchoredPosition = new Vector2( + displayIndex % 2 == 0 ? -42f : 42f, + 58f - (displayIndex / 2) * 58f); + rect.localRotation = Quaternion.Euler(0f, 0f, -90f); + + var image = panel.GetComponent(); + image.raycastTarget = true; + var meta = card != null && _catalog.TryGetValue(card.PrintingId, out var found) + ? found + : null; + if (faceUp) + { + CardImageService.Apply( + image, + meta != null ? meta.ImageKey : null, + CardArt.ForCard( + meta != null ? meta.NameId : card?.PrintingId ?? "damage", + meta != null ? meta.Clan : "None")); + } + else + { + image.sprite = CardArt.Back; + image.color = Color.white; + } + + var outline = panel.gameObject.AddComponent(); + outline.effectColor = damageChoice + ? new Color(0.98f, 0.82f, 0.42f) + : new Color(0.42f, 0.18f, 0.18f); + outline.effectDistance = damageChoice + ? new Vector2(3f, -3f) + : new Vector2(1f, -1f); + + var button = panel.gameObject.AddComponent