using Vanguard.Rules.Cards; using Vanguard.Rules.Engine.Abilities; namespace Vanguard.Rules.Engine; public sealed class BattleState { public required int AttackerPlayer { get; init; } /// Индекс атакующего: -1 — Авангард, 0..4 — круг Арьергарда. public required int AttackerSlot { get; init; } /// Индекс цели: -1 — Авангард противника. public required int TargetSlot { get; init; } public int GuardShield { get; set; } public int ChecksRemaining { get; set; } /// Атака отменена идеальной защитой: попадания не будет при любой силе. public bool Nullified { get; set; } /// Карта, вышедшая на перехват. Сила сравнения берётся по ней. public CardInstance? Interceptor { get; set; } /// Круг карты поддержки (-1 — поддержки не было). public int BoosterSlot { get; set; } = -1; public List 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; } /// Исходное зерно партии: нужно для записи и воспроизведения реплея. public ulong Seed { get; } public int NextInstanceId { get; internal set; } = 1; public BattleState? Battle { get; internal set; } public PendingTrigger? PendingTrigger { get; internal set; } /// Способность ждёт решения «да / нет». public TriggeredAbility? PendingAbility { get; internal set; } /// Сработавшие способности ждут выбора порядка. public List? PendingOrder { get; internal set; } /// Ожидание выбора цели или карты. public PendingChoice? PendingChoice { get; internal set; } /// Продолжение разрешения, которое надо выполнить после способностей. public Action? Continuation { get; internal set; } /// /// Триггеры, сработавшие во время другого эффекта. Разрешаются после него, /// чтобы цепочка шла строго друг за другом. /// public List? PendingQueue { get; internal set; } /// /// Карты, которые уже покинули колоду, но ещё не положены в новую зону /// (например, ожидают выбора круга для призыва). /// 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); /// /// Итоговая способность поддержки: выданная эффектом важнее печатной. /// public bool CanBoost(CardInstance unit) => !HasRestriction(unit, RestrictionType.CannotBoost) && (unit.BoostOverride ?? Definition(unit).HasBoost); /// Итоговая способность перехвата: выданная эффектом важнее печатной. public bool CanIntercept(CardInstance unit) => !HasRestriction(unit, RestrictionType.CannotIntercept) && (unit.InterceptOverride ?? Definition(unit).HasIntercept); /// Есть ли у карты запрет указанного вида. public bool HasRestriction(CardInstance unit, RestrictionType type) => unit.Restrictions.Any(r => r.Type == type); /// Действует ли на карте Сдерживание с учётом переопределения эффектом. 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]; }