// Copione del video «Come si gioca: le bocce» (video/SCALETTA-CARTE.md, clip 4). // Giro: video/narra.py, poi rec.mjs come in video/SCALETTA.md, poi video/monta.py --tutorial. import { c, sleep, setup as base, regista } from "./tutorial-comune.mjs"; export const title = { it: "Come si gioca · le bocce", en: "Come si gioca · le bocce" }; export const cues = [ c("dove", "Le bocce si giocano al pallaio, accanto al tennis della chiesa. Mariano, il campione, sfida chiunque"), c("livello", "Si sceglie quanto deve impegnarsi: alla bona, seria, o a fassi male"), c("campo", "Il campo visto da dietro: in fondo c'è il pallino, e a sinistra il dettaglio, per vedere da vicino chi è più accosto"), c("mira", "Per mirare si tocca il campo, o il dettaglio vicino al pallino. Il cerchio azzurro dice dove si fermerebbe la boccia"), c("forza", "Poi si regola la forza col cursore, e si preme Lancia"), c("turno", "Tira sempre chi non ha il punto. Chi è dietro può accostare, oppure bocciare: colpire la boccia dell'altro per toglierla di lì"), c("tieni", "C'è anche un altro modo: si tiene premuto sul campo, la forza sale, e lasciando parte la boccia. Vanno bene anche le frecce e la barra spaziatrice"), c("punti", "Tre bocce a testa. Alla fine fa un punto ogni boccia più vicina al pallino della migliore dell'avversario"), c("fine", "E se batti Mariano, ti porta a Brento Sanico. Buona partita!"), ]; export const setup = base; export async function run(d) { const p = d.page, r = regista(d, "tutorial-bocce"); await r.ascolta(); await r.vaiA("tennis_chiesa", [430, 310]); await r.cue("dove"); await r.parlaCon("mariano"); await r.scegli("Facciamo una partita"); await r.cue("livello"); await r.scegli("Alla bona."); // Una mano fissa: accostando bene, Andrea fa tre punti (anche se il tiro a pressione viene un po' corto o lungo). await p.evaluate(async () => { const { newBocce } = await import("/src/engine/bocce.js"); game.closeup = { id: "bocce", ...newBocce(9, { level: "bona" }) }; }); await sleep(800); await p.waitForFunction(() => window.music?.want === "assets/audio/bocce.mp3", null, { timeout: 10000 }); await r.cue("campo"); await r.muovi([300, 200], 1.0); await sleep(400); await r.muovi([90, 170], 1.0); // Dove mirare: poco prima del pallino, così la boccia si ferma accosto (il cerchio azzurro ci finisce sopra). const mira = () => p.evaluate(async () => { const B = await import("/src/engine/bocce.js"), c = game.closeup, u = c.jack.u - 0.55, w = c.jack.w; const s = B.project(u, w); return { at: [s.x, s.y], u, w, power: B.powerFor(Math.hypot(u, w) - 0.29) }; }); const tocca = async () => { for (let i = 0; i < 600; i++) { const s = await p.evaluate(async () => { const { canThrow } = await import("/src/engine/bocce.js"); return game.closeup.step === "result" ? "fine" : canThrow(game.closeup) && !game.speech ? "tocca" : "aspetta"; }); if (s !== "aspetta") return s === "tocca"; await sleep(150); } return false; }; let tiro = 0; while (await tocca()) { tiro++; const m = await mira(); if (tiro === 1) await r.cue("mira"); if (tiro < 3) { // Mira col clic, forza col cursore, poi Lancia. await r.clicca(m.at, 0.8); await p.evaluate(async ({ u, w }) => (await import("/src/engine/bocce.js")).aim(game.closeup, u, w), m); if (tiro === 1) await r.cue("forza"); await d.hover(p.locator("#bocce-power"), 0.6); await p.locator("#bocce-power").fill(String(Math.round(m.power * 100))); await p.evaluate(async (v) => (await import("/src/engine/bocce.js")).setPower(game.closeup, v), m.power); await sleep(600); await d.click(p.locator("#bocce-throw"), 0.6); if (tiro === 1) await r.cue("turno"); } else { // L'ultima tenendo premuto: la forza sale finché non si lascia. await r.cue("tieni"); await r.muovi(m.at, 0.8); const [a, b] = await r.punto(...m.at); d.vm(`DISPLAY=:0 xdotool mousemove ${Math.round(a)} ${Math.round(b)} mousedown 1 sleep ${(m.power * 1.6).toFixed(2)} mouseup 1`); } await p.locator("#scene").scrollIntoViewIfNeeded(); } await p.waitForFunction(() => game.closeup.step === "result", null, { timeout: 90000 }); await sleep(1000); await r.cue("punti"); await r.cue("fine"); await r.aspetta(); await d.click(p.locator("#closeup-close"), 0.6); await r.fermi(800); await r.fine(); await r.salvaAudio(); }