Files
Dune/tests/smuggler-kwisatz-journey.test.ts
T

92 lines
5.7 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { applyAction, normalizeAutomaticGame, viewGame } from '../game/engine';
import { advancedNativePlayer, assertAdvancedNativeCustody } from './fixture-advanced-native-skills';
import {
createSmugglerKwisatzJourney, finishSmugglerKwisatzJourney,
revealSmugglerKwisatzJourney, settleSmugglerKwisatzJourney,
} from './fixture-smuggler-kwisatz-journey';
void test('native Atreides earns KH with seven paid Arrakeen casualties, then its original Smuggler collects a short real Spice Blow', () => {
const fixture = createSmugglerKwisatzJourney();
const { game, owner, opponent, trainer, key, firstBattle } = fixture;
assert.equal(advancedNativePlayer(fixture.afterSetup, 'atreides').forces['arrakeen:10'], 10);
assert.equal(viewGame(firstBattle.game, owner).players.find(p => p.id === owner)!.kwisatz!.active, false);
assert.notEqual(firstBattle.revealed.battle!.plans[owner].leader, trainer);
assert.equal(firstBattle.revealed.battle!.plans[owner].dial, 7);
assert.equal(firstBattle.revealed.battle!.plans[owner].support, 7);
assert.equal(firstBattle.settled.lastBattleContext!.winner, owner);
const veteran = advancedNativePlayer(firstBattle.settled, 'atreides');
assert.equal(veteran.battleLosses, 7);
assert.equal(veteran.tanks, 7);
assert.equal(veteran.forces['arrakeen:10'], 3);
assert.equal(veteran.spice, advancedNativePlayer(firstBattle.revealed, 'atreides').spice - 7,
'The actual supported battle pays seven before the pending first Collection opens.');
assert.equal(viewGame(game, owner).players.find(p => p.id === owner)!.kwisatz!.active, true);
for (const shipment of fixture.shipments) {
const payerBefore = shipment.before.players.find(p => p.id === shipment.step.actor)!;
const payerAfter = shipment.after.players.find(p => p.id === shipment.step.actor)!;
assert.equal(payerBefore.spice - payerAfter.spice, shipment.step.actor === owner ? 2 : 1);
assert.equal(payerBefore.reserves - payerAfter.reserves, 1);
}
assert.equal(game.turn, 2);
assert.equal(game.phase, 6);
assert.deepEqual(game.battle!.plans, {});
assert.equal(game.spice[key], 6);
const wallet = advancedNativePlayer(game, 'atreides').spice;
const ownSealed = applyAction(game, owner, fixture.planActions[0].action);
assert.equal(ownSealed.battle!.plans[owner].kwisatz, true);
assert.equal(ownSealed.battle!.plans[owner].defense, fixture.shield);
assert.deepEqual(viewGame(ownSealed, opponent).battle!.plans, {});
assert.equal(advancedNativePlayer(ownSealed, 'atreides').spice, wallet);
const pending = revealSmugglerKwisatzJourney(fixture);
const printed = advancedNativePlayer(game, 'atreides').leaders.find(l => l.id === trainer)!.strength;
assert.equal(pending.battle!.smugglerCollection!.strength, printed + 2);
assert.equal(pending.battle!.smugglerCollection!.amount, Math.min(printed + 2, 6));
assert.equal(pending.battle!.smugglerCollection!.stage, 'pending');
assert.equal(advancedNativePlayer(pending, 'atreides').spice, wallet);
assert.equal(pending.spice[key], 6);
const paid = settleSmugglerKwisatzJourney(pending);
assert.equal(paid.phase, 6);
assert.equal(paid.decision?.player, owner);
assert.equal(paid.lastBattleContext!.smugglerCollection!.stage, 'collected');
assert.equal(advancedNativePlayer(paid, 'atreides').spice, wallet + 6);
assert.equal(paid.spice[key], 0);
assert.equal(advancedNativePlayer(paid, 'atreides').leaders.find(l => l.id === trainer)!.dead, false);
assert.equal(advancedNativePlayer(paid, 'atreides').kwisatz!.usedAt, fixture.territory);
assertAdvancedNativeCustody(paid);
});
void test('earned KH adds two beyond printed Smuggler strength, pays once before cleanup, and leaves ordinary Collection separate', () => {
const fixture = createSmugglerKwisatzJourney({ pile: 'ample' });
const wallet = advancedNativePlayer(fixture.game, 'atreides').spice;
const pending = revealSmugglerKwisatzJourney(fixture);
const printed = advancedNativePlayer(pending, 'atreides').leaders.find(l => l.id === fixture.trainer)!.strength;
const amount = printed + 2;
assert.ok(amount < pending.spice[fixture.key]);
assert.equal(pending.battle!.smugglerCollection!.amount, amount);
assert.equal(advancedNativePlayer(pending, 'atreides').spice, wallet);
const paid = settleSmugglerKwisatzJourney(normalizeAutomaticGame(JSON.parse(JSON.stringify(pending))));
assert.equal(paid.phase, 6);
assert.equal(paid.decision?.kind, 'battleCards');
assert.equal(paid.lastBattleContext!.winner, fixture.owner);
assert.equal(paid.lastBattleContext!.smugglerCollection!.stage, 'collected');
assert.equal(advancedNativePlayer(paid, 'atreides').spice, wallet + amount);
assert.equal(paid.spice[fixture.key], 8 - amount);
assert.equal(advancedNativePlayer(paid, 'atreides').tanks, 7);
const restored = normalizeAutomaticGame(JSON.parse(JSON.stringify(paid)));
assert.equal(advancedNativePlayer(restored, 'atreides').spice, wallet + amount);
assert.equal(restored.spice[fixture.key], 8 - amount);
const beforeDuplicate = structuredClone(restored);
assert.throws(() => applyAction(restored, fixture.opponent, { type: 'traitorCall', call: false }));
assert.deepEqual(restored, beforeDuplicate);
const collected = finishSmugglerKwisatzJourney(restored);
assert.equal(collected.phase, 7);
assert.equal(collected.spice[fixture.key], 0);
assert.equal(advancedNativePlayer(collected, 'atreides').spice, wallet + amount + (8 - amount) + 2,
'Ordinary Collection separately gathers the remainder and native Arrakeen income; it does not pay the skill again.');
assert.equal(collected.lastBattleContext!.smugglerCollection!.amount, amount);
assert.equal(collected.lastBattleContext!.smugglerCollection!.stage, 'collected');
assertAdvancedNativeCustody(collected);
});