Compare commits

..
4 Commits
21 changed files with 160 additions and 39 deletions
+70
View File
@@ -0,0 +1,70 @@
{
"image": "zio_mario.png",
"height": 120,
"frames": {
"explain": {
"x": 0,
"y": 0,
"w": 67,
"h": 120,
"ax": 33.8,
"ay": 120
},
"talk": {
"x": 69,
"y": 0,
"w": 79,
"h": 120,
"ax": 44.8,
"ay": 120
},
"blink": {
"x": 150,
"y": 0,
"w": 57,
"h": 120,
"ax": 28.1,
"ay": 120
},
"stand": {
"x": 209,
"y": 0,
"w": 57,
"h": 120,
"ax": 27.8,
"ay": 120
},
"shrug": {
"x": 268,
"y": 0,
"w": 94,
"h": 120,
"ax": 48.1,
"ay": 120
},
"point": {
"x": 364,
"y": 0,
"w": 87,
"h": 120,
"ax": 51.0,
"ay": 120
},
"think": {
"x": 453,
"y": 0,
"w": 58,
"h": 121,
"ax": 29.2,
"ay": 121
},
"laugh": {
"x": 513,
"y": 0,
"w": 59,
"h": 121,
"ax": 30.1,
"ay": 121
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+16 -8
View File
@@ -1187,14 +1187,6 @@
"file": "andrea-00f2e70a4d.mp3", "file": "andrea-00f2e70a4d.mp3",
"sec": 2.95 "sec": 2.95
}, },
"andrea|La Ghiacciomobile nera. Hai visto cose che noi poveri umani non potremmo neppur lontanamente immaginare.": {
"file": "andrea-7be29434e0.mp3",
"sec": 7.25
},
"andrea|Con questo sole, di ghiaccio c'è rimasto giusto il nome. Vo a piedi.": {
"file": "andrea-def44809bc.mp3",
"sec": 5.08
},
"andrea|Il circolino: il Circolo SMS di Campomigliaio. Un'istituzione, qui i volontari hanno sempre fatto miracoli.": { "andrea|Il circolino: il Circolo SMS di Campomigliaio. Un'istituzione, qui i volontari hanno sempre fatto miracoli.": {
"file": "andrea-90bbad0de0.mp3", "file": "andrea-90bbad0de0.mp3",
"sec": 9.59 "sec": 9.59
@@ -1627,6 +1619,14 @@
"file": "andrea-7c17aa384c.mp3", "file": "andrea-7c17aa384c.mp3",
"sec": 3.2 "sec": 3.2
}, },
"andrea|La Ghiacciomobile nera, mezza dentro il muro. Hai visto cose che noi poveri umani non potremmo neppur lontanamente immaginare.": {
"file": "andrea-decbc1c807.mp3",
"sec": 9.49
},
"andrea|Per tirarla fuori di lì ci vuole altro che le mie braccia.": {
"file": "andrea-a193a43f3e.mp3",
"sec": 3.78
},
"andrea|Nessuno ha mai capito davvero il tuo immenso valore.": { "andrea|Nessuno ha mai capito davvero il tuo immenso valore.": {
"file": "andrea-3e85200509.mp3", "file": "andrea-3e85200509.mp3",
"sec": 2.93 "sec": 2.93
@@ -1639,6 +1639,14 @@
"file": "andrea-3d15dd47bb.mp3", "file": "andrea-3d15dd47bb.mp3",
"sec": 4.82 "sec": 4.82
}, },
"andrea|Lo zio Mario. Guarda il muro, guarda la macchina, e si gratta la testa sotto il berretto.": {
"file": "andrea-759a969d58.mp3",
"sec": 6.69
},
"andrea|Lo lascio pensare: quando ha trovato il modo di tirarla fuori, me lo dice lui.": {
"file": "andrea-84ff10b5f4.mp3",
"sec": 4.86
},
"andrea|Il parcheggio sotto casa. Col gesso ci si disegnava la pista delle macchinine, e si giocava finché non chiamavano per cena.": { "andrea|Il parcheggio sotto casa. Col gesso ci si disegnava la pista delle macchinine, e si giocava finché non chiamavano per cena.": {
"file": "andrea-8670e6ce99.mp3", "file": "andrea-8670e6ce99.mp3",
"sec": 7.6 "sec": 7.6
+2
View File
@@ -31,6 +31,8 @@ ne è un'opera derivata. Le foto scattate da Andrea non hanno problemi; quelle p
| `provinciale-pignone.png`, `piazzetta-cambray-digny.png`, `via-cipriani.png`, `via-massorondinaio.png`, `mozzete.png`, `ponticino-mozzete.png`, `coldaia.png`, `falegnameria-coldaia.png`, `gabbiano.png` | Codex | screenshot di Google Street View | Google | **no**: da rifare con foto di Andrea | | `provinciale-pignone.png`, `piazzetta-cambray-digny.png`, `via-cipriani.png`, `via-massorondinaio.png`, `mozzete.png`, `ponticino-mozzete.png`, `coldaia.png`, `falegnameria-coldaia.png`, `gabbiano.png` | Codex | screenshot di Google Street View | Google | **no**: da rifare con foto di Andrea |
| `closeups/micro-parcheggio.png`, `closeups/micro/*.png` (macchinine) | Codex, solo testo | nessuna | — | sì | | `closeups/micro-parcheggio.png`, `closeups/micro/*.png` (macchinine) | Codex, solo testo | nessuna | — | sì |
| `characters/chiaru.png` | Codex | `foto/chiaru.jpg` | Andrea (29 ottobre) | sì (il Chiaru consenziente) | | `characters/chiaru.png` | Codex | `foto/chiaru.jpg` | Andrea (29 ottobre) | sì (il Chiaru consenziente) |
| `via-liguri-magelli-muro.png` | Codex, ritocco di `via-liguri-magelli.png` con la Ghiacciomobile nel muro | come `via-liguri-magelli.png` | Street View | **no**: come lo sfondo da cui viene |
| `characters/zio_mario.png` | Codex | `foto/zio-mario.png` | Andrea (29 ottobre) | sì (famiglia di Andrea) |
| `cardetole.png` | Codex | `cardetole.jpg` | Andrea (EXIF) | **da decidere**: è la casa vera di Andrea, pubblicarla dice dove abita | | `cardetole.png` | Codex | `cardetole.jpg` | Andrea (EXIF) | **da decidere**: è la casa vera di Andrea, pubblicarla dice dove abita |
| `pieve-interno.png` | Codex | `pieve-interno.png` | Mariano Mirannalti (mandata ad Andrea su WhatsApp) | sì, se Mariano è d'accordo; citarlo nei crediti | | `pieve-interno.png` | Codex | `pieve-interno.png` | Mariano Mirannalti (mandata ad Andrea su WhatsApp) | sì, se Mariano è d'accordo; citarlo nei crediti |
| `panorama-intro.png` | Codex | `altre/panorama-intro.png` | da internet (screenshot con l'icona di Google Lens) | **no**, finché non si sostituisce | | `panorama-intro.png` | Codex | `altre/panorama-intro.png` | da internet (screenshot con l'icona di Google Lens) | **no**, finché non si sostituisce |
+6
View File
@@ -18,6 +18,12 @@ Online su 50037.manzolo.it tutto fino agli effetti ambientali di Codex. Aperto,
## Dove siamo arrivati ## Dove siamo arrivati
- **La Ghiacciomobile nel muro (29 ottobre)**: non è più al circolino di Campomigliaio. In Via Liguri Magelli, prima
del tramonto (`!indizio_regolo`), è schiantata dentro il muro giallo coi mattoni rotti e senza targa
(`via-liguri-magelli-muro.png`, ritocco di Codex); dal tramonto il muro è rifatto e c'è la targa. Il motore ha le
varianti di sfondo per scena (`backdrops`, con `when`; `game.backdrop()`). Lo zio Mario (sprite di Codex dalla
foto di Andrea) davanti alla macchina che si gratta la testa; scala della scena rifatta (le persone erano troppo
piccole). [DA ANDREA] le battute dello zio (scherzava su tutto, anche sulla morte) e quella dello schianto.
- **GP di Fortezza, guida semplice (29 ottobre)**: alla bona e Seria si tiene premuto per il gas e lasciando si - **GP di Fortezza, guida semplice (29 ottobre)**: alla bona e Seria si tiene premuto per il gas e lasciando si
frena; lo sterzo segue la strada da solo (scansa le buche, sorpassa, prende la miscela), ma oltre la velocità che la frena; lo sterzo segue la strada da solo (scansa le buche, sorpassa, prende la miscela), ma oltre la velocità che la
curva regge il motorino scivola fuori verso la paglia (`SIMPLE` in `gara.js`). Ginocchio in terra resta con lo curva regge il motorino scivola fuori verso la paglia (`SIMPLE` in `gara.js`). Ginocchio in terra resta con lo
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "leggenda-del-regolo", "name": "leggenda-del-regolo",
"version": "0.1.43", "version": "0.1.45",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
+3
View File
@@ -162,6 +162,9 @@ export class Game {
} }
get scene() { return this.story.scenes[this.state.scene]; } get scene() { return this.story.scenes[this.state.scene]; }
// Lo sfondo di adesso: la prima variante della scena (`backdrops`, ognuna con la sua condizione `when`) che vale,
// sennò il suo `background`. Così un posto cambia con la storia (la Ghiacciomobile nel muro, poi la targa).
backdrop(scene = this.scene) { return scene.backdrops?.find(b => check(b.when, this.state))?.src ?? scene.background; }
// Occupato: c'è qualcosa in corso che il giocatore non può interrompere. La camminata verso un punto // Occupato: c'è qualcosa in corso che il giocatore non può interrompere. La camminata verso un punto
// o verso un oggetto si può sempre cambiare con un altro clic: la coda che la seguiva viene scartata. // o verso un oggetto si può sempre cambiare con un altro clic: la coda che la seguiva viene scartata.
get busy() { return !!this.speech || !!this.closeup || this.reach > 0 || (this.task ? !this.task.interruptible : this.queue.length > 0); } get busy() { return !!this.speech || !!this.closeup || this.reach > 0 || (this.task ? !this.task.interruptible : this.queue.length > 0); }
+6 -6
View File
@@ -131,7 +131,7 @@ export function backgroundOrder(story, first) {
for (const h of story.scenes[queue[i]]?.hotspots ?? []) for (const h of story.scenes[queue[i]]?.hotspots ?? [])
if (h.exit && story.scenes[h.exit.scene] && !seen.has(h.exit.scene)) { seen.add(h.exit.scene); queue.push(h.exit.scene); } if (h.exit && story.scenes[h.exit.scene] && !seen.has(h.exit.scene)) { seen.add(h.exit.scene); queue.push(h.exit.scene); }
for (const id of Object.keys(story.scenes)) if (!seen.has(id)) queue.push(id); for (const id of Object.keys(story.scenes)) if (!seen.has(id)) queue.push(id);
return [...new Set(queue.map(id => story.scenes[id].background).filter(Boolean))]; return [...new Set(queue.flatMap(id => [story.scenes[id].background, ...(story.scenes[id].backdrops ?? []).map(b => b.src)]).filter(Boolean))];
} }
// Il personaggio alto PERSON pixel a grandezza 1 (per `size` 1), con i piedi in (x, y); rivolto a sinistra si specchia. // Il personaggio alto PERSON pixel a grandezza 1 (per `size` 1), con i piedi in (x, y); rivolto a sinistra si specchia.
@@ -153,8 +153,8 @@ function drawSprite(ctx, { atlas, img }, frame, x, y, scale, facing, size = 1) {
} }
export function render(ctx, game, { hover, spots, debug, time = performance.now() } = {}) { export function render(ctx, game, { hover, spots, debug, time = performance.now() } = {}) {
const scene = game.scene, s = game.state, bg = backgrounds.get(scene.background); const scene = game.scene, s = game.state, backdrop = game.backdrop(), bg = backgrounds.get(backdrop);
if (!bg && scene.background) loadBackground(scene.background); if (!bg && backdrop) loadBackground(backdrop);
ctx.imageSmoothingEnabled = false; ctx.imageSmoothingEnabled = false;
ctx.clearRect(0, 0, WIDTH, HEIGHT); ctx.clearRect(0, 0, WIDTH, HEIGHT);
if (bg) ctx.drawImage(bg, 0, 0, WIDTH, HEIGHT); if (bg) ctx.drawImage(bg, 0, 0, WIDTH, HEIGHT);
@@ -395,7 +395,7 @@ export const EFFECTS = {
// Alberi al vento (i cipressi): il pezzo di sfondo si piega tutto insieme dalla base, di frazioni di pixel e con // Alberi al vento (i cipressi): il pezzo di sfondo si piega tutto insieme dalla base, di frazioni di pixel e con
// due onde lente sovrapposte, così il movimento è morbido e non a scatti. // due onde lente sovrapposte, così il movimento è morbido e non a scatti.
sway(ctx, e, time, game) { sway(ctx, e, time, game) {
const bg = backgrounds.get(game.scene.background); const bg = backgrounds.get(game.backdrop());
if (!bg) return; if (!bg) return;
const k = bg.width / WIDTH, amount = e.amount ?? 3.2; const k = bg.width / WIDTH, amount = e.amount ?? 3.2;
for (const [i, [x, y, w, h]] of e.rects.entries()) { for (const [i, [x, y, w, h]] of e.rects.entries()) {
@@ -412,7 +412,7 @@ export const EFFECTS = {
// ognuna a una sua altezza e velocità, uscita da un lato rientra dall'altro. Si vedono solo dove lo sfondo è // ognuna a una sua altezza e velocità, uscita da un lato rientra dall'altro. Si vedono solo dove lo sfondo è
// cielo (skyMask): passano dietro alberi, torri e tetti. Le due grandi solo coi cieli larghi (`big`). // cielo (skyMask): passano dietro alberi, torri e tetti. Le due grandi solo coi cieli larghi (`big`).
clouds(ctx, e, time, game) { clouds(ctx, e, time, game) {
const bg = backgrounds.get(game.scene.background), mask = bg && skyMask(bg); const bg = backgrounds.get(game.backdrop()), mask = bg && skyMask(bg);
if (!mask) return; if (!mask) return;
const layer = scratch(), lc = layer.getContext('2d'), [ax, ay, aw, ah] = e.area; const layer = scratch(), lc = layer.getContext('2d'), [ax, ay, aw, ah] = e.area;
const pool = e.big ? CLOUDS : CLOUDS.slice(2); const pool = e.big ? CLOUDS : CLOUDS.slice(2);
@@ -452,7 +452,7 @@ export const EFFECTS = {
// Una bandiera dipinta nello sfondo che sventola: a strisce verticali che salgono e scendono, ferme dalla parte // Una bandiera dipinta nello sfondo che sventola: a strisce verticali che salgono e scendono, ferme dalla parte
// dell'asta (`pole`: 'left' o 'right') e sempre più mosse verso il lembo libero. // dell'asta (`pole`: 'left' o 'right') e sempre più mosse verso il lembo libero.
cloth(ctx, e, time, game) { cloth(ctx, e, time, game) {
const bg = backgrounds.get(game.scene.background); const bg = backgrounds.get(game.backdrop());
if (!bg) return; if (!bg) return;
const k = bg.width / WIDTH; const k = bg.width / WIDTH;
for (const [i, [x, y, w, h]] of e.rects.entries()) { for (const [i, [x, y, w, h]] of e.rects.entries()) {
+1 -1
View File
@@ -1099,7 +1099,7 @@ function frame(now) {
ambience.update(soundscapeFor(game?.state.scene, game?.closeup?.id), game?.phase()?.id, dt); ambience.update(soundscapeFor(game?.state.scene, game?.closeup?.id), game?.phase()?.id, dt);
// A gioco fermo (titolo, pausa, fine) la scena non cambia: un ultimo disegno e poi niente, per la batteria del // A gioco fermo (titolo, pausa, fine) la scena non cambia: un ultimo disegno e poi niente, per la batteria del
// telefono. Si ridisegna solo se nel frattempo arriva lo sfondo che mancava. // telefono. Si ridisegna solo se nel frattempo arriva lo sfondo che mancava.
const still = game && !running && `${game.state.scene}|${hasBackground(game.scene.background)}`; const still = game && !running && `${game.state.scene}|${hasBackground(game.backdrop())}`;
if (game && (!still || still !== drawnStill)) { if (game && (!still || still !== drawnStill)) {
if (running) game.update(dt); if (running) game.update(dt);
render(ctx, game, { hover: debug && hoverTarget ? game.hotspot(hoverTarget) : null, spots: running && now < spotsUntil, debug: debugView() }); render(ctx, game, { hover: debug && hoverTarget ? game.hotspot(hoverTarget) : null, spots: running && now < spotsUntil, debug: debugView() });
+33 -18
View File
@@ -312,6 +312,8 @@ export const story = {
tozzino: { name: 'Il Tozzino', color: '#c8f5b0', sprite: 'assets/characters/tozzino.json' }, tozzino: { name: 'Il Tozzino', color: '#c8f5b0', sprite: 'assets/characters/tozzino.json' },
// Il Chiaru (Matteo Chiarusi, consenso dato ad Andrea il 29 ottobre), alla pista col gesso di Cardetole: sprite di // Il Chiaru (Matteo Chiarusi, consenso dato ad Andrea il 29 ottobre), alla pista col gesso di Cardetole: sprite di
// Codex dalla foto di Andrea. // Codex dalla foto di Andrea.
// Lo zio Mario di Andrea (sprite di Codex dalla foto di Andrea, 29 ottobre), alla Ghiacciomobile nel muro.
zio_mario: { name: 'Lo zio Mario', color: '#cfe3ff', sprite: 'assets/characters/zio_mario.json' },
chiaru: { name: 'Il Chiaru', color: '#ffd6a0', sprite: 'assets/characters/chiaru.json' }, chiaru: { name: 'Il Chiaru', color: '#ffd6a0', sprite: 'assets/characters/chiaru.json' },
barondeduke: { name: 'Il BaronDeDuke', color: '#e0c090', sprite: 'assets/characters/barondeduke.json' }, barondeduke: { name: 'Il BaronDeDuke', color: '#e0c090', sprite: 'assets/characters/barondeduke.json' },
mariano: { name: 'Mariano', color: '#ffb0a3', sprite: 'assets/characters/mariano.json' }, mariano: { name: 'Mariano', color: '#ffb0a3', sprite: 'assets/characters/mariano.json' },
@@ -2116,23 +2118,11 @@ export const story = {
entry: [320, 330], entry: [320, 330],
// L'Arcu davanti al circolino, accanto alla fontanella (sprite di Codex, 25 ottobre). // L'Arcu davanti al circolino, accanto alla fontanella (sprite di Codex, 25 ottobre).
speakers: { arcu: [418, 214] }, speakers: { arcu: [418, 214] },
// La Ghiacciomobile non è più qui: sta nel muro di Via Liguri Magelli (Andrea, 29 ottobre).
people: [ people: [
{ who: 'arcu', at: [418, 292], facing: -1, idle: 'stand', talk: ['talk', 'explain'], blink: 'blink', every: 4.2 }, { who: 'arcu', at: [418, 292], facing: -1, idle: 'stand', talk: ['talk', 'explain'], blink: 'blink', every: 4.2 },
// Oggetti statici: ordinati per profondità come la macchina del tempo, senza voce.
// Con la depth della scena misura circa 160 px; resta sopra il bordo di walk. (Il Betino dell'Arcu sta in
// cima alla salita di Via Liguri Magelli, Andrea 28 ottobre.)
{ who: 'ghiacciomobile', at: [176, 286], size: 0.986, idle: 'idle', talk: [] },
], ],
hotspots: [ hotspots: [
{
id: 'ghiacciomobile', name: 'la Ghiacciomobile', box: [96, 215, 160, 71], at: [240, 308], face: 'up', default: 'look',
// La Corsa nera degli amici (sprite di Codex, 26 ottobre). Parlandole, Andrea ricorda; lei non risponde.
actions: {
look: [{ say: 'La Ghiacciomobile nera. Hai visto cose che noi poveri umani non potremmo neppur lontanamente immaginare.' }],
talk: [{ dialogue: 'ghiacciomobile' }],
use: [{ say: 'Con questo sole, di ghiaccio c\'è rimasto giusto il nome. Vo a piedi.' }],
},
},
{ {
id: 'circolo', name: 'il circolino', box: [100, 0, 380, 205], at: [300, 290], face: 'up', id: 'circolo', name: 'il circolino', box: [100, 0, 380, 205], at: [300, 290], face: 'up',
actions: { actions: {
@@ -2710,14 +2700,21 @@ export const story = {
name: 'Via Liguri Magelli', name: 'Via Liguri Magelli',
map: [76, 97], map: [76, 97],
background: 'assets/scenes/via-liguri-magelli.png', background: 'assets/scenes/via-liguri-magelli.png',
// All'inizio la Ghiacciomobile è dentro il muro giallo, coi mattoni rotti (Codex, 29 ottobre); dal tramonto
// (le impronte del Regolo) il muro è rifatto e c'è la sua targa (Andrea, 29 ottobre).
backdrops: [{ when: '!indizio_regolo', src: 'assets/scenes/via-liguri-magelli-muro.png' }],
// La strada gira intorno all'Audi nera parcheggiata davanti al Trappola. // La strada gira intorno all'Audi nera parcheggiata davanti al Trappola.
walk: [[0, 360], [0, 320], [140, 262], [226, 198], [272, 198], [300, 242], [370, 246], [400, 252], [580, 318], [640, 330], [640, 360]], walk: [[0, 360], [0, 320], [140, 262], [226, 198], [272, 198], [300, 242], [370, 246], [400, 252], [580, 318], [640, 330], [640, 360]],
depth: [[198, 0.3], [360, 1.1]], // Le persone in proporzione con la Ghiacciomobile e l'Audi (Andrea, 29 ottobre: erano troppo piccole).
depth: [[198, 0.4], [360, 2.4]],
entry: [320, 340], entry: [320, 340],
speakers: { arcu: [374, 176] }, speakers: { arcu: [374, 176], zio_mario: [440, 196] },
people: [ people: [
// L'Arcu sotto la tenda del Trappola: due minuti fa era a Campomigliaio (Andrea, 28 ottobre). // L'Arcu sotto la tenda del Trappola: due minuti fa era a Campomigliaio (Andrea, 28 ottobre).
{ who: 'arcu', at: [374, 248], facing: -1, size: 1.3, idle: 'stand', talk: ['talk', 'explain'], blink: 'blink', every: 4.2 }, { who: 'arcu', at: [374, 248], facing: -1, size: 0.75, idle: 'stand', talk: ['talk', 'explain'], blink: 'blink', every: 4.2 },
// Lo zio Mario davanti alla Ghiacciomobile nel muro, che si gratta la testa (sprite di Codex dalla sua foto,
// 29 ottobre). Solo finché la macchina è lì. [DA ANDREA: le sue battute]
{ who: 'zio_mario', when: '!indizio_regolo', at: [440, 330], facing: 1, idle: 'think', talk: ['talk', 'explain', 'point'] },
], ],
hotspots: [ hotspots: [
{ {
@@ -2745,11 +2742,21 @@ export const story = {
}, },
}, },
{ {
id: 'targa', name: 'targa della Ghiacciomobile', box: [570, 130, 62, 78], at: [565, 336], face: 'right', default: 'look', id: 'targa', name: 'targa della Ghiacciomobile', box: [570, 130, 62, 78], at: [565, 336], face: 'right', default: 'look', when: 'indizio_regolo',
actions: { actions: {
look: [{ say: '«Qui riposa la Ghiacciomobile, che si è schiantata lì.»' }, { say: 'C\'è anche la fotina. Pareva sempre nuova.' }], look: [{ say: '«Qui riposa la Ghiacciomobile, che si è schiantata lì.»' }, { say: 'C\'è anche la fotina. Pareva sempre nuova.' }],
}, },
}, },
{
// La Ghiacciomobile nel muro (prima del tramonto). Le battute erano del circolino (Andrea, 26 ottobre);
// [DA ANDREA] quella dello schianto. Parlandole, Andrea ricorda; lei non risponde.
id: 'ghiacciomobile', name: 'la Ghiacciomobile', box: [462, 192, 140, 92], at: [440, 300], face: 'right', default: 'look', when: '!indizio_regolo',
actions: {
look: [{ say: 'La Ghiacciomobile nera, mezza dentro il muro. Hai visto cose che noi poveri umani non potremmo neppur lontanamente immaginare.' }],
talk: [{ dialogue: 'ghiacciomobile' }],
use: [{ say: 'Per tirarla fuori di lì ci vuole altro che le mie braccia.' }],
},
},
{ {
// La prima battuta è di Andrea (dal circolino, 26 ottobre). // La prima battuta è di Andrea (dal circolino, 26 ottobre).
id: 'betino', name: 'il Betino dell\'Arcu', box: [232, 172, 40, 24], at: [250, 206], face: 'up', default: 'look', id: 'betino', name: 'il Betino dell\'Arcu', box: [232, 172, 40, 24], at: [250, 206], face: 'up', default: 'look',
@@ -2764,7 +2771,15 @@ export const story = {
}, },
{ {
// Il campo del Giannini è laggiù a destra, oltre la siepe (Andrea, 28 ottobre). // Il campo del Giannini è laggiù a destra, oltre la siepe (Andrea, 28 ottobre).
id: 'al_giannini', name: 'verso il campo del Giannini', box: [430, 150, 132, 100], at: [520, 306], exit: { scene: 'campo_giannini', at: [60, 250], face: 'right' }, id: 'al_giannini', name: 'verso il campo del Giannini', box: [404, 150, 58, 50], at: [520, 306], exit: { scene: 'campo_giannini', at: [60, 250], face: 'right' },
},
// In fondo all'elenco, così sta sopra all'uscita e alla siepe.
{
id: 'zio_mario', name: 'lo zio Mario', box: [418, 206, 46, 124], at: [362, 334], face: 'right', default: 'look', when: '!indizio_regolo',
actions: {
look: [{ say: 'Lo zio Mario. Guarda il muro, guarda la macchina, e si gratta la testa sotto il berretto.' }],
talk: [{ say: 'Lo lascio pensare: quando ha trovato il modo di tirarla fuori, me lo dice lui.' }],
},
}, },
], ],
}, },
+1 -1
View File
@@ -1,5 +1,5 @@
// La versione del gioco: la cambia scripts/bump.sh, insieme a package.json. // La versione del gioco: la cambia scripts/bump.sh, insieme a package.json.
export const VERSION = '0.1.43'; export const VERSION = '0.1.45';
// Immagini, musiche e voci con ?v=<versione>: a ogni versione l'indirizzo cambia e il browser le riscarica, // Immagini, musiche e voci con ?v=<versione>: a ogni versione l'indirizzo cambia e il browser le riscarica,
// mentre fra una versione e l'altra le tiene in cache a lungo (nginx.conf). // mentre fra una versione e l'altra le tiene in cache a lungo (nginx.conf).
+1 -1
View File
@@ -437,7 +437,7 @@ test('interrompere la catena del ghiacciolo non perde la torcia né la chiavetta
test('gli sfondi si caricano dalla scena di partenza verso le più lontane, tutti e una volta sola', () => { test('gli sfondi si caricano dalla scena di partenza verso le più lontane, tutti e una volta sola', () => {
const order = backgroundOrder(story, story.start.scene); const order = backgroundOrder(story, story.start.scene);
const all = new Set(Object.values(story.scenes).map(s => s.background).filter(Boolean)); const all = new Set(Object.values(story.scenes).flatMap(s => [s.background, ...(s.backdrops ?? []).map(b => b.src)]).filter(Boolean));
assert.equal(order.length, all.size); assert.equal(order.length, all.size);
assert.deepEqual(new Set(order), all); assert.deepEqual(new Set(order), all);
assert.equal(order[0], story.scenes[story.start.scene].background, 'prima la piazza'); assert.equal(order[0], story.scenes[story.start.scene].background, 'prima la piazza');
+16 -3
View File
@@ -6,9 +6,10 @@ import { Game } from '../src/engine/game.js';
import { inside } from '../src/engine/geometry.js'; import { inside } from '../src/engine/geometry.js';
import { settle } from './helpers.mjs'; import { settle } from './helpers.mjs';
// La Ghiacciomobile al circolino è uno sprite; il Betino in cima alla salita di Via Liguri Magelli è dipinto nel quadro. // I veicoli sono dipinti nel quadro: il Betino in cima alla salita di Via Liguri Magelli e, prima del tramonto, la
const SPRITES = [['campomigliaio_circolo', 'ghiacciomobile', [150, 170]]]; // Ghiacciomobile dentro il muro giallo (Andrea, 29 ottobre). Nessuno è più uno sprite.
const VEHICLES = [...SPRITES, ['via_liguri_magelli', 'betino']]; const SPRITES = [];
const VEHICLES = [['via_liguri_magelli', 'betino'], ['via_liguri_magelli', 'ghiacciomobile']];
test('i veicoli restano fuori dal percorso e lasciano liberi gli altri hotspot', () => { test('i veicoli restano fuori dal percorso e lasciano liberi gli altri hotspot', () => {
for (const [scene, id, [lo, hi]] of SPRITES) { for (const [scene, id, [lo, hi]] of SPRITES) {
const g = new Game(story); const g = new Game(story);
@@ -62,3 +63,15 @@ test('guarda e usa i veicoli: parla solo Andrea e non cambia il progresso', () =
} }
} }
}); });
test('Via Liguri Magelli: prima la Ghiacciomobile nel muro (senza targa), dal tramonto il muro rifatto con la targa', () => {
const g = new Game(story);
g.go('via_liguri_magelli'); settle(g);
assert.equal(g.backdrop(), 'assets/scenes/via-liguri-magelli-muro.png');
assert.ok(g.hotspot('ghiacciomobile') && !g.hotspot('targa'));
assert.ok(!story.scenes.campomigliaio_circolo.hotspots.some(h => h.id === 'ghiacciomobile'), 'al circolino non c\'è più');
g.state.flags.indizio_regolo = true;
assert.equal(g.backdrop(), 'assets/scenes/via-liguri-magelli.png');
assert.ok(g.hotspot('targa') && !g.hotspot('ghiacciomobile'));
assert.ok(existsSync(new URL('../assets/scenes/via-liguri-magelli-muro.png', import.meta.url)));
});
+4
View File
@@ -35,6 +35,10 @@
"speaker": "Xavier Hayasaka", "speaker": "Xavier Hayasaka",
"filtro": "asetrate=24000*1.12,aresample=24000,atempo=0.92" "filtro": "asetrate=24000*1.12,aresample=24000,atempo=0.92"
}, },
"zio_mario": {
"speaker": "Viktor Menelaos",
"filtro": "asetrate=24000*0.95,aresample=24000,atempo=1.04"
},
"chiaru": { "chiaru": {
"speaker": "Luis Moray" "speaker": "Luis Moray"
}, },