144 lines
5.4 KiB
C#
144 lines
5.4 KiB
C#
using Vanguard.Rules.Cards;
|
||
|
||
namespace Vanguard.Rules.Engine;
|
||
|
||
public enum Phase
|
||
{
|
||
Mulligan,
|
||
Stand,
|
||
Draw,
|
||
Ride,
|
||
Main,
|
||
Battle,
|
||
End,
|
||
}
|
||
|
||
public enum Step
|
||
{
|
||
None,
|
||
Guard,
|
||
Drive,
|
||
Trigger,
|
||
Ability,
|
||
Choice,
|
||
}
|
||
|
||
/// <summary>Вариант выбора, который предлагается игроку.</summary>
|
||
public sealed record ChoiceOption(int Slot, string Label);
|
||
|
||
/// <summary>Карта на поле: игрок и круг (-1 — Авангард).</summary>
|
||
public sealed record UnitTarget(int Player, int Slot);
|
||
|
||
/// <summary>
|
||
/// Ожидание выбора игрока. Resolve получает индекс выбранного варианта.
|
||
/// Пока выбор не сделан, движок не продолжает разрешение способности.
|
||
/// </summary>
|
||
public sealed class PendingChoice
|
||
{
|
||
public required int Player { get; init; }
|
||
public required string Prompt { get; init; }
|
||
public required IReadOnlyList<ChoiceOption> Options { get; init; }
|
||
public required Action<int> Resolve { get; init; }
|
||
}
|
||
|
||
public enum TriggerContext
|
||
{
|
||
DriveCheck,
|
||
DamageCheck,
|
||
}
|
||
|
||
/// <summary>Когда карта, находившаяся на поле, возвращается в колоду.</summary>
|
||
public enum ReturnToDeckTiming
|
||
{
|
||
AfterBattle,
|
||
EndOfTurn,
|
||
}
|
||
|
||
/// <summary>Триггер, который ждёт выбора целей от владельца.</summary>
|
||
public sealed class PendingTrigger
|
||
{
|
||
public required int Player { get; init; }
|
||
public required string PrintingId { get; init; }
|
||
public required CardInstance Card { get; init; }
|
||
public required TriggerType Trigger { get; init; }
|
||
public required TriggerContext Context { get; init; }
|
||
|
||
/// <summary>На drive check триггер сначала даёт +5000 силы, на damage check — нет.</summary>
|
||
public required bool GrantsPower { get; init; }
|
||
|
||
/// <summary>Сколько урона осталось раздать после этого триггера (контекст damage check).</summary>
|
||
public int RemainingDamage { get; init; }
|
||
}
|
||
|
||
/// <summary>Экземпляр карты в партии. Один принт может встречаться много раз.</summary>
|
||
public sealed class CardInstance
|
||
{
|
||
public required int Id { get; init; }
|
||
public required string PrintingId { get; init; }
|
||
|
||
/// <summary>Повёрнута ли карта (Rest). Актуально только для юнитов на поле.</summary>
|
||
public bool Rested { get; set; }
|
||
|
||
/// <summary>Открыта ли карта. Для урона — лицом вверх после Counter Blast.</summary>
|
||
public bool FaceUp { get; set; }
|
||
|
||
/// <summary>Модификаторы силы и крита с указанием источника и срока жизни.</summary>
|
||
public List<StatModifier> Modifiers { get; } = new();
|
||
|
||
/// <summary>Способности, выданные эффектами, а не напечатанные на карте.</summary>
|
||
public List<GrantedAbility> GrantedAbilities { get; } = new();
|
||
|
||
/// <summary>Запреты, выданные эффектами.</summary>
|
||
public List<CardRestriction> Restrictions { get; } = new();
|
||
|
||
/// <summary>Вернуть карту в колоду после боя или в конце хода (Juggernaut, Lozenge).</summary>
|
||
public ReturnToDeckTiming? ReturnToDeck { get; set; }
|
||
|
||
/// <summary>
|
||
/// Переопределение Сдерживания, выданное эффектом.
|
||
/// null — как напечатано на карте.
|
||
/// </summary>
|
||
public bool? RestraintOverride { get; set; }
|
||
/// <summary>
|
||
/// Переопределение способности поддержки, выданное эффектом.
|
||
/// null — как напечатано на карте.
|
||
/// </summary>
|
||
public bool? BoostOverride { get; set; }
|
||
|
||
/// <summary>Переопределение перехвата, выданное эффектом.</summary>
|
||
public bool? InterceptOverride { get; set; }
|
||
|
||
/// <summary>Эффект разрешил перехватывать из заднего ряда.</summary>
|
||
public bool InterceptFromBackRow { get; set; }
|
||
|
||
/// <summary>
|
||
/// Переопределение числа проверок, выданное эффектом.
|
||
/// null — по умолчанию: 1 для 0–2 ранга, 2 для 3+, у Арьергарда 0.
|
||
/// </summary>
|
||
public int? DriveChecksOverride { get; set; }
|
||
}
|
||
|
||
public sealed class PlayerState
|
||
{
|
||
public PlayerState(string name) => Name = name;
|
||
|
||
public string Name { get; }
|
||
|
||
public List<CardInstance> Deck { get; } = new();
|
||
public List<CardInstance> Hand { get; } = new();
|
||
public CardInstance? Vanguard { get; set; }
|
||
|
||
/// <summary>Пять кругов Арьергарда: 0–2 задний ряд, 3–4 передний (3 — левый, 4 — правый).</summary>
|
||
public CardInstance?[] RearGuards { get; } = new CardInstance?[RearGuardSlots];
|
||
|
||
public const int RearGuardSlots = 5;
|
||
|
||
public List<CardInstance> Guardian { get; } = new();
|
||
public List<CardInstance> Soul { get; } = new();
|
||
public List<CardInstance> Damage { get; } = new();
|
||
public List<CardInstance> Drop { get; } = new();
|
||
public List<CardInstance> Trigger { get; } = new();
|
||
|
||
public bool IsDefeated { get; set; }
|
||
}
|