91 lines
5.0 KiB
TypeScript
91 lines
5.0 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { dukeController } from '../game/duke-vidal';
|
|
import { viewGame } from '../game/engine';
|
|
import {
|
|
assassinateAfterCapturedDukeUse, cancelMoritaniDukeReclaim,
|
|
createMoritaniDukeCaptureFixture, reclaimMoritaniDuke, useMoritaniReclaimedDuke,
|
|
} from './fixture-moritani-duke-capture';
|
|
import { nextNexusDukeStep, nexusDukePlayer, stepNexusDuke } from './fixture-nexus-duke-capture';
|
|
|
|
void test('original Moritani qualification takes its real Harkonnen captive and releases after one native battle', () => {
|
|
const f = createMoritaniDukeCaptureFixture();
|
|
assert.equal(dukeController(f.game.dukeVidal!), f.captor);
|
|
const reclaimed = reclaimMoritaniDuke(f);
|
|
const duke = reclaimed.after.dukeVidal!;
|
|
assert.equal(dukeController(duke), f.owner);
|
|
assert.equal(duke.leader.capturedBy, undefined);
|
|
assert.equal(duke.leader.concealed, undefined);
|
|
assert.equal(duke.captureVisibility, undefined);
|
|
assert.equal(duke.leader.dead, false);
|
|
assert.equal(duke.leader.deaths, f.game.dukeVidal!.leader.deaths);
|
|
assert.equal(duke.source, 'moritani');
|
|
assert.equal(nexusDukePlayer(reclaimed.after, f.owner).spice, nexusDukePlayer(reclaimed.before, f.owner).spice);
|
|
const used = useMoritaniReclaimedDuke(reclaimed.after, f);
|
|
assert.equal(dukeController(used.dukeVidal!), null);
|
|
assert.equal(used.dukeVidal!.leader.dead, false);
|
|
assert.equal(used.dukeVidal!.leader.usedAt, 'carthag');
|
|
assert.equal(used.dukeVidal!.leader.capturedBy, undefined);
|
|
});
|
|
|
|
void test('unused original Moritani reclamation expires without restoring Harkonnen custody', () => {
|
|
const f = createMoritaniDukeCaptureFixture();
|
|
const reclaimed = reclaimMoritaniDuke(f);
|
|
const expired = useMoritaniReclaimedDuke(reclaimed.after, f, false);
|
|
assert.equal(dukeController(expired.dukeVidal!), null);
|
|
assert.equal(expired.dukeVidal!.leader.dead, false);
|
|
assert.equal(expired.dukeVidal!.leader.capturedBy, undefined);
|
|
assert.equal(expired.dukeVidal!.leader.deaths, f.game.dukeVidal!.leader.deaths);
|
|
});
|
|
|
|
void test('a qualified public acquisition cannot revive an actually executed captive Duke', () => {
|
|
const f = createMoritaniDukeCaptureFixture({ execute: true });
|
|
assert.equal(f.game.dukeVidal!.leader.dead, true);
|
|
const resolved = reclaimMoritaniDuke(f);
|
|
assert.equal(dukeController(resolved.after.dukeVidal!), null);
|
|
assert.equal(resolved.after.dukeVidal!.leader.dead, true);
|
|
assert.equal(resolved.after.dukeVidal!.leader.deaths, 2);
|
|
assert.equal(resolved.after.dukeVidal!.leader.concealed, undefined);
|
|
assert.equal(nexusDukePlayer(resolved.after, f.owner).spice, nexusDukePlayer(resolved.before, f.owner).spice);
|
|
});
|
|
|
|
void test('original Karama preserves the captive and its actual winning use still opens native Harkonnen Assassinate', () => {
|
|
const f = createMoritaniDukeCaptureFixture({ karama: true });
|
|
const karama = nexusDukePlayer(f.game, f.captor).hand.find(c => c.effect === 'karama')!;
|
|
const canceled = cancelMoritaniDukeReclaim(f);
|
|
assert.equal(dukeController(canceled.after.dukeVidal!), f.captor);
|
|
assert.deepEqual(canceled.after.dukeVidal, canceled.before.dukeVidal);
|
|
assert.ok(canceled.after.discard.some(c => c.id === karama.id));
|
|
const used = assassinateAfterCapturedDukeUse(canceled.after, f);
|
|
assert.equal(dukeController(used.window.dukeVidal!), null);
|
|
assert.equal(used.window.dukeVidal!.leader.dead, false);
|
|
const targetBefore = nexusDukePlayer(used.window, f.captor).leaders.find(l => l.id === f.target)!;
|
|
const targetAfter = nexusDukePlayer(used.after, f.captor).leaders.find(l => l.id === f.target)!;
|
|
assert.equal(targetAfter.dead, true);
|
|
assert.equal(targetAfter.deaths, targetBefore.deaths + 1);
|
|
assert.equal(nexusDukePlayer(used.after, f.owner).spice,
|
|
nexusDukePlayer(used.window, f.owner).spice + targetBefore.strength);
|
|
assert.equal(nexusDukePlayer(used.after, f.owner).traitors.includes(f.target), true);
|
|
assert.equal(nexusDukePlayer(used.replaced, f.owner).traitors.includes(f.target), false);
|
|
assert.equal(used.replaced.moritaniAssassinate!.opportunities.filter(r =>
|
|
r.card === f.target && r.stage === 'replaced').length, 1);
|
|
});
|
|
|
|
void test('a private execution does not remove or identify the public qualifying acquisition window', () => {
|
|
const living = createMoritaniDukeCaptureFixture({ karama: true });
|
|
const executed = createMoritaniDukeCaptureFixture({ karama: true, execute: true });
|
|
const open = (f: typeof living) => {
|
|
const next = nextNexusDukeStep(f.game, f.plan);
|
|
assert.ok(next);
|
|
return stepNexusDuke(f.game, f.plan, next, f.actions);
|
|
};
|
|
const livePending = open(living), deadPending = open(executed);
|
|
assert.equal(livePending.response?.kind, 'moritaniDuke');
|
|
assert.equal(deadPending.response?.kind, 'moritaniDuke');
|
|
const livePublic = viewGame(livePending, living.guild);
|
|
const deadPublic = viewGame(deadPending, executed.guild);
|
|
assert.deepEqual(deadPublic.response, livePublic.response);
|
|
assert.deepEqual(deadPublic.dukeVidal, livePublic.dukeVidal);
|
|
assert.equal(deadPending.dukeVidal!.leader.dead, true);
|
|
});
|