Primo capitolo: la torcia nella fessura del bastione mostra il palio e due occhi gialli
- le impronte portano a una fessura nel bastione; con la torcia si vede un angolo del palio (l'omino con la maglia rossa del quadro vero, già descritto sul manifesto) e due occhi gialli: fine del primo capitolo - la soluzione passa per indovinello, oratorio e catena del ghiacciolo; tragitti calcolati dalle uscite - il Trebbio ha un indizio per ogni tappa della torcia - tools/pronuncia.json: le parole che XTTS legge male, riscritte solo per la voce («celo» → «ce l'ho») - voci delle battute nuove Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ApqNBvNbNCwXqR2RLo8QJh
This commit is contained in:
+13
-2
@@ -40,7 +40,11 @@ async function settle(page) {
|
||||
throw new Error('il gioco non si ferma');
|
||||
}
|
||||
|
||||
const hotspotCenter = (page, id) => page.evaluate(id => { const h = game.hotspot(id); return [h.box[0] + h.box[2] / 2, h.box[1] + h.box[3] / 2]; }, id);
|
||||
const hotspotCenter = async (page, id) => {
|
||||
const c = await page.evaluate(id => { const h = game.hotspot(id); return h && [h.box[0] + h.box[2] / 2, h.box[1] + h.box[3] / 2]; }, id);
|
||||
if (!c) throw new Error(`non c'è ${id} in ${await page.evaluate(() => game.state.scene)}`);
|
||||
return c;
|
||||
};
|
||||
|
||||
try {
|
||||
const page = await open({ width: 1280, height: 860 });
|
||||
@@ -163,10 +167,17 @@ try {
|
||||
await page.click(`#verbs [data-verb="${verb}"]`);
|
||||
await page.click(`#inventory [data-item="${item}"]`);
|
||||
} else if (!smart) await page.click(`#verbs [data-verb="${verb}"]`);
|
||||
await clickScene(page, await hotspotCenter(page, target));
|
||||
// Un oggetto dell'inventario su un altro (cedrata col ghiacciolo) si clicca nell'inventario, non nella scena.
|
||||
if (await page.evaluate(t => !!game.story.items[t], target)) await page.click(`#inventory [data-item="${target}"]`);
|
||||
else await clickScene(page, await hotspotCenter(page, target));
|
||||
}
|
||||
await page.waitForTimeout(80);
|
||||
if (verb === 'talk') await page.screenshot({ path: `${OUT}/03-dialogo.png` });
|
||||
// La torcia nella fessura: il palio illuminato e i due occhi gialli, prima che spariscano.
|
||||
if (target === 'fessura' && item) {
|
||||
await page.waitForFunction(() => game.state.flags.occhi_regolo, null, { timeout: 30000 });
|
||||
await page.screenshot({ path: `${OUT}/05b-occhi.png` });
|
||||
}
|
||||
await settle(page);
|
||||
if (target === 'cosa_luccicante') await page.screenshot({ path: `${OUT}/04-squama.png` });
|
||||
if (target === 'su_fortezza') await page.screenshot({ path: `${OUT}/05-fortezza.png` });
|
||||
|
||||
+21
-1
@@ -105,7 +105,7 @@ test('la soluzione si percorre tutta dall\'inizio alla fine', () => {
|
||||
settle(g);
|
||||
}
|
||||
assert.ok(g.state.ended, 'la partita non è finita');
|
||||
assert.ok(g.state.flags.indizio_regolo);
|
||||
assert.ok(g.state.flags.indizio_regolo && g.state.flags.palio_trovato, 'il palio visto nella fessura');
|
||||
assert.ok(saves.at(-1).ended, 'la fine non è salvata');
|
||||
});
|
||||
|
||||
@@ -363,3 +363,23 @@ test('un salvataggio da file si accetta solo se torna in tutto con la storia', (
|
||||
assert.ok(bad({ ended: 'no' }));
|
||||
assert.ok(checkSave(story, null));
|
||||
});
|
||||
|
||||
test('il Trebbio ha un indizio per ogni tappa della torcia, e la torcia usata troppo presto non chiude niente', () => {
|
||||
const hint = (inventory, flags) => {
|
||||
const g = new Game(story, { state: { scene: 'trebbio', x: 330, y: 312, facing: 1, inventory, flags: { luccichio: true, squama_presa: true, indizio_regolo: true, ...flags }, used: {}, ended: false } });
|
||||
g.act('talk', 'torre'); settle(g);
|
||||
g.choose(g.options().findIndex(o => o.text.startsWith('Sono bloccato')));
|
||||
return settle(g).map(s => s.text).at(-1);
|
||||
};
|
||||
const stages = [
|
||||
hint([], {}), hint(['stecco'], {}), hint(['stecco', 'chiave_oratorio'], { chiave_data: true }),
|
||||
hint(['stecco'], { chiave_data: true, oratorio_aperto: true }), hint(['stecco', 'gomma'], { oratorio_aperto: true }),
|
||||
hint(['stecco_gomma'], {}), hint(['chiavetta'], {}), hint(['torcia'], { casetta_aperta: true }),
|
||||
];
|
||||
assert.equal(new Set(stages).size, stages.length, 'ogni tappa il suo indizio:\n' + stages.join('\n'));
|
||||
assert.match(stages[0], /Tosca/);
|
||||
assert.match(stages.at(-1), /luce/);
|
||||
const early = new Game(story, { state: { scene: 'fortezza', x: 462, y: 310, facing: 1, inventory: ['torcia'], flags: {}, used: {}, ended: false } });
|
||||
early.act('use', 'fessura', 'torcia'); settle(early);
|
||||
assert.ok(!early.state.ended && !early.state.flags.palio_trovato, 'senza le impronte la fessura è solo buia');
|
||||
});
|
||||
|
||||
@@ -95,3 +95,12 @@ test('la pausa ferma la voce e riprendendo continua; stop la toglie', () => {
|
||||
delete globalThis.Audio;
|
||||
}
|
||||
});
|
||||
|
||||
test('le parole che XTTS legge male si riscrivono solo per la voce, intere e con la maiuscola', async () => {
|
||||
const { spoken, rules } = await import('../tools/pronuncia.mjs');
|
||||
assert.equal(spoken('Qui si scambiavano le figurine: celo, celo, manca.'), 'Qui si scambiavano le figurine: ce l\'ho, ce l\'ho, manca.');
|
||||
assert.equal(spoken('Celo!'), 'Ce l\'ho!');
|
||||
assert.equal(spoken('Guarda il cielo e il celofan.'), 'Guarda il cielo e il celofan.', 'non i pezzi di altre parole');
|
||||
assert.equal(spoken('Il Regolo', { regolo: 'Règolo' }), 'Il Règolo');
|
||||
for (const [w, s] of Object.entries(rules)) if (!w.startsWith('_')) assert.ok(typeof s === 'string' && s.trim(), `pronuncia vuota per ${w}`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user