test(battlenode): board-dependent when_evolve_other cost validated headless (M-HC-4d)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-06 23:54:13 -04:00
parent 3285097d1b
commit daaec20afb
2 changed files with 167 additions and 0 deletions

View File

@@ -108,6 +108,30 @@ internal sealed class NodeNativeBattleHarness : IDisposable
/// <summary>The second choice option of <see cref="ChoiceCardId"/> (token added to hand).</summary>
public const long ChoiceTokenB = 120011010;
/// <summary>A BOARD-DEPENDENT cost-reducer follower (M-HC-4d fixture). cards.json id 127011020:
/// char_type 1 (follower), clan 0 (Neutral — playable under any seat class), base cost 6, 3/3, skill
/// <c>cost_change,rush</c> / skill_timing <c>when_evolve_other,when_change_inplay</c> / skill_option
/// <c>set=1,none</c> / skill_condition (cost_change) <c>turn=self&amp;{me.hand_self.unit.count}&gt;0&amp;
/// character=me&amp;target=evolution_card&amp;card_type=unit</c> / skill_target <c>character=me&amp;target=self
/// &amp;card_type=unit</c> — i.e. "WHILE in hand, when ANOTHER of your followers evolves on your turn (and you
/// hold at least one other unit in hand), SET this card's cost to 1." The engine's evolve path
/// (<c>UnitBattleCard</c> non-skill evolve) scans the evolving player's HAND for cards whose skills have
/// <c>OnWhenEvolveOtherStart != 0</c> and registers them via <c>SkillCollectionBase.CreateWhenEvolveOtherInfo</c>;
/// <c>Skill_cost_change</c> then applies a <c>CostSetModifier(1)</c> to this card, so its resolved
/// <c>Cost</c> drops 6 → 1. Because the node reads opponent-facing cost straight off the resolved engine
/// (<c>SessionBattleEngine.PlayedCardCost</c>, M-HC-3), this board-dependent reduction is captured BY
/// CONSTRUCTION once evolve resolves headless (M-HC-4b) — this card validates that. Present + creatable in
/// cards.json.</summary>
public const long BoardDependentCostCardId = 127011020;
/// <summary>Base cost of <see cref="BoardDependentCostCardId"/> (6) — the pre-evolve resolved cost.</summary>
public const int BoardDependentCostBase = 6;
/// <summary>The flat cost <see cref="BoardDependentCostCardId"/> resolves to AFTER another follower evolves
/// on the controller's turn (skill_option <c>set=1</c> → <c>CostSetModifier(1)</c>). Independent of how many
/// followers evolved (a SET, not an add) — exactly 1.</summary>
public const int BoardDependentCostReduced = 1;
public BattleSessionState State { get; }
public StubParticipant SeatA { get; }
public StubParticipant SeatB { get; }
@@ -138,6 +162,20 @@ internal sealed class NodeNativeBattleHarness : IDisposable
return deck;
}
/// <summary>A deck for the M-HC-4d board-dependent-cost test: an alternating mix of the vanilla
/// follower (to play turn 1 and EVOLVE on seat A's evolve turn) and the <see cref="BoardDependentCostCardId"/>
/// (the <c>when_evolve_other set=1</c> cost-reducer that must sit IN HAND across the evolve). Alternating
/// 15/15 guarantees BOTH identities populate the opening hand + early draws regardless of the fixed shuffle;
/// the test locates each by identity (not a shuffle-dependent position). The cost-reducer's condition
/// <c>{me.hand_self.unit.count}&gt;0</c> (another unit in hand) is satisfied because copies of BOTH followers
/// remain in hand at the evolve.</summary>
public static IReadOnlyList<long> BoardDependentCostDeck()
{
var deck = new List<long>(30);
for (int i = 0; i < 15; i++) { deck.Add(VanillaFollowerId); deck.Add(BoardDependentCostCardId); }
return deck;
}
/// <summary>Seat the engine exactly as <c>BattleSession.EnsureEngineSetup</c> does: shuffle each
/// side's deck from the fixed seed via <see cref="BattleSessionState.GetShuffledDeck"/>, then
/// <c>SessionBattleEngine.Setup(seed, deckA, deckB, classA, classB)</c>.</summary>