Il GP di Fortezza: gara dei cinquantini attorno alle mura (pista di Codex dalla planimetria, sterzo, acceleratori, miscela, buche, presentazione dei piloti coi motorini dalle foto); Via Liguri Magelli col Trappola, la targa della Ghiacciomobile e il Betino in cima alla salita; l'Arcu lancia la sfida dal Trappola e ha la voce nuova (Andrea)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GiECdCPptNRwbVzjzHbohi
This commit is contained in:
2026-10-28 19:55:16 +01:00
co-authored by Claude Opus 5.5
parent c96dec4692
commit 800a82045d
79 changed files with 1205 additions and 67 deletions
+15 -8
View File
@@ -6,12 +6,16 @@ import { Game } from '../src/engine/game.js';
import { inside } from '../src/engine/geometry.js';
import { settle } from './helpers.mjs';
test('i veicoli del circolino restano fuori dal percorso e lasciano liberi gli altri hotspot', () => {
// La Ghiacciomobile al circolino è uno sprite; il Betino in cima alla salita di Via Liguri Magelli è dipinto nel quadro.
const SPRITES = [['campomigliaio_circolo', 'ghiacciomobile', [150, 170]]];
const VEHICLES = [...SPRITES, ['via_liguri_magelli', 'betino']];
test('i veicoli restano fuori dal percorso e lasciano liberi gli altri hotspot', () => {
for (const [scene, id, [lo, hi]] of SPRITES) {
const g = new Game(story);
g.go('campomigliaio_circolo');
g.go(scene);
settle(g);
const vehicles = ['betino', 'ghiacciomobile'];
for (const id of vehicles) {
const vehicles = [id];
{
const person = g.people().find(p => p.who === id), h = g.hotspot(id);
const url = new URL('../' + story.characters[id].sprite, import.meta.url);
const atlas = JSON.parse(readFileSync(url, 'utf8')), frame = atlas.frames.idle;
@@ -19,7 +23,7 @@ test('i veicoli del circolino restano fuori dal percorso e lasciano liberi gli a
assert.deepEqual(Object.keys(atlas.frames), ['idle']);
const k = 62 * g.scaleAt(person.at[1]) * person.size / atlas.height;
const width = frame.w * k;
assert.ok(id === 'betino' ? width >= 70 && width <= 80 : width >= 150 && width <= 170);
assert.ok(width >= lo && width <= hi, `${id}: ${width}`);
// Tutto l'ingombro (non soltanto l'ancora) deve restare fuori dall'area calpestabile.
for (let x = h.box[0]; x <= h.box[0] + h.box[2]; x++)
for (let y = h.box[1]; y <= h.box[1] + h.box[3]; y++)
@@ -34,14 +38,16 @@ test('i veicoli del circolino restano fuori dal percorso e lasciano liberi gli a
assert.equal(g.personPose(person), 'idle');
}
}
}
});
test('guarda e usa i veicoli: parla solo Andrea e non cambia il progresso', () => {
for (const [scene, id] of VEHICLES) {
const g = new Game(story);
g.go('campomigliaio_circolo');
g.go(scene);
settle(g);
const flags = { ...g.state.flags }, inventory = [...g.state.inventory];
for (const id of ['betino', 'ghiacciomobile']) {
{
const h = g.hotspot(id);
assert.equal(g.hotspotAt([h.box[0] + h.box[2] / 2, h.box[1] + h.box[3] / 2]).id, id);
for (const verb of ['look', 'use']) {
@@ -51,7 +57,8 @@ test('guarda e usa i veicoli: parla solo Andrea e non cambia il progresso', () =
assert.deepEqual([g.state.x, g.state.y], h.at);
assert.deepEqual(g.state.flags, flags);
assert.deepEqual(g.state.inventory, inventory);
assert.equal(g.state.scene, 'campomigliaio_circolo');
assert.equal(g.state.scene, scene);
}
}
}
});