import assert from 'node:assert/strict'; import test from 'node:test'; import { applyAction, viewGame } from '../game/engine'; import { takeHarassCard } from './fixture-harass-withdraw'; import { createReinforcementsHomeworldFixture, reinforcementsHomeworldPool as pool, reinforcementsHomeworldPlayer as player, REINFORCEMENTS_KAITAIN as K, REINFORCEMENTS_SALUSA as S, REINFORCEMENTS_CARD, } from './fixture-reinforcements-homeworld'; /** The original native setup moves one actual ordinary counter to Salusa. * Its remaining native troops, the real invading force and all cards are * conserved; choosing the special reserve fee leaves two extra normal * counters on the native battlefield compared with the legacy fee. */ void test('a named Reinforcements promise finds a necessary special-reserve Homeworld fee', () => { const f = createReinforcementsHomeworldFixture({ advanced: true, role: 'native', nativeTransfer: 1, slot: 'weapon', }); const owner = player(f.game, f.owner); assert.deepEqual(pool(f.game, f.owner, K), { normal: 14, elite: 0 }); assert.deepEqual(pool(f.game, f.owner, S), { normal: 1, elite: 5 }); const support = Math.min(owner.spice, 14); const wantedDial = (14 + support) / 2; const legacyMax = (12 + Math.min(owner.spice, 12)) / 2; assert.ok(wantedDial > legacyMax, 'The legal plan must require preserving normal counters at Kaitain'); const mixed = { [K]: { normal: 0, elite: 0 }, [S]: { normal: 1, elite: 2 }, }; const manual = { ...f.planActions[0].action, type: 'battlePlan', weapon: REINFORCEMENTS_CARD, defense: null, dial: wantedDial, support, reinforcementsSources: mixed, reinforcementsElite: 2 }; assert.doesNotThrow(() => applyAction(f.game, f.owner, manual), 'The actual native plan establishes the chosen physical fee is legal'); let game = structuredClone(f.game); const truth = game.deck.find(card => card.effect === 'truthtrance'); assert.ok(truth); takeHarassCard(game, f.observer, truth.id); game = applyAction(game, f.observer, { type: 'card', card: truth.id }); while (game.truthtrance!.stage === 'priority') { const actor = game.players.find(p => !game.truthtrance!.passed.includes(p.id))!.id; game = applyAction(game, actor, { type: 'truthPass' }); } game = applyAction(game, f.observer, { type: 'truthAsk', question: { kind: 'battlePlan', target: f.owner, claim: { kind: 'and', terms: [ { kind: 'weapon', name: 'Reinforcements' }, { kind: 'dial', compare: 'eq', value: wantedDial }, ] }, } }); assert.ok(viewGame(game, f.owner).truthBattleAnswers!.includes('yes'), 'The real special-reserve plan supports a truthful Yes'); game = applyAction(game, f.owner, { type: 'truthAnswer', answer: 'yes' }); const witness = viewGame(game, f.owner).battle!.compliantPlan; assert.ok(witness); assert.equal(witness.dial, wantedDial); assert.ok((witness.reinforcementsElite ?? 0) >= 2); assert.equal(Object.values(witness.reinforcementsSources!).reduce((sum, group) => sum + group.elite, 0), witness.reinforcementsElite); const sealed = applyAction(game, f.owner, { type: 'battlePlan', ...witness }); assert.equal(sealed.battle!.plans[f.owner].dial, wantedDial); assert.equal(sealed.battle!.plans[f.owner].reinforcementsElite, witness.reinforcementsElite); });