Intercept also works when the vanguard is attacked

Removed the rear-guard-only restriction. Interceptor resolution now runs before the vanguard damage branch, so a successful intercept retires the interceptor and the vanguard takes no damage. The attacked rear-guard still cannot intercept itself. Two tests.
This commit is contained in:
MpakobecEx 2026-10-21 00:43:10 +05:00
parent fdc21c8a26
commit 4dd96e6f02
2 changed files with 43 additions and 12 deletions

View File

@ -12,8 +12,9 @@ namespace Vanguard.Rules.Engine;
/// * поддержка работает как отдельная способность: карты 0 и 1 ранга могут передать
/// свою силу атакующему Арьергарду из той же колонны, сила действует только в этом бою;
/// * перехват — отдельная способность карт 2 ранга: карта из переднего ряда выходит
/// в круг защиты, и сила атаки сравнивается с ней; из заднего ряда —
/// только если эффект разрешил (InterceptFromBackRow);
/// в круг защиты и при атаке по Авангарду, и при атаке по Арьергарду;
/// атакованный Арьергард не может перехватить атаку на самого себя;
/// из заднего ряда — только если эффект разрешил (InterceptFromBackRow);
/// * триггер требует выбора целей через ResolveTriggerCommand:
/// +5000 любой карте в кругах Авангарда или Арьергарда, затем второй эффект;
/// правило одинаково для drive check и damage check;
@ -373,9 +374,6 @@ public sealed class GameEngine
if (State.ActivePlayer != defenderIndex)
return CommandResult.Reject("Перехватывает только обороняющийся.");
if (battle.TargetSlot < 0)
return CommandResult.Reject("Перехват возможен только при атаке по Арьергарду.");
if (battle.Interceptor is not null)
return CommandResult.Reject("Перехват уже объявлен.");
@ -647,16 +645,17 @@ public sealed class GameEngine
if (hit)
{
if (battle.TargetSlot < 0)
if (battle.Interceptor is not null)
{
// перехватчик уже вышел из круга и уйдёт в сброс при закрытии боя,
// первоначальная цель (Авангард или Арьергард) не страдает
_events.Add(new InterceptorRetiredEvent(defenderIndex, battle.Interceptor.PrintingId));
}
else if (battle.TargetSlot < 0)
{
var damage = attackerDef.Critical + attacker.TemporaryCritical;
DealDamage(defenderIndex, damage);
}
else if (battle.Interceptor is not null)
{
// перехватчик уже вышел из круга и уйдёт в сброс при закрытии боя
_events.Add(new InterceptorRetiredEvent(defenderIndex, battle.Interceptor.PrintingId));
}
else
{
State.Players[defenderIndex].RearGuards[battle.TargetSlot] = null;

View File

@ -17,6 +17,7 @@ public class GameEngineTests
private const string Govannon = "BT01/045EN"; // Draw
private const string Iseult = "BT01/011EN"; // Sentinel, Royal Paladin
private const string Nehalem = "BT01/022EN"; // Kagero
private const string Overlord = "BT01/004EN"; // Kagero, 11000
[Fact]
public void Start_Places_Starting_Vanguard_And_Draws_Five()
@ -382,6 +383,37 @@ public class GameEngineTests
Assert.True(engine.Execute(new InterceptCommand(1)).Accepted);
}
[Fact]
public void Intercept_Works_Against_Vanguard_Attack()
{
var engine = StartedEngine();
engine.Execute(new SkipRideCommand());
SetVanguard(engine, 0, Overlord);
StackDeck(engine.State.Players[0], Gallatin, Gallatin);
engine.Execute(new EnterBattleCommand());
var defender = engine.State.Players[1];
defender.RearGuards[3] = TakeFromDeck(defender, Gallatin);
Assert.True(engine.Execute(new AttackCommand(-1, -1)).Accepted);
Assert.True(engine.Execute(new InterceptCommand(3)).Accepted);
Assert.True(engine.Execute(new PassGuardCommand()).Accepted);
Assert.Empty(defender.Damage);
Assert.NotNull(defender.Vanguard);
Assert.Contains(defender.Drop, c => c.PrintingId == Gallatin);
Assert.Contains(engine.Events, e => e is InterceptorRetiredEvent);
}
[Fact]
public void Attacked_RearGuard_Cannot_Intercept_Itself()
{
var engine = ReadyToAttackRearGuard();
Assert.True(engine.Execute(new AttackCommand(3, 0)).Accepted);
Assert.False(engine.Execute(new InterceptCommand(0)).Accepted);
}
[Fact]
public void ResolveTrigger_Rejects_When_Nothing_Is_Pending()
{
@ -493,7 +525,7 @@ public class GameEngineTests
private List<string> BuildDeck()
{
var mustInclude = new[] { Barcgal, Marron, Gallatin, Alfred, Nike, Flogal, Govannon, Iseult, Nehalem };
var mustInclude = new[] { Barcgal, Marron, Gallatin, Alfred, Nike, Flogal, Govannon, Iseult, Nehalem, Overlord };
var names = mustInclude
.Select(_catalog.CardOf)
.Select(c => c.NameId)