feat(battlenode): emit engine-resolved cost on every knownList entry (M-HC-3)
The opponent-facing PlayActions knownList now carries the engine-RESOLVED play-time cost (KnownCardEntry.cost), sourced from the headless shadow engine's PlayedCost on the just-resolved card. This closes the spellboost cost-desync BY CONSTRUCTION: the engine already knows the true discounted cost (spellboost + board modifiers folded in), so no bookkeeping is needed. - DTO: add non-nullable cost to KnownCardEntry (prod emits cost 45/45). - SessionBattleEngine.PlayedCardCost(seat, idx, fallback): finds the resolved card by engine Index across in-play/cemetery/hand zones and returns PlayedCost (captured by PlayCard at resolution == discounted Cost), degrading to fallback when the engine is not owned/ready. - PlayActionsHandler sources the played card's cost from ctx.Engine (ShadowIngest already resolved the play before the handler runs). Spellboost-map plumbing stays for now; Task 6 (M-HC-3b) retires it. - Validation: engine-read test (charge-seeded reducer 101314020: base 5, cost 5/1/0 at charge 0/4/5) + handler-emit test asserting knownList[0].cost == 1 (discounted, not base 5) with non-vacuity. Board-dependent (when_evolve_other) case deferred to M-HC-4 (evolve not yet headless); cost is read off the resolved engine so board modifiers are captured by construction once their ops resolve. - Harness: promote alt vanilla follower id (101211120) to AltVanillaFollowerId. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@ using SVSim.BattleNode.Protocol;
|
||||
using SVSim.BattleNode.Sessions;
|
||||
using SVSim.BattleNode.Sessions.Dispatch;
|
||||
using SVSim.BattleNode.Sessions.Engine;
|
||||
using SVSim.BattleNode.Sessions.Participants;
|
||||
|
||||
namespace SVSim.UnitTests.BattleNode.Integration;
|
||||
|
||||
@@ -55,6 +56,13 @@ internal sealed class NodeNativeBattleHarness : IDisposable
|
||||
/// it will produce a traceable failure here.</summary>
|
||||
public const long VanillaFollowerId = 100011010;
|
||||
|
||||
/// <summary>A SECOND, distinct cost-1 vanilla follower (char_type 1, cost 1, no skill) — present +
|
||||
/// creatable in cards.json. Used by the opponent-reveal substitution test as the WIRE cardId that
|
||||
/// must override a seeded identity (it is deliberately NOT in any harness deck, so its only route
|
||||
/// onto the board is a reveal). Named here so card-id provenance stays traceable as ids accumulate
|
||||
/// (Task-4 review nit promoted in M-HC-3).</summary>
|
||||
public const long AltVanillaFollowerId = 101211120;
|
||||
|
||||
public BattleSessionState State { get; }
|
||||
public StubParticipant SeatA { get; }
|
||||
public StubParticipant SeatB { get; }
|
||||
@@ -156,11 +164,18 @@ internal sealed class NodeNativeBattleHarness : IDisposable
|
||||
/// (<c>PushAsync</c>, <c>RunAsync</c>, <c>TerminateAsync</c>) throw <see cref="NotSupportedException"/>
|
||||
/// — the harness drives the engine directly, so a frame must never reach the participant relay.
|
||||
/// Silent no-ops would let a misrouted push pass undetected.</summary>
|
||||
internal sealed class StubParticipant : IBattleParticipant
|
||||
internal sealed class StubParticipant : IBattleParticipant, IHasHandshakePhase
|
||||
{
|
||||
public long ViewerId { get; }
|
||||
public MatchContext Context { get; }
|
||||
|
||||
/// <summary>Handshake cursor (M-HC-3a handler-emit test). Implementing
|
||||
/// <see cref="IHasHandshakePhase"/> lets a test build a <c>FrameDispatchContext</c> over two
|
||||
/// StubParticipants and advance both to <see cref="HandshakePhase.AfterReady"/> so
|
||||
/// <c>BothSidesAfterReady()</c> passes (the PvP relay gate). Harness tests that drive the engine
|
||||
/// directly never read this; it defaults to the pre-handshake state and is harmless to them.</summary>
|
||||
public HandshakePhase Phase { get; set; } = HandshakePhase.AwaitingInitNetwork;
|
||||
|
||||
public StubParticipant(long viewerId, MatchContext context)
|
||||
{
|
||||
ViewerId = viewerId;
|
||||
|
||||
Reference in New Issue
Block a user