116 lines
5.2 KiB
C#
116 lines
5.2 KiB
C#
using Vanguard.Rules.Cards;
|
||
using Vanguard.Rules.Engine.Abilities;
|
||
|
||
namespace Vanguard.Rules.Engine;
|
||
|
||
public sealed class BattleState
|
||
{
|
||
public required int AttackerPlayer { get; init; }
|
||
|
||
/// <summary>Индекс атакующего: -1 — Авангард, 0..4 — круг Арьергарда.</summary>
|
||
public required int AttackerSlot { get; init; }
|
||
|
||
/// <summary>Индекс цели: -1 — Авангард противника.</summary>
|
||
public required int TargetSlot { get; init; }
|
||
|
||
public int GuardShield { get; set; }
|
||
public int ChecksRemaining { get; set; }
|
||
|
||
/// <summary>Атака отменена идеальной защитой: попадания не будет при любой силе.</summary>
|
||
public bool Nullified { get; set; }
|
||
|
||
/// <summary>Карта, вышедшая на перехват. Сила сравнения берётся по ней.</summary>
|
||
public CardInstance? Interceptor { get; set; }
|
||
|
||
/// <summary>Круг карты поддержки (-1 — поддержки не было).</summary>
|
||
public int BoosterSlot { get; set; } = -1;
|
||
|
||
public List<CardInstance> GuardCards { get; } = new();
|
||
}
|
||
|
||
public sealed class GameState
|
||
{
|
||
public GameState(CardCatalog catalog, ulong seed, string firstPlayerName, string secondPlayerName)
|
||
{
|
||
Catalog = catalog;
|
||
Seed = seed;
|
||
RngState = seed;
|
||
Players[0] = new PlayerState(firstPlayerName);
|
||
Players[1] = new PlayerState(secondPlayerName);
|
||
}
|
||
|
||
public CardCatalog Catalog { get; }
|
||
public PlayerState[] Players { get; } = new PlayerState[2];
|
||
|
||
public int ActivePlayer { get; internal set; }
|
||
public Phase Phase { get; internal set; } = Phase.Mulligan;
|
||
public Step Step { get; internal set; } = Step.None;
|
||
public int TurnNumber { get; internal set; }
|
||
|
||
public ulong RngState { get; internal set; }
|
||
|
||
/// <summary>Исходное зерно партии: нужно для записи и воспроизведения реплея.</summary>
|
||
public ulong Seed { get; }
|
||
public int NextInstanceId { get; internal set; } = 1;
|
||
|
||
public BattleState? Battle { get; internal set; }
|
||
public PendingTrigger? PendingTrigger { get; internal set; }
|
||
|
||
/// <summary>Способность ждёт решения «да / нет».</summary>
|
||
public TriggeredAbility? PendingAbility { get; internal set; }
|
||
|
||
/// <summary>Сработавшие способности ждут выбора порядка.</summary>
|
||
public List<TriggeredAbility>? PendingOrder { get; internal set; }
|
||
|
||
/// <summary>Ожидание выбора цели или карты.</summary>
|
||
public PendingChoice? PendingChoice { get; internal set; }
|
||
|
||
/// <summary>Продолжение разрешения, которое надо выполнить после способностей.</summary>
|
||
public Action? Continuation { get; internal set; }
|
||
|
||
/// <summary>
|
||
/// Триггеры, сработавшие во время другого эффекта. Разрешаются после него,
|
||
/// чтобы цепочка шла строго друг за другом.
|
||
/// </summary>
|
||
public List<TriggeredAbility>? PendingQueue { get; internal set; }
|
||
|
||
/// <summary>
|
||
/// Карты, которые уже покинули колоду, но ещё не положены в новую зону
|
||
/// (например, ожидают выбора круга для призыва).
|
||
/// </summary>
|
||
public List<(int Player, CardInstance Card)> InTransit { get; } = new();
|
||
|
||
public bool IsFinished { get; internal set; }
|
||
public int? Winner { get; internal set; }
|
||
|
||
public PlayerState Active => Players[ActivePlayer];
|
||
public PlayerState Opponent => Players[1 - ActivePlayer];
|
||
|
||
public CardDefinition Definition(CardInstance card) => Catalog.CardOf(card.PrintingId);
|
||
|
||
/// <summary>
|
||
/// Итоговая способность поддержки: выданная эффектом важнее печатной.
|
||
/// </summary>
|
||
public bool CanBoost(CardInstance unit) =>
|
||
!HasRestriction(unit, RestrictionType.CannotBoost)
|
||
&& (unit.BoostOverride ?? Definition(unit).HasBoost);
|
||
|
||
/// <summary>Итоговая способность перехвата: выданная эффектом важнее печатной.</summary>
|
||
public bool CanIntercept(CardInstance unit) =>
|
||
!HasRestriction(unit, RestrictionType.CannotIntercept)
|
||
&& (unit.InterceptOverride ?? Definition(unit).HasIntercept);
|
||
|
||
/// <summary>Есть ли у карты запрет указанного вида.</summary>
|
||
public bool HasRestriction(CardInstance unit, RestrictionType type) =>
|
||
unit.Restrictions.Any(r => r.Type == type);
|
||
|
||
/// <summary>Действует ли на карте Сдерживание с учётом переопределения эффектом.</summary>
|
||
public bool IsRestraint(CardInstance unit) =>
|
||
unit.RestraintOverride ?? Definition(unit).IsRestraint;
|
||
|
||
public CardInstance? GetUnit(int player, int slot) =>
|
||
slot < 0
|
||
? Players[player].Vanguard
|
||
: Players[player].RearGuards[slot];
|
||
}
|