Enable advanced mixed-faction paired arrivals
Verify and publish checkpoint container / container (push) Canceled after 0s

This commit is contained in:
Quintine committed 2026-10-29 09:42:27 +11:00
1 parent 49f9ebdea0
commit eb68f28a3a
9 files changed
+312 -65

No files matched your search

+35 -26
View File
@@ -598,8 +598,8 @@ function balisetFlight(mode: 'range3' | 'twoGroups', conflict = false) {
});
assert.equal(g.response?.kind, 'choamWorthless');
assert.equal(g.pendingChoamWorthless?.movement, true);
// Fresh declarations now reject this topology before opening CHOAM. Model
// an already-persisted window (or changed topology) to retain cost preflight coverage.
// Model a saved prevention window whose destination gained the paired
// arrival tokens after the original uncommitted declaration.
if (conflict) addLegacyConflict();
assert.deepEqual(physical(g), inventory);
return { g, orni, baliset, printed, worthless, destination };
@@ -617,37 +617,46 @@ function allowConversion(initial: Game) {
for (const form of ['printed', 'worthless'] as const)
for (const mode of ['range3', 'twoGroups'] as const)
void test(`${form} cancellation of real Baliset rejects competing Ambassador and Terror arrival before cost (${mode})`, (t) => {
const { g, printed, worthless, orni, baliset } = balisetFlight(
void test(`${form} cancellation of real Baliset commits one ${mode} flight and serializes both arrival reactions`, () => {
const { g, printed, worthless, orni, baliset, destination } = balisetFlight(
mode,
true,
);
const before = structuredClone(g);
const inventory = physical(g);
const random = t.mock.method(crypto, 'getRandomValues', () => {
throw Error('Rejected arrival preflight drew randomness.');
const spent = form === 'printed' ? printed : worthless;
let done = applyAction(g, form === 'printed' ? 'p' : 'b', {
type: 'card',
mode: 'cancel',
card: spent,
});
const uuid = t.mock.method(crypto, 'randomUUID', () => {
throw Error('Rejected arrival preflight created an event.');
});
assert.throws(() =>
applyAction(g, form === 'printed' ? 'p' : 'b', {
type: 'card',
mode: 'cancel',
card: form === 'printed' ? printed : worthless,
}));
assert.deepEqual(g, before);
assert.deepEqual(physical(g), inventory);
assert.equal(g.pendingKarama ?? null, null);
assert.equal(g.ornithopter?.card.id, orni);
assert.equal(
g.discard.some((c) =>
[printed, worthless, baliset, orni].includes(c.id),
),
false,
);
assert.equal(random.mock.callCount(), 0);
assert.equal(uuid.mock.callCount(), 0);
if (form === 'worthless') {
assert.equal(done.response?.kind, 'worthlessKarama');
assert.equal(seat(done, 'p').forces[destination] ?? 0, 0);
done = allowConversion(reload(done));
}
assert.equal(seat(done, 'p').forces[destination], 1);
assert.equal(seat(done, 'p').forces[source], mode === 'twoGroups' ? 1 : 2);
assert.equal(seat(done, 'p').moved, mode === 'twoGroups' ? 2 : 1);
assert.equal(done.ornithopter, null);
assert.equal(done.pendingChoamMove, null);
assert.equal(done.discard.filter((c) => c.id === orni).length, 1);
assert.equal(done.discard.filter((c) => c.id === spent).length, 1);
assert.ok(seat(done, 'c').hand.some((c) => c.id === baliset));
assert.deepEqual(physical(done), inventory);
assert.equal(done.decision?.kind, 'ecazAmbassador');
done = applyAction(reload(done), 'e', {
type: 'decision',
event: done.pendingAmbassador!.event,
decline: true,
});
assert.equal(done.decision?.kind, 'moritaniTerror');
done = applyAction(reload(done), 'm', { type: 'decision', decline: true });
assert.equal(done.decision, null);
assert.equal(seat(done, 'p').forces[destination], 1);
assert.equal(seat(done, 'p').moved, mode === 'twoGroups' ? 2 : 1);
assert.deepEqual(physical(done), inventory);
});
for (const form of ['printed', 'worthless'] as const)