feat(battle-node): reveal copy tokens on play via baseIdx resolution

PlayActionsHandler + EchoHandler now call RecordCopyTokensFrom (ordered
after plain/choice mining) to resolve a copy add's baseIdx against the
side's live idx->cardId map and record copyIdx->cardId. A copy played in a
later (or same) frame synthesizes a knownList instead of degrading.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-04 10:11:34 -04:00
parent f9c7e6124b
commit b6edfbcf15
4 changed files with 202 additions and 5 deletions

View File

@@ -67,4 +67,21 @@ internal sealed class BattleSessionState
foreach (var (idx, cardId, isSelf) in KnownListBuilder.MineChoicePicks(orderList, keyAction))
RecordToken(isSelf == 1 ? from : other, idx, cardId);
}
/// <summary>Mine + record copy/clone-token identities (<see cref="KnownListBuilder.MineCopyTokens"/>)
/// into the correct side's map. A copy's source lives at <c>baseIdx</c> in the actor's own index
/// space, so the resolution side == the record side, both selected by the same <c>isSelf</c> routing
/// as <see cref="RecordTokensFrom"/>. Passing the LIVE per-side maps (via
/// <see cref="GetOrSeedDeckMap"/>, not snapshots) lets a copy that references a plain/choice token
/// added earlier THIS frame resolve — provided this runs AFTER
/// <see cref="RecordTokensFrom"/>/<see cref="RecordChoicePicksFrom"/> (the handler orders it last).
/// Seeding both maps up front matters because a copy-only frame (no concrete/choice add) would never
/// have hit <see cref="RecordToken"/> yet, leaving the maps unseeded.</summary>
public void RecordCopyTokensFrom(IBattleParticipant from, IBattleParticipant other, object? orderList)
{
var selfMap = GetOrSeedDeckMap(from);
var otherMap = GetOrSeedDeckMap(other);
foreach (var (idx, cardId, isSelf) in KnownListBuilder.MineCopyTokens(orderList, selfMap, otherMap))
RecordToken(isSelf == 1 ? from : other, idx, cardId);
}
}