Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a5a80d7af | ||
|
|
88f0439f79 |
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "leggenda-del-regolo",
|
"name": "leggenda-del-regolo",
|
||||||
"version": "0.1.42",
|
"version": "0.1.43",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
+3
-1
@@ -495,4 +495,6 @@ export function status(c) {
|
|||||||
if (simple(c)) return `Giro ${lapOf(me)} di ${LAPS}, ${place}° posto. ${c.clean !== undefined && c.t - c.clean < 1.5 ? 'Curva pulita!' : mustLift(c) && c.holding ? 'Lascia!' : mustLift(c, PREAVVISO) && c.holding ? 'Curva!' : c.holding ? 'Gas!' : 'Freno.'}`;
|
if (simple(c)) return `Giro ${lapOf(me)} di ${LAPS}, ${place}° posto. ${c.clean !== undefined && c.t - c.clean < 1.5 ? 'Curva pulita!' : mustLift(c) && c.holding ? 'Lascia!' : mustLift(c, PREAVVISO) && c.holding ? 'Curva!' : c.holding ? 'Gas!' : 'Freno.'}`;
|
||||||
return `Giro ${lapOf(me)} di ${LAPS}, ${place}° posto. ${c.braking ? 'Freno!' : c.holding ? 'Gas!' : 'Senza gas.'}`;
|
return `Giro ${lapOf(me)} di ${LAPS}, ${place}° posto. ${c.braking ? 'Freno!' : c.holding ? 'Gas!' : 'Senza gas.'}`;
|
||||||
}
|
}
|
||||||
export const button = c => c.step === 'intro' ? 'Avanti' : c.step === 'result' ? 'Finita' : c.holding ? 'Molla' : 'Gas';
|
// Nella guida semplice il pulsante si tiene premuto: la scritta resta Gas (su iPhone un pulsante che cambia sotto il dito
|
||||||
|
// perde il tocco).
|
||||||
|
export const button = c => c.step === 'intro' ? 'Avanti' : c.step === 'result' ? 'Finita' : simple(c) ? 'Gas' : c.holding ? 'Molla' : 'Gas';
|
||||||
|
|||||||
+16
-2
@@ -634,7 +634,17 @@ for (const ev of ['pointerup', 'pointercancel', 'lostpointercapture']) $('gara-p
|
|||||||
padPointer = null; $('gara-pad').classList.remove('active');
|
padPointer = null; $('gara-pad').classList.remove('active');
|
||||||
});
|
});
|
||||||
$('gara-pad').addEventListener('contextmenu', e => e.preventDefault());
|
$('gara-pad').addEventListener('contextmenu', e => e.preventDefault());
|
||||||
$('bocce-throw').addEventListener('click', () => { const c = miniState(); if (c && !game.speech) mini().shoot?.(c); });
|
// GP, guida semplice: il pulsante Gas si tiene premuto (giù gas, su freno) invece di accendersi e spegnersi al clic;
|
||||||
|
// sul telefono, alla bona, il clic arrivava solo alzando il dito (Andrea, 29 ottobre).
|
||||||
|
const holdGas = c => !!c && story.closeups[c.id].type === 'gara' && gara.simple(c) && c.step !== 'intro' && c.step !== 'result';
|
||||||
|
$('bocce-throw').addEventListener('click', () => { const c = miniState(); if (c && !game.speech && !holdGas(c)) mini().shoot?.(c); });
|
||||||
|
$('bocce-throw').addEventListener('pointerdown', e => {
|
||||||
|
const c = miniState(); if (!holdGas(c) || game.speech) return;
|
||||||
|
e.preventDefault();
|
||||||
|
if (gara.press(c, 'gas-button')) try { $('bocce-throw').setPointerCapture(e.pointerId); } catch { /* un tocco sintetico: va bene lo stesso */ }
|
||||||
|
});
|
||||||
|
for (const ev of ['pointerup', 'pointercancel', 'lostpointercapture']) $('bocce-throw').addEventListener(ev, () => { const c = miniState(); if (holdGas(c)) gara.release(c, 'gas-button'); });
|
||||||
|
$('bocce-throw').addEventListener('contextmenu', e => { if (holdGas(miniState())) e.preventDefault(); });
|
||||||
// Le carte da gioco: dove si tocca la carta sul tavolo, gioco per gioco.
|
// Le carte da gioco: dove si tocca la carta sul tavolo, gioco per gioco.
|
||||||
const CARD_AT = { briscola: cardAt, tressette: tressetteAt, scopa: scopaAt };
|
const CARD_AT = { briscola: cardAt, tressette: tressetteAt, scopa: scopaAt };
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
@@ -935,7 +945,10 @@ function updateUi() {
|
|||||||
updateSpeech();
|
updateSpeech();
|
||||||
const mg = miniState() && mini(), def = mg && story.closeups[c.id];
|
const mg = miniState() && mini(), def = mg && story.closeups[c.id];
|
||||||
const cards = ['briscola', 'tressette', 'scopa'].includes(def?.type);
|
const cards = ['briscola', 'tressette', 'scopa'].includes(def?.type);
|
||||||
setProp($('bocce-controls'), 'hidden', !mg || cards);
|
// La presentazione dei piloti del GP a tutto schermo: i comandi arrivano col semaforo (Andrea, 29 ottobre).
|
||||||
|
const presenta = !!mg && story.closeups[c.id].type === 'gara' && c.step === 'intro';
|
||||||
|
$('app').classList.toggle('presenta', presenta);
|
||||||
|
setProp($('bocce-controls'), 'hidden', !mg || cards || presenta);
|
||||||
setProp($('bocce-controls'), 'inert', !running);
|
setProp($('bocce-controls'), 'inert', !running);
|
||||||
setProp($('briscola-controls'), 'hidden', def?.type !== 'briscola');
|
setProp($('briscola-controls'), 'hidden', def?.type !== 'briscola');
|
||||||
setProp($('briscola-controls'), 'inert', !running);
|
setProp($('briscola-controls'), 'inert', !running);
|
||||||
@@ -1027,6 +1040,7 @@ function updateUi() {
|
|||||||
setText($('bocce-left'), def.type === 'gara' ? '← Sterza' : '← Mira');
|
setText($('bocce-left'), def.type === 'gara' ? '← Sterza' : '← Mira');
|
||||||
setText($('bocce-right'), def.type === 'gara' ? 'Sterza →' : 'Mira →');
|
setText($('bocce-right'), def.type === 'gara' ? 'Sterza →' : 'Mira →');
|
||||||
setProp($('gara-brake'), 'hidden', def.type !== 'gara' || easy);
|
setProp($('gara-brake'), 'hidden', def.type !== 'gara' || easy);
|
||||||
|
$('bocce-throw').classList.toggle('hold', easy);
|
||||||
setProp($('gara-brake'), 'disabled', !(mg.canAdjust?.(c) ?? false) || !!game.speech);
|
setProp($('gara-brake'), 'disabled', !(mg.canAdjust?.(c) ?? false) || !!game.speech);
|
||||||
setText($('bocce-throw'), mg.button?.(c) ?? (c.step === 'result' ? 'Finita' : c.step === 'rolling' ? 'In movimento…' : c.current === 'cpu' ? `Tira ${def.names.cpu}…` : def.type === 'bocce' ? 'Lancia' : 'Tira'));
|
setText($('bocce-throw'), mg.button?.(c) ?? (c.step === 'result' ? 'Finita' : c.step === 'rolling' ? 'In movimento…' : c.current === 'cpu' ? `Tira ${def.names.cpu}…` : def.type === 'bocce' ? 'Lancia' : 'Tira'));
|
||||||
setProp($('bocce-help'), 'hidden', def.type !== 'bocce');
|
setProp($('bocce-help'), 'hidden', def.type !== 'bocce');
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
// La versione del gioco: la cambia scripts/bump.sh, insieme a package.json.
|
// La versione del gioco: la cambia scripts/bump.sh, insieme a package.json.
|
||||||
export const VERSION = '0.1.42';
|
export const VERSION = '0.1.43';
|
||||||
|
|
||||||
// Immagini, musiche e voci con ?v=<versione>: a ogni versione l'indirizzo cambia e il browser le riscarica,
|
// Immagini, musiche e voci con ?v=<versione>: a ogni versione l'indirizzo cambia e il browser le riscarica,
|
||||||
// mentre fra una versione e l'altra le tiene in cache a lungo (nginx.conf).
|
// mentre fra una versione e l'altra le tiene in cache a lungo (nginx.conf).
|
||||||
|
|||||||
@@ -56,7 +56,11 @@ body { display: flex; justify-content: center; overflow-x: hidden; -webkit-tap-h
|
|||||||
text-align: center; color: #c5c6b6; border: 2px dashed #897b57; border-radius: 10px; background: #1d2320; }
|
text-align: center; color: #c5c6b6; border: 2px dashed #897b57; border-radius: 10px; background: #1d2320; }
|
||||||
#gara-pad.active { border-style: solid; color: #f3dcac; }
|
#gara-pad.active { border-style: solid; color: #f3dcac; }
|
||||||
#stage, #bocce-controls, #gara-pad { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
|
#stage, #bocce-controls, #gara-pad { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
|
||||||
#bocce-throw { background: #ead09a; color: #202b25; min-width: 100px; }
|
#bocce-throw { background: #ead09a; color: #202b25; min-width: 100px; touch-action: none; }
|
||||||
|
/* La presentazione dei piloti del GP: la scena da sola, i comandi arrivano col semaforo. */
|
||||||
|
#app.presenta #side { display: none; }
|
||||||
|
/* La guida semplice del GP: il Gas si tiene premuto col pollice, più alto. */
|
||||||
|
#bocce-throw.hold { min-height: 72px; font-size: 14px; }
|
||||||
.bocce-adjust button:disabled { opacity: .4; cursor: default; }
|
.bocce-adjust button:disabled { opacity: .4; cursor: default; }
|
||||||
#bocce-help, #biliardo-help, #basket-help, #pesca-help, #gara-help, #rinquarto-help { margin-top: 9px; color: #c5c6b6; font-size: 10px; }
|
#bocce-help, #biliardo-help, #basket-help, #pesca-help, #gara-help, #rinquarto-help { margin-top: 9px; color: #c5c6b6; font-size: 10px; }
|
||||||
#bocce-help summary, #biliardo-help summary, #basket-help summary, #pesca-help summary, #gara-help summary, #rinquarto-help summary { cursor: pointer; padding: 6px 0; }
|
#bocce-help summary, #biliardo-help summary, #basket-help summary, #pesca-help summary, #gara-help summary, #rinquarto-help summary { cursor: pointer; padding: 6px 0; }
|
||||||
@@ -318,6 +322,8 @@ body.full #sound { position: fixed; z-index: 13; top: max(8px, env(safe-area-ins
|
|||||||
#app { width: 100vw; flex-direction: row; }
|
#app { width: 100vw; flex-direction: row; }
|
||||||
#stage { flex: none; width: min(calc(100dvh * 16 / 9), 68vw); align-self: flex-start; }
|
#stage { flex: none; width: min(calc(100dvh * 16 / 9), 68vw); align-self: flex-start; }
|
||||||
#stage.biliardo { width: min(calc((100dvh - 90px) * 16 / 9), 68vw); }
|
#stage.biliardo { width: min(calc((100dvh - 90px) * 16 / 9), 68vw); }
|
||||||
|
#app.presenta { justify-content: center; }
|
||||||
|
#app.presenta #stage.biliardo { width: min(calc((100dvh - 44px) * 16 / 9), 100vw); }
|
||||||
#stage.briscola { width: min(calc((100dvh - 90px) * 16 / 9), 68vw); }
|
#stage.briscola { width: min(calc((100dvh - 90px) * 16 / 9), 68vw); }
|
||||||
#briscola-controls, #tressette-controls, #scopa-controls { overflow-y: auto; min-height: 0; padding: 8px; font-size: 9px; }
|
#briscola-controls, #tressette-controls, #scopa-controls { overflow-y: auto; min-height: 0; padding: 8px; font-size: 9px; }
|
||||||
/* Nella colonna stretta accanto al tavolo: carte e segni su due colonne, parole che vanno a capo. */
|
/* Nella colonna stretta accanto al tavolo: carte e segni su due colonne, parole che vanno a capo. */
|
||||||
|
|||||||
+15
-4
@@ -29,19 +29,30 @@ try {
|
|||||||
const { settle } = await import('/tests/helpers.mjs');
|
const { settle } = await import('/tests/helpers.mjs');
|
||||||
settle(game); game.run({ closeup: 'gara', level }); settle(game);
|
settle(game); game.run({ closeup: 'gara', level }); settle(game);
|
||||||
}, level);
|
}, level);
|
||||||
await page.waitForSelector('#bocce-controls:not([hidden])');
|
// La presentazione dei piloti a tutto schermo: niente comandi finché non c'è il semaforo.
|
||||||
|
await page.waitForFunction(() => game.closeup?.step === 'intro');
|
||||||
|
await page.waitForTimeout(300);
|
||||||
|
assert.equal(await page.locator('#bocce-controls').isVisible(), false, `${name}: comandi nascosti nella presentazione`);
|
||||||
|
assert.equal(await page.locator('#side').isVisible(), false, `${name}: la scena da sola`);
|
||||||
|
await page.screenshot({ path: `${out}/${name}-presentazione.png` });
|
||||||
// Salta la presentazione dei piloti e aspetta il via.
|
// Salta la presentazione dei piloti e aspetta il via.
|
||||||
await page.evaluate(async () => { const g = await import('/src/engine/gara.js'); while (game.closeup.step === 'intro') g.press(game.closeup); });
|
await page.evaluate(async () => { const g = await import('/src/engine/gara.js'); while (game.closeup.step === 'intro') g.press(game.closeup); });
|
||||||
await page.waitForFunction(() => game.closeup.step === 'race', null, { timeout: 15000 });
|
await page.waitForFunction(() => game.closeup.step === 'race', null, { timeout: 15000 });
|
||||||
|
await page.waitForSelector('#bocce-controls:not([hidden])');
|
||||||
const easy = level !== 'male';
|
const easy = level !== 'male';
|
||||||
for (const id of ['#bocce-left', '#bocce-right', '#gara-brake', '#gara-pad'])
|
for (const id of ['#bocce-left', '#bocce-right', '#gara-brake', '#gara-pad'])
|
||||||
assert.equal(await page.locator(id).isVisible(), !easy, `${name}: ${id} ${easy ? 'nascosto' : 'visibile'}`);
|
assert.equal(await page.locator(id).isVisible(), !easy, `${name}: ${id} ${easy ? 'nascosto' : 'visibile'}`);
|
||||||
assert.equal(await page.locator('#bocce-power').isVisible(), !easy, 'la sensibilità solo con lo sterzo vero');
|
assert.equal(await page.locator('#bocce-power').isVisible(), !easy, 'la sensibilità solo con lo sterzo vero');
|
||||||
// Il pulsante Gas accende il gas; un altro tocco lo spegne e nella guida semplice si frena.
|
// Nella guida semplice il pulsante Gas si tiene premuto (giù gas, su freno) e la scritta non cambia; con lo
|
||||||
if (mobile) await page.locator('#bocce-throw').tap(); else await page.locator('#bocce-throw').click();
|
// sterzo vero un tocco accende il gas e un altro lo spegne.
|
||||||
|
const gas = page.locator('#bocce-throw');
|
||||||
|
if (easy) await gas.dispatchEvent('pointerdown', { pointerId: 5, pointerType: mobile ? 'touch' : 'mouse', isPrimary: true });
|
||||||
|
else await gas.click();
|
||||||
await page.waitForFunction(() => game.closeup.riders.find(r => r.id === 'andrea').v > 40, null, { timeout: 15000 });
|
await page.waitForFunction(() => game.closeup.riders.find(r => r.id === 'andrea').v > 40, null, { timeout: 15000 });
|
||||||
|
assert.equal(await gas.textContent(), easy ? 'Gas' : 'Molla');
|
||||||
await page.screenshot({ path: `${out}/${name}-${level}.png` });
|
await page.screenshot({ path: `${out}/${name}-${level}.png` });
|
||||||
if (mobile) await page.locator('#bocce-throw').tap(); else await page.locator('#bocce-throw').click();
|
if (easy) await gas.dispatchEvent('pointerup', { pointerId: 5, pointerType: mobile ? 'touch' : 'mouse', isPrimary: true });
|
||||||
|
else await gas.click();
|
||||||
const v = await page.evaluate(() => game.closeup.riders.find(r => r.id === 'andrea').v);
|
const v = await page.evaluate(() => game.closeup.riders.find(r => r.id === 'andrea').v);
|
||||||
await page.waitForTimeout(300);
|
await page.waitForTimeout(300);
|
||||||
const after = await page.evaluate(() => game.closeup.riders.find(r => r.id === 'andrea').v);
|
const after = await page.evaluate(() => game.closeup.riders.find(r => r.id === 'andrea').v);
|
||||||
|
|||||||
Reference in New Issue
Block a user