Scuola, strada per Cardetole, indovinello di San Pietro con la chiave dell'oratorio, verbo Butta e Pausa

- La scuola (sfondo di Codex dalla foto di Andrea): dalla salita di Villa Adami, dal cancello alle porte a vetri.
- Alla Pieve la strada per Cardetole (per ora una battuta).
- La statua di San Pietro chiede quanti bastioni ha la Fortezza: con la risposta giusta dà la chiave
  dell'oratorio; la porta, aperta una volta, resta aperta e la chiave sparisce. Voce propria per San Pietro.
- Verbo Butta: solo gli oggetti droppable (il libro), quelli che servono alla storia no.
- Pulsante Pausa (o Esc): Riprendi, Mappa, Crediti, Torna al titolo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017egeN2amL84ErjfgQFtEDn
This commit is contained in:
2026-10-23 17:48:49 +02:00
co-authored by Claude Opus 5.5
parent 1ea83d71c5
commit ab03ee0b5a
42 changed files with 339 additions and 28 deletions
+11
View File
@@ -84,6 +84,17 @@ try {
assert.ok(await fits(page), 'verbi e inventario fuori dallo schermo');
await settle(page);
// Pausa: Esc o il pulsante fermano il gioco; Riprendi torna dov'eri; il titolo offre «Continua».
await page.keyboard.press('Escape');
await page.waitForSelector('#pause:not([hidden])');
await page.screenshot({ path: `${OUT}/02b-pausa.png` });
await page.click('#resume');
assert.ok(await page.isHidden('#pause'));
await page.click('#pause-button');
await page.click('#to-title');
await page.waitForSelector('#continue:not([hidden])');
await page.click('#continue');
await settle(page);
// Musica: dopo il primo clic suona il brano del paese; muto e volume si ricordano.
assert.ok((await page.evaluate(() => music.current?.src)).endsWith('paese.mp3'), 'musica del paese');
await page.click('#mute');
+43
View File
@@ -169,3 +169,46 @@ test('la mappa: ogni scena ci sta, i posti compaiono solo visti, il viaggio risp
assert.ok(g.dialogue);
assert.equal(g.travel('pieve'), false, 'non si scappa da un dialogo');
});
test('l\'indovinello di San Pietro dà la chiave; l\'oratorio, aperto, resta aperto e la chiave sparisce', () => {
const g = new Game(story);
g.go('pieve', [345, 238]);
settle(g);
assert.ok(!g.hotspot('oratorio') && g.hotspot('porta_oratorio'), 'all\'inizio la porta è chiusa');
g.act('open', 'porta_oratorio');
settle(g);
assert.equal(g.state.scene, 'pieve', 'senza chiave non si entra');
g.act('talk', 'statua');
settle(g);
const answer = text => { g.choose(g.options().findIndex(o => o.text === text)); return settle(g); };
answer('Sette.');
assert.ok(g.dialogue && !g.state.inventory.includes('chiave_oratorio'), 'risposta sbagliata: niente chiave, si riprova');
answer('Nove.');
assert.ok(!g.dialogue && g.state.inventory.includes('chiave_oratorio'), 'risposta giusta: la chiave');
g.act('drop', 'chiave_oratorio');
settle(g);
assert.ok(g.state.inventory.includes('chiave_oratorio'), 'la chiave serve: non si butta');
g.act('use', 'porta_oratorio', 'chiave_oratorio');
settle(g);
assert.equal(g.state.scene, 'oratorio');
assert.ok(!g.state.inventory.includes('chiave_oratorio'), 'la chiave resta nella serratura');
g.go('pieve', [345, 238]);
assert.ok(g.hotspot('oratorio')?.exit && !g.hotspot('porta_oratorio'), 'da ora la porta è aperta');
g.act('talk', 'statua');
settle(g);
assert.ok(!g.dialogue, 'San Pietro non ridà la chiave');
});
test('si buttano solo gli oggetti che non servono', () => {
const g = new Game(story);
g.go('oratorio');
settle(g);
g.state.inventory.push('libro', 'squama');
g.act('drop', 'libro');
settle(g);
g.act('drop', 'squama');
settle(g);
assert.deepEqual(g.state.inventory, ['squama']);
for (const [id, item] of Object.entries(story.items))
if (id !== 'libro') assert.ok(!item.droppable, `${id} serve alla storia: non deve potersi buttare`);
});