Select hand cards for Morgana discard by clicking hand
CI / test (push) Successful in 2m13s Details

This commit is contained in:
MpakobecEx 2026-10-23 19:46:05 +05:00
parent bf41fbe6d0
commit 136db66455
3 changed files with 147 additions and 4 deletions

View File

@ -1385,6 +1385,51 @@ namespace Vanguard.UI
&& options.All(option => TryGetChoicePrintingId(option, out _));
}
private bool IsHandChoice()
{
var choice = _view?.Choice;
if (choice == null
|| _view == null
|| _view.ActivePlayer != _view.You
|| choice.Options == null
|| choice.Options.Count == 0)
return false;
var prompt = choice.Prompt ?? string.Empty;
if (prompt.IndexOf("рук", StringComparison.OrdinalIgnoreCase) < 0
&& prompt.IndexOf("сброс", StringComparison.OrdinalIgnoreCase) < 0)
return false;
var hand = _view.Players
.FirstOrDefault(player => player.Index == _view.You)
?.Hand;
return hand != null
&& choice.Options.All(option => option.Slot >= 0 && option.Slot < hand.Count);
}
private void HandleHandChoiceCard(BoardCardRef card)
{
if (_view?.Choice == null || card.Zone != BoardZone.Hand || card.Player != _view.You)
{
SetStatus("Выберите карту в руке.", new Color(0.98f, 0.82f, 0.42f));
return;
}
var handIndex = HandIndexOf(card.InstanceId);
var optionIndex = _view.Choice.Options
.ToList()
.FindIndex(option => option.Slot == handIndex);
if (optionIndex < 0)
{
SetStatus("Эта карта недоступна для выбора.", new Color(1f, 0.55f, 0.45f));
return;
}
OnIntentClicked(
new ChooseIntent { Index = optionIndex },
ignoreInputLock: true);
}
private void SyncCardChoicePrompt()
{
if (_cardChoiceOverlay == null || _sending)
@ -1663,6 +1708,21 @@ namespace Vanguard.UI
}
}
if (IsHandChoice())
{
var hand = _view.Players
.FirstOrDefault(player => player.Index == _view.You)
?.Hand;
if (hand != null)
{
foreach (var option in _view.Choice.Options)
{
if (option.Slot >= 0 && option.Slot < hand.Count)
state.SelectedHandInstanceIds.Add(hand[option.Slot].InstanceId);
}
}
}
if (state.MulliganSelecting && _view != null && _mulliganSelected.Count > 0)
{
var hand = _view.Players
@ -1722,7 +1782,7 @@ namespace Vanguard.UI
private void OnBoard3DCardClicked(BoardCardRef card)
{
if (_view == null || _sending || _inputLock.IsLocked)
if (_view == null || _sending)
return;
if (_discardChoiceActive)
@ -1731,6 +1791,15 @@ namespace Vanguard.UI
return;
}
if (IsHandChoice())
{
HandleHandChoiceCard(card);
return;
}
if (_inputLock.IsLocked)
return;
var targetSelection = _pendingIntents.Count > 0
|| IsMulliganSelecting()
|| IsDamageChoice()
@ -2528,7 +2597,7 @@ namespace Vanguard.UI
{
title = IsRearGuardChoice()
? "ВЫБОР КРУГА"
: IsCardChoice() ? "ВЫБОР КАРТЫ" : "ВЫБОР";
: IsHandChoice() || IsCardChoice() ? "ВЫБОР КАРТЫ" : "ВЫБОР";
hint = _view.Choice.Prompt;
}
else if (_view.ActivePlayer != _view.You)
@ -3299,7 +3368,7 @@ namespace Vanguard.UI
&& intent is not ActivateAbilityIntent
&& intent is not ResolveAbilityIntent
&& !(intent is ChooseIntent
&& (IsRearGuardChoice() || IsCardChoice())))
&& (IsRearGuardChoice() || IsHandChoice() || IsCardChoice())))
.ToList();
if (_pendingIntents.Count > 0)

View File

@ -437,6 +437,78 @@ namespace Vanguard.Tests
}
}
[Test]
public void Hand_Choice_Uses_Hand_Cards_Without_Intent_Buttons()
{
var config = new AppConfig();
config.Load();
var tokens = new TokenStore();
var api = new ApiClient(config, tokens);
var player = new PlayerState();
var auth = new AuthService(api, tokens, player);
var meta = new MetaService(api, player);
var canvas = UiKit.CreateCanvas("Hand Choice Test Canvas");
try
{
var battle = new BattleView(canvas.transform, meta, () => { });
var match = new MatchView
{
You = 0,
ActivePlayer = 0,
Players = new List<PlayerView>
{
new()
{
Index = 0,
Hand = new List<CardView>
{
new() { InstanceId = 11, PrintingId = "BT01/046EN" },
new() { InstanceId = 12, PrintingId = "BT01/042EN" },
},
},
},
Choice = new ChoiceView
{
Player = 0,
Prompt = "Выберите карту из руки",
Options = new List<ChoiceOptionView>
{
new() { Slot = 0, Label = "Flogal" },
new() { Slot = 1, Label = "Little Sage, Marron" },
},
},
LegalIntents = new List<IntentPayload>(),
};
typeof(BattleView)
.GetField("_view", BindingFlags.Instance | BindingFlags.NonPublic)!
.SetValue(battle, match);
var isHandChoice = typeof(BattleView)
.GetMethod("IsHandChoice", BindingFlags.Instance | BindingFlags.NonPublic)!
.Invoke(battle, null);
Assert.AreEqual(true, isHandChoice);
typeof(BattleView)
.GetMethod("RefreshActionPrompt", BindingFlags.Instance | BindingFlags.NonPublic)!
.Invoke(battle, null);
var title = Resources.FindObjectsOfTypeAll<Text>()
.First(text => text.name == "ActionPromptTitle");
Assert.AreEqual("ВЫБОР КАРТЫ", title.text);
typeof(BattleView)
.GetMethod("RebuildIntents", BindingFlags.Instance | BindingFlags.NonPublic)!
.Invoke(battle, new object[] { match });
Assert.IsFalse(Resources.FindObjectsOfTypeAll<GameObject>()
.Any(go => go.name == "Intent_ChooseIntent"));
}
finally
{
Object.DestroyImmediate(canvas.gameObject);
Cleanup();
}
}
[Test]
public void Action_Prompt_Shows_Current_Required_Action()
{

View File

@ -1140,7 +1140,9 @@ public sealed class GameEngine
Player = player,
Prompt = prompt,
Options = cards
.Select((card, index) => new ChoiceOption(index, State.Catalog.CardOf(card.PrintingId).NameEn))
.Select(card => new ChoiceOption(
State.Players[player].Hand.IndexOf(card),
State.Catalog.CardOf(card.PrintingId).NameEn))
.ToList(),
Resolve = index => onChosen(cards[index]),
};