Files
Dune/tests/phase-module-ecaz-runtime.test.ts

93 lines
7.7 KiB
TypeScript

import assert from 'node:assert/strict';
import test from 'node:test';
import { ownedTech } from '../game/tech-tokens';
import { strongholdBenefit } from '../game/stronghold-cards';
import {
createPhaseModuleEcazFixture as fixture, resolvePhaseModuleEcazFixture as resolve,
phaseModuleEcazInventory as inventory, phaseModuleEcazPlayer as player,
type PhaseModuleEcazFixture,
} from './fixture-phase-module-ecaz';
function source(f: PhaseModuleEcazFixture) {
assert.equal(f.initial.status, 'lobby'); assert.equal(f.ready.status, 'lobby'); assert.equal(f.started.status, 'setup');
assert.equal(f.afterSetup.status, 'playing'); assert.equal(f.game.status, 'playing');
assert.equal(f.game.turn, 3); assert.equal(f.game.phase, 6); assert.equal(f.game.advanced, f.advanced);
assert.deepEqual(f.game.expansions, ['ix', 'choam', 'ecaz']);
assert.deepEqual(f.game.players.map(p => p.faction), ['ecaz', 'ixians', 'emperor']);
assert.ok(f.game.techTokens); assert.equal(!!f.game.strongholdCards, f.advanced);
assert.ok(!f.game.leaderSkills && !f.game.homeworlds && !f.game.nexusCards && !f.game.discoveryEnabled && !f.game.ecazTreachery && !f.game.semutaPreview);
assert.ok(f.actions.some(step => step.action.type === 'techTokens' && step.action.enabled === true));
assert.ok(f.actions.some(step => step.action.type === 'start' && (!f.advanced || step.action.advancedPreview === true)));
assert.equal(f.beforeAlliance.turn, 2); assert.equal(f.beforeAlliance.phase, 1); assert.equal(f.beforeAlliance.nexus, true);
assert.ok(f.beforeAlliance.spiceDiscard.flat().some(card => 'worm' in card && !card.suppressed));
assert.equal(player(f.afterAlliance, f.ecaz).ally, f.ally); assert.equal(player(f.afterAlliance, f.ally).ally, f.ecaz);
assert.ok(f.actions.some(step => step.actor === f.ecaz && step.action.type === 'alliance' && step.action.target === f.ally));
assert.ok(f.actions.some(step => step.actor === f.ally && step.action.type === 'alliance' && step.action.target === f.ecaz));
assert.equal(f.beforeMentat.turn, 2); assert.equal(f.beforeMentat.phase, 8); assert.equal(f.afterMentat.turn, 3);
assert.equal(f.mentatStep.action.type, 'ready');
if (f.advanced) {
assert.equal(f.afterMentat.strongholdCards!.owners.sietch_tabr, f.ecaz);
assert.equal(f.afterMentat.strongholdCards!.claimedTurn, 2);
assert.equal(strongholdBenefit(f.game.strongholdCards, f.ecaz, f.territory), f.territory);
assert.equal(strongholdBenefit(f.game.strongholdCards, f.ally, f.territory), null);
}
assert.equal(f.beforeLead.decision?.kind, 'ecazBattleLead'); assert.equal(f.beforeLead.decision?.player, f.ecaz);
assert.equal(f.game.battle!.revealed, false); assert.equal(f.game.decision ?? null, null); assert.equal(f.game.response ?? null, null);
assert.equal(f.profile.ecaz, f.ecaz); assert.equal(f.profile.ally, f.ally); assert.equal(f.profile.planOwner, f.actor);
assert.equal(f.profile.payer, f.actor); assert.equal(f.profile.forceOwner, f.ally); assert.equal(f.profile.canceled, false);
assert.equal(f.profile.fixedEcazDial, Math.ceil(f.ecazForces / 2));
assert.equal(f.profile.ecazForces.normal, f.ecazForces);
assert.equal(f.profile.allyForces.normal, 3); assert.equal(f.profile.allyForces.elite, 3);
assert.equal(f.profile.allyForces.normalFixedHalf, true); assert.equal(f.profile.allyForces.eliteStrength, 2);
assert.equal(player(f.game, f.ecaz).forces[f.location], f.ecazForces);
assert.equal(player(f.game, f.ally).forces[f.location], 6); assert.equal(player(f.game, f.ally).elites!.forces[f.location], 3);
assert.equal(player(f.game, f.opponent).forces[f.location], 8);
assert.equal(ownedTech(f.afterFirstStorm.techTokens, f.ecaz).length, 1);
assert.equal(ownedTech(f.afterFirstStorm.techTokens, f.ally).length, 1);
assert.equal(ownedTech(f.afterFirstStorm.techTokens, f.opponent).length, 1);
assert.deepEqual(f.game.techTokens, f.afterFirstStorm.techTokens);
assert.ok(player(f.game, f.actor).hand.some(card => card.id === f.shield));
assert.equal(f.sourceActionCount, f.actions.length); assert.match(f.staging[1], /CONTROLLED/); assert.match(f.staging[2], /CONTROLLED/);
assert.deepEqual(inventory(f.game), f.originalInventory); assert.equal(f.originalInventory.length, 47);
}
for (const advanced of [false, true]) for (const lead of ['ecaz', 'ally'] as const) {
void test(`public ${advanced ? 'Advanced Stronghold+Tech' : 'Basic Tech'} all-three-deck coalition: ${lead} lead retains original native losses, holder benefit and winner Tech`, () => {
const f = fixture({ advanced, lead }); source(f);
const before = structuredClone(f.game), result = resolve(f), { quote, revealed, beforeCleanup, game } = result;
assert.deepEqual(f.game, before);
assert.equal(quote.winner, f.actor); assert.equal(beforeCleanup.lastBattleContext!.winner, f.actor);
assert.deepEqual(quote.fixedLosses, [{ owner: f.ecaz, normal: Math.ceil(f.ecazForces / 2), elite: 0 }]);
assert.equal(quote.casualties!.owner, f.ally);
assert.deepEqual(quote.casualties!.options, [{ normal: 1, elite: 0, paidNormal: 0, paidElite: 0 }]);
assert.ok(quote.payments.every(payment => payment.ownPayment === 0 && payment.bankSupport === 0));
const income = advanced && lead === 'ecaz' ? 1 : 0;
assert.deepEqual(quote.strongholdIncome, income ? [{ player: f.actor, amount: income }] : []);
assert.equal(player(beforeCleanup, f.actor).spice, player(revealed, f.actor).spice + income);
const nonLead = f.actor === f.ecaz ? f.ally : f.ecaz;
assert.equal(player(beforeCleanup, nonLead).spice, player(revealed, nonLead).spice);
assert.equal(player(beforeCleanup, f.opponent).spice, player(revealed, f.opponent).spice);
assert.equal(beforeCleanup.decision?.kind, 'battleCards'); assert.equal(beforeCleanup.decision?.player, f.actor);
assert.equal(beforeCleanup.techTokens![f.enemyToken].owner, f.opponent, 'Original winner-card cleanup precedes the original enemy token transfer');
assert.equal(player(beforeCleanup, f.ecaz).tanks - player(f.game, f.ecaz).tanks, Math.ceil(f.ecazForces / 2));
assert.equal(player(beforeCleanup, f.ally).tanks - player(f.game, f.ally).tanks, 1);
assert.equal(player(beforeCleanup, f.ally).elites!.tanks, player(f.game, f.ally).elites!.tanks);
assert.equal(player(beforeCleanup, f.opponent).tanks - player(f.game, f.opponent).tanks, 8);
assert.equal(player(game, f.ecaz).forces[f.location], 2);
assert.equal(player(game, f.ally).forces[f.location], 5); assert.equal(player(game, f.ally).elites!.forces[f.location], 3);
assert.equal(player(game, f.opponent).forces[f.location] ?? 0, 0);
assert.equal(game.lastBattleContext!.winner, f.actor); assert.equal(game.lastBattleContext!.result, 'normal');
assert.equal(game.techTokens![f.enemyToken].owner, f.actor);
assert.equal(ownedTech(game.techTokens, f.actor).length, 2); assert.equal(ownedTech(game.techTokens, nonLead).length, 1);
assert.equal(ownedTech(game.techTokens, f.opponent).length, 0);
assert.ok(player(game, f.actor).hand.some(card => card.id === f.shield));
assert.equal(player(game, f.actor).leaders.find(leader => leader.id === f.winnerLeader)!.dead, false);
if (advanced) assert.equal(game.strongholdCards!.owners.sietch_tabr, f.ecaz, 'Held-card custody is not transferred to the selected ally lead');
assert.ok(result.actions.some(step => step.actor === f.actor && step.action.type === 'decision' && Array.isArray(step.action.discard)));
assert.equal(result.actions.filter(step => step.action.type === 'battlePlan').length, 2);
assert.ok(result.actions.some(step => step.action.type === 'traitorCall' && step.action.call === false));
assert.equal(game.battle ?? null, null); assert.equal(game.decision ?? null, null);
assert.deepEqual(inventory(game), f.originalInventory);
});
}