Revisione di Codex: salvataggi a punti fermi, salva e carica da file, volume delle voci

- si salva solo a sequenza finita: uscire a metà di una risposta o della casetta riporta a prima; la squama
  presa resta salvata anche senza cambiare scena; test di interruzione su soluzione e catena del ghiacciolo
- «Salva su file» nella pausa e «Carica» nel titolo, con controllo di versione e contenuto prima di
  sostituire il salvataggio del browser
- cursore del volume delle voci («bla»), 50% di partenza; il muto zittisce subito la voce, la pausa la riprende
- col dito un oggetto mancato di poco si prende, e i piccoli vincono sui grandi che li contengono (la squama);
  verbi su due colonne nel telefono in orizzontale
- sfondi caricati per vicinanza alla scena di partenza, con tentativi limitati se falliscono; a gioco fermo
  non si ridisegna
- modalità ?debug per scrivere le scene: area calpestabile, hotspot, punti, coordinate copiabili
- corretto: i crediti dal titolo restavano dietro il titolo

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ApqNBvNbNCwXqR2RLo8QJh
This commit is contained in:
2026-10-24 12:06:49 +02:00
co-authored by Claude Opus 5.5
parent 66d946b230
commit 605e9a6dd1
17 changed files with 590 additions and 64 deletions
+32
View File
@@ -56,6 +56,16 @@ test('le voci si cercano per chi parla e testo; senza indice il gioco resta muto
assert.equal(v.playing, false);
});
test('le voci hanno il loro volume, più basso della musica finché non lo si cambia', () => {
const v = new Voices();
assert.equal(v.volume, 0.5);
assert.equal(v.setVolume(1.7), 1);
assert.equal(v.setVolume(-1), 0);
const quiet = new Voices({ [voiceKey('leone', 'Grr')]: { file: 'leone-x.mp3', sec: 1.5 } }, 'x/', 0);
assert.equal(quiet.play('leone', 'Grr'), false, 'a volume zero non parte niente');
assert.equal(new Voices({ [voiceKey('leone', 'Grr')]: { file: 'leone-x.mp3', sec: 1.5 } }).play('leone', 'Grr', true), false, 'col muto non parte niente');
});
test('il leone e il castello parlano dalla loro posizione, non da quella di Andrea', () => {
const g = new Game(story);
g.go('salita_villa_adami', [340, 352]);
@@ -63,3 +73,25 @@ test('il leone e il castello parlano dalla loro posizione, non da quella di Andr
g.go('trebbio', [110, 345]);
assert.deepEqual(g.speakerPoint('castello'), story.scenes.trebbio.speakers.castello);
});
test('la pausa ferma la voce e riprendendo continua; stop la toglie', () => {
globalThis.Audio = class { constructor(src) { this.src = src; this.paused = true; this.ended = false; } play() { this.paused = false; return Promise.resolve(); } pause() { this.paused = true; } };
try {
const v = new Voices({ [voiceKey('leone', 'Grr')]: { file: 'leone-x.mp3', sec: 1.5 } }, 'x/', 0.4);
assert.ok(v.play('leone', 'Grr'));
assert.equal(v.audio.volume, 0.4);
assert.ok(v.playing);
v.pause();
assert.ok(!v.playing && v.audio, 'in pausa la voce resta, ferma');
v.resume();
assert.ok(v.playing, 'riprende la stessa battuta');
v.setVolume(0.8);
assert.equal(v.audio.volume, 0.8, 'il cursore cambia anche la voce che sta parlando');
v.stop();
assert.ok(!v.playing && !v.audio);
v.resume();
assert.ok(!v.playing, 'dopo stop non riparte niente');
} finally {
delete globalThis.Audio;
}
});