Connect paired E3 Skills without Nexus and retain native arrival independence

Reuse original paired roster validation with plain all14 native setup and optional independent cards. Preserve real coalition, trained death and Mentat paths; extend the existing paid Ambassador/Terror queue to paired Skills and card-only factions. Frozen29-file323/323, types/lint/build, native programmes and390px entry pass. No save conversion or deployment.
This commit is contained in:
Quintine committed 2026-10-17 21:12:35 +11:00
1 parent fde44baab5
commit 17adffa6a7
20 files changed
+573 -93

No files matched your search

+1 -24
View File
@@ -1,6 +1,6 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { applyAction, createGame, initializeLeaderSkillsGameForAudit, joinGame, newPlayer, normalizeAutomaticGame, viewGame, type Game } from '../game/engine';
import { applyAction, normalizeAutomaticGame, viewGame, type Game } from '../game/engine';
import { LEADER_SKILL_CARDS } from '../game/leader-skill-cards';
import { planetologistMoveDraft } from '../components/planetologist-movement';
import { TERRITORIES, distance, location, splitLocation } from '../game/board';
@@ -33,29 +33,6 @@ void test('every canonical skill can be dealt and publicly assigned to Basic Mor
}
});
void test('Moritani skill starts retain immutable Ecaz and optional-module rejection', () => {
// Native Discovery Leader Skills are now admitted for this fresh lobby.
const discovery = createGame('MORIGATE', newPlayer('m', 'Moritani', 'moritani'), false, ['ecaz']);
joinGame(discovery, newPlayer('a', 'Atreides', 'atreides'));
discovery.players.forEach(p => { p.ready = true; });
discovery.discoveryEnabled = true;
assert.ok(initializeLeaderSkillsGameForAudit(discovery).leaderSkills);
for (const change of [
(g: Game) => { g.players[1] = newPlayer('a', 'Ecaz', 'ecaz'); },
(g: Game) => { g.expansions.push('choam'); },
(g: Game) => { g.discoveryEnabled = true; g.expansions.push('choam'); },
(g: Game) => { g.discoveryEnabled = true; g.players[1] = newPlayer('a', 'Ecaz', 'ecaz'); },
]) {
const lobby = createGame('MORIGATE', newPlayer('m', 'Moritani', 'moritani'), false, ['ecaz']);
joinGame(lobby, newPlayer('a', 'Atreides', 'atreides'));
lobby.players.forEach(p => { p.ready = true; });
change(lobby);
const before = JSON.stringify(lobby);
assert.throws(() => initializeLeaderSkillsGameForAudit(lobby));
assert.equal(JSON.stringify(lobby), before);
}
});
void test('all four profiles legally choose from the same private Moritani setup offer', () => {
const game = initializedMoritaniSkillsOffers({ requestedSkill: 'planetologist' });
for (const difficulty of DIFFICULTIES) {