import assert from 'node:assert/strict'; import test from 'node:test'; import { type Action, type Game } from '../game/engine'; import { nextTruthRevival, truthRevivalClean, truthRevivalPlayer } from './fixture-truth-revival'; import { actFutureBattleRevival as act, askFutureBattleRevival as ask, createFutureBattleRevivalFixture as fixture, futureBattleRevivalInventory as inventory, futureBattleRevivalRecords as records, reachFutureBattleRevivalBattle as reachBattle, reachFutureBattleRevivalMovement as reachMovement, } from './fixture-truth-future-battle-revival'; function rejected(game: Game, actor: string, action: Action) { const before = structuredClone(game); assert.throws(() => act(game, actor, action)); assert.deepEqual(game, before); } for (const answer of ['yes', 'no'] as const) { void test(`Basic Revival future-battle leader ${answer} binds the first actual later battle`, () => { const f = fixture(), asked = ask(f); assert.equal(asked.phase, 4); assert.deepEqual(asked.truthtrance?.question, f.question); let game = act(asked, f.target, {type: 'truthAnswer', answer}); assert.equal(records(game).length, 1); assert.equal(records(game)[0].status, 'waiting'); game = reachMovement(game, f); assert.equal(records(game)[0].status, 'waiting'); game = reachBattle(game, f); assert.equal(records(game)[0].status, 'bound'); assert.equal(records(game)[0].battle, game.battle!.event); const plan = (leader: string): Action => ({type: 'battlePlan', leader, dial: 0, support: 0, weapon: null, defense: null}); rejected(game, f.target, plan(answer === 'yes' ? f.alternative : f.leader)); game = act(game, f.target, plan(answer === 'yes' ? f.leader : f.alternative)); assert.equal(records(game)[0].status, 'bound'); const opponent = game.battle!.attacker === f.target ? game.battle!.defender : game.battle!.attacker; const other = truthRevivalPlayer(game, opponent).leaders.find(leader => !leader.dead && !leader.capturedBy && !leader.gholaBy && !leader.usedAt); assert.ok(other); game = act(game, opponent, plan(other.id)); assert.ok(game.battle?.revealed); assert.equal(records(game)[0].status, 'settled'); assert.equal(records(game).length, 1); assert.equal(game.discard.filter(card => card.id === f.truth).length, 1); assert.deepEqual(inventory(game), f.originalCards); }); } void test('Basic Revival conditional leader answers expire if the respondent never fights', () => { const f = fixture(); for (const answer of ['yes', 'no'] as const) { let game = act(ask(f), f.target, {type: 'truthAnswer', answer}); game = reachMovement(game, f); assert.ok(Object.values(truthRevivalPlayer(game, f.target).forces).every(amount => amount === 0)); for (let count = 0; count < 1200 && game.turn === f.game.turn && game.phase <= 6 && game.status === 'playing'; count++) { if (game.phase === 5 && game.active && truthRevivalClean(game)) { game = act(game, game.active, {type: 'endMovement'}); continue; } const next = nextTruthRevival(game); assert.ok(next, 'Finish the original turn without inventing a target battle.'); game = act(game, next.actor, next.action); } assert.equal(records(game).length, 1); assert.equal(records(game)[0].status, 'expired'); assert.equal(game.discard.filter(card => card.id === f.truth).length, 1); assert.deepEqual(inventory(game), f.originalCards); } }); void test('a pending native Truthtrance priority must finish before its Revival-phase question can be asked', () => { const f = fixture(); const game = act(f.game, f.asker, {type: 'card', card: f.truth}); assert.equal(game.truthtrance?.stage, 'priority'); rejected(game, f.asker, f.ask); assert.deepEqual(inventory(game), f.originalCards); });