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:
+41
-4
@@ -8,6 +8,7 @@ import { Music, trackFor } from './engine/music.js';
|
||||
import { Voices } from './engine/voices.js';
|
||||
import { Soundscape } from './engine/soundscape.js';
|
||||
import { soundscapeFor } from './story/soundscapes.js';
|
||||
import { aim as bocceAim, shoot as bocceShoot, setPower as boccePower, canThrow as bocceReady, status as bocceStatus } from './engine/bocce.js';
|
||||
import { VERSION, versioned } from './version.js';
|
||||
|
||||
const $ = id => document.getElementById(id);
|
||||
@@ -265,6 +266,7 @@ $('spots-button').addEventListener('click', showSpots);
|
||||
function openPause() {
|
||||
if (!running) return;
|
||||
running = false;
|
||||
game.closeupCancel();
|
||||
music.hold = true;
|
||||
voices.pause();
|
||||
ambience.configure({ active: false });
|
||||
@@ -397,9 +399,9 @@ canvas.addEventListener('pointerdown', e => {
|
||||
// Nel primo piano un tocco sfoglia (o salta la battuta): gli oggetti della scena dietro non si toccano.
|
||||
if (game.closeup) {
|
||||
press = { closeup: true };
|
||||
game.closeupAim(scenePoint(e));
|
||||
// Alle bocce si tiene premuto per caricare la forza (la battuta in corso, un tocco la salta).
|
||||
if (!game.skip()) game.closeupPress();
|
||||
game.closeupAim(scenePoint(e));
|
||||
canvas.setPointerCapture(e.pointerId);
|
||||
return;
|
||||
}
|
||||
@@ -419,7 +421,8 @@ canvas.addEventListener('pointerup', e => {
|
||||
}
|
||||
press = null;
|
||||
});
|
||||
canvas.addEventListener('pointercancel', () => { if (press) clearTimeout(press.timer); press = null; });
|
||||
canvas.addEventListener('pointercancel', () => { if (press) clearTimeout(press.timer); press = null; game?.closeupCancel(); });
|
||||
canvas.addEventListener('lostpointercapture', () => { if (press?.closeup) { press = null; game?.closeupCancel(); } });
|
||||
canvas.addEventListener('contextmenu', e => {
|
||||
e.preventDefault();
|
||||
if (running && !game.closeup) command.clickScene(scenePoint(e), { look: true });
|
||||
@@ -431,6 +434,15 @@ canvas.addEventListener('pointermove', e => {
|
||||
});
|
||||
canvas.addEventListener('pointerleave', () => { mouse = null; });
|
||||
|
||||
// Comandi delle bocce separati dai verbi dell'avventura: forza regolabile e lancio
|
||||
// con un solo clic, anche per chi non vuole usare la pressione temporizzata.
|
||||
const bocceState = () => running && game?.closeup?.id === 'bocce' ? game.closeup : null;
|
||||
$('bocce-power').addEventListener('input', e => { const c = bocceState(); if (c) boccePower(c, Number(e.target.value) / 100); });
|
||||
$('bocce-throw').addEventListener('click', () => { const c = bocceState(); if (c && !game.speech) bocceShoot(c); });
|
||||
for (const [id, move] of [['bocce-left', -0.3], ['bocce-right', 0.3]])
|
||||
$(id).addEventListener('click', () => { const c = bocceState(); if (c) bocceAim(c, c.aim.u, c.aim.w + move); });
|
||||
addEventListener('blur', () => game?.closeupCancel());
|
||||
|
||||
// --- Verbi.
|
||||
for (const verb of VERBS) {
|
||||
const b = document.createElement('button');
|
||||
@@ -516,6 +528,17 @@ window.addEventListener('keydown', e => {
|
||||
if (!$('map').hidden) { if (e.key === 'Escape' || e.key === 'p' || e.key === 'P') $('map').hidden = true; return; }
|
||||
// Nel primo piano: Invio, spazio o freccia sfogliano (o saltano la battuta), Esc chiude il libro.
|
||||
if (running && game.closeup) {
|
||||
if (game.closeup.id === 'bocce') {
|
||||
if (e.target.closest?.('#bocce-controls') && ['BUTTON', 'SUMMARY'].includes(e.target.tagName)) return;
|
||||
const c = game.closeup;
|
||||
if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.key)) {
|
||||
e.preventDefault();
|
||||
if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') bocceAim(c, c.aim.u, c.aim.w + (e.key === 'ArrowLeft' ? -0.3 : 0.3));
|
||||
else boccePower(c, c.power + (e.key === 'ArrowUp' ? 0.01 : -0.01));
|
||||
return;
|
||||
}
|
||||
if (c.step === 'result' && [' ', 'Enter'].includes(e.key)) { e.preventDefault(); game.closeupClose(); return; }
|
||||
}
|
||||
if (story.closeups[game.closeup.id].type === 'torch' && ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Enter'].includes(e.key)) {
|
||||
// Invio cerca il prossimo dettaglio anche per chi non può usare il puntatore.
|
||||
e.preventDefault();
|
||||
@@ -590,16 +613,30 @@ function updateUi() {
|
||||
updateInventory();
|
||||
updateChoices();
|
||||
updateSpeech();
|
||||
const bocce = c?.id === 'bocce';
|
||||
$('bocce-controls').hidden = !bocce;
|
||||
$('bocce-controls').inert = !running;
|
||||
if (bocce) {
|
||||
$('panel').hidden = $('choices').hidden = true;
|
||||
const line = bocceStatus(c, story.closeups.bocce.names);
|
||||
if ($('bocce-status').textContent !== line) $('bocce-status').textContent = line;
|
||||
$('bocce-power').value = Math.round(c.power * 100);
|
||||
$('bocce-power-value').value = `${Math.round(c.power * 100)}%`;
|
||||
for (const id of ['bocce-power', 'bocce-left', 'bocce-right', 'bocce-throw']) $(id).disabled = !bocceReady(c) || c.holding || !!game.speech;
|
||||
$('bocce-throw').textContent = c.step === 'result' ? 'Mano conclusa' : c.step === 'rolling' ? 'In movimento…' : c.current === 'cpu' ? 'Tira Mariano…' : 'Lancia';
|
||||
for (const event of c.events.splice(0)) ambience.play(event.kind, { pan: 0, strength: event.power });
|
||||
}
|
||||
// Il pulsante della mappa c'è solo in partita, fuori dai dialoghi, e quando c'è almeno un altro posto dove andare.
|
||||
$('map-button').hidden = !running || !!game.dialogue || !!game.closeup || game.mapPlaces().length < 2;
|
||||
$('pause-button').hidden = !running;
|
||||
$('spots-button').hidden = !running || !!game.closeup;
|
||||
$('notebook-button').hidden = !running || !story.notebook || !!game.closeup;
|
||||
$('closeup-close').hidden = !running || !game.closeup;
|
||||
$('closeup-close').textContent = torch ? c.step === 'done' ? 'Continua' : 'Torna fuori' : c && story.closeups[c.id].type === 'bocce' ? 'Lascia stare' : 'Chiudi';
|
||||
$('closeup-close').textContent = torch ? c.step === 'done' ? 'Continua' : 'Torna fuori' : bocce ? c.step === 'result' ? 'Torna al pallaio' : 'Lascia stare' : 'Chiudi';
|
||||
$('panel').inert = !!c;
|
||||
canvas.classList.toggle('torch', !!torch);
|
||||
canvas.setAttribute('aria-label', torch ? 'Fessura: sposta la luce con mouse, dito o frecce. Invio cerca il prossimo dettaglio; Esc esce.' : "La scena dell'avventura");
|
||||
canvas.classList.toggle('bocce', bocce);
|
||||
canvas.setAttribute('aria-label', torch ? 'Fessura: sposta la luce con mouse, dito o frecce. Invio cerca il prossimo dettaglio; Esc esce.' : bocce ? 'Bocce: tocca il campo o il dettaglio per mirare. Regola la forza e premi Lancia.' : "La scena dell'avventura");
|
||||
// La pagina che comincia a girare fa il suo fruscio.
|
||||
const step = game.closeup?.step ?? null;
|
||||
if (step === 'turn' && turning !== 'turn') ambience.play('page');
|
||||
|
||||
Reference in New Issue
Block a user