Sfondi veri di Piazza Colonna, Fortezza e Trebbio, aiuti del castello, Docker

Tre scene con aree calpestabili e punti cliccabili ricavati dagli sfondi,
tools/prepare_background.py per ridurli a 640x360, il castello del Trebbio
che dà indizi in base ai progressi, container nginx sulla porta 8080.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-23 00:32:32 +02:00
co-authored by Claude Opus 5.5
parent 826f5f99ec
commit a855b5805f
18 changed files with 325 additions and 94 deletions
+113 -74
View File
@@ -1,20 +1,15 @@
// Storia del prototipo: due scene di prova per collaudare il motore.
// Storia del prototipo: tre scene con gli sfondi veri (Piazza Colonna, Fortezza, Trebbio) 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',
};
// Le forme in `art` sono segnaposto disegnati sopra lo sfondo (vecchietti, squama, catena) in attesa degli sprite.
export const story = {
title: 'La Leggenda del Regolo',
start: { scene: 'piazza', at: [120, 300] },
start: { scene: 'piazza', at: [250, 320] },
characters: {
andrea: { name: 'Andrea', color: '#ffffff' },
vecchioA: { name: 'Vecchietto col cappello', color: '#ffd27a' },
vecchioB: { name: 'Vecchietto col bastone', color: '#9fe3ff' },
castello: { name: 'Il Castello', color: '#c8f0a0' },
},
items: {
squama: {
@@ -28,43 +23,23 @@ export const story = {
},
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 },
],
name: 'Piazza Colonna',
background: 'assets/scenes/piazza-colonna.png',
walk: [[84, 244], [330, 238], [345, 230], [362, 238], [462, 246], [466, 276], [544, 276], [548, 248], [588, 250], [600, 290], [640, 300], [640, 360], [0, 360], [0, 330], [84, 318]],
depth: [[236, 0.5], [360, 1.35]],
entry: [345, 240],
speakers: { vecchioA: [18, 244], vecchioB: [47, 244] },
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 }],
id: 'colonna', name: 'colonna', box: [492, 134, 36, 140], at: [505, 290], face: 'up',
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.' }],
look: [{ say: 'La colonna, il centro del paese. Da qui passa tutto: le notizie, il Palio, i pettegolezzi.' }, { say: 'Ai piedi c\'è una strana scia luccicante che va verso il vicolo della Fortezza.' }],
take: [{ say: 'Se mi porto via la colonna, la piazza come la chiamano?' }],
use: [{ say: 'Arrampicarmi? Il drappo lassù non c\'è comunque.' }],
},
},
{
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 }],
id: 'bar', name: 'La Colonna', box: [428, 208, 30, 40], at: [443, 252], face: 'up',
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.' }],
@@ -72,20 +47,18 @@ export const story = {
},
},
{
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' }],
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: '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.' }],
look: [{ say: 'Il programma del Palio della Fortezza. Qualcuno ci ha scritto sopra col pennarello: «IL REGOLO SI È RIPRESO IL DRAPPO».' }],
take: [{ say: 'Il programma lo so a memoria. Il problema è il drappo.' }],
},
},
{
id: 'vecchietti', name: 'vecchietti', box: [430, 196, 104, 60], at: [480, 290], face: 'up', default: 'talk',
id: 'vecchietti', name: 'vecchietti', box: [2, 244, 62, 50], at: [100, 320], face: 'left', 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' },
{ rect: [8, 264, 20, 26], fill: '#5d6b8a' }, { rect: [11, 250, 14, 14], fill: '#e7b58e' }, { rect: [8, 247, 20, 5], fill: '#3e3227' }, { rect: [10, 290, 7, 14], fill: '#3a3f52' }, { rect: [19, 290, 7, 14], fill: '#3a3f52' },
{ rect: [37, 264, 20, 26], fill: '#8a6a4f' }, { rect: [40, 250, 14, 14], fill: '#e7b58e' }, { rect: [40, 248, 14, 4], fill: '#d8d8d8' }, { rect: [38, 290, 7, 14], fill: '#4a4036' }, { rect: [47, 290, 7, 14], fill: '#4a4036' }, { rect: [58, 262, 3, 44], fill: '#4a3424' },
],
actions: {
look: [{ say: 'I vecchietti della panchina. Sanno tutto di tutti, soprattutto quello che non è successo.' }],
@@ -97,44 +70,46 @@ export const story = {
},
},
{
id: 'panchina', name: 'sotto la panchina', box: [440, 256, 84, 16], at: [482, 292], face: 'up',
id: 'panchina', name: 'sotto la panchina', box: [0, 304, 64, 18], at: [100, 330], face: 'left',
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' }],
id: 'cosa_luccicante', name: 'cosa luccicante', box: [26, 308, 14, 10], at: [100, 330], face: 'left', when: ['luccichio', '!has:squama', '!squama_presa'],
art: [{ rect: [29, 311, 8, 5], fill: '#7fe08a' }, { rect: [31, 311, 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 }],
id: 'vicolo', name: 'vicolo verso la Fortezza', box: [330, 190, 34, 48], at: [345, 234], exit: { scene: 'fortezza', at: [175, 352], face: 'right' },
},
{
id: 'verso_trebbio', name: 'strada per il Trebbio', box: [604, 290, 36, 70], at: [632, 335], exit: { scene: 'trebbio', at: [110, 345], face: 'right' },
},
],
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 },
],
fortezza: {
name: 'Sotto le mura della Fortezza',
background: 'assets/scenes/fortezza-esterno.png',
walk: [[110, 284], [300, 280], [330, 272], [348, 274], [400, 292], [442, 294], [640, 352], [640, 360], [0, 360], [0, 315], [60, 310], [105, 295]],
depth: [[272, 0.55], [360, 1.15]],
entry: [175, 352],
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' }],
id: 'mura', name: 'bastione', box: [420, 0, 220, 290],
actions: {
look: [{ say: 'Nove bastioni, li volle Cosimo I. Per tenere fuori i nemici, dicono. Secondo me per tenere dentro il Regolo.' }],
use: [{ say: 'Arrampicarmi sul bastione? Ho visto film che finivano meglio.' }],
},
},
{
id: 'porta', name: 'porta della Fortezza', box: [325, 226, 26, 46], at: [338, 278], face: 'up',
// La catena: la Fortezza è chiusa da anni.
art: [{ rect: [327, 249, 22, 2], fill: '#9a9aa4' }, { rect: [330, 252, 16, 2], fill: '#7c7c86' }, { rect: [335, 251, 6, 6], 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.' }],
@@ -142,10 +117,10 @@ export const story = {
},
},
{
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' }],
id: 'impronte', name: 'strane impronte', box: [246, 304, 84, 18], at: [288, 330],
art: [{ poly: [[248, 318], [266, 310], [288, 314], [308, 306], [328, 304], [329, 307], [309, 310], [288, 318], [266, 315], [249, 321]], fill: 'rgba(70, 52, 30, 0.75)' }, { rect: [289, 314, 3, 2], fill: '#9dffa8' }],
actions: {
look: [{ say: 'Niente scarpe, niente zampe. Qualcosa è strisciato su per la salita.' }, { say: 'Qualcosa di grosso.' }],
look: [{ say: 'Niente scarpe, niente zampe. Qualcosa è strisciato nell\'erba fino alla porta.' }, { say: 'Qualcosa di grosso.' }],
take: [{ say: 'Le impronte non si prendono. Si seguono.' }],
},
with: {
@@ -159,7 +134,42 @@ export const story = {
},
},
{
id: 'verso_piazza', name: 'verso la Piazza', box: [0, 270, 30, 90], at: [6, 320], exit: { scene: 'piazza', at: [600, 300], face: 'left' },
id: 'verso_piazza', name: 'verso la Piazza', box: [120, 344, 110, 16], at: [175, 356], exit: { scene: 'piazza', at: [345, 240], face: 'left' },
},
],
},
trebbio: {
name: 'Castello del Trebbio',
background: 'assets/scenes/trebbio.png',
walk: [[86, 308], [300, 306], [356, 308], [470, 312], [500, 324], [486, 360], [88, 360], [80, 330]],
depth: [[306, 0.75], [360, 1.05]],
entry: [110, 345],
enter: [{ if: '!trebbio_visto', then: [{ set: 'trebbio_visto' }, { say: 'Il Trebbio. Quassù anche i pensieri vanno più piano.' }] }],
hotspots: [
{
id: 'torre', name: 'torre del castello', box: [345, 26, 88, 196], at: [330, 312], face: 'up', default: 'talk',
actions: {
look: [{ say: 'La torre del Trebbio. Da ragazzo ci si rifugiò Amerigo Vespucci, per scappare dalla peste di Firenze.' }, { say: 'Poi ha trovato l\'America. Anche lui partendo da un posto tranquillo.' }],
talk: [{ dialogue: 'castello' }],
open: [{ say: 'È un castello, mica una scatola di biscotti.' }],
},
},
{
id: 'pergolato', name: 'pergolato', box: [278, 222, 122, 52], at: [328, 312], face: 'up',
actions: {
look: [{ say: 'Il pergolato, coi suoi pilastri. Un giorno li conto tutti.' }],
take: [{ say: 'Una vite? Ci vuole la vendemmia, non un ragazzo.' }],
},
},
{
id: 'scalinata', name: 'scalinata', box: [304, 276, 50, 32], at: [328, 312], face: 'up',
actions: {
look: [{ say: 'La scala che sale al pergolato.' }],
use: [{ say: 'Più tardi salgo. Per ora mi godo il silenzio.' }],
},
},
{
id: 'verso_paese', name: 'verso San Piero', box: [80, 318, 26, 42], at: [92, 345], exit: { scene: 'piazza', at: [628, 335], face: 'left' },
},
],
},
@@ -199,5 +209,34 @@ export const story = {
},
},
},
// Lo "psicologo": il castello ascolta e risponde con un indizio su quello che manca.
castello: {
nodes: {
start: {
options: [
{
text: 'Sono bloccato. Mi dai un consiglio?',
then: [
{ say: 'Siediti. Guarda il Mugello. Respira.', who: 'castello' },
{
if: '!luccichio',
then: [{ say: 'Chi sa tutto del paese di solito sta seduto. Prova a chiedere a chi passa le giornate in piazza.', who: 'castello' }],
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' }],
}],
},
],
},
{
text: 'Ma tu ce l\'hai mai visto, il Regolo?',
then: [{ say: 'Io ho visto passare i Medici, la peste e Vespucci. Un serpente in più non mi spaventa.', who: 'castello' }],
},
{ text: 'Niente, volevo solo un po\' di pace.', next: 'end', then: [{ say: 'Quella qui non manca mai. Torna quando vuoi.', who: 'castello' }] },
],
},
},
},
},
};