test(battle-engine-port): M4 COMPLETE — when_play self-buff follower resolves headless (4/4 green)

Fold SetupCardEvent into a shared HeadlessEngineEnv.CreateHeadlessHandCard primitive
(consolidating the duplicated M2/M3 helpers), then add the M4 oracle: card 103111050
(ELF cost-1 1/1, when_play powerup add_offense=1&add_life=1 to target=self). New oracle
dimension = the played card's OWN stat delta (1/1 -> 2/2). Gate play_count>2 seeded via
the public AddCurrentTrunPlayCount; proven load-bearing (without the seed the fanfare
gates out and Atk stays 1). No new shim/data gaps were needed — only harness seeding.
Engine still 0 errors; check_drift clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-06 02:36:02 -04:00
parent c47ae93027
commit b13cfa0fad
4 changed files with 142 additions and 35 deletions

View File

@@ -26,25 +26,6 @@ namespace SVSim.BattleEngine.Tests
f.SetValue(obj, value);
}
private static BattleCardBase CreateHeadlessHandCard(int cardId, int index, bool isPlayer, BattleManagerBase mgr)
{
// Engine's own null-view creation path (CreateBase -> new *BattleCard(buildInfo).Setup(true));
// private, so reflect it — same seam the M2 oracle uses.
var io = mgr.CreatePlayerInnerOptionsBuilder();
var m = typeof(CardCreatorBase).GetMethod("CreateCardWithoutResources",
BindingFlags.NonPublic | BindingFlags.Static);
var card = (BattleCardBase)m.Invoke(null, new object[] { cardId, index, isPlayer, mgr, io });
// The engine's CreateCard wires per-card play events via SetupCardEvent; the raw
// CreateCardWithoutResources path skips it. For a SPELL this matters: SetupCardEvent
// attaches OnPlay -> RemoveSpellCardFromHand and OnFinishWhenPlaySkill ->
// AddSpellCardToCemetery (BattlePlayerBase.cs:1462-1466). Without it the spell resolves
// its damage but never leaves the hand. (Harmless for the M2 follower, whose hand->field
// move is intrinsic to SetUpInplay, not event-driven.)
BattlePlayerBase owner = isPlayer ? (BattlePlayerBase)mgr.BattlePlayer : mgr.BattleEnemy;
owner.SetupCardEvent(card);
return card;
}
[Test]
public void Fixed_damage_spell_reduces_opponent_leader_life()
{
@@ -70,7 +51,7 @@ namespace SVSim.BattleEngine.Tests
var cardParam = CardMaster.GetInstanceForBattle().GetCardParameterFromId(HeadlessEngineEnv.SpellId);
// Place the spell in the active player's hand with PP to spare; empty board otherwise.
var card = CreateHeadlessHandCard(HeadlessEngineEnv.SpellId, 1, isPlayer: true, mgr);
var card = HeadlessEngineEnv.CreateHeadlessHandCard(HeadlessEngineEnv.SpellId, 1, isPlayer: true, mgr);
player.HandCardList.Add(card);
player.Pp = 10;