Bocce più vere (lavoro di Codex): mira libera sul campo o nel dettaglio del pallino, forza regolabile senza tempismo, urti fra masse diverse, tira chi non ha il punto, distanze in centimetri, suoni di rotolamento e urto, comandi anche a pulsanti e tastiera; test aggiornati alle nuove regole

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ks2K99uqCZjAxvy7Rdj1R
This commit is contained in:
2026-10-25 19:26:23 +01:00
co-authored by Claude Opus 5.5
parent a0201fea18
commit 44485cff52
10 changed files with 386 additions and 154 deletions
+5 -4
View File
@@ -1,7 +1,7 @@
// Il cuore dell'avventura, senza DOM: stato, comandi, coda delle azioni, dialoghi.
// La storia (scene, oggetti, dialoghi) arriva tutta dai dati: qui non c'è nessun enigma scritto a mano.
import { findPath, dist, inBox, boxDistance, nearestInside } from './geometry.js';
import { newBocce, update as bocceUpdate, press as boccePress, release as bocceRelease } from './bocce.js';
import { newBocce, update as bocceUpdate, press as boccePress, release as bocceRelease, cancel as bocceCancel, aimScreen } from './bocce.js';
export const VERBS = ['walk', 'look', 'take', 'use', 'talk', 'open', 'give', 'drop'];
export const VERB_LABELS = { walk: 'Vai a', look: 'Guarda', take: 'Prendi', use: 'Usa', talk: 'Parla con', open: 'Apri', give: 'Dai', drop: 'Butta' };
@@ -250,7 +250,7 @@ export class Game {
}
// Le bocce: a mano finita, la battuta di chi ha vinto; uscendo prima, quella di chi lascia.
if (def?.type === 'bocce') {
this.queue.unshift(...(c.step === 'result' ? def[c.result?.winner === 'player' ? 'win' : 'lose'] : def.quit ?? []));
this.queue.unshift(...(c.step === 'result' ? def[c.result?.winner === 'player' ? 'win' : c.result?.winner === 'cpu' ? 'lose' : 'draw'] ?? [] : def.quit ?? []));
return true;
}
// Chi è arrivato all'ultima pagina, chiudendo, la commenta (`closing`).
@@ -261,11 +261,13 @@ export class Game {
// Le bocce: si tiene premuto per caricare la forza e si lascia per tirare (mouse, dito o spazio).
closeupPress() { const c = this.closeup; return !!c && this.story.closeups[c.id].type === 'bocce' && !this.speech && boccePress(c); }
closeupRelease() { const c = this.closeup; return !!c && this.story.closeups[c.id].type === 'bocce' && bocceRelease(c); }
closeupCancel() { const c = this.closeup; return !!c && this.story.closeups[c.id].type === 'bocce' && bocceCancel(c); }
// Solo luce, nessun clic sugli oggetti dietro al primo piano. Il progresso è transitorio:
// uscire o ricaricare durante la ricerca permette di ripeterla, senza anticipare il finale.
closeupAim([x, y]) {
const c = this.closeup;
if (c && this.story.closeups[c.id].type === 'bocce') return aimScreen(c, [x, y]);
if (!c || this.story.closeups[c.id].type !== 'torch' || !Number.isFinite(x) || !Number.isFinite(y)) return false;
c.beam = [Math.max(70, Math.min(570, x)), Math.max(65, Math.min(295, y))];
return true;
@@ -390,8 +392,7 @@ export class Game {
if (this.story.closeups[c.id].type === 'torch') { this.updateTorch(dt); return; }
if (this.story.closeups[c.id].type === 'bocce') {
bocceUpdate(c, dt);
// Il risultato resta a schermo un momento, poi si torna al pallaio per i commenti.
if (c.step === 'result' && c.t >= 2.4) this.closeupClose();
// Il risultato resta leggibile finché il giocatore torna al pallaio.
return;
}
c.t += dt;