Retain trained Ixian response inside paused Semuta cost
This commit is contained in:
1 parent
90c6f0020c
commit
5b3729e2db
7 files changed
+92
-8
No files matched your search
@@ -26,12 +26,12 @@ export function semutaIxPhysical(game: Game) {
|
||||
}
|
||||
|
||||
/** Original native lobby, private Ix card choice, Traitors and actual first Storm/HMS placement. */
|
||||
export function initializeSemutaIxGame(advanced = false): Game {
|
||||
export function initializeSemutaIxGame(advanced = false, skills = false): Game {
|
||||
let game = createGame('SEMUTAIX', newPlayer('r', 'Richese', 'richese'), advanced, ['choam', 'ix']);
|
||||
joinGame(game, newPlayer('i', 'Ixians', 'ixians'));
|
||||
joinGame(game, newPlayer('e', 'Emperor', 'emperor'));
|
||||
for (const p of game.players) { p.bot = 'Medium'; p.ready = true; }
|
||||
game = initializeSemutaGameForAudit(game);
|
||||
game = initializeSemutaGameForAudit(game, skills);
|
||||
for (let step = 0; (game.status === 'setup' || game.phase === 1 || !game.mobileStronghold?.location) && step < 160; step++) {
|
||||
let next: Game | undefined;
|
||||
for (const p of game.players) {
|
||||
@@ -49,8 +49,8 @@ export function initializeSemutaIxGame(advanced = false): Game {
|
||||
}
|
||||
|
||||
/** Later rule position uses conserved native pieces, not a synthetic Game or replacement players. */
|
||||
export function semutaIxBattleFixture(advanced = false): SemutaIxFixture {
|
||||
const game = initializeSemutaIxGame(advanced);
|
||||
export function semutaIxBattleFixture(advanced = false, skills = false): SemutaIxFixture {
|
||||
const game = initializeSemutaIxGame(advanced, skills);
|
||||
const cards = semutaIxInventory(game);
|
||||
assert.equal(new Set(cards).size, cards.length);
|
||||
for (const p of game.players) {
|
||||
|
||||
@@ -24,8 +24,8 @@ export function semutaNativeKaramaAct(game: Game, step: SemutaNativeKaramaStep,
|
||||
}
|
||||
|
||||
/** Original lobby and conserved later battle; only the existing printed Karama changes hands. */
|
||||
export function semutaNativeIxKaramaFixture(advanced = false): SemutaNativeKaramaFixture {
|
||||
const ix = semutaIxBattleFixture(advanced);
|
||||
export function semutaNativeIxKaramaFixture(advanced = false, skills = false): SemutaNativeKaramaFixture {
|
||||
const ix = semutaIxBattleFixture(advanced, skills);
|
||||
const richese = semutaIxPlayer(ix.game, ix.holder);
|
||||
const index = richese.hand.findIndex(card => card.effect === 'karama');
|
||||
assert.ok(index >= 0);
|
||||
@@ -85,6 +85,10 @@ export function semutaNativeKaramaPreCost(f: SemutaNativeKaramaFixture, actions?
|
||||
step = { actor: game.battle.preparation.owner, action: { type: 'declineBattlePower' } };
|
||||
else if (game.decision?.kind === 'fullPlanOffer')
|
||||
step = { actor: game.decision.player, action: { type: 'decision', decline: true } };
|
||||
else if (game.decision?.kind === 'leaderSkillVisibility')
|
||||
step = { actor: game.decision.player, action: { type: 'leaderSkillVisibility', event: game.decision.event, hide: true } };
|
||||
else if (game.decision?.kind === 'mentatQuestion')
|
||||
step = { actor: game.decision.player, action: { type: 'decision', event: game.decision.event, decline: true } };
|
||||
else break;
|
||||
game = semutaNativeKaramaAct(game, step, actions);
|
||||
}
|
||||
|
||||
@@ -203,3 +203,29 @@ void test('All four profiles legally retire native printed costs and their origi
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (const claim of [false, true]) void test(`Skill-trained Ix cancellation cost ${claim ? 'claim' : 'pass'} preserves the declared response while Semuta owns controls`, () => {
|
||||
const f = semutaNativeIxKaramaFixture(true, true); assert.ok(f.ix);
|
||||
const before = semutaNativeKaramaPreCost(f);
|
||||
assert.ok(before.pendingIxSubstitution?.receipt);
|
||||
const pending = semutaNativeKaramaCost(before, f);
|
||||
const event = pending.pendingTreacheryDiscard!.batch.event;
|
||||
assert.deepEqual(pending.pendingIxSubstitution!.sources, { [f.ix.location]: 1 });
|
||||
assert.deepEqual(pending.pendingIxSubstitution!.recover, { [f.ix.location]: 1 });
|
||||
for (const player of pending.players)
|
||||
assert.equal(viewGame(reload(pending), player.id).semutaReaction!.event, event);
|
||||
let game = semutaNativeKaramaReact(reload(pending), f, claim);
|
||||
assert.equal(game.pendingIxSubstitution, null);
|
||||
assert.equal(game.lastBattleContext!.ixSubstitution!.completed, true);
|
||||
assert.equal(game.pendingTreacheryDiscard!.continuation.kind, 'winnerMandatoryDiscard');
|
||||
game = semutaNativeKaramaRemainder(game, f);
|
||||
assert.equal(game.phase, 7);
|
||||
assert.equal(semutaIxPlayer(game, f.owner).forces[f.ix.location], 2);
|
||||
assert.equal(semutaIxPlayer(game, f.owner).elites!.forces[f.ix.location] ?? 0, 0);
|
||||
assert.equal(semutaIxPlayer(game, f.owner).elites!.tanks, 1);
|
||||
assert.equal(semutaIxPlayer(game, f.holder).hand.some(card => card.id === f.karama), claim);
|
||||
assert.deepEqual(semutaIxInventory(game), f.cards);
|
||||
for (const player of game.players) viewGame(reload(game), player.id);
|
||||
const cost = semutaNativeKaramaCostStep(f); rejected(game, cost.actor, cost.action);
|
||||
rejected(game, f.holder, { type: 'semutaCommit', event });
|
||||
});
|
||||
Reference in new issue
Block a user