From 80907f2fa0adc1648a40caec984986968e521586 Mon Sep 17 00:00:00 2001 From: Andrea Manzi Date: Sat, 24 Oct 2026 15:32:53 +0200 Subject: [PATCH] Per ora si corre solo per Campomigliaio: gli altri rioni si vedono chiusi MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Piazza, Pieve e Cardetole restano nella scelta, col lucchetto e «prossimamente» (locked in story.rioni), per non moltiplicare battute e voci; in docs/STATO.md cosa fare quando si sbloccano. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01ApqNBvNbNCwXqR2RLo8QJh --- docs/STATO.md | 5 +++++ src/main.js | 4 +++- src/story/story.js | 8 +++++--- style.css | 3 +++ tests/browser.mjs | 7 ++++--- tests/story.test.mjs | 1 + 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/STATO.md b/docs/STATO.md index 5ef87df..1ed29b2 100644 --- a/docs/STATO.md +++ b/docs/STATO.md @@ -107,6 +107,11 @@ I prompt fissi (stile, scene, foglio sprite) sono in `prompts/STILE.md`, escluso (`story.rioni`: Piazza rossi, Pieve bianchi, Cardetole verdi, Campomigliaio blu); resta nella partita come flag `rione:`. Cambiano la riga dell'introduzione e le battute su Pieve, Cardetole, Campomigliaio e la colonna. Le parti future col rione (l'Arcu, il capitano) vanno scritte per ogni scelta. + **Per ora si sceglie solo Campomigliaio** (Andrea, 24 ottobre, per non moltiplicare battute e voci): Piazza, Pieve e + Cardetole si vedono chiusi (`locked: true` in `story.rioni`). **Quando si decide di sbloccarli**: togliere `locked`, + rileggere le battute per rione già scritte (introduzione, colonna, Pieve, strada per Cardetole e per Campomigliaio: + cercare `rione:` in `story.js`), scrivere per ogni rione le parti nuove nate nel frattempo (l'Arcu, il capitano), + `make voci`, e aggiornare il test «per ora si corre solo per Campomigliaio». - **Audio sul telefono**: passando a un'altra app (pagina nascosta) musica, voce e musichetta si fermano subito e la partita va in pausa; la musica riparte con Riprendi. - **Pronuncia** (`tools/pronuncia.json`): le parole che XTTS legge male, scritte come vanno lette; vale solo per la voce. diff --git a/src/main.js b/src/main.js index 2bcfbef..155d33f 100644 --- a/src/main.js +++ b/src/main.js @@ -67,7 +67,9 @@ $('rione-buttons').replaceChildren(...Object.entries(story.rioni ?? {}).map(([id b.style.setProperty('--rione', r.color); b.innerHTML = ''; b.querySelector('.rione-name').textContent = r.name; - b.querySelector('.rione-colors').textContent = r.colors; + b.querySelector('.rione-colors').textContent = r.locked ? 'prossimamente' : r.colors; + // Un rione chiuso si vede ma non si sceglie (per ora si corre solo per Campomigliaio). + if (r.locked) { b.disabled = true; b.classList.add('locked'); b.title = 'Prossimamente'; } b.addEventListener('click', () => { rione = id; $('rione').hidden = true; showIntro(); }); return b; })); diff --git a/src/story/story.js b/src/story/story.js index 8ffb356..d768c0d 100644 --- a/src/story/story.js +++ b/src/story/story.js @@ -38,10 +38,12 @@ export const story = { start: { scene: 'piazza', at: [250, 320] }, // I quattro rioni del Palio: dopo «Nuova partita» si sceglie per chi corre Andrea, e la partita lo ricorda col // flag `rione:`. Le battute che parlano del rione di Andrea lo controllano con `if`. + // Per ora si corre solo per Campomigliaio (decisione di Andrea, 24 ottobre: ogni rione vuol dire battute e voci + // in più); gli altri si vedono chiusi (`locked`) e si sbloccano togliendo la riga. rioni: { - piazza: { name: 'Piazza', colors: 'i rossi', color: '#d0453a' }, - pieve: { name: 'Pieve', colors: 'i bianchi', color: '#f2eee2' }, - cardetole: { name: 'Cardetole', colors: 'i verdi', color: '#3fa34d' }, + piazza: { name: 'Piazza', colors: 'i rossi', color: '#d0453a', locked: true }, + pieve: { name: 'Pieve', colors: 'i bianchi', color: '#f2eee2', locked: true }, + cardetole: { name: 'Cardetole', colors: 'i verdi', color: '#3fa34d', locked: true }, campomigliaio: { name: 'Campomigliaio', colors: 'i blu', color: '#2f6fd0' }, }, // Le righe dell'introduzione, sopra il panorama del paese, prima della prima scena. diff --git a/style.css b/style.css index eb50ee6..5d78fd9 100644 --- a/style.css +++ b/style.css @@ -222,3 +222,6 @@ body.full #sound { position: fixed; z-index: 13; top: max(8px, env(safe-area-ins #rione-buttons button:hover, #rione-buttons button:focus-visible { background: color-mix(in srgb, var(--rione) 30%, #1b1420); } #rione-buttons .rione-colors { font-size: .7em; color: var(--rione); } #rione .hint { color: var(--dim); font-size: clamp(8px, 1.2vw, 11px); text-align: center; } +#rione-buttons button.locked { cursor: not-allowed; opacity: .5; filter: grayscale(.6); } +#rione-buttons button.locked .rione-name::before { content: '🔒 '; font-family: sans-serif; font-size: .8em; } +#rione-buttons button.locked .rione-colors { color: var(--dim); } diff --git a/tests/browser.mjs b/tests/browser.mjs index e3a54fe..f5abe82 100644 --- a/tests/browser.mjs +++ b/tests/browser.mjs @@ -81,11 +81,12 @@ try { await page.waitForSelector('#rione:not([hidden])'); assert.equal(await page.locator('#rione-buttons button').count(), 4); await page.screenshot({ path: `${OUT}/01a-rione.png` }); - await page.click('#rione [data-rione="pieve"]'); + assert.equal(await page.locator('#rione-buttons button:disabled').count(), 3, 'per ora gli altri tre rioni sono chiusi'); + await page.click('#rione [data-rione="campomigliaio"]'); // L'introduzione: una riga per clic, poi comincia la partita. await page.waitForSelector('#intro:not([hidden])'); for (let i = 0; i < 2; i++) await page.click('#intro', { position: { x: 40, y: 40 } }); - assert.match(await page.textContent('#intro-text'), /Pieve, i bianchi/, 'la riga del rione scelto'); + assert.match(await page.textContent('#intro-text'), /Campomigliaio, i blu/, 'la riga del rione scelto'); await page.screenshot({ path: `${OUT}/01b-intro.png` }); for (let i = 0; i < 10 && await page.isVisible('#intro'); i++) await page.click('#intro', { position: { x: 40, y: 40 } }); assert.ok(await page.isHidden('#intro'), 'l\'introduzione non finisce'); @@ -95,7 +96,7 @@ try { assert.match(await page.evaluate(() => voices.audio.src), /assets\/voices\/andrea-[0-9a-f]+\.mp3$/); await page.waitForFunction(() => music.duck === 0.45, null, { timeout: 2000 }); await page.screenshot({ path: `${OUT}/02-inizio.png` }); - assert.ok(await page.evaluate(() => game.state.flags['rione:pieve']), 'il rione resta nella partita'); + assert.ok(await page.evaluate(() => game.state.flags['rione:campomigliaio']), 'il rione resta nella partita'); const fits = async p => p.evaluate(() => document.querySelector('#panel').getBoundingClientRect().bottom <= innerHeight); assert.ok(await fits(page), 'verbi e inventario fuori dallo schermo'); await settle(page); diff --git a/tests/story.test.mjs b/tests/story.test.mjs index 860e478..b638f0a 100644 --- a/tests/story.test.mjs +++ b/tests/story.test.mjs @@ -394,6 +394,7 @@ test('ogni posto della mappa ha la sua miniatura (make miniature)', () => { test('i quattro rioni: ognuno ha la sua riga nell\'introduzione, e le battute sul rione di Andrea lo seguono', () => { assert.deepEqual(Object.keys(story.rioni), ['piazza', 'pieve', 'cardetole', 'campomigliaio']); + assert.deepEqual(Object.keys(story.rioni).filter(id => !story.rioni[id].locked), ['campomigliaio'], 'per ora si corre solo per Campomigliaio'); const line = story.intro.find(l => typeof l !== 'string'); assert.deepEqual(Object.keys(line.rione).sort(), Object.keys(story.rioni).sort(), 'una riga per rione'); for (const [id, r] of Object.entries(story.rioni)) assert.ok(introText(line, id).includes(r.colors.replace('i ', '')), `${id}: ${introText(line, id)}`);