Compose Harkonnen Ixian replacement before native purchase bonus
This commit is contained in:
1 parent
f268a36a11
commit
2c6bb02ccb
12 files changed
+229
-55
No files matched your search
@@ -0,0 +1,73 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { applyAction, viewGame, type Game } from '../game/engine';
|
||||
import { createOriginalHarkonnenReplacement } from './fixture-harkonnen-ixian-replacement';
|
||||
import { settleIxianReplacementFixture } from './fixture-nexus-ixian-replacement';
|
||||
|
||||
const player = (game: Game, id: string) => game.players.find(p => p.id === id)!;
|
||||
function passIncome(state: Game): Game {
|
||||
let game = state;
|
||||
for (let n = 0; game.response?.kind === 'emperorIncome' && n < 10; n++) {
|
||||
const actor = game.players.find(p => !game.response!.passed.includes(p.id))!;
|
||||
game = applyAction(game, actor.id, { type: 'passResponse' });
|
||||
}
|
||||
return game;
|
||||
}
|
||||
|
||||
for (const advanced of [false, true]) {
|
||||
void test(`${advanced ? 'Advanced' : 'Basic'} Harkonnen replacement precedes one original cancelable purchase bonus`, () => {
|
||||
for (const replace of [false, true]) for (const cancelBonus of [false, true]) {
|
||||
const f = createOriginalHarkonnenReplacement(advanced);
|
||||
const source = f.game.pendingNexusIxianReplacement!;
|
||||
assert.equal(source.card.id, f.lot.id);
|
||||
assert.equal(player(f.game, 'h').hand.length, 3, 'No bonus is drawn before the replacement choice');
|
||||
assert.ok(viewGame(f.game, 'h').nexusIxianReplacement!.canUse);
|
||||
assert.equal(f.game.response, null);
|
||||
let game = applyAction(f.game, 'h', { type: replace ? 'nexusIxianReplacementUse' : 'nexusIxianReplacementPass', event: source.event });
|
||||
assert.equal(player(game, 'h').hand.some(c => c.id === f.lot.id), !replace);
|
||||
assert.equal(player(game, 'h').hand.some(c => c.id === f.next.id), replace);
|
||||
game = passIncome(game);
|
||||
assert.equal(game.response?.kind, 'harkonnenBonus');
|
||||
assert.equal(player(game, 'h').hand.length, 3);
|
||||
const bonus = replace ? f.afterNext : f.next;
|
||||
assert.ok(bonus);
|
||||
if (cancelBonus) {
|
||||
const counter = player(game, f.counter).hand.find(c => c.effect === 'karama')!;
|
||||
game = applyAction(game, f.counter, { type: 'card', card: counter.id, mode: 'cancel' });
|
||||
}
|
||||
game = settleIxianReplacementFixture(game);
|
||||
assert.equal(player(game, 'h').hand.length, cancelBonus ? 3 : 4);
|
||||
assert.equal(player(game, 'h').hand.some(c => c.id === bonus.id), !cancelBonus);
|
||||
assert.equal(player(game, 'h').spice, player(f.beforeBid, 'h').spice - 2);
|
||||
assert.equal(player(game, 'e').spice, player(f.beforeBid, 'e').spice + 2);
|
||||
assert.equal(game.nexusCards!.cards!.hands.h, replace ? null : 'ixians');
|
||||
assert.equal(game.nexusIxianReplacementHistory!.length, 2);
|
||||
assert.equal(game.nexusIxianReplacementHistory!.at(-1)!.source.card.id, f.lot.id);
|
||||
assert.equal(game.pendingNexusIxianReplacement, null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void test('Harkonnen replacement at eight cards cannot manufacture a purchase-bonus slot', () => {
|
||||
for (const advanced of [false, true]) for (const replace of [false, true]) {
|
||||
const f = createOriginalHarkonnenReplacement(advanced);
|
||||
const parent = structuredClone(f.beforePurchase), owner = player(parent, 'h');
|
||||
// CONTROLLED capacity boundary: conserve original undealt cards into
|
||||
// Harkonnen custody without changing the actual auction, money or Nexus.
|
||||
while (owner.hand.length < 7) {
|
||||
const index = parent.deck.findIndex(c => c.effect !== 'karama'); assert.ok(index >= 0);
|
||||
owner.hand.push(parent.deck.splice(index, 1)[0]);
|
||||
}
|
||||
let game = applyAction(parent, f.actor, f.purchaseAction);
|
||||
assert.equal(player(game, 'h').hand.length, 8);
|
||||
const count = game.deck.length;
|
||||
const source = game.pendingNexusIxianReplacement!; assert.equal(source.card.id, f.lot.id);
|
||||
game = settleIxianReplacementFixture(applyAction(game, 'h',
|
||||
{ type: replace ? 'nexusIxianReplacementUse' : 'nexusIxianReplacementPass', event: source.event }));
|
||||
assert.equal(player(game, 'h').hand.length, 8);
|
||||
assert.equal(game.deck.length, count - Number(replace));
|
||||
assert.equal(player(game, 'h').hand.some(c => c.id === f.lot.id), !replace);
|
||||
assert.equal(player(game, 'h').spice, owner.spice - 2);
|
||||
assert.equal(game.nexusIxianReplacementHistory!.length, 2);
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user