diff --git a/client/Assets/Vanguard/Runtime/UI/BattleView.cs b/client/Assets/Vanguard/Runtime/UI/BattleView.cs index 2f6d3f7..899d593 100644 --- a/client/Assets/Vanguard/Runtime/UI/BattleView.cs +++ b/client/Assets/Vanguard/Runtime/UI/BattleView.cs @@ -71,6 +71,10 @@ namespace Vanguard.UI private Text _abilityOverlayName; private RectTransform _abilityOverlayButtons; private int _abilityPromptInstanceId; + private RectTransform _cardChoiceOverlay; + private Text _cardChoiceTitle; + private RectTransform _cardChoiceContent; + private string _cardChoiceKey; private MatchConnectionInfo _info; private MatchView _view; private bool _connecting; @@ -238,6 +242,7 @@ namespace Vanguard.UI BuildPhasePanel(); BuildCombatStats(); BuildAbilityOverlay(); + BuildCardChoiceOverlay(); BuildReconnectOverlay(); _cardMenu = new CardActionMenuView(); _cardMenu.Build(_root); @@ -310,6 +315,7 @@ namespace Vanguard.UI _board3D?.SetVisible(true); _overlays?.CloseAll(); HideAbilityOverlay(); + HideCardChoiceOverlay(); _selfZones?.Update(null, self: true); _opponentZones?.Update(null, self: false); _topInfo.text = (info.DeckName ?? string.Empty) + " · " + info.MatchId; @@ -343,6 +349,7 @@ namespace Vanguard.UI _skipFeedback.gameObject.SetActive(false); _overlays?.CloseAll(); HideAbilityOverlay(); + HideCardChoiceOverlay(); _cardMenu?.Hide(); _combatStats?.gameObject.SetActive(false); _board3D?.SetVisible(false); @@ -363,6 +370,7 @@ namespace Vanguard.UI RefreshActionPrompt(); SanitizeInputLocks(); SyncAbilityPrompt(); + SyncCardChoicePrompt(); UpdateAutoPhases(); } @@ -385,6 +393,8 @@ namespace Vanguard.UI _inputLock.Release("card-menu"); if (_abilityOverlay == null || !_abilityOverlay.gameObject.activeSelf) _inputLock.Release("ability"); + if (_cardChoiceOverlay == null || !_cardChoiceOverlay.gameObject.activeSelf) + _inputLock.Release("card-choice"); if (!_feedbackPlaying && _feedbackQueue.Count == 0) { _feedbackLockHeld = false; @@ -747,6 +757,7 @@ namespace Vanguard.UI Render(); SyncAbilityPrompt(); + SyncCardChoicePrompt(); } private void OnEvents(ServerEvents events) @@ -1307,6 +1318,175 @@ namespace Vanguard.UI || prompt.IndexOf("rear", StringComparison.OrdinalIgnoreCase) >= 0); } + private void BuildCardChoiceOverlay() + { + _cardChoiceOverlay = UiKit.CreatePanel( + _root, + "CardChoiceOverlay", + new Color(0f, 0f, 0f, 0.78f)); + var card = UiKit.CreateCenteredCard( + _cardChoiceOverlay, + "CardChoiceCard", + new Vector2(1120f, 620f), + Panel); + UiKit.AddVerticalLayout(card, 20, 10); + + var title = UiKit.CreateText( + card, + "CardChoiceTitle", + "ВЫБОР КАРТЫ", + 22, + new Color(1f, 0.80f, 0.42f), + TextAnchor.MiddleCenter); + title.fontStyle = FontStyle.Bold; + UiKit.SetPreferredHeight(title, 34f); + + _cardChoiceTitle = UiKit.CreateText( + card, + "CardChoicePrompt", + string.Empty, + 17, + new Color(0.82f, 0.88f, 0.98f), + TextAnchor.MiddleCenter); + UiKit.SetPreferredHeight(_cardChoiceTitle, 42f); + + var scroll = UiKit.CreateGridScrollView( + card, + "CardChoiceScroll", + new Vector2(160f, 230f), + new Vector2(12f, 12f), + out _cardChoiceContent); + var element = scroll.gameObject.AddComponent(); + element.minHeight = 400f; + element.flexibleHeight = 1f; + + _cardChoiceOverlay.gameObject.SetActive(false); + } + + private static bool TryGetChoicePrintingId( + ChoiceOptionView option, + out string printingId) + { + printingId = null; + var label = option?.Label ?? string.Empty; + var open = label.LastIndexOf('('); + var close = label.LastIndexOf(')'); + if (open < 0 || close <= open + 1) + return false; + + printingId = label.Substring(open + 1, close - open - 1).Trim(); + return printingId.Length > 0; + } + + private bool IsCardChoice() + { + var options = _view?.Choice?.Options; + return options is { Count: > 0 } + && options.All(option => TryGetChoicePrintingId(option, out _)); + } + + private void SyncCardChoicePrompt() + { + if (_cardChoiceOverlay == null || _sending) + return; + + var choice = _view?.Choice; + if (choice == null + || _view == null + || _view.ActivePlayer != _view.You + || !IsCardChoice()) + { + HideCardChoiceOverlay(); + return; + } + + var key = (choice.Prompt ?? string.Empty) + "|" + + string.Join(",", choice.Options.Select(option => option.Label)); + if (_cardChoiceOverlay.gameObject.activeSelf + && string.Equals(_cardChoiceKey, key, StringComparison.Ordinal)) + return; + + _cardChoiceKey = key; + _cardChoiceTitle.text = choice.Prompt ?? "Выберите карту"; + UiKit.MakeLiteral(_cardChoiceTitle); + ClearChildren(_cardChoiceContent); + + for (var i = 0; i < choice.Options.Count; i++) + { + var index = i; + var option = choice.Options[i]; + if (!TryGetChoicePrintingId(option, out var printingId)) + continue; + + var tile = UiKit.CreatePanel( + _cardChoiceContent, + "CardChoice_" + index, + new Color(0.05f, 0.075f, 0.11f, 0.98f)); + var tileElement = tile.gameObject.AddComponent(); + tileElement.preferredWidth = 160f; + tileElement.preferredHeight = 230f; + tileElement.flexibleWidth = 0f; + tileElement.flexibleHeight = 0f; + + var button = tile.gameObject.AddComponent