Il viale alberato della Provinciale e la Carza verso La Luna; la mappa si cerca scrivendo
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ApqNBvNbNCwXqR2RLo8QJh
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 348 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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -619,6 +619,22 @@
|
|||||||
"file": "andrea-d39b7f7e61.mp3",
|
"file": "andrea-d39b7f7e61.mp3",
|
||||||
"sec": 8.25
|
"sec": 8.25
|
||||||
},
|
},
|
||||||
|
"andrea|I negozi sotto i palazzi, al riparo degli alberi. Con la festa domani, stasera chiudono tardi.": {
|
||||||
|
"file": "andrea-77832a5082.mp3",
|
||||||
|
"sec": 6.76
|
||||||
|
},
|
||||||
|
"andrea|Gli alberi del viale: d'estate fanno un'ombra che in piazza se la sognano.": {
|
||||||
|
"file": "andrea-e82710e398.mp3",
|
||||||
|
"sec": 3.77
|
||||||
|
},
|
||||||
|
"andrea|Arrampicarmi? Ho ventisette anni, non sette.": {
|
||||||
|
"file": "andrea-1c43e80b87.mp3",
|
||||||
|
"sec": 4.92
|
||||||
|
},
|
||||||
|
"andrea|Case coi balconi pieni di fiori. Qui il palio si sente da lontano: il giusto.": {
|
||||||
|
"file": "andrea-5bd253332d.mp3",
|
||||||
|
"sec": 6.36
|
||||||
|
},
|
||||||
"andrea|Più avanti c'è La Luna, e poi Campomigliaio, il mio rione: i blu.": {
|
"andrea|Più avanti c'è La Luna, e poi Campomigliaio, il mio rione: i blu.": {
|
||||||
"file": "andrea-a96e07a9f3.mp3",
|
"file": "andrea-a96e07a9f3.mp3",
|
||||||
"sec": 5.92
|
"sec": 5.92
|
||||||
@@ -639,9 +655,13 @@
|
|||||||
"file": "andrea-7883437f7d.mp3",
|
"file": "andrea-7883437f7d.mp3",
|
||||||
"sec": 3.46
|
"sec": 3.46
|
||||||
},
|
},
|
||||||
"andrea|La Sieve. Più sassi che acqua: a farci il bagno ci si sbuccia le ginocchia.": {
|
"andrea|La Carza, la stessa che passa sotto il ponticino per Cardetole. Più sassi che acqua.": {
|
||||||
"file": "andrea-c0180ddbd4.mp3",
|
"file": "andrea-6248354f0f.mp3",
|
||||||
"sec": 6.46
|
"sec": 6.38
|
||||||
|
},
|
||||||
|
"andrea|Da quando scavano le gallerie dell'alta velocità, d'estate sparisce. Torna viva d'inverno.": {
|
||||||
|
"file": "andrea-41e25f6dd0.mp3",
|
||||||
|
"sec": 7.07
|
||||||
},
|
},
|
||||||
"andrea|Scendere nel greto ora? Il palio non sta mica sotto un sasso.": {
|
"andrea|Scendere nel greto ora? Il palio non sta mica sotto un sasso.": {
|
||||||
"file": "andrea-cf81a4a625.mp3",
|
"file": "andrea-cf81a4a625.mp3",
|
||||||
@@ -655,13 +675,13 @@
|
|||||||
"file": "andrea-fd634c7a9b.mp3",
|
"file": "andrea-fd634c7a9b.mp3",
|
||||||
"sec": 3.81
|
"sec": 3.81
|
||||||
},
|
},
|
||||||
"andrea|Una casa bianca sotto il bosco, coi pini sopra. Bella vista sulla Sieve, e sui camion della Provinciale.": {
|
"andrea|Una casa bianca sotto il bosco, coi pini sopra. Bella vista sulla Carza, e sui camion della Provinciale.": {
|
||||||
"file": "andrea-701e3d4e55.mp3",
|
"file": "andrea-9618e5db93.mp3",
|
||||||
"sec": 7.65
|
"sec": 6.65
|
||||||
},
|
},
|
||||||
"andrea|Il muretto lungo la Sieve, tutto licheni. È più vecchio di me, e sta in piedi meglio.": {
|
"andrea|Il muretto lungo la Carza, tutto licheni. È più vecchio di me, e sta in piedi meglio.": {
|
||||||
"file": "andrea-e3d25b718c.mp3",
|
"file": "andrea-dc49e0c100.mp3",
|
||||||
"sec": 6.54
|
"sec": 6.08
|
||||||
},
|
},
|
||||||
"andrea|Il pallaio, dove si gioca a bocce. Qui un punto si discute più di un rigore.": {
|
"andrea|Il pallaio, dove si gioca a bocce. Qui un punto si discute più di un rigore.": {
|
||||||
"file": "andrea-e94382adb6.mp3",
|
"file": "andrea-e94382adb6.mp3",
|
||||||
|
|||||||
@@ -103,6 +103,12 @@ I prompt fissi (stile, scene, foglio sprite) sono in `prompts/STILE.md`, escluso
|
|||||||
**ancora da collegare** (camminata, hotspot, uscite, posto sulla mappa). Andrea, 24 ottobre: ci si arriva dal bivio
|
**ancora da collegare** (camminata, hotspot, uscite, posto sulla mappa). Andrea, 24 ottobre: ci si arriva dal bivio
|
||||||
della Via Provinciale (verso stazione e forno), andando a sinistra; ma prima viene **La Luna**, che Andrea deve
|
della Via Provinciale (verso stazione e forno), andando a sinistra; ma prima viene **La Luna**, che Andrea deve
|
||||||
ancora fotografare: si collega bivio → La Luna → Campomigliaio.
|
ancora fotografare: si collega bivio → La Luna → Campomigliaio.
|
||||||
|
- **Verso La Luna** (24 ottobre, foto di Andrea): dal bivio, a sinistra, il viale alberato della Provinciale
|
||||||
|
(`provinciale_viale`), poi la Provinciale lungo la Carza in secca con la luna (`verso_luna`; la Carza d'estate si
|
||||||
|
secca da quando hanno scavato le gallerie dell'alta velocità, d'inverno torna viva). In basso si va verso La Luna e
|
||||||
|
Campomigliaio (per ora solo battute). Da mettere: le case vecchie con la curva, il rettilineo col cartello della
|
||||||
|
rotonda, l'incrocio coi cartelli (`assets/raw/foto/luna-*.jpg`): ordine da chiedere ad Andrea.
|
||||||
|
- **Ricerca nella mappa**: casella «Cerca un posto…», filtra mentre si scrive (`matchPlace`), Invio porta al primo.
|
||||||
- **Scelta del rione** (24 ottobre): dopo «Nuova partita», «Per chi corri quest'anno?» fra i quattro rioni
|
- **Scelta del rione** (24 ottobre): dopo «Nuova partita», «Per chi corri quest'anno?» fra i quattro rioni
|
||||||
(`story.rioni`: Piazza rossi, Pieve bianchi, Cardetole verdi, Campomigliaio blu); resta nella partita come flag
|
(`story.rioni`: Piazza rossi, Pieve bianchi, Cardetole verdi, Campomigliaio blu); resta nella partita come flag
|
||||||
`rione:<id>`. Cambiano la riga dell'introduzione e le battute su Pieve, Cardetole, Campomigliaio e la colonna.
|
`rione:<id>`. Cambiano la riga dell'introduzione e le battute su Pieve, Cardetole, Campomigliaio e la colonna.
|
||||||
|
|||||||
+2
-1
@@ -52,7 +52,8 @@
|
|||||||
<div class="buttons"><button id="restart">Ricomincia</button><button class="open-credits secondary">Crediti</button></div>
|
<div class="buttons"><button id="restart">Ricomincia</button><button class="open-credits secondary">Crediti</button></div>
|
||||||
</section>
|
</section>
|
||||||
<section id="map" class="overlay" hidden aria-label="Mappa del paese">
|
<section id="map" class="overlay" hidden aria-label="Mappa del paese">
|
||||||
<h2>San Piero a Sieve</h2>
|
<div id="map-head"><h2>San Piero a Sieve</h2><input id="map-search" type="search" placeholder="Cerca un posto…" autocomplete="off" spellcheck="false" aria-label="Cerca un posto"></div>
|
||||||
|
<p id="map-none" hidden></p>
|
||||||
<div id="map-scroll"><div id="map-board"><svg id="map-roads" viewBox="0 0 100 100" preserveAspectRatio="none"></svg></div></div>
|
<div id="map-scroll"><div id="map-board"><svg id="map-roads" viewBox="0 0 100 100" preserveAspectRatio="none"></svg></div></div>
|
||||||
<div class="buttons"><button id="close-map">Chiudi</button></div>
|
<div class="buttons"><button id="close-map">Chiudi</button></div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -50,6 +50,14 @@ export function shuffledCredits(credits, random = Math.random) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// La ricerca della mappa: ogni parola scritta deve stare nel nome del posto, senza badare a maiuscole, accenti e
|
||||||
|
// apostrofi («camp» trova Campomigliaio, «de medici» trova Via de' Medici).
|
||||||
|
const plain = text => text.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g, '').replace(/[^a-z0-9]+/g, ' ').trim();
|
||||||
|
export function matchPlace(name, query) {
|
||||||
|
const words = plain(query).split(' ').filter(Boolean), hay = plain(name);
|
||||||
|
return words.every(w => hay.includes(w));
|
||||||
|
}
|
||||||
|
|
||||||
export const sayTime = text => Math.max(1.6, 0.9 + text.length * 0.055);
|
export const sayTime = text => Math.max(1.6, 0.9 + text.length * 0.055);
|
||||||
|
|
||||||
export function newState(story) {
|
export function newState(story) {
|
||||||
|
|||||||
+32
-2
@@ -1,6 +1,6 @@
|
|||||||
// Avvio nel browser: collega motore, disegno e interfaccia HTML (verbi, inventario, dialoghi, fumetti).
|
// Avvio nel browser: collega motore, disegno e interfaccia HTML (verbi, inventario, dialoghi, fumetti).
|
||||||
import { story } from './story/story.js';
|
import { story } from './story/story.js';
|
||||||
import { Game, VERBS, VERB_LABELS, checkSave, introText, shuffledCredits } from './engine/game.js';
|
import { Game, VERBS, VERB_LABELS, checkSave, introText, shuffledCredits, matchPlace } from './engine/game.js';
|
||||||
import { Command } from './engine/command.js';
|
import { Command } from './engine/command.js';
|
||||||
import { render, loadAssets, hasBackground, WIDTH, HEIGHT } from './engine/render.js';
|
import { render, loadAssets, hasBackground, WIDTH, HEIGHT } from './engine/render.js';
|
||||||
import { readSave, writeSave, clearSave, readAudio, writeAudio, saveFile, saveFileName, readSaveFile } from './engine/storage.js';
|
import { readSave, writeSave, clearSave, readAudio, writeAudio, saveFile, saveFileName, readSaveFile } from './engine/storage.js';
|
||||||
@@ -143,16 +143,41 @@ function openMap() {
|
|||||||
}));
|
}));
|
||||||
return row;
|
return row;
|
||||||
}));
|
}));
|
||||||
|
$('map-search').value = '';
|
||||||
|
filterMap();
|
||||||
$('map').hidden = false;
|
$('map').hidden = false;
|
||||||
drawRoads();
|
drawRoads();
|
||||||
|
// Col mouse si può scrivere subito; sul telefono la tastiera si apre solo toccando la casella.
|
||||||
|
if (matchMedia('(pointer: fine)').matches) $('map-search').focus({ preventScroll: true });
|
||||||
// Sul telefono la mappa scorre: si parte col posto dove si è, al centro.
|
// Sul telefono la mappa scorre: si parte col posto dove si è, al centro.
|
||||||
board.querySelector('.here')?.scrollIntoView({ block: 'center', inline: 'center' });
|
board.querySelector('.here')?.scrollIntoView({ block: 'center', inline: 'center' });
|
||||||
}
|
}
|
||||||
|
// La ricerca: mentre si scrive restano solo i posti che corrispondono; Invio porta al primo.
|
||||||
|
function filterMap() {
|
||||||
|
const query = $('map-search').value;
|
||||||
|
let shown = 0;
|
||||||
|
for (const row of $('map-board').querySelectorAll('.map-band')) {
|
||||||
|
let inRow = 0;
|
||||||
|
for (const b of row.children) inRow += (b.hidden = !matchPlace(b.title, query)) ? 0 : 1;
|
||||||
|
row.hidden = !inRow;
|
||||||
|
shown += inRow;
|
||||||
|
}
|
||||||
|
$('map-none').hidden = shown > 0;
|
||||||
|
$('map-none').textContent = `Nessun posto con «${query.trim()}»`;
|
||||||
|
drawRoads();
|
||||||
|
}
|
||||||
|
$('map-search').addEventListener('input', filterMap);
|
||||||
|
$('map-search').addEventListener('keydown', e => {
|
||||||
|
if (e.key !== 'Enter') return;
|
||||||
|
const first = [...$('map-board').querySelectorAll('button')].find(b => !b.hidden && !b.classList.contains('here'));
|
||||||
|
if (first) first.click();
|
||||||
|
});
|
||||||
// Le strade fra le schede, misurate dopo l'impaginazione (e di nuovo se la finestra cambia misura).
|
// Le strade fra le schede, misurate dopo l'impaginazione (e di nuovo se la finestra cambia misura).
|
||||||
function drawRoads() {
|
function drawRoads() {
|
||||||
const board = $('map-board'), svg = $('map-roads'), origin = board.getBoundingClientRect();
|
const board = $('map-board'), svg = $('map-roads'), origin = board.getBoundingClientRect();
|
||||||
const center = id => {
|
const center = id => {
|
||||||
const r = board.querySelector(`[data-scene="${id}"] img`)?.getBoundingClientRect();
|
const card = board.querySelector(`[data-scene="${id}"]`);
|
||||||
|
const r = card && !card.hidden && !card.parentElement.hidden && card.querySelector('img').getBoundingClientRect();
|
||||||
return r && [r.left + r.width / 2 - origin.left, r.top + r.height / 2 - origin.top];
|
return r && [r.left + r.width / 2 - origin.left, r.top + r.height / 2 - origin.top];
|
||||||
};
|
};
|
||||||
svg.setAttribute('viewBox', `0 0 ${board.scrollWidth} ${board.scrollHeight}`);
|
svg.setAttribute('viewBox', `0 0 ${board.scrollWidth} ${board.scrollHeight}`);
|
||||||
@@ -383,6 +408,11 @@ function updateChoices() {
|
|||||||
|
|
||||||
window.addEventListener('keydown', e => {
|
window.addEventListener('keydown', e => {
|
||||||
if (e.target === $('volume') || e.target === $('voice-volume')) return;
|
if (e.target === $('volume') || e.target === $('voice-volume')) return;
|
||||||
|
// Nella ricerca della mappa le lettere si scrivono; Esc prima svuota la casella, poi chiude.
|
||||||
|
if (e.target === $('map-search')) {
|
||||||
|
if (e.key === 'Escape') { if (e.target.value) { e.target.value = ''; filterMap(); } else $('map').hidden = true; }
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (debugKey(e)) return;
|
if (debugKey(e)) return;
|
||||||
if (!$('credits').hidden) { if (e.key === 'Escape') $('credits').hidden = true; return; }
|
if (!$('credits').hidden) { if (e.key === 'Escape') $('credits').hidden = true; return; }
|
||||||
if (!$('pause').hidden) { if (e.key === 'Escape') closePause(); return; }
|
if (!$('pause').hidden) { if (e.key === 'Escape') closePause(); return; }
|
||||||
|
|||||||
+47
-11
@@ -1032,7 +1032,7 @@ export const story = {
|
|||||||
id: 'alla_scuola', name: 'più avanti, la stradina della scuola', box: [170, 196, 80, 40], at: [208, 226], exit: { scene: 'scuola', at: [600, 320], face: 'left' },
|
id: 'alla_scuola', name: 'più avanti, la stradina della scuola', box: [170, 196, 80, 40], at: [208, 226], exit: { scene: 'scuola', at: [600, 320], face: 'left' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'la_luna', name: 'a sinistra, verso La Luna e Campomigliaio', box: [0, 216, 44, 56], at: [12, 248], exit: { scene: 'verso_luna', at: [150, 350], face: 'up' },
|
id: 'la_luna', name: 'a sinistra, verso La Luna e Campomigliaio', box: [0, 216, 44, 56], at: [12, 248], exit: { scene: 'provinciale_viale', at: [300, 350], face: 'up' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'al_forno', name: 'laggiù, verso il forno', box: [280, 196, 80, 40], at: [318, 224], exit: { scene: 'forno', at: [12, 300], face: 'right' },
|
id: 'al_forno', name: 'laggiù, verso il forno', box: [280, 196, 80, 40], at: [318, 224], exit: { scene: 'forno', at: [12, 300], face: 'right' },
|
||||||
@@ -1042,17 +1042,53 @@ export const story = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// La Provinciale lungo la Sieve, uscendo dal paese verso La Luna (foto di Andrea, 24 ottobre).
|
// La Provinciale dopo il bivio della stazione, fra gli alberi, prima della Carza (foto di Andrea, 24 ottobre).
|
||||||
|
provinciale_viale: {
|
||||||
|
name: 'Via Provinciale, il viale alberato',
|
||||||
|
map: [72, 68],
|
||||||
|
background: 'assets/scenes/provinciale-viale.png',
|
||||||
|
walk: [[0, 360], [0, 330], [400, 232], [462, 232], [620, 360]],
|
||||||
|
depth: [[232, 0.4], [360, 1.7]],
|
||||||
|
entry: [300, 350],
|
||||||
|
hotspots: [
|
||||||
|
{
|
||||||
|
id: 'verso_la_sieve', name: 'avanti, verso La Luna', box: [392, 220, 80, 22], at: [435, 236], exit: { scene: 'verso_luna', at: [150, 206], face: 'down' },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'negozi', name: 'negozi', box: [20, 150, 200, 95], at: [150, 330], face: 'left',
|
||||||
|
actions: {
|
||||||
|
look: [{ say: 'I negozi sotto i palazzi, al riparo degli alberi. Con la festa domani, stasera chiudono tardi.' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'alberi', name: 'alberi del viale', box: [230, 20, 160, 200], at: [330, 290], face: 'up',
|
||||||
|
actions: {
|
||||||
|
look: [{ say: 'Gli alberi del viale: d\'estate fanno un\'ombra che in piazza se la sognano.' }],
|
||||||
|
use: [{ say: 'Arrampicarmi? Ho ventisette anni, non sette.' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'villette', name: 'case col balcone', box: [500, 0, 140, 230], at: [540, 330], face: 'right',
|
||||||
|
actions: {
|
||||||
|
look: [{ say: 'Case coi balconi pieni di fiori. Qui il palio si sente da lontano: il giusto.' }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'al_bivio', name: 'indietro, verso il bivio', box: [0, 334, 620, 26], at: [300, 354], exit: { scene: 'bivio_provinciale', at: [12, 248], face: 'right' },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// La Provinciale lungo la Carza, uscendo dal paese verso La Luna (foto di Andrea, 24 ottobre).
|
||||||
verso_luna: {
|
verso_luna: {
|
||||||
name: 'La Provinciale lungo la Sieve',
|
name: 'La Provinciale lungo la Carza',
|
||||||
map: [70, 70],
|
map: [66, 73],
|
||||||
background: 'assets/scenes/verso-luna.png',
|
background: 'assets/scenes/verso-luna.png',
|
||||||
walk: [[0, 360], [0, 200], [168, 190], [182, 196], [330, 360]],
|
walk: [[0, 360], [0, 200], [168, 190], [182, 196], [330, 360]],
|
||||||
depth: [[192, 0.45], [360, 1.7]],
|
depth: [[192, 0.45], [360, 1.7]],
|
||||||
entry: [150, 350],
|
entry: [150, 206],
|
||||||
hotspots: [
|
hotspots: [
|
||||||
{
|
{
|
||||||
id: 'verso_la_luna', name: 'avanti, verso La Luna e Campomigliaio', box: [0, 186, 172, 26], at: [110, 200], face: 'up', default: 'walk',
|
id: 'verso_la_luna', name: 'avanti, verso La Luna e Campomigliaio', box: [0, 334, 330, 26], at: [150, 352], face: 'down', default: 'walk',
|
||||||
actions: {
|
actions: {
|
||||||
walk: [{
|
walk: [{
|
||||||
if: 'rione:campomigliaio',
|
if: 'rione:campomigliaio',
|
||||||
@@ -1063,9 +1099,9 @@ export const story = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'sieve', name: 'la Sieve', box: [340, 205, 300, 155], at: [250, 300], face: 'right',
|
id: 'carza', name: 'la Carza', box: [340, 205, 300, 155], at: [250, 300], face: 'right',
|
||||||
actions: {
|
actions: {
|
||||||
look: [{ say: 'La Sieve. Più sassi che acqua: a farci il bagno ci si sbuccia le ginocchia.' }],
|
look: [{ say: 'La Carza, la stessa che passa sotto il ponticino per Cardetole. Più sassi che acqua.' }, { say: 'Da quando scavano le gallerie dell\'alta velocità, d\'estate sparisce. Torna viva d\'inverno.' }],
|
||||||
use: [{ say: 'Scendere nel greto ora? Il palio non sta mica sotto un sasso.' }],
|
use: [{ say: 'Scendere nel greto ora? Il palio non sta mica sotto un sasso.' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -1079,17 +1115,17 @@ export const story = {
|
|||||||
{
|
{
|
||||||
id: 'casa_bianca', name: 'casa bianca', box: [84, 112, 80, 64], at: [120, 220], face: 'up',
|
id: 'casa_bianca', name: 'casa bianca', box: [84, 112, 80, 64], at: [120, 220], face: 'up',
|
||||||
actions: {
|
actions: {
|
||||||
look: [{ say: 'Una casa bianca sotto il bosco, coi pini sopra. Bella vista sulla Sieve, e sui camion della Provinciale.' }],
|
look: [{ say: 'Una casa bianca sotto il bosco, coi pini sopra. Bella vista sulla Carza, e sui camion della Provinciale.' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'muretto', name: 'muretto', box: [178, 196, 120, 150], at: [190, 300], face: 'right',
|
id: 'muretto', name: 'muretto', box: [178, 196, 120, 150], at: [190, 300], face: 'right',
|
||||||
actions: {
|
actions: {
|
||||||
look: [{ say: 'Il muretto lungo la Sieve, tutto licheni. È più vecchio di me, e sta in piedi meglio.' }],
|
look: [{ say: 'Il muretto lungo la Carza, tutto licheni. È più vecchio di me, e sta in piedi meglio.' }],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'al_bivio', name: 'indietro, verso il bivio', box: [0, 334, 330, 26], at: [150, 354], exit: { scene: 'bivio_provinciale', at: [12, 248], face: 'right' },
|
id: 'al_viale', name: 'indietro, verso il paese', box: [0, 182, 240, 26], at: [150, 200], exit: { scene: 'provinciale_viale', at: [435, 238], face: 'down' },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -145,7 +145,13 @@ body.full #sound { position: fixed; z-index: 13; top: max(8px, env(safe-area-ins
|
|||||||
#pause .hint { color: var(--dim); max-width: 34em; text-align: center; }
|
#pause .hint { color: var(--dim); max-width: 34em; text-align: center; }
|
||||||
.load-error { margin: .6em 0 0; padding: .4em .8em; color: #fff; background: #7a1f1f; border-radius: 6px; font-size: max(9px, calc(var(--u) * 1.4)); }
|
.load-error { margin: .6em 0 0; padding: .4em .8em; color: #fff; background: #7a1f1f; border-radius: 6px; font-size: max(9px, calc(var(--u) * 1.4)); }
|
||||||
#map { z-index: 3; justify-content: flex-start; padding-top: 2.5%; background: rgba(15, 10, 20, .94); }
|
#map { z-index: 3; justify-content: flex-start; padding-top: 2.5%; background: rgba(15, 10, 20, .94); }
|
||||||
#map h2 { font-size: clamp(12.96px, 2.16vw, 23.04px); }
|
#map h2 { font-size: clamp(12.96px, 2.16vw, 23.04px); margin: 0; }
|
||||||
|
#map-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: .4em 1.2em; width: 94%; margin: .3em 0; }
|
||||||
|
#map-search { font-size: clamp(8px, 1.1vw, 11px); padding: .5em .7em; width: 16em; max-width: 60%; border-radius: 6px;
|
||||||
|
border: 2px solid #5a4866; background: #231a29; color: var(--ink); }
|
||||||
|
#map-search:focus { outline: none; border-color: var(--accent); }
|
||||||
|
#map-none { margin: .6em 0 0; font-size: clamp(8px, 1.1vw, 11px); color: #b9a9c2; }
|
||||||
|
#map-board button[hidden], .map-band[hidden] { display: none; }
|
||||||
/* La mappa a gradini: una fascia per livello del paese, schede con miniatura e nome; si scorre se non ci sta. */
|
/* La mappa a gradini: una fascia per livello del paese, schede con miniatura e nome; si scorre se non ci sta. */
|
||||||
#map-scroll { width: 94%; flex: 1; min-height: 0; margin: .3em 0; overflow: auto; -webkit-overflow-scrolling: touch; border-radius: 8px;
|
#map-scroll { width: 94%; flex: 1; min-height: 0; margin: .3em 0; overflow: auto; -webkit-overflow-scrolling: touch; border-radius: 8px;
|
||||||
background: radial-gradient(circle at 50% 60%, #3a2d42, #231a29); }
|
background: radial-gradient(circle at 50% 60%, #3a2d42, #231a29); }
|
||||||
|
|||||||
+12
-1
@@ -237,7 +237,18 @@ try {
|
|||||||
assert.equal(await page.locator('#map-board button[data-scene="pieve"]').count(), 0, 'la Pieve non è ancora vista');
|
assert.equal(await page.locator('#map-board button[data-scene="pieve"]').count(), 0, 'la Pieve non è ancora vista');
|
||||||
assert.ok(await page.isVisible('#map-board button.here[data-scene="trebbio"]'));
|
assert.ok(await page.isVisible('#map-board button.here[data-scene="trebbio"]'));
|
||||||
await page.screenshot({ path: `${OUT}/07b-mappa.png` });
|
await page.screenshot({ path: `${OUT}/07b-mappa.png` });
|
||||||
await page.click('#map-board button[data-scene="piazza"]');
|
// La ricerca: scrivendo restano solo i posti giusti; una «p» nella casella non chiude la mappa; Invio ci va.
|
||||||
|
await page.fill('#map-search', 'xyz');
|
||||||
|
assert.ok(await page.isVisible('#map-none'), 'nessun posto: lo dice');
|
||||||
|
await page.fill('#map-search', '');
|
||||||
|
await page.click('#map-search');
|
||||||
|
await page.keyboard.type('piaz');
|
||||||
|
assert.ok(await page.isVisible('#map'), 'scrivere «p» nella ricerca non chiude la mappa');
|
||||||
|
assert.ok(await page.isHidden('#map-none'));
|
||||||
|
const shown = await page.locator('#map-board button:visible').evaluateAll(bs => bs.map(b => b.dataset.scene));
|
||||||
|
assert.deepEqual(shown, ['piazza']);
|
||||||
|
await page.screenshot({ path: `${OUT}/07c-mappa-ricerca.png` });
|
||||||
|
await page.keyboard.press('Enter');
|
||||||
assert.ok(await page.isHidden('#map'));
|
assert.ok(await page.isHidden('#map'));
|
||||||
assert.equal(await page.evaluate(() => game.state.scene), 'piazza');
|
assert.equal(await page.evaluate(() => game.state.scene), 'piazza');
|
||||||
|
|
||||||
|
|||||||
+12
-1
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict';
|
|||||||
import { backgroundOrder } from '../src/engine/render.js';
|
import { backgroundOrder } from '../src/engine/render.js';
|
||||||
import { story } from '../src/story/story.js';
|
import { story } from '../src/story/story.js';
|
||||||
import { solution } from '../src/story/solution.js';
|
import { solution } from '../src/story/solution.js';
|
||||||
import { Game, VERBS, checkSave, introText, shuffledCredits } from '../src/engine/game.js';
|
import { Game, VERBS, checkSave, introText, shuffledCredits, matchPlace } from '../src/engine/game.js';
|
||||||
import { inside } from '../src/engine/geometry.js';
|
import { inside } from '../src/engine/geometry.js';
|
||||||
import { existsSync, readFileSync } from 'node:fs';
|
import { existsSync, readFileSync } from 'node:fs';
|
||||||
import { settle } from './helpers.mjs';
|
import { settle } from './helpers.mjs';
|
||||||
@@ -101,6 +101,17 @@ test('i crediti: i nomi di ogni voce escono in ordine casuale, sempre tutti', ()
|
|||||||
assert.ok(orders.size > 3, `${idee}: l'ordine non cambia`);
|
assert.ok(orders.size > 3, `${idee}: l'ordine non cambia`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('la ricerca della mappa: pezzi di parola, senza maiuscole, accenti e apostrofi', () => {
|
||||||
|
assert.ok(matchPlace('Campomigliaio', 'camp'));
|
||||||
|
assert.ok(matchPlace('Via de\' Medici', 'de medici'));
|
||||||
|
assert.ok(matchPlace('Via de\' Medici', 'MEDICI via'), 'le parole in qualsiasi ordine');
|
||||||
|
assert.ok(matchPlace('La Pieve di San Pietro', 'pieve '));
|
||||||
|
assert.ok(matchPlace('Piazza', ''), 'casella vuota: tutti');
|
||||||
|
assert.ok(!matchPlace('Piazza', 'pieve'));
|
||||||
|
const names = Object.values(story.scenes).filter(s => s.map).map(s => s.name);
|
||||||
|
assert.ok(names.filter(n => matchPlace(n, 'provinciale')).length >= 2, 'più posti sulla Provinciale');
|
||||||
|
});
|
||||||
|
|
||||||
test('la soluzione si percorre tutta dall\'inizio alla fine', () => {
|
test('la soluzione si percorre tutta dall\'inizio alla fine', () => {
|
||||||
const saves = [];
|
const saves = [];
|
||||||
const g = new Game(story, { onSave: s => saves.push(s) });
|
const g = new Game(story, { onSave: s => saves.push(s) });
|
||||||
|
|||||||
Reference in New Issue
Block a user