diff --git a/assets/voices/andrea-1b59141c98.mp3 b/assets/voices/andrea-1b59141c98.mp3 deleted file mode 100644 index 9ba7b5d..0000000 Binary files a/assets/voices/andrea-1b59141c98.mp3 and /dev/null differ diff --git a/assets/voices/andrea-83abae1419.mp3 b/assets/voices/andrea-83abae1419.mp3 new file mode 100644 index 0000000..d9b85c9 Binary files /dev/null and b/assets/voices/andrea-83abae1419.mp3 differ diff --git a/assets/voices/barondeduke-944c3e57dc.mp3 b/assets/voices/barondeduke-944c3e57dc.mp3 deleted file mode 100644 index b07ca31..0000000 Binary files a/assets/voices/barondeduke-944c3e57dc.mp3 and /dev/null differ diff --git a/assets/voices/barondeduke-d4ff967179.mp3 b/assets/voices/barondeduke-d4ff967179.mp3 new file mode 100644 index 0000000..f793439 Binary files /dev/null and b/assets/voices/barondeduke-d4ff967179.mp3 differ diff --git a/assets/voices/index.json b/assets/voices/index.json index 44d8eca..c828a65 100644 --- a/assets/voices/index.json +++ b/assets/voices/index.json @@ -627,9 +627,9 @@ "file": "andrea-0bd1b0f32e.mp3", "sec": 8.7 }, - "andrea|Baron! Che ci fai qui?": { - "file": "andrea-1b59141c98.mp3", - "sec": 2.59 + "andrea|Barone! Che ci fai qui?": { + "file": "andrea-83abae1419.mp3", + "sec": 2.91 }, "barondeduke|Aspetto uno che mi deve riportare le mutande.": { "file": "barondeduke-3ea60b7083.mp3", @@ -643,9 +643,9 @@ "file": "barondeduke-5542a06624.mp3", "sec": 1.65 }, - "barondeduke|In mano avevo full. E ho detto: «Male male si divide».": { - "file": "barondeduke-944c3e57dc.mp3", - "sec": 5.03 + "barondeduke|Avevo due donne e due jack. Entra la terza donna, e penso: «Male male si divide».": { + "file": "barondeduke-d4ff967179.mp3", + "sec": 7.64 }, "andrea|E invece?": { "file": "andrea-435306c242.mp3", diff --git a/src/main.js b/src/main.js index de8d1b0..bc27175 100644 --- a/src/main.js +++ b/src/main.js @@ -217,6 +217,7 @@ function filterMap() { $('map-none').hidden = shown > 0; $('map-none').textContent = `Nessun posto con «${query.trim()}»`; drawRoads(); + $('map-scroll').scrollTo(0, 0); // i posti rimasti stanno in cima: niente mappa vuota scorsa in fondo } $('map-search').addEventListener('input', filterMap); $('map-search').addEventListener('keydown', e => { @@ -226,7 +227,11 @@ $('map-search').addEventListener('keydown', e => { }); // Le strade fra le schede, misurate dopo l'impaginazione (e di nuovo se la finestra cambia misura). function drawRoads() { - const board = $('map-board'), svg = $('map-roads'), origin = board.getBoundingClientRect(); + const board = $('map-board'), svg = $('map-roads'); + // Prima si toglie la misura vecchia: il disegno delle strade, grande quanto la mappa intera, la terrebbe lunga + // anche dopo un filtro. + svg.style.width = svg.style.height = '0'; + const origin = board.getBoundingClientRect(); const center = id => { const card = board.querySelector(`[data-scene="${id}"]`); const r = card && !card.hidden && !card.parentElement.hidden && card.querySelector('img').getBoundingClientRect(); diff --git a/src/story/story.js b/src/story/story.js index 7a88fc2..1f1b145 100644 --- a/src/story/story.js +++ b/src/story/story.js @@ -1018,11 +1018,11 @@ export const story = { actions: { look: [{ say: 'Il BaronDeDuke, col cappello da cowboy. Ha l\'aria di uno che aspetta qualcuno, e che spera non lo veda nessuno.' }], talk: [ - { say: 'Baron! Che ci fai qui?' }, + { say: 'Barone! Che ci fai qui?' }, { say: 'Aspetto uno che mi deve riportare le mutande.', who: 'barondeduke' }, { say: 'Le... mutande?' }, { say: 'Le ho perse a poker, ieri sera.', who: 'barondeduke', pose: 'facepalm' }, - { say: 'In mano avevo full. E ho detto: «Male male si divide».', who: 'barondeduke', pose: 'cards' }, + { say: 'Avevo due donne e due jack. Entra la terza donna, e penso: «Male male si divide».', who: 'barondeduke', pose: 'cards' }, { say: 'E invece?' }, { say: 'L\'altro aveva colore.', who: 'barondeduke', pose: 'shrug' }, ], diff --git a/tests/ambient.browser.mjs b/tests/ambient.browser.mjs index 745bf6c..b330bdf 100644 --- a/tests/ambient.browser.mjs +++ b/tests/ambient.browser.mjs @@ -2,14 +2,13 @@ // ritagli dei nuovi effetti, pause degli animali e nessuna modifica alla partita. // npm run browser:effects — immagini in /tmp/regolo-effects (oppure $OUT). import { chromium } from 'playwright'; -import { spawn } from 'node:child_process'; +import { staticServer } from './helpers.mjs'; import { mkdirSync, writeFileSync } from 'node:fs'; import assert from 'node:assert/strict'; const out = process.env.OUT ?? '/tmp/regolo-effects'; mkdirSync(out, { recursive: true }); -const port = 9000 + Math.floor(Math.random() * 900); -const server = spawn('python3', ['-m', 'http.server', String(port), '--bind', '127.0.0.1'], { stdio: 'ignore' }); +const server = await staticServer(), port = server.port; let browser; try { browser = await chromium.launch({ args: ['--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader'] }); diff --git a/tests/browser.mjs b/tests/browser.mjs index 73acd46..54893ac 100644 --- a/tests/browser.mjs +++ b/tests/browser.mjs @@ -2,14 +2,14 @@ // fino alla fine, salvataggio e impaginazione su telefono. Schermate in $OUT (predefinito: /tmp/regolo-shots). // npm run browser import { chromium } from 'playwright'; -import { spawn } from 'node:child_process'; +import { staticServer } from './helpers.mjs'; import { mkdirSync, readFileSync } from 'node:fs'; import assert from 'node:assert/strict'; import { solution, route } from '../src/story/solution.js'; -const OUT = process.env.OUT ?? '/tmp/regolo-shots', PORT = 8000 + Math.floor(Math.random() * 900); +const OUT = process.env.OUT ?? '/tmp/regolo-shots'; mkdirSync(OUT, { recursive: true }); -const server = spawn('python3', ['-m', 'http.server', String(PORT), '--bind', '127.0.0.1'], { stdio: 'ignore' }); +const server = await staticServer(), PORT = server.port; const browser = await chromium.launch({ args: ['--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader'] }); const errors = []; @@ -276,6 +276,22 @@ try { await page.keyboard.press('Enter'); assert.ok(await page.isHidden('#map')); assert.equal(await page.evaluate(() => game.state.scene), 'piazza'); + // Con tutti i posti visti e la finestra piccola la mappa si scorre: filtrando da in fondo, i posti trovati si vedono + // (prima la mappa restava lunga quanto quella intera, scorsa su un fondo vuoto). + await page.setViewportSize({ width: 560, height: 340 }); + await page.evaluate(() => { for (const id of Object.keys(game.story.scenes)) game.state.flags['visto:' + id] = true; }); + await page.click('#map-button'); + assert.ok(await page.evaluate(() => { const s = document.getElementById('map-scroll'); s.scrollTop = s.scrollHeight; return s.scrollTop > 0; }), 'la mappa piena si scorre'); + await page.fill('#map-search', 'campo'); + const found = await page.evaluate(() => { + const s = document.getElementById('map-scroll'), r = s.getBoundingClientRect(); + const c = [...document.querySelectorAll('#map-board button')].find(b => !b.hidden && !b.parentElement.hidden).getBoundingClientRect(); + return { inside: c.top >= r.top && c.bottom <= r.bottom, scrollTop: s.scrollTop, h: s.scrollHeight, ch: s.clientHeight, top: c.top - r.top, q: document.getElementById('map-search').value }; + }); + assert.ok(found.inside, `filtrando, il primo posto trovato non si vede: ${JSON.stringify(found)}`); + await page.screenshot({ path: `${OUT}/07d-mappa-ricerca-piccola.png` }); + await page.click('#close-map'); + await page.setViewportSize({ width: 1280, height: 860 }); const phone = await open({ width: 390, height: 844 }); await phone.click('#splash'); // un clic salta il cartello diff --git a/tests/helpers.mjs b/tests/helpers.mjs index 336a5bb..567e223 100644 --- a/tests/helpers.mjs +++ b/tests/helpers.mjs @@ -16,3 +16,16 @@ export function settle(game, { maxSteps = 20000 } = {}) { export function memoryStorage() { return { data: {}, getItem(k) { return this.data[k] ?? null; }, setItem(k, v) { this.data[k] = String(v); }, removeItem(k) { delete this.data[k]; } }; } + +// Il server statico delle prove nel browser, su una porta libera scelta dal sistema: con una porta a caso poteva +// capitare la 8080 del gioco in Docker (make up), e la prova girava sul codice vecchio del container. +export async function staticServer() { + const { spawn } = await import('node:child_process'); + const server = spawn('python3', ['-u', '-m', 'http.server', '0', '--bind', '127.0.0.1'], { stdio: ['ignore', 'pipe', 'ignore'] }); + const port = await new Promise((resolve, reject) => { + let out = ''; + server.stdout.on('data', d => { out += d; const m = out.match(/port (\d+)/); if (m) resolve(Number(m[1])); }); + server.on('exit', () => reject(new Error('il server di prova non è partito'))); + }); + return { port, kill: () => server.kill() }; +} diff --git a/tests/story.test.mjs b/tests/story.test.mjs index 9d2520d..e32d1ad 100644 --- a/tests/story.test.mjs +++ b/tests/story.test.mjs @@ -478,6 +478,6 @@ test('gli amici in giro: l\'Arcu al circolino, il Tozzino al cancello del tennis assert.deepEqual(talk('campomigliaio_circolo', 'arcu'), ['andrea: Arcu! Ma che è sempre là, Borgo?', 'arcu: E chi lo sposta???']); assert.ok(talk('carza', 'tozzino').includes('tozzino: E chi sennò? Ha chiamato ora: è imbottigliato in Bolognese.')); const baron = talk('polisportiva', 'barondeduke'); - assert.ok(baron.includes('barondeduke: In mano avevo full. E ho detto: «Male male si divide».')); + assert.ok(baron.includes('barondeduke: Avevo due donne e due jack. Entra la terza donna, e penso: «Male male si divide».')); assert.equal(baron.at(-1), 'barondeduke: L\'altro aveva colore.'); });