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:
+45
-6
@@ -1,14 +1,53 @@
|
||||
// La soluzione completa, passo per passo: la percorre tests/story.test.mjs a ogni modifica della storia.
|
||||
// Passi: [verbo, bersaglio, oggetto?] oppure ['choose', testo dell'opzione].
|
||||
// La soluzione completa, passo per passo: la percorre tests/story.test.mjs a ogni modifica della storia,
|
||||
// e tests/browser.mjs con clic veri. Passi: [verbo, bersaglio, oggetto?] oppure ['choose', testo dell'opzione].
|
||||
// I tragitti fra le scene (`route`) seguono le uscite più brevi: cambiano da soli se cambia la mappa.
|
||||
import { story } from './story.js';
|
||||
|
||||
// Le uscite che si prendono sempre col Vai a: senza condizioni e senza una battuta che le sostituisce.
|
||||
const exits = id => (story.scenes[id].hotspots ?? []).filter(h => h.exit && !h.when && !h.actions?.walk);
|
||||
|
||||
export function route(from, to) {
|
||||
const back = new Map([[from, null]]), queue = [from];
|
||||
for (let i = 0; i < queue.length && !back.has(to); i++)
|
||||
for (const h of exits(queue[i]))
|
||||
if (!back.has(h.exit.scene)) { back.set(h.exit.scene, [queue[i], h.id]); queue.push(h.exit.scene); }
|
||||
if (!back.has(to)) throw new Error(`nessuna strada da ${from} a ${to}`);
|
||||
const steps = [];
|
||||
for (let at = to; back.get(at); at = back.get(at)[0]) steps.unshift(['walk', back.get(at)[1]]);
|
||||
return steps;
|
||||
}
|
||||
|
||||
export const solution = [
|
||||
// La squama: i vecchietti raccontano del luccichio sotto la panchina.
|
||||
['look', 'colonna'],
|
||||
['talk', 'vecchietti'],
|
||||
['choose', 'Avete notato niente di strano stanotte?'],
|
||||
['choose', 'Ci vediamo dopo.'],
|
||||
['take', 'cosa_luccicante'],
|
||||
['walk', 'verso_villa_adami'],
|
||||
['walk', 'su_villa_adami'],
|
||||
['walk', 'salita'],
|
||||
['walk', 'su_fortezza'],
|
||||
// Le impronte sotto la Fortezza: il Regolo è passato di qui, e le impronte vanno verso il bastione.
|
||||
...route('piazza', 'fortezza'),
|
||||
['use', 'impronte', 'squama'],
|
||||
['look', 'fessura'],
|
||||
// La chiave dell'oratorio: l'indovinello di San Pietro (la risposta la dà il bastione).
|
||||
...route('fortezza', 'pieve'),
|
||||
['talk', 'statua'],
|
||||
['choose', 'Nove.'],
|
||||
['open', 'porta_oratorio'],
|
||||
['take', 'gomma_terra'],
|
||||
// La Tosca: cedrata e ghiacciolo, e resta lo stecco; con la gomma diventa uno stecco che appiccica.
|
||||
...route('oratorio', 'tennis_chiesa'),
|
||||
['talk', 'chiosco'],
|
||||
['choose', 'Una cedrata, da portare via.'],
|
||||
['choose', 'Un ghiacciolo al limone.'],
|
||||
['choose', 'Niente, grazie Tosca.'],
|
||||
['use', 'cedrata', 'ghiacciolo'],
|
||||
['use', 'gomma', 'stecco'],
|
||||
// La chiavetta sotto la griglia del ponticino, la casetta dell'area feste, la torcia.
|
||||
...route('tennis_chiesa', 'ponticino'),
|
||||
['use', 'griglia', 'stecco_gomma'],
|
||||
...route('ponticino', 'area_feste'),
|
||||
['open', 'casetta'],
|
||||
// La torcia nella fessura: il palio, e due occhi gialli. Fine del primo capitolo.
|
||||
...route('area_feste', 'fortezza'),
|
||||
['use', 'fessura', 'torcia'],
|
||||
];
|
||||
|
||||
+99
-9
@@ -2,6 +2,35 @@
|
||||
// Testi, personaggi ed enigmi sono provvisori e verranno sostituiti con i ricordi di Andrea (docs/PROGETTO.md).
|
||||
// Le forme in `art` sono segnaposto disegnati sopra lo sfondo (vecchietti, squama, catena) in attesa degli sprite.
|
||||
|
||||
// Gli indizi del Trebbio per la catena della torcia (dopo le impronte, finché la torcia non c'è): uno per tappa,
|
||||
// dalla più avanti alla prima.
|
||||
const castello = say => [{ say, who: 'castello' }];
|
||||
const torchHints = [{
|
||||
if: 'has:chiavetta',
|
||||
then: castello('Una chiavetta piccola apre una cosa piccola. All\'area feste c\'è una casetta che aspetta.'),
|
||||
else: [{
|
||||
if: 'has:stecco_gomma',
|
||||
then: castello('Uno stecco che appiccica pesca dove le mani non arrivano. Al ponticino, sotto la griglia, qualcosa luccica.'),
|
||||
else: [{
|
||||
if: ['has:stecco', 'has:gomma'],
|
||||
then: castello('Lo stecco e la gomma, da soli, non servono a niente. Insieme, chissà.'),
|
||||
else: [{
|
||||
if: 'has:stecco',
|
||||
then: [{
|
||||
if: 'oratorio_aperto',
|
||||
then: castello('Allo stecco serve qualcosa che appiccica. Guarda per terra all\'oratorio: i ragazzi lasciano sempre qualcosa.'),
|
||||
else: [{
|
||||
if: 'has:chiave_oratorio',
|
||||
then: castello('Hai una chiave in tasca, e alla Pieve c\'è una porta che la aspetta.'),
|
||||
else: castello('San Pietro tiene le chiavi, e un indovinello per chi le vuole. La risposta è scritta nelle mura della Fortezza.'),
|
||||
}],
|
||||
}],
|
||||
else: castello('Per il buio ci vuole una luce. Comincia dal fresco: la Tosca, al tennis della chiesa, ha un ghiacciolo che fa al caso tuo.'),
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
}];
|
||||
|
||||
export const story = {
|
||||
title: 'La Leggenda del Regolo',
|
||||
// La mappa (pulsante «Mappa»): ogni scena con `map: [x, y]` (percentuali della pianta) ci compare quando è
|
||||
@@ -214,7 +243,10 @@ export const story = {
|
||||
id: 'manifesto', name: 'manifesto del Palio', box: [256, 196, 18, 24], at: [265, 250], face: 'up',
|
||||
art: [{ rect: [256, 196, 18, 24], fill: '#f4efe4' }, { rect: [258, 199, 14, 5], fill: '#b7342e' }, { rect: [258, 207, 12, 2], fill: '#3b3b44' }, { rect: [258, 211, 10, 2], fill: '#3b3b44' }, { rect: [258, 215, 12, 2], fill: '#2f5fb3' }],
|
||||
actions: {
|
||||
look: [{ say: 'Il programma del Palio della Fortezza. Qualcuno ci ha scritto sopra col pennarello: «IL REGOLO SI È RIPRESO IL PALIO».' }],
|
||||
look: [
|
||||
{ say: 'Il programma del Palio della Fortezza, con la foto del palio: la strada bianca che sale alla Fortezza, i ragazzi in fila, e uno con la maglia rossa che alza le braccia.' },
|
||||
{ say: 'Qualcuno ci ha scritto sopra col pennarello: «IL REGOLO SI È RIPRESO IL PALIO».' },
|
||||
],
|
||||
take: [{ say: 'Il programma lo so a memoria. Il problema è il palio.' }],
|
||||
},
|
||||
},
|
||||
@@ -291,13 +323,67 @@ export const story = {
|
||||
take: [{ say: 'Le impronte non si prendono. Si seguono.' }],
|
||||
},
|
||||
with: {
|
||||
squama: [
|
||||
{ say: 'Le metto vicine...' },
|
||||
{ say: 'Stesso luccichio, stessa puzza di cantina. Il Regolo è passato di qui!' },
|
||||
{ set: 'indizio_regolo' },
|
||||
{ say: 'Per stavolta finisce qui: il resto della storia lo dobbiamo ancora scrivere.' },
|
||||
{ end: true },
|
||||
],
|
||||
squama: [{
|
||||
if: 'indizio_regolo',
|
||||
then: [{ say: 'Ormai lo so: è passato di qui. E le impronte piegano verso il bastione.' }],
|
||||
else: [
|
||||
{ say: 'Le metto vicine...' },
|
||||
{ say: 'Stesso luccichio, stessa puzza di cantina. Il Regolo è passato di qui!' },
|
||||
{ set: 'indizio_regolo' },
|
||||
{ say: 'Ma la porta è incatenata da anni. E allora da dove è entrato?' },
|
||||
{ say: 'Le impronte non finiscono alla porta: piegano verso il bastione.' },
|
||||
],
|
||||
}],
|
||||
},
|
||||
},
|
||||
// Fine del primo capitolo: le impronte portano qui; con la torcia si vede il palio, e due occhi gialli.
|
||||
// Il dettaglio che lo fa riconoscere è quello del quadro vero (foto di Andrea, assets/raw/palio-2007-foto.jpg),
|
||||
// già visto sul manifesto in piazza: l'omino con la maglia rossa e le braccia alzate.
|
||||
{
|
||||
id: 'fessura', name: 'fessura nel bastione', box: [486, 266, 30, 38], at: [462, 310], face: 'right',
|
||||
art: [
|
||||
{ poly: [[490, 301], [493, 288], [497, 276], [502, 270], [507, 278], [510, 290], [512, 302]], fill: '#120c08' },
|
||||
{ when: 'luce_fessura', poly: [[494, 299], [497, 286], [502, 278], [506, 286], [508, 299]], fill: 'rgba(255, 228, 140, 0.6)' },
|
||||
{ when: 'luce_fessura', rect: [497, 291, 9, 8], fill: '#d9d2b0' },
|
||||
{ when: 'luce_fessura', rect: [499, 293, 1, 3], fill: '#c0392b' },
|
||||
{ when: 'luce_fessura', rect: [503, 294, 1, 3], fill: '#9bb04a' },
|
||||
{ when: 'occhi_regolo', rect: [498, 282, 2, 2], fill: '#ffe14a' },
|
||||
{ when: 'occhi_regolo', rect: [504, 282, 2, 2], fill: '#ffe14a' },
|
||||
],
|
||||
actions: {
|
||||
look: [{
|
||||
if: 'indizio_regolo',
|
||||
then: [{ say: 'Ecco dove vanno le impronte: dentro questa fessura!' }, { say: 'Dentro è buio pesto. Senza luce non vedo niente.' }],
|
||||
else: [{ say: 'Una fessura alla base del bastione, larga quanto un gatto grasso.' }, { say: 'Dentro è buio pesto. E ne esce un\'aria fresca da cantina.' }],
|
||||
}],
|
||||
use: [{ say: 'Infilarci la mano al buio? Neanche per sogno.' }],
|
||||
take: [{ say: 'Una fessura non si prende. Al massimo ci si guarda dentro.' }],
|
||||
open: [{ say: 'È già aperta. Il problema è che è piccola.' }],
|
||||
talk: [{ say: 'C\'è nessuno?' }, { say: '...' }, { say: 'Solo l\'eco. Spero.' }],
|
||||
},
|
||||
with: {
|
||||
torcia: [{
|
||||
if: 'indizio_regolo',
|
||||
then: [
|
||||
{ say: 'Accendo la torcia e la punto dentro...' },
|
||||
{ set: 'luce_fessura' },
|
||||
{ say: 'Laggiù, appoggiato al muro, c\'è un angolo di tela dipinta: una strada bianca, e un omino con la maglia rossa e le braccia alzate.' },
|
||||
{ say: 'È il palio! Il quadro dei ragazzi delle medie!' },
|
||||
{ set: 'occhi_regolo' },
|
||||
{ say: 'E quelli... sono due occhi gialli!' },
|
||||
{ unset: 'occhi_regolo' },
|
||||
{ say: 'Spariti nel buio.' },
|
||||
{ unset: 'luce_fessura' },
|
||||
{ set: 'palio_trovato' },
|
||||
{ say: 'Il Regolo. E ha il nostro palio.' },
|
||||
{ say: 'Domani c\'è il Palio. Stanotte, in un modo o nell\'altro, in quella Fortezza ci entro.' },
|
||||
{ end: true },
|
||||
],
|
||||
else: [
|
||||
{ say: 'Accendo la torcia e guardo dentro... pietre, ragnatele, buio.' },
|
||||
{ say: 'Non so nemmeno cosa sto cercando. Prima devo capire chi è passato di qui.' },
|
||||
],
|
||||
}],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1480,7 +1566,11 @@ export const story = {
|
||||
else: [{
|
||||
if: ['!has:squama', '!squama_presa'],
|
||||
then: [{ say: 'Le cose che luccicano non stanno mai in alto. Guarda in basso, vicino a chi te ne ha parlato.', who: 'castello' }],
|
||||
else: [{ say: 'Una squama da sola non dice niente. Ma vicino alle sue impronte, sotto la Fortezza, magari sì.', who: 'castello' }],
|
||||
else: [{
|
||||
if: '!indizio_regolo',
|
||||
then: [{ say: 'Una squama da sola non dice niente. Ma vicino alle sue impronte, sotto la Fortezza, magari sì.', who: 'castello' }],
|
||||
else: [{ if: 'has:torcia', then: [{ say: 'Hai la luce, e sotto la Fortezza c\'è il buio. Mettili insieme.', who: 'castello' }], else: torchHints }],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user