feat(battlenode): opponent reveal resolves on engine state via ReplaceReceivedCards (M-HC-2)

Drive a node-native battle to seat B's turn, then ingest an opponent
PlayActions reveal frame (knownList[{idx,cardId,to:Field}], isPlayerSeat:false)
matching battle_test_cl2's wire shape. The engine's ReplaceReceivedCard.ReplaceCard
-> CreateActualCard -> CreateBattleCardWithGameObject path resolves headless and
seats the substituted card on seat B's board with the wire cardId. No Engine/ logic
edits and no new view shims were needed — the card-creation view surface is fully
covered by the BackGround/icon-anim/play-queue/hand stubs from Tasks 2/3.

Adds InPlayCardId(seat, boardPos) accessor (SessionBattleEngine + harness) to read a
seated in-play follower's true identity, leader-excluded like BoardCount.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-06 20:51:55 -04:00
parent b1d17fb97d
commit 07ffc8906d
3 changed files with 84 additions and 0 deletions

View File

@@ -131,6 +131,11 @@ internal sealed class NodeNativeBattleHarness : IDisposable
/// Play frame would carry to play it).</summary>
public int PlayerHandCardIndex(int handPos) => Engine.HandCardIndex(playerSeat: true, handPos);
/// <summary>The real wire <c>CardId</c> of the in-play follower at <paramref name="boardPos"/> on the
/// given seat (0-based, leader excluded). Asserts an opponent reveal seated the substituted identity
/// (M-HC-2).</summary>
public int InPlayCardId(bool playerSeat, int boardPos) => Engine.InPlayCardId(playerSeat, boardPos);
/// <summary>Build an envelope for <paramref name="body"/> and ingest it into the engine for the
/// given seat (player == seat A). Mirrors <c>BattleNodeFlowTests.MakeEnvelopeWith</c> +
/// <c>SessionBattleEngine.Receive</c>.</summary>