Add trigger target selection and finish battle UX
CI / test (push) Successful in 6m48s Details

This commit is contained in:
MpakobecEx 2026-10-22 00:55:33 +05:00
parent 5874d6982f
commit 8217e8225e
5 changed files with 98 additions and 10 deletions

View File

@ -279,7 +279,8 @@
сила/крит; REST/скрытая карта.
- [x] Старт: маллиган (сервер пока даёт только «закончить маллиган»).
- [x] Ввод: кнопки легальных интентов; клик по картам/зонам,
подсветка целей, группировка действий и журнал боя.
подсветка целей, группировка действий, выбор силы/эффекта триггера
и журнал боя.
- [x] Boost: выбор карты заднего ряда как поддержки перед атакой.
- [x] Event-фидбек: атака, guard, drive, урон, heal, retire, perfect guard.
- [x] Отображение силы/крита из `MatchView`; модификаторы уже посчитаны сервером.

View File

@ -69,6 +69,7 @@ namespace Vanguard.UI
private readonly List<IntentPayload> _pendingIntents = new List<IntentPayload>();
private readonly HashSet<string> _highlightKeys = new HashSet<string>(StringComparer.Ordinal);
private int _pendingBoosterSlot = -1;
private int? _triggerPowerSlot;
public BattleView(Transform parent, MetaService meta, Action onExit)
{
@ -187,6 +188,7 @@ namespace Vanguard.UI
_pendingIntents.Clear();
_highlightKeys.Clear();
_pendingBoosterSlot = -1;
_triggerPowerSlot = null;
_showAllIntents = false;
_logLines.Clear();
RebuildLog();
@ -432,7 +434,8 @@ namespace Vanguard.UI
_finished = _view.IsFinished;
_pendingIntents.Clear();
_highlightKeys.Clear();
_pendingBoosterSlot = -1;
_triggerPowerSlot = null;
PrepareTriggerSelection();
if (_view.Clock != null)
{
_clockServerMs = _view.Clock.ServerTimeMs;
@ -624,6 +627,7 @@ namespace Vanguard.UI
_pendingIntents.Clear();
_highlightKeys.Clear();
_pendingBoosterSlot = -1;
_triggerPowerSlot = null;
_sending = true;
SetStatus("Отправляем: " + Label(intent), Muted);
@ -1115,6 +1119,12 @@ namespace Vanguard.UI
var legal = _view.LegalIntents ?? new List<IntentPayload>();
if (_pendingIntents.Any(intent => intent is ResolveTriggerIntent)
&& HandleTriggerTarget(target))
{
return;
}
if (_pendingIntents.Count > 0)
{
// Клик по своему заднему ряду выбирает карту поддержки.
@ -1199,13 +1209,84 @@ namespace Vanguard.UI
_pendingIntents.Clear();
_highlightKeys.Clear();
_pendingBoosterSlot = -1;
_triggerPowerSlot = null;
if (rebuild && _view != null)
RebuildIntents(_view);
}
private void PrepareTriggerSelection()
{
if (_view?.Trigger == null || _view.ActivePlayer != _view.You)
return;
var triggers = (_view.LegalIntents ?? new List<IntentPayload>())
.OfType<ResolveTriggerIntent>()
.ToList();
if (triggers.Count == 0)
return;
_pendingIntents.Clear();
_pendingIntents.AddRange(triggers);
_triggerPowerSlot = null;
RebuildHighlights();
}
private bool HandleTriggerTarget(BoardTarget target)
{
if (_view?.Trigger == null || target.Player != _view.You)
return false;
var triggers = _pendingIntents.OfType<ResolveTriggerIntent>().ToList();
if (triggers.Count == 0)
return false;
if (_triggerPowerSlot == null)
{
var powerTargets = triggers
.Where(trigger => trigger.PowerTarget == target.Slot)
.ToList();
if (powerTargets.Count == 0)
return false;
_triggerPowerSlot = target.Slot;
_pendingIntents.Clear();
_pendingIntents.AddRange(powerTargets);
RebuildHighlights();
RebuildIntents(_view);
SetStatus(
"Триггер: выберите цель эффекта.",
new Color(0.98f, 0.82f, 0.42f));
return true;
}
var effect = triggers.FirstOrDefault(trigger => trigger.EffectTarget == target.Slot);
if (effect == null)
return false;
ClearSelection(rebuild: false);
OnIntentClicked(effect);
return true;
}
private void RebuildHighlights()
{
_highlightKeys.Clear();
if (_pendingIntents.Any(intent => intent is ResolveTriggerIntent))
{
foreach (var trigger in _pendingIntents.OfType<ResolveTriggerIntent>())
{
var slot = _triggerPowerSlot == null
? trigger.PowerTarget
: trigger.EffectTarget;
var card = CardAt(_view.You, slot);
_highlightKeys.Add(TargetKey(
_view.You, slot, card != null ? card.PrintingId : null));
}
return;
}
foreach (var intent in _pendingIntents)
{
if (TryGetTarget(intent, out var target))
@ -1358,11 +1439,15 @@ namespace Vanguard.UI
var prompt = UiKit.CreateText(
_intents,
"TargetPrompt",
_pendingBoosterSlot >= 0
? "Поддержка: " + CardName(
CardAt(_view.You, _pendingBoosterSlot)?.PrintingId ?? string.Empty)
+ ".\nВыберите цель атаки или «Отмена»."
: "Выберите цель на поле.\nНажмите «Отмена», чтобы снять выбор.",
_pendingIntents.Any(intent => intent is ResolveTriggerIntent)
? (_triggerPowerSlot == null
? "Триггер: выберите цель силы."
: "Триггер: выберите цель эффекта.")
: _pendingBoosterSlot >= 0
? "Поддержка: " + CardName(
CardAt(_view.You, _pendingBoosterSlot)?.PrintingId ?? string.Empty)
+ ".\nВыберите цель атаки или «Отмена»."
: "Выберите цель на поле.\nНажмите «Отмена», чтобы снять выбор.",
16,
new Color(0.98f, 0.82f, 0.42f),
TextAnchor.UpperLeft);

View File

@ -65,7 +65,8 @@ http://localhost:5080
- Боевой gray-box: доска, рука, часы, кнопки всех легальных интентов,
сдача с подтверждением и экран результата.
- Боевой UX: клик по картам/зонам, подсветка целей, сгруппированные
действия, журнал событий и подсказки; event-анимации с очередью и скипом.
действия, выбор силы/эффекта триггера, журнал событий и подсказки;
event-анимации с очередью и скипом.
- Карты в бою и коллекции: процедурные арты по клану, рамка, имя, ранг,
триггер, сила/крит, REST и рубашка для скрытых карт.
- Реальные арты: `CardImageService` ищет `Resources/CardArt/{imageKey}`;

View File

@ -756,7 +756,8 @@ Battle; Boot и общие сервисы остаются персистент
- Event-фидбек: всплывающие атака/guard/drive/урон/heal/retire, не
блокирует ввод; очередь событий и кнопка «Пропустить анимации».
- Боевой UX: клик по карте/зоне, подсветка целей, отдельная группировка
действий, журнал последних событий и подсказки выбора.
действий, выбор силы/эффекта триггера, журнал последних событий и
подсказки выбора.
- Поле: `R V R` / `R R R` у каждого игрока, зона урона слева, колода и
дроп справа, зеркально у противника, зона защиты между полями.
- Проверки визуального блока: Unity EditMode 2/2, `SCENE_SMOKE success=True`,

View File

@ -67,7 +67,7 @@
`tools/import_card_art.py`.
- Взаимодействие в бою: клик по картам/зонам, подсветка целей,
группировка действий (карты → цели, глобальные кнопки отдельно),
журнал последних событий.
выбор силы/эффекта триггера, журнал последних событий.
- Отдельная сцена `Collection` и `CollectionView` удалены; коллекция
открывается из Lobby кнопкой «Коллекция» (сцена `DeckBuilder`).
- Не готово: файлы реальных артов (пайплайн готов), 3D-модели,