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:
+5
-2
@@ -2,8 +2,8 @@
|
||||
// La storia (scene, oggetti, dialoghi) arriva tutta dai dati: qui non c'è nessun enigma scritto a mano.
|
||||
import { findPath, dist, inBox, nearestInside } from './geometry.js';
|
||||
|
||||
export const VERBS = ['walk', 'look', 'take', 'use', 'talk', 'open', 'give'];
|
||||
export const VERB_LABELS = { walk: 'Vai a', look: 'Guarda', take: 'Prendi', use: 'Usa', talk: 'Parla con', open: 'Apri', give: 'Dai' };
|
||||
export const VERBS = ['walk', 'look', 'take', 'use', 'talk', 'open', 'give', 'drop'];
|
||||
export const VERB_LABELS = { walk: 'Vai a', look: 'Guarda', take: 'Prendi', use: 'Usa', talk: 'Parla con', open: 'Apri', give: 'Dai', drop: 'Butta' };
|
||||
const DEFAULT_LINES = {
|
||||
walk: null,
|
||||
look: 'Niente di speciale.',
|
||||
@@ -12,6 +12,7 @@ const DEFAULT_LINES = {
|
||||
talk: 'Non mi sembra un gran chiacchierone.',
|
||||
open: 'Non si apre.',
|
||||
give: 'Non credo che lo voglia.',
|
||||
drop: 'Non è roba mia da buttare.',
|
||||
with: 'Non funziona.',
|
||||
};
|
||||
const SPEED = 95;
|
||||
@@ -106,6 +107,8 @@ export class Game {
|
||||
if (def.actions?.[verb]) return def.actions[verb];
|
||||
if (verb === 'walk') return h?.exit ? [{ go: h.exit.scene, at: h.exit.at, face: h.exit.face }] : [];
|
||||
if (verb === 'take' && !h) return [{ say: 'Ce l\'ho già.' }];
|
||||
// Si butta solo quello che non serve alla storia (`droppable`): gli oggetti indispensabili restano.
|
||||
if (verb === 'drop' && !h) return def.droppable ? [{ say: 'Questo non mi serve: via.' }, { drop: target }] : [{ say: 'Meglio tenerlo: potrebbe servirmi.' }];
|
||||
return DEFAULT_LINES[verb] ? [{ say: DEFAULT_LINES[verb] }] : [];
|
||||
}
|
||||
|
||||
|
||||
+25
-1
@@ -101,6 +101,27 @@ function openMap() {
|
||||
$('map').hidden = false;
|
||||
}
|
||||
$('map-button').addEventListener('click', openMap);
|
||||
|
||||
// --- Pausa: ferma il gioco; da qui mappa, crediti o ritorno al titolo (la partita resta salvata per «Continua»).
|
||||
function openPause() {
|
||||
if (!running) return;
|
||||
running = false;
|
||||
command.reset();
|
||||
$('pause-map').hidden = game.mapPlaces().length < 2;
|
||||
$('pause').hidden = false;
|
||||
}
|
||||
function closePause() {
|
||||
$('pause').hidden = true;
|
||||
running = true;
|
||||
}
|
||||
$('pause-button').addEventListener('click', openPause);
|
||||
$('resume').addEventListener('click', closePause);
|
||||
$('pause-map').addEventListener('click', () => { closePause(); openMap(); });
|
||||
$('to-title').addEventListener('click', () => {
|
||||
$('pause').hidden = true;
|
||||
game.onSave(game.snapshot());
|
||||
showTitle();
|
||||
});
|
||||
$('close-map').addEventListener('click', () => { $('map').hidden = true; });
|
||||
|
||||
function showTitle() {
|
||||
@@ -195,13 +216,15 @@ function updateChoices() {
|
||||
window.addEventListener('keydown', e => {
|
||||
if (e.target === $('volume')) return;
|
||||
if (!$('credits').hidden) { if (e.key === 'Escape') $('credits').hidden = true; return; }
|
||||
if (!$('pause').hidden) { if (e.key === 'Escape') closePause(); return; }
|
||||
if (!$('map').hidden) { if (e.key === 'Escape' || e.key === 'p' || e.key === 'P') $('map').hidden = true; return; }
|
||||
if ((e.key === 'p' || e.key === 'P') && running) { openMap(); return; }
|
||||
if (!$('intro').hidden && [' ', 'Enter'].includes(e.key)) { e.preventDefault(); nextIntro(); return; }
|
||||
if (e.key === 'm' || e.key === 'M') { music.toggle(); saveAudio(); showSound(); return; }
|
||||
if (!running) return;
|
||||
if ([' ', '.', 'Enter'].includes(e.key) && game.speech) { e.preventDefault(); game.skip(); return; }
|
||||
if (e.key === 'Escape') command.reset();
|
||||
// Esc annulla il comando a metà; se non c'è niente da annullare, mette in pausa.
|
||||
if (e.key === 'Escape') { if (command.verb || command.item || game.dialogue) command.reset(); else openPause(); }
|
||||
const n = Number(e.key);
|
||||
if (game.dialogue && n >= 1 && n <= 9) game.choose(n - 1);
|
||||
});
|
||||
@@ -233,6 +256,7 @@ function updateUi() {
|
||||
updateSpeech();
|
||||
// Il pulsante della mappa c'è solo in partita, fuori dai dialoghi, e quando c'è almeno un altro posto dove andare.
|
||||
$('map-button').hidden = !running || !!game.dialogue || game.mapPlaces().length < 2;
|
||||
$('pause-button').hidden = !running;
|
||||
if (game.state.ended && !game.speech && !game.queue.length) {
|
||||
running = false;
|
||||
$('ending').hidden = false;
|
||||
|
||||
+116
-6
@@ -33,6 +33,7 @@ export const story = {
|
||||
vecchietto: { name: 'Vecchietto', color: '#9fe3ff', sprite: 'assets/characters/vecchietto.json' },
|
||||
castello: { name: 'Il Castello', color: '#c8f0a0' },
|
||||
leone: { name: 'Il leone', color: '#f0a070' },
|
||||
san_pietro: { name: 'San Pietro', color: '#e8e0c8' },
|
||||
},
|
||||
items: {
|
||||
squama: {
|
||||
@@ -47,7 +48,9 @@ export const story = {
|
||||
libro: {
|
||||
name: 'libro',
|
||||
icon: { fill: '#c46a3a', shape: 'book' },
|
||||
droppable: true, // non serve alla storia: si può buttare
|
||||
actions: {
|
||||
drop: [{ say: 'Una pagina sola, e pure con la fine. Lo lascio qui per il prossimo lettore.' }, { drop: 'libro' }],
|
||||
look: [{ say: '«La storia infinita». Bello spesso: questo mi tiene compagnia fino a settembre.' }],
|
||||
open: [
|
||||
{ say: 'Vediamo da dove comincia...' },
|
||||
@@ -57,6 +60,14 @@ export const story = {
|
||||
use: [{ say: 'Leggere adesso? Prima il palio. E poi, a quanto pare, si fa presto.' }],
|
||||
},
|
||||
},
|
||||
// La chiave dell'oratorio: la dà San Pietro a chi risolve il suo indovinello. Indispensabile: non si butta.
|
||||
chiave_oratorio: {
|
||||
name: 'chiave dell\'oratorio',
|
||||
icon: { fill: '#d9b54a', shape: 'key' },
|
||||
actions: {
|
||||
look: [{ say: 'Una chiave grossa e antica. Quella dell\'oratorio, parola di San Pietro.' }],
|
||||
},
|
||||
},
|
||||
},
|
||||
scenes: {
|
||||
piazza: {
|
||||
@@ -196,6 +207,7 @@ export const story = {
|
||||
name: 'La Pieve',
|
||||
map: [46, 70],
|
||||
background: 'assets/scenes/pieve-dalla-salita.png',
|
||||
speakers: { san_pietro: [343, 166] },
|
||||
// La rampa in primo piano e, dietro il muretto, il sagrato (ci si arriva da sinistra).
|
||||
walk: [[0, 270], [80, 266], [86, 252], [100, 222], [270, 215], [300, 224], [480, 234], [560, 242], [600, 252], [610, 268], [276, 240], [276, 270], [292, 278], [640, 352], [640, 360], [0, 360]],
|
||||
depth: [[215, 0.42], [360, 1.15]],
|
||||
@@ -215,14 +227,50 @@ export const story = {
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'statua', name: 'statua', box: [334, 172, 18, 52], at: [330, 300], face: 'up',
|
||||
// San Pietro, quello delle chiavi: a chi risolve l'indovinello dà la chiave dell'oratorio.
|
||||
id: 'statua', name: 'statua di San Pietro', box: [330, 170, 26, 56], at: [345, 238], face: 'up', default: 'talk',
|
||||
actions: {
|
||||
look: [{ say: 'Una statua sul piedistallo. Lei il palio l\'ha visto passare di sicuro, ma non parla.' }],
|
||||
talk: [{ say: 'Buongiorno.' }, { say: '...' }, { say: 'Come i vecchietti quando gli chiedi dei debiti.' }],
|
||||
look: [{ say: 'La statua di San Pietro, con le chiavi in mano. Lui il palio l\'ha visto passare di sicuro.' }],
|
||||
talk: [{
|
||||
if: 'chiave_data',
|
||||
then: [{ say: 'La chiave te l\'ho già data, figliolo. Di solito ne do di più importanti.', who: 'san_pietro' }],
|
||||
else: [
|
||||
{ say: 'Buongiorno, San Pietro.' },
|
||||
{ say: 'Buongiorno a te, Andrea.', who: 'san_pietro' },
|
||||
{ say: 'La statua parla?!' },
|
||||
{ say: 'Tengo le chiavi, è il mio mestiere. Quella dell\'oratorio te la do se rispondi a un indovinello su San Piero.', who: 'san_pietro' },
|
||||
{ say: 'Quanti bastioni ha la Fortezza di San Martino?', who: 'san_pietro' },
|
||||
{ dialogue: 'indovinello' },
|
||||
],
|
||||
}],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'oratorio', name: 'porta dell\'oratorio', box: [452, 180, 42, 56], at: [473, 240], face: 'up', exit: { scene: 'oratorio', at: [320, 345], face: 'right' },
|
||||
// La porta resta chiusa finché non si usa la chiave; poi è aperta per sempre e la chiave sparisce.
|
||||
id: 'porta_oratorio', name: 'porta dell\'oratorio', box: [452, 180, 42, 56], at: [473, 240], face: 'up', default: 'open', when: '!oratorio_aperto',
|
||||
actions: {
|
||||
look: [{ say: 'La porta che dà sull\'oratorio. Chiusa a chiave.' }],
|
||||
open: [{
|
||||
if: 'has:chiave_oratorio',
|
||||
then: [{ drop: 'chiave_oratorio' }, { set: 'oratorio_aperto' }, { say: 'Clic! Aperta. La chiave la lascio nella serratura: così resta aperta.' }, { go: 'oratorio', at: [320, 345], face: 'right' }],
|
||||
else: [{ say: 'Chiusa a chiave. E le chiavi, da queste parti, chi le tiene?' }],
|
||||
}],
|
||||
walk: [{ say: 'Chiusa a chiave. E le chiavi, da queste parti, chi le tiene?' }],
|
||||
},
|
||||
with: {
|
||||
chiave_oratorio: [{ drop: 'chiave_oratorio' }, { set: 'oratorio_aperto' }, { say: 'Clic! Aperta. La chiave la lascio nella serratura: così resta aperta.' }, { go: 'oratorio', at: [320, 345], face: 'right' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'oratorio', name: 'porta dell\'oratorio', box: [452, 180, 42, 56], at: [473, 240], face: 'up', when: 'oratorio_aperto', exit: { scene: 'oratorio', at: [320, 345], face: 'right' },
|
||||
},
|
||||
{
|
||||
// Per ora solo una battuta: la scena di Cardetole arriverà con le foto di Andrea.
|
||||
id: 'verso_cardetole', name: 'strada per Cardetole', box: [0, 204, 82, 54], at: [95, 250], face: 'left', default: 'walk',
|
||||
actions: {
|
||||
walk: [{ say: 'Di là si scende a Cardetole, a casa mia.' }, { say: 'Ma se torno a casa ora, mi mettono ad apparecchiare. Prima il palio.' }],
|
||||
look: [{ say: 'La strada che scende a Cardetole, il rione dei verdi.' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'verso_piazza', name: 'verso la Piazza', box: [0, 262, 26, 98], at: [8, 320], exit: { scene: 'piazza', at: [610, 320], face: 'left' },
|
||||
@@ -418,9 +466,8 @@ export const story = {
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'verso_scuola', name: 'strada verso la scuola', box: [0, 286, 120, 44], at: [40, 336], face: 'left', default: 'walk',
|
||||
id: 'verso_scuola', name: 'strada verso la scuola', box: [0, 286, 120, 44], at: [40, 336], face: 'left', exit: { scene: 'scuola', at: [300, 350], face: 'up' },
|
||||
actions: {
|
||||
walk: [{ say: 'A scuola? A maggio? Nemmeno per sogno.' }],
|
||||
look: [{ say: 'Di là si va alla scuola. Ci passo già abbastanza tempo durante l\'anno.' }],
|
||||
},
|
||||
},
|
||||
@@ -432,6 +479,47 @@ export const story = {
|
||||
},
|
||||
],
|
||||
},
|
||||
// L'ingresso della scuola, giù per la strada dalla salita di Villa Adami: dal cancello alle porte a vetri.
|
||||
scuola: {
|
||||
name: 'La scuola',
|
||||
map: [8, 32],
|
||||
background: 'assets/scenes/scuola.png',
|
||||
walk: [[110, 360], [118, 226], [140, 222], [268, 220], [290, 232], [520, 360]],
|
||||
depth: [[220, 0.42], [360, 1.32]],
|
||||
entry: [300, 350],
|
||||
hotspots: [
|
||||
{
|
||||
id: 'pino', name: 'pino', box: [222, 40, 120, 70], at: [250, 232], face: 'up',
|
||||
actions: {
|
||||
look: [{ say: 'Un pino a ombrello enorme. Alla ricreazione, tutti all\'ombra lì sotto.' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'bandiere', name: 'bandiere', box: [110, 110, 170, 52], at: [200, 230], face: 'up',
|
||||
actions: {
|
||||
look: [{ say: 'Il tricolore e la bandiera europea. Almeno loro a scuola ci stanno volentieri.' }],
|
||||
take: [{ say: 'Rubare una bandiera davanti alla scuola? Poi chi la sente la preside.' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'porte', name: 'porte della scuola', box: [130, 164, 136, 56], at: [200, 230], face: 'up',
|
||||
actions: {
|
||||
look: [{ say: 'Le porte a vetri della scuola. Di là ci sono i banchi, la lavagna e la campanella.' }],
|
||||
open: [{ say: 'A scuola? A maggio? Nemmeno per sogno.' }],
|
||||
walk: [{ say: 'A scuola? A maggio? Nemmeno per sogno.' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'palazzine', name: 'palazzine gialle', box: [340, 30, 300, 196], at: [330, 262], face: 'right',
|
||||
actions: {
|
||||
look: [{ say: 'Le palazzine gialle accanto alla scuola, con la scala arancione.' }, { say: 'Da lassù la ricreazione si vede tutta.' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'alla_salita', name: 'indietro, verso la salita', box: [0, 330, 640, 30], at: [300, 352], exit: { scene: 'salita_villa_adami', at: [40, 336], face: 'right' },
|
||||
},
|
||||
],
|
||||
},
|
||||
// Il viale dei cipressi, la strada bianca tra la Fortezza e il Trebbio: in fondo c'è il castello.
|
||||
viale_cipressi: {
|
||||
name: 'Viale dei cipressi',
|
||||
@@ -496,6 +584,28 @@ export const story = {
|
||||
},
|
||||
},
|
||||
dialogues: {
|
||||
// L'indovinello di San Pietro. La risposta si trova nel gioco: il bastione della Fortezza la dice.
|
||||
indovinello: {
|
||||
nodes: {
|
||||
start: {
|
||||
options: [
|
||||
{ text: 'Cinque.', then: [{ say: 'Cinque? Ne hai contati la metà. Vai a guardarli bene, lassù.', who: 'san_pietro' }] },
|
||||
{ text: 'Sette.', then: [{ say: 'Sette sono i peccati. I bastioni sono di più.', who: 'san_pietro' }] },
|
||||
{
|
||||
text: 'Nove.', next: 'end',
|
||||
then: [
|
||||
{ say: 'Bravo! Nove, come li volle Cosimo I.', who: 'san_pietro' },
|
||||
{ say: 'Eccoti la chiave dell\'oratorio. Trattala bene: è più vecchia di tuo nonno.', who: 'san_pietro' },
|
||||
{ give: 'chiave_oratorio' }, { set: 'chiave_data' },
|
||||
{ say: 'Grazie, San Pietro!' },
|
||||
],
|
||||
},
|
||||
{ text: 'Dodici.', then: [{ say: 'Dodici erano gli apostoli. Io lo so bene: c\'ero.', who: 'san_pietro' }] },
|
||||
{ text: 'Ci penso e torno.', next: 'end', then: [{ say: 'Le chiavi non scappano. E io nemmeno.', who: 'san_pietro' }] },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
vecchietti: {
|
||||
nodes: {
|
||||
start: {
|
||||
|
||||
Reference in New Issue
Block a user