diff --git a/index.html b/index.html index ce000b4..8b40345 100644 --- a/index.html +++ b/index.html @@ -305,9 +305,9 @@ sacco (o Invio). Contano le bruciate buone: alla bona ne bastano 10 su 18, seria 15, a fassi male 16.
Il Regolo, il flipper del River. Tieni premuto per caricare la molla e lascia per lanciare, oppure usa - Spazio o il pulsante Lancia. Una valvola impedisce alla pallina entrata in campo di tornare sulla molla. - Le frecce sinistra e destra, i pulsanti Flipper o le due metà della scena comandano le palette; +
Il Regolo, il flipper del River. Tieni premuto per caricare la molla e lascia per lanciare, oppure tieni + premuto Spazio o la freccia giù, o usa il pulsante Lancia. Una valvola impedisce alla pallina entrata in campo di tornare sulla molla. + Le frecce sinistra e destra, i due Shift, i pulsanti Flipper o le due metà della scena comandano le palette; puoi usare due dita insieme e il tasto destro del mouse comanda sempre la paletta destra.
Le rampe FORTEZZA (ciano) e TREBBIO (ambra) valgono 15.000 punti. Tre passaggi completi sulla stessa rampa entro 20 secondi dal primo fanno LOCK: la pallina viene trattenuta e ne arriva una nuova gratis. diff --git a/src/engine/flipper.js b/src/engine/flipper.js index 7158b27..d5e6a1a 100644 --- a/src/engine/flipper.js +++ b/src/engine/flipper.js @@ -498,7 +498,7 @@ export function cancel(c, pointerId) { for (const f of Object.values(c.flippers)) f.held = all ? [] : f.held.filter(id => id !== pointerId); return true; } -// I pulsanti «← Flipper» e «Flipper →» (tenuti premuti; da tastiera un colpo breve), e le frecce. +// I pulsanti «← Flipper» e «Flipper →» (tenuti premuti; da tastiera un colpo breve), le frecce e i due Shift. export const turn = (c, dir, who = 'button') => c.step === 'play' && hold(c, dir < 0 ? 'left' : 'right', who, true); export function stopTurn(c, who = 'button') { if (who === 'click') return false; // il colpo breve finisce da sé @@ -509,8 +509,9 @@ export const nudge = () => false; export function setPower(c, v) { if (!canThrow(c) || !Number.isFinite(v)) return false; c.power = clamp(v, 0, 1); return true; } export function key(c, k, down) { if (c.step !== 'play') return false; // a partita finita Spazio e Invio chiudono il risultato (main.js) - if (k === 'ArrowLeft' || k === 'ArrowRight') { hold(c, k === 'ArrowLeft' ? 'left' : 'right', 'key-' + k, down); return true; } - if (k === ' ') { if (down) { if (!c.holding && waiting(c)) press(c, 'key'); } else if (c.holding && c.pointerId === 'key') release(c, 'key'); return true; } + if (['ArrowLeft', 'ArrowRight', 'ShiftLeft', 'ShiftRight'].includes(k)) { hold(c, k.endsWith('Left') ? 'left' : 'right', 'key-' + k, down); return true; } + // La molla: Spazio, o la freccia giù (si tira indietro come la molla vera). + if (k === ' ' || k === 'ArrowDown') { if (down) { if (!c.holding && waiting(c)) press(c, 'key'); } else if (c.holding && c.pointerId === 'key') release(c, 'key'); return true; } if (k === 'Enter') { if (down) shoot(c); return true; } return false; } diff --git a/src/main.js b/src/main.js index 5335f60..d0b056b 100644 --- a/src/main.js +++ b/src/main.js @@ -661,7 +661,7 @@ const MINI = { condor: { ...condor, back: 'Torna al campone', label: 'La Condor: muovi il mouse o tocca il campo per mirare, tieni premuto per trattenere il fiato e lascia per sparare; oppure premi Spara. Frecce per spostare il mirino.' }, campana: { ...campana, back: 'Torna al campone', label: 'La campana: muovi il mouse o tocca la campana per mirare, tieni premuto per la forza e lascia per tirare il sassolino; oppure regola la forza e premi Tira (frecce su e giù per mirare, destra e sinistra per la forza). Ai salti premi, o Spazio, quando la lancetta è nel verde.' }, bruciate: { ...bruciate, back: 'Torna alla festa', label: 'Le bruciate: tieni premuto e fai dei giri, col mouse o col dito, per girare la manovella; oppure Spazio o le frecce, una spinta a ogni colpo. Né troppo piano né troppo forte; quando son cotte, Rovescia nel sacco (o Invio).' }, - flipper: { ...flipper, toggle: true, back: 'Torna in strada', label: 'Il flipper del River: tieni premuto per caricare la molla e lascia per lanciare (o regola la forza e premi Lancia, o Spazio). In gioco, tieni premuto sulla metà sinistra o destra della scena per alzare il flipper di quel lato, anche con due dita o col tasto destro del mouse; oppure i pulsanti Flipper o le frecce sinistra e destra.' }, + flipper: { ...flipper, toggle: true, back: 'Torna in strada', label: 'Il flipper del River: tieni premuto per caricare la molla e lascia per lanciare (o regola la forza e premi Lancia; o tieni premuto Spazio o la freccia giù). In gioco, tieni premuto sulla metà sinistra o destra della scena per alzare il flipper di quel lato, anche con due dita o col tasto destro del mouse; oppure i pulsanti Flipper, le frecce sinistra e destra o i due Shift.' }, micro: { ...micro, back: 'Torna dal Chiaru', label: 'La pista col gesso: muovi il mouse o tocca il parcheggio per mirare, tieni premuto per caricare la spinta e lascia; oppure regola la forza e premi Spingi. Frecce o pulsanti Mira per girare.' }, basket: { ...basket, back: 'Torna in strada', label: 'Fai due tiri: muovi il mouse o tocca per mirare, tieni premuto per caricare la forza, lascia per tirare.' }, // La gara: niente mira né forza, il pulsante alterna gas e freno (chi non può tenere premuto). @@ -825,6 +825,8 @@ function updateChoices() { })); } +// Ai minigiochi lo Shift arriva coi due lati distinti (ShiftLeft, ShiftRight): nel flipper comandano le due palette. +const keyName = e => e.key === 'Shift' ? e.code : e.key; window.addEventListener('keydown', e => { if (e.target instanceof HTMLInputElement && e.target.type === 'range' && e.key !== 'Escape') return; // Nella ricerca della mappa le lettere si scrivono; Esc prima svuota la casella, poi chiude. @@ -917,7 +919,7 @@ window.addEventListener('keydown', e => { if (e.key === 'Escape') { game.closeupClose(); return; } const onButton = ['BUTTON', 'SUMMARY'].includes(e.target.tagName), onControl = onButton && e.target.closest?.('#bocce-controls'); // Il GP di Fortezza: frecce, Spazio e Invio finché si tengono giù (su un pulsante Spazio e Invio lo premono). - if (!(onButton && [' ', 'Enter'].includes(e.key)) && mini().key?.(game.closeup, e.key, true, e.shiftKey)) { e.preventDefault(); return; } + if (!(onButton && [' ', 'Enter'].includes(e.key)) && mini().key?.(game.closeup, keyName(e), true, e.shiftKey)) { e.preventDefault(); return; } if (onControl && [' ', 'Enter'].includes(e.key)) return; const c = game.closeup, m = mini(); if (['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(e.key)) { @@ -964,7 +966,7 @@ window.addEventListener('keydown', e => { // Alle bocce e al biliardo, lasciando spazio o Invio parte il tiro. window.addEventListener('keyup', e => { // Il GP di Fortezza tiene conto di ogni tasto per conto suo: lasciarne uno non toglie il gas del dito o degli altri. - if (miniState() && mini().key?.(game.closeup, e.key, false)) return; + if (miniState() && mini().key?.(game.closeup, keyName(e), false)) return; if (running && [' ', 'Enter'].includes(e.key)) game?.closeupRelease(); }); diff --git a/tests/flipper.test.mjs b/tests/flipper.test.mjs index 1a8c9b3..b37ca5f 100644 --- a/tests/flipper.test.mjs +++ b/tests/flipper.test.mjs @@ -146,10 +146,14 @@ test('comandi: la molla si carica e si lancia lasciando; annullare non lancia; d m.turn(c, 1, 'click'); m.stopTurn(c, 'click'); assert.ok(c.flippers.right.held.includes('click')); const a0 = c.flippers.right.angle; run(c, 0.1); assert.notEqual(c.flippers.right.angle, a0, 'il flipper si è mosso'); run(c, 0.3); assert.ok(!c.flippers.right.held.length); assert.ok(m.key(c, 'ArrowRight', true)); assert.ok(c.flippers.right.held.length); m.key(c, 'ArrowRight', false); assert.ok(!c.flippers.right.held.length); + assert.ok(m.key(c, 'ShiftLeft', true)); assert.ok(c.flippers.left.held.includes('key-ShiftLeft') && !c.flippers.right.held.length); + m.key(c, 'ShiftRight', true); assert.ok(c.flippers.right.held.includes('key-ShiftRight')); + m.key(c, 'ShiftLeft', false); m.key(c, 'ShiftRight', false); assert.ok(!c.flippers.left.held.length && !c.flippers.right.held.length); assert.ok(!m.key(c, 'x', true)); assert.ok(!m.setPower(c, 0.3), 'in gioco il cursore della molla non vale'); // Spazio: carica e lancia; Invio: lancia con la forza del cursore; a partita finita i tasti non sono suoi. const d = m.newFlipper(9); assert.ok(m.key(d, ' ', true)); run(d, 0.3); assert.ok(d.holding); m.key(d, ' ', false); assert.ok(!m.waiting(d)); + const g = m.newFlipper(11); assert.ok(m.key(g, 'ArrowDown', true)); run(g, 0.3); assert.ok(g.holding, 'anche la freccia giù carica la molla'); m.key(g, 'ArrowDown', false); assert.ok(!m.waiting(g)); const e = m.newFlipper(10); assert.ok(m.setPower(e, 0.5)); assert.equal(m.button(e), 'Lancia'); m.key(e, 'Enter', true); assert.ok(!m.waiting(e)); assert.equal(m.button(e), 'In gioco…'); e.step = 'result'; e.result = { winner: 'cpu', score: 0, goal: 120000 }; assert.ok(!m.key(e, ' ', true) && !m.key(e, 'Enter', true)); });