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
+14 -5
View File
@@ -68,7 +68,7 @@ try {
if (verb === 'talk') await page.screenshot({ path: `${OUT}/03-dialogo.png` });
await settle(page);
if (target === 'cosa_luccicante') await page.screenshot({ path: `${OUT}/04-squama.png` });
if (target === 'verso_salita') await page.screenshot({ path: `${OUT}/05-salita.png` });
if (target === 'vicolo') await page.screenshot({ path: `${OUT}/05-fortezza.png` });
}
await page.waitForSelector('#ending:not([hidden])');
await page.screenshot({ path: `${OUT}/06-fine.png` });
@@ -78,24 +78,33 @@ try {
// Una partita a metà riprende da dove era rimasta.
await page.click('#restart');
await settle(page);
await clickScene(page, await hotspotCenter(page, 'verso_salita'));
await clickScene(page, await hotspotCenter(page, 'verso_trebbio'));
await settle(page);
await page.click('#verbs [data-verb="talk"]');
await clickScene(page, await hotspotCenter(page, 'torre'));
await page.locator('#choices li', { hasText: 'bloccato' }).click();
await page.waitForFunction(() => game.speech?.who === 'castello');
await page.waitForTimeout(100);
await page.screenshot({ path: `${OUT}/07-trebbio.png` });
await settle(page);
await page.locator('#choices li', { hasText: 'pace' }).click();
await settle(page);
await page.reload();
await page.waitForSelector('#continue:not([hidden])');
await page.click('#continue');
assert.equal(await page.evaluate(() => game.state.scene), 'salita');
assert.equal(await page.evaluate(() => game.state.scene), 'trebbio');
const phone = await open({ width: 390, height: 844 });
await phone.click('#new-game');
await settle(phone);
const overflow = await phone.evaluate(() => document.documentElement.scrollWidth > innerWidth);
assert.equal(overflow, false, 'scorrimento orizzontale su telefono');
await phone.screenshot({ path: `${OUT}/07-telefono.png` });
await phone.screenshot({ path: `${OUT}/08-telefono.png` });
const landscape = await open({ width: 844, height: 390 });
await landscape.click('#new-game');
await settle(landscape);
assert.equal(await landscape.evaluate(() => document.documentElement.scrollWidth > innerWidth), false);
await landscape.screenshot({ path: `${OUT}/08-orizzontale.png`, fullPage: true });
await landscape.screenshot({ path: `${OUT}/09-orizzontale.png`, fullPage: true });
assert.deepEqual(errors, [], 'errori nella console');
console.log(`Browser OK: soluzione completa, ripresa del salvataggio, telefono. Schermate in ${OUT}`);
+5 -5
View File
@@ -14,8 +14,8 @@ const setup = () => {
test('clic intelligente: parla con le persone, guarda le cose, attraversa le uscite', () => {
const { g, c, at } = setup();
assert.equal(c.sentence('vecchietti'), 'Parla con vecchietti');
assert.equal(c.sentence('bacheca'), 'Guarda bacheca');
assert.equal(c.sentence('verso_salita'), 'Vai a verso la Fortezza');
assert.equal(c.sentence('manifesto'), 'Guarda manifesto del Palio');
assert.equal(c.sentence('vicolo'), 'Vai a vicolo verso la Fortezza');
assert.equal(c.clickScene(at('vecchietti')), 'act');
settle(g);
assert.equal(g.dialogue?.id, 'vecchietti');
@@ -25,10 +25,10 @@ test('verbo scelto, poi bersaglio; il verbo si azzera dopo il comando', () => {
const { g, c, at } = setup();
c.pickVerb('take');
assert.equal(c.sentence(), 'Prendi…');
assert.equal(c.sentence('asta'), 'Prendi asta del drappo');
c.clickScene(at('asta'));
assert.equal(c.sentence('colonna'), 'Prendi colonna');
c.clickScene(at('colonna'));
assert.equal(c.verb, null);
assert.match(settle(g)[0].text, /rincorrerebbero/);
assert.match(settle(g)[0].text, /come la chiamano/);
});
test('pressione lunga o clic destro guarda', () => {
+2
View File
@@ -4,6 +4,7 @@ import { story } from '../src/story/story.js';
import { solution } from '../src/story/solution.js';
import { Game, VERBS } from '../src/engine/game.js';
import { inside } from '../src/engine/geometry.js';
import { existsSync } from 'node:fs';
import { settle } from './helpers.mjs';
const EFFECTS = ['say', 'walk', 'face', 'give', 'drop', 'set', 'unset', 'if', 'dialogue', 'node', 'endDialogue', 'go', 'end'];
@@ -34,6 +35,7 @@ test('la storia è coerente: scene, oggetti, dialoghi e punti calpestabili esist
assert.ok(story.scenes[story.start.scene] && inside(story.scenes[story.start.scene].walk, story.start.at));
for (const [id, scene] of Object.entries(story.scenes)) {
assert.ok(inside(scene.walk, scene.entry), `${id}: ingresso fuori dall'area`);
if (scene.background) assert.ok(existsSync(new URL('../' + scene.background, import.meta.url)), `${id}: manca ${scene.background}`);
const ids = new Set();
for (const h of scene.hotspots ?? []) {
assert.ok(!ids.has(h.id), `${id}.${h.id} doppio`);