Prototipo del motore: scena, camminata, verbi, inventario, dialoghi, salvataggio
Motore guidato dai dati con due scene di prova (Piazza e salita alla Fortezza), percorsi su area concava, clic intelligente e pressione lunga, test della soluzione completa in node e nel browser con Playwright. Nel documento la leggenda del nonno. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
// Storia del prototipo: due scene di prova per collaudare il motore.
|
||||
// Testi, personaggi ed enigmi sono provvisori e verranno sostituiti con i ricordi di Andrea (docs/PROGETTO.md).
|
||||
// La grafica è fatta di forme semplici (`art`): verrà rimpiazzata dagli sfondi in pixel art.
|
||||
|
||||
const C = {
|
||||
sky: '#9fd0e8', skyLow: '#d9ecd9', hill: '#6f9b55', hillDark: '#557a43', fort: '#a08a6a', fortDark: '#7d6a50',
|
||||
wall: '#d9b98c', wallDark: '#b8946a', roof: '#a5533b', stone: '#c9b79a', stoneDark: '#ad9b7f', door: '#5b3a28',
|
||||
wood: '#7a5132', green: '#3f7d3a', iron: '#3b3b44', white: '#f4efe4', red: '#b7342e',
|
||||
};
|
||||
|
||||
export const story = {
|
||||
title: 'La Leggenda del Regolo',
|
||||
start: { scene: 'piazza', at: [120, 300] },
|
||||
characters: {
|
||||
andrea: { name: 'Andrea', color: '#ffffff' },
|
||||
vecchioA: { name: 'Vecchietto col cappello', color: '#ffd27a' },
|
||||
vecchioB: { name: 'Vecchietto col bastone', color: '#9fe3ff' },
|
||||
},
|
||||
items: {
|
||||
squama: {
|
||||
name: 'squama',
|
||||
icon: { fill: '#4fae5e', shape: 'scale' },
|
||||
actions: {
|
||||
look: [{ say: 'Una squama verde, grande come una moneta da due euro. Puzza di cantina.' }],
|
||||
use: [{ say: 'Potrei usarla come plettro. Ma prima scopro di chi è.' }],
|
||||
},
|
||||
},
|
||||
},
|
||||
scenes: {
|
||||
piazza: {
|
||||
name: 'La Piazza',
|
||||
walk: [[20, 222], [405, 222], [405, 276], [555, 276], [555, 222], [620, 222], [640, 250], [640, 352], [0, 352], [0, 250]],
|
||||
depth: [[222, 0.82], [352, 1.12]],
|
||||
entry: [600, 300],
|
||||
speakers: { vecchioA: [455, 214], vecchioB: [512, 214] },
|
||||
art: [
|
||||
{ rect: [0, 0, 640, 130], fill: C.sky },
|
||||
{ rect: [0, 100, 640, 40], fill: C.skyLow },
|
||||
{ rect: [0, 140, 640, 82], fill: C.wallDark },
|
||||
{ poly: [[380, 140], [470, 70], [640, 60], [640, 140]], fill: C.hill },
|
||||
// La Fortezza sulla collina, sullo sfondo: chiusa, come dice la leggenda.
|
||||
{ poly: [[470, 92], [490, 74], [600, 70], [625, 90], [610, 104], [480, 106]], fill: C.fort },
|
||||
{ rect: [530, 58, 26, 18], fill: C.fortDark },
|
||||
{ rect: [0, 40, 180, 182], fill: C.wall },
|
||||
{ rect: [0, 32, 186, 12], fill: C.roof },
|
||||
{ rect: [180, 70, 110, 152], fill: C.wallDark },
|
||||
{ rect: [176, 62, 118, 10], fill: C.roof },
|
||||
{ rect: [340, 110, 260, 112], fill: C.wall },
|
||||
{ rect: [334, 100, 272, 12], fill: C.roof },
|
||||
{ rect: [20, 70, 30, 40], fill: C.green }, { rect: [80, 70, 30, 40], fill: C.green },
|
||||
{ rect: [360, 130, 26, 34], fill: C.green }, { rect: [560, 130, 26, 34], fill: C.green },
|
||||
{ rect: [0, 222, 640, 138], fill: C.stone },
|
||||
{ lines: { from: [0, 240], to: [640, 360], step: 36 }, stroke: C.stoneDark },
|
||||
],
|
||||
hotspots: [
|
||||
{
|
||||
id: 'bacheca', name: 'bacheca', box: [62, 140, 70, 52], at: [97, 246], face: 'up',
|
||||
art: [{ rect: [62, 140, 70, 52], fill: C.wood }, { rect: [68, 146, 58, 40], fill: C.white }, { rect: [74, 152, 46, 6], fill: C.red }, { rect: [74, 164, 40, 3], fill: C.iron }, { rect: [74, 172, 30, 3], fill: C.iron }],
|
||||
actions: {
|
||||
look: [{ say: 'Il programma del Palio della Fortezza. Qualcuno ci ha scritto sopra col pennarello: «IL REGOLO SI È RIPRESO IL DRAPPO».' }],
|
||||
take: [{ say: 'È avvitata al muro. E poi il programma lo so a memoria.' }],
|
||||
open: [{ say: 'È una bacheca, non un frigorifero.' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'bar', name: 'porta del bar', box: [206, 140, 46, 82], at: [229, 240], face: 'up',
|
||||
art: [{ rect: [206, 140, 46, 82], fill: C.door }, { rect: [200, 120, 58, 16], fill: C.iron }, { text: 'BAR', at: [229, 132], fill: C.white }],
|
||||
actions: {
|
||||
look: [{ say: 'Il bar della piazza. Chi c\'era dietro il bancone nel 2007? Questo lo sa solo Andrea.' }],
|
||||
open: [{ say: 'Ci torno quando ho qualche soldo in tasca.' }],
|
||||
talk: [{ say: 'Parlare con una porta. Neanche al Palio si arriva a tanto.' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'asta', name: 'asta del drappo', box: [296, 60, 14, 172], at: [303, 262], face: 'up',
|
||||
art: [{ rect: [300, 60, 6, 172], fill: C.iron }, { rect: [290, 224, 26, 10], fill: C.stoneDark }, { rect: [296, 56, 14, 6], fill: '#d8b23a' }],
|
||||
actions: {
|
||||
look: [{ say: 'Qui doveva sventolare il drappo del Palio, quello col Regolo. Ora c\'è solo l\'asta.' }, { say: 'E una strana scia luccicante che va verso la salita.' }],
|
||||
take: [{ say: 'L\'asta del Palio? Mi rincorrerebbero tutti e quattro i rioni.' }],
|
||||
use: [{ say: 'Arrampicarmi? Il drappo non c\'è comunque.' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'vecchietti', name: 'vecchietti', box: [430, 196, 104, 60], at: [480, 290], face: 'up', default: 'talk',
|
||||
art: [
|
||||
{ rect: [420, 244, 124, 10], fill: C.wood }, { rect: [424, 254, 6, 18], fill: C.wood }, { rect: [534, 254, 6, 18], fill: C.wood },
|
||||
{ rect: [440, 214, 28, 32], fill: '#5d6b8a' }, { rect: [444, 198, 20, 18], fill: '#e7b58e' }, { rect: [440, 194, 28, 7], fill: '#3e3227' },
|
||||
{ rect: [498, 214, 28, 32], fill: '#8a6a4f' }, { rect: [502, 198, 20, 18], fill: '#e7b58e' }, { rect: [522, 210, 4, 50], fill: '#4a3424' },
|
||||
],
|
||||
actions: {
|
||||
look: [{ say: 'I vecchietti della panchina. Sanno tutto di tutti, soprattutto quello che non è successo.' }],
|
||||
talk: [{ dialogue: 'vecchietti' }],
|
||||
take: [{ say: 'Se li porto via, il paese resta senza notizie.' }],
|
||||
},
|
||||
give: {
|
||||
squama: [{ say: 'Guardate cosa ho trovato.' }, { say: 'Bella! È una patatina?', who: 'vecchioA' }, { say: 'Ma che patatina, è il Regolo che fa la muta!', who: 'vecchioB' }, { say: 'Me la tengo io, grazie.' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'panchina', name: 'sotto la panchina', box: [440, 256, 84, 16], at: [482, 292], face: 'up',
|
||||
actions: {
|
||||
look: [{ if: 'luccichio', then: [{ say: 'Qualcosa luccica, proprio sotto i piedi dei vecchietti.' }], else: [{ say: 'Polvere, un tappo e una cicca. La solita archeologia di piazza.' }] }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'cosa_luccicante', name: 'cosa luccicante', box: [474, 260, 16, 10], at: [482, 292], face: 'up', when: ['luccichio', '!has:squama', '!squama_presa'],
|
||||
art: [{ rect: [478, 262, 8, 5], fill: '#7fe08a' }, { rect: [480, 262, 3, 2], fill: '#e6ffe0' }],
|
||||
actions: {
|
||||
look: [{ say: 'Una cosa verde e luccicante. Non è un tappo.' }],
|
||||
take: [{ give: 'squama' }, { set: 'squama_presa' }, { say: 'Una squama! E bella grossa.' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'verso_salita', name: 'verso la Fortezza', box: [600, 190, 40, 120], at: [632, 290], exit: { scene: 'salita', at: [40, 320], face: 'right' },
|
||||
art: [{ poly: [[610, 222], [640, 206], [640, 250]], fill: C.stoneDark }],
|
||||
},
|
||||
],
|
||||
enter: [{ if: '!intro', then: [{ set: 'intro' }, { say: 'Il drappo del Palio è sparito! E la festa è domani.' }, { say: 'Se nessuno lo ritrova, il Palio salta. Tocca a me.' }] }],
|
||||
},
|
||||
salita: {
|
||||
name: 'La salita alla Fortezza',
|
||||
walk: [[0, 290], [300, 240], [470, 218], [560, 222], [560, 260], [640, 300], [640, 352], [0, 352]],
|
||||
depth: [[218, 0.7], [352, 1.1]],
|
||||
entry: [40, 320],
|
||||
art: [
|
||||
{ rect: [0, 0, 640, 360], fill: C.sky },
|
||||
{ poly: [[0, 200], [240, 150], [640, 120], [640, 360], [0, 360]], fill: C.hill },
|
||||
{ poly: [[0, 290], [300, 240], [470, 218], [560, 222], [640, 300], [640, 360], [0, 360]], fill: '#b8a27c' },
|
||||
// Il bastione e la porta della Fortezza, in cima alla salita.
|
||||
{ poly: [[400, 222], [420, 60], [640, 40], [640, 230]], fill: C.fort },
|
||||
{ rect: [400, 52, 240, 14], fill: C.fortDark },
|
||||
{ poly: [[0, 360], [0, 300], [90, 280], [60, 360]], fill: C.hillDark },
|
||||
],
|
||||
hotspots: [
|
||||
{
|
||||
id: 'cancello', name: 'porta della Fortezza', box: [470, 120, 76, 102], at: [508, 236], face: 'up',
|
||||
art: [{ rect: [470, 120, 76, 102], fill: '#2b2420' }, { rect: [474, 124, 68, 98], fill: C.iron }, { lines: { from: [474, 124], to: [542, 222], step: 10, vertical: true }, stroke: '#1d1d22' }, { rect: [500, 170, 16, 12], fill: '#c9a23a' }],
|
||||
actions: {
|
||||
look: [{ say: 'La porta della Fortezza. Chiusa con una catena grossa come il mio braccio.' }],
|
||||
open: [{ say: 'Niente da fare. La Fortezza è chiusa da anni, e il lucchetto lo sa.' }],
|
||||
talk: [{ say: 'Regolo? Ci sei?' }, { say: '...' }, { say: 'Ho sentito qualcosa. O era la mia pancia.' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'impronte', name: 'strane impronte', box: [240, 262, 120, 30], at: [300, 300],
|
||||
art: [{ poly: [[244, 286], [270, 274], [300, 280], [330, 268], [356, 262], [358, 266], [332, 274], [300, 286], [270, 280], [246, 290]], fill: '#8e7a58' }, { rect: [300, 279, 3, 2], fill: '#7fe08a' }],
|
||||
actions: {
|
||||
look: [{ say: 'Niente scarpe, niente zampe. Qualcosa è strisciato su per la salita.' }, { say: 'Qualcosa di grosso.' }],
|
||||
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 },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'verso_piazza', name: 'verso la Piazza', box: [0, 270, 30, 90], at: [6, 320], exit: { scene: 'piazza', at: [600, 300], face: 'left' },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
dialogues: {
|
||||
vecchietti: {
|
||||
nodes: {
|
||||
start: {
|
||||
options: [
|
||||
{
|
||||
text: 'Avete visto chi ha preso il drappo?',
|
||||
then: [
|
||||
{ say: 'È stato il Regolo! Quello che cadde dal cielo quando scavavano le fondamenta.', who: 'vecchioA' },
|
||||
{ say: 'Macché cielo! Mangiava le bestie, e lo presero i soldati di Napoleone.', who: 'vecchioB' },
|
||||
{ say: 'Napoleone? A San Piero? Ma se un c\'è mai venuto!', who: 'vecchioA' },
|
||||
{ say: 'E il Regolo sì?', who: 'vecchioB' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'stanotte', once: true, text: 'Avete notato niente di strano stanotte?',
|
||||
then: [
|
||||
{ say: 'Io dormivo. Alla mia età si dorme anche in piedi.', who: 'vecchioB' },
|
||||
{ say: 'Io stamani ho visto luccicare qualcosa sotto la panchina.', who: 'vecchioA' },
|
||||
{ say: 'Ma con la mia schiena, chi ci si china?', who: 'vecchioA' },
|
||||
{ set: 'luccichio' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Come vi sembra il Palio di quest\'anno?',
|
||||
then: [
|
||||
{ say: 'Senza drappo? Un Palio così non s\'è mai visto.', who: 'vecchioB' },
|
||||
{ say: 'Nel mio, di Palio, si correva con le carriole vere. Mica come voi.', who: 'vecchioA' },
|
||||
],
|
||||
},
|
||||
{ text: 'Ci vediamo dopo.', next: 'end', then: [{ say: 'Salutaci i tuoi!', who: 'vecchioA' }] },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user