v0.7.5 — solitaire asks before it deals, the same way multiplayer already does
A new #solitairesetup screen in play.html asks the full shared game-options block — type, starting hand, Extra start, revenue, victory conditions, optional rules — before a genuinely fresh visit deals a game. A saved game, an explicit ?seed=, or a URL a Deal already wrote all skip past it, same as ?lobby already skips the front doors on an invite link. The in-game dialog, the lobby and this screen now share one wireGameTypeBlock()/commitNewGame() pair instead of the dialog carrying its own copy of the questions. 859 tests pass. Not yet played in a browser. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdG46Ja2PEDBkpqiDazMoX
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
a02d1fcffe
commit
3e961496b0
+27
-7
@@ -3815,18 +3815,20 @@ describe('the lobby and the dialog ask the same questions', () => {
|
||||
return readFileSync(join(dist, 'play.html'), 'utf8');
|
||||
};
|
||||
|
||||
it('carries every field of the shared block on both screens', () => {
|
||||
it('carries every field of the shared block on all three screens', () => {
|
||||
// `ss-` joined `lb-`/`ng-` 2026-08-29: the pre-game solitaire setup screen drives the identical
|
||||
// block ("asking first is the only path"). Same drift guard, one more prefix.
|
||||
const html = page();
|
||||
for (const prefix of ['lb-', 'ng-']) {
|
||||
for (const prefix of ['lb-', 'ng-', 'ss-']) {
|
||||
for (const selector of fieldSelectors(prefix)) {
|
||||
assert.ok(html.includes(selector), `the ${prefix} block is missing ${selector}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('offers all five game types on both screens', () => {
|
||||
it('offers all five game types on all three screens', () => {
|
||||
const html = page();
|
||||
for (const prefix of ['lb-', 'ng-']) {
|
||||
for (const prefix of ['lb-', 'ng-', 'ss-']) {
|
||||
for (const type of ['solitaire', 'coop', 'competitive', 'cutthroat', 'custom']) {
|
||||
assert.ok(
|
||||
html.includes(`name="${prefix}type" value="${type}"`),
|
||||
@@ -3905,6 +3907,13 @@ describe('the New Game dialog', () => {
|
||||
'ng-hand': group(['threeRandom', 'sixRandom', 'threeTrackThreeOther'], 'sixRandom'),
|
||||
'ng-extra': group(['divisionPointsOnly', 'ownOffice', 'anyOffice'], 'anyOffice'),
|
||||
'ng-type': group(['solitaire', 'coop', 'competitive', 'cutthroat', 'custom'], 'coop'),
|
||||
// The pre-game setup screen (Gitea, "asking first is the only path", 2026-08-29) drives the
|
||||
// same shared block under the `ss-` prefix — one set here too, matching the markup's own
|
||||
// `checked` defaults rather than the dialog's (Solitaire, not Co-op: there is no live game to
|
||||
// reopen on, so the static default IS the Solitaire default).
|
||||
'ss-hand': group(['threeRandom', 'sixRandom', 'threeTrackThreeOther'], 'sixRandom'),
|
||||
'ss-extra': group(['divisionPointsOnly', 'ownOffice', 'anyOffice'], 'anyOffice'),
|
||||
'ss-type': group(['solitaire', 'coop', 'competitive', 'cutthroat', 'custom'], 'solitaire'),
|
||||
};
|
||||
const matching = (sel: string): Radio[] => {
|
||||
const name = /name="([^"]+)"/.exec(sel)?.[1] ?? '';
|
||||
@@ -4142,11 +4151,22 @@ describe('the New Game dialog', () => {
|
||||
assert.match(String(els.get('gametype')!['title']), /Days: 5/, 'the tooltip does not carry the victory conditions');
|
||||
});
|
||||
|
||||
it('asks before the first deal — a bare visit shows the setup screen, not a dealt game', async () => {
|
||||
// Jesse, 2026-08-29: "let the user choose their options like the start of a multiplayer game";
|
||||
// "asking first is the only path". A saved game, an explicit seed, or a URL a Deal already wrote
|
||||
// (checked via `hand`, below) all skip this screen — nothing else does.
|
||||
const { els } = await load('');
|
||||
assert.equal(els.get('solitairesetup')!['hidden'], false, 'the setup screen stayed hidden');
|
||||
assert.equal(els.get('gameui')!['hidden'], true, 'a game was dealt before anyone chose anything');
|
||||
});
|
||||
|
||||
it('deals six cards by default now, matching what the lobby calls Solitaire', async () => {
|
||||
// Jesse, 2026-08-23: every game type opens with six. `SOLO_CONFIG` — the ENGINE's fallback, which
|
||||
// every sim measurement is taken against — deliberately did not move; this is the page's deal.
|
||||
const { els } = await load('');
|
||||
assert.match(String(els.get('houserules')!['textContent']), /6 cards/);
|
||||
// every sim measurement is taken against — deliberately did not move; this is what the setup
|
||||
// screen deals when nothing on it is touched, the same way the dialog always has.
|
||||
const { els, nav } = await load('');
|
||||
(els.get('ss-deal')!['onclick'] as () => void)();
|
||||
assert.match(nav.search, /hand=sixRandom/, "the setup screen's own default was not six cards");
|
||||
});
|
||||
|
||||
it('ignores a seed the browser cannot parse rather than refusing to deal', async () => {
|
||||
|
||||
Reference in New Issue
Block a user