Schermo intero (pulsante accanto ai volumi e tasto F) e gioco fino a 2560 px; nei minigiochi la scena lascia lo spazio vero dei comandi; flipper: «Solo tavola», sul telefono senza pulsantiera e «Lascia stare» in alto, molla toccando al centro con «TIENI PREMUTO QUI», ponti rifatti da Codex; prove più salde (tressette)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GiECd9RWGMKV7n3K1mdy8T
This commit is contained in:
@@ -508,6 +508,22 @@ try {
|
||||
assert.ok(stage0.width >= 1200, `a 1280×860 la scena è larga ${stage0.width} px`);
|
||||
assert.ok(await page.evaluate(() => document.documentElement.scrollHeight <= innerHeight), 'la pagina scorre in verticale a 1280×860');
|
||||
assert.ok(await page.evaluate(() => [...document.querySelectorAll('#verbs button')].every(b => b.scrollWidth <= b.clientWidth + 1 && b.scrollHeight <= b.clientHeight + 1)), 'verbi tagliati a 1280×860');
|
||||
// Su uno schermo grande (1920×1080, a schermo intero) il gioco non si ferma più a 1280 px: prende tutta l'altezza.
|
||||
await page.setViewportSize({ width: 1920, height: 1080 });
|
||||
await page.waitForFunction(() => document.getElementById('stage').getBoundingClientRect().width > 1500);
|
||||
assert.ok(await page.evaluate(() => document.documentElement.scrollHeight <= innerHeight && document.getElementById('app').getBoundingClientRect().height >= innerHeight - 2), 'a 1920×1080 il gioco prende tutta l\'altezza, senza scorrere');
|
||||
await page.setViewportSize({ width: 1280, height: 860 });
|
||||
// Schermo intero: il pulsante accanto ai volumi e il tasto F, per entrare e per uscire.
|
||||
if (await page.evaluate(() => document.fullscreenEnabled)) {
|
||||
await page.click('#fullscreen-hud');
|
||||
await page.waitForFunction(() => !!document.fullscreenElement && document.getElementById('fullscreen-hud').getAttribute('aria-pressed') === 'true');
|
||||
await page.keyboard.press('f');
|
||||
await page.waitForFunction(() => !document.fullscreenElement);
|
||||
await page.keyboard.press('F');
|
||||
await page.waitForFunction(() => !!document.fullscreenElement);
|
||||
await page.click('#fullscreen-hud');
|
||||
await page.waitForFunction(() => !document.fullscreenElement && document.getElementById('fullscreen-hud').getAttribute('aria-pressed') === 'false');
|
||||
} else assert.ok(await page.evaluate(() => document.getElementById('fullscreen-hud').hidden), 'senza schermo intero il pulsante sparisce');
|
||||
// Pausa: Esc o il pulsante fermano il gioco; Riprendi torna dov'eri; il titolo offre «Continua».
|
||||
await page.keyboard.press('Escape');
|
||||
await page.waitForSelector('#pause:not([hidden])');
|
||||
|
||||
+20
-11
@@ -25,16 +25,31 @@ try {
|
||||
game.act('use', 'river'); settle(game);
|
||||
game.choose(game.options().findIndex(o => o.text.startsWith('Una partita alla bona'))); settle(game);
|
||||
});
|
||||
await page.waitForSelector('#bocce-controls:not([hidden])');
|
||||
await page.waitForSelector('#bocce-controls:not([hidden])', { state: 'attached' });
|
||||
await page.waitForFunction(async () => (await import('/src/engine/render.js')).hasBackground('assets/closeups/river-flipper.png'));
|
||||
// Aspetta che finisca la dissolvenza d'ingresso: le immagini devono mostrare i colori della tavola.
|
||||
const readyAt = await page.evaluate(() => game.closeup.visual.time);
|
||||
await page.waitForFunction(t => game.closeup.visual.time > t + 1, readyAt);
|
||||
assert.equal(await page.locator('#scene').getAttribute('width'), '1280', 'il flipper usa la risoluzione doppia');
|
||||
assert.equal(await page.locator('#bocce-throw').textContent(), 'Lancia');
|
||||
assert.ok(await page.locator('#flipper-help').isVisible());
|
||||
assert.equal(await page.locator('#bocce-left').textContent(), '← Flipper');
|
||||
assert.ok(!(await page.locator('#bocce-left').isDisabled()), 'i pulsanti dei flipper sono attivi anche prima del lancio');
|
||||
if (!mobile) {
|
||||
// «Solo tavola»: la pulsantiera sparisce e la tavola si allarga; ripremuto, torna tutto com'era.
|
||||
const before = (await page.locator('#scene').boundingBox()).width;
|
||||
await page.click('#table-only');
|
||||
await page.waitForFunction(() => getComputedStyle(document.getElementById('side')).display === 'none');
|
||||
await page.waitForFunction(w => document.getElementById('scene').getBoundingClientRect().width > w + 50, before);
|
||||
assert.equal(await page.locator('#table-only').textContent(), 'Pulsantiera');
|
||||
await page.click('#table-only');
|
||||
await page.waitForFunction(() => getComputedStyle(document.getElementById('side')).display !== 'none');
|
||||
assert.ok(await page.locator('#flipper-help').isVisible());
|
||||
assert.equal(await page.locator('#bocce-left').textContent(), '← Flipper');
|
||||
assert.ok(!(await page.locator('#bocce-left').isDisabled()), 'i pulsanti dei flipper sono attivi anche prima del lancio');
|
||||
} else {
|
||||
// Sul telefono in orizzontale (Andrea): niente pulsantiera, la scena larga sotto i due pollici.
|
||||
assert.ok(!(await page.locator('#side').isVisible()), 'sul telefono la pulsantiera del flipper sparisce');
|
||||
const w = (await page.locator('#scene').boundingBox()).width;
|
||||
assert.ok(w > viewport.width * 0.6, `sul telefono la scena del flipper è larga ${w} px`);
|
||||
}
|
||||
await page.screenshot({ path: `${out}/${name}-tavola.png` });
|
||||
const box = await page.locator('#scene').boundingBox(), P = (x, y) => [box.x + x / 640 * box.width, box.y + y / 360 * box.height];
|
||||
if (!mobile) await page.screenshot({ path: `${out}/desktop-dettaglio.png`, clip: { x: P(200, 0)[0], y: box.y, width: 248 / 640 * box.width, height: box.height } });
|
||||
@@ -42,7 +57,7 @@ try {
|
||||
const touch = (type, points) => cdp.send('Input.dispatchTouchEvent', { type, touchPoints: points.map(([x, y]) => ({ x, y })) });
|
||||
// La molla: tenendo premuto sulla scena, col mouse e col dito.
|
||||
if (mobile) {
|
||||
await touch('touchStart', [P(440, 320)]);
|
||||
await touch('touchStart', [P(320, 320)]); // al centro: la molla
|
||||
await page.waitForFunction(() => game.closeup.holding && game.closeup.power > 0.3, null, { polling: 'raf' });
|
||||
await touch('touchEnd', []);
|
||||
} else {
|
||||
@@ -63,12 +78,6 @@ try {
|
||||
await page.waitForFunction(() => game.closeup.flippers.left.held.length === 0 && game.closeup.flippers.right.held.length > 0, null, { timeout: 3000 });
|
||||
await touch('touchEnd', []);
|
||||
await page.waitForFunction(() => game.closeup.flippers.right.held.length === 0);
|
||||
// I pulsanti tenuti premuti.
|
||||
const b = await page.locator('#bocce-left').boundingBox();
|
||||
await touch('touchStart', [[b.x + b.width / 2, b.y + b.height / 2]]);
|
||||
await page.waitForFunction(() => game.closeup.flippers.left.held.length > 0);
|
||||
await touch('touchEnd', []);
|
||||
await page.waitForFunction(() => game.closeup.flippers.left.held.length === 0);
|
||||
} else {
|
||||
await page.mouse.move(...P(400, 200)); await page.mouse.down();
|
||||
await page.waitForFunction(() => game.closeup.flippers.right.held.length > 0);
|
||||
|
||||
@@ -130,13 +130,17 @@ test('funghi, bersagli, Regolo e corsie fanno punti solo a un urto nuovo; le qua
|
||||
assert.ok(!c.lanes[1].lit);
|
||||
});
|
||||
|
||||
test('comandi: la molla si carica e si lancia lasciando; annullare non lancia; due dita, pulsanti e tasti', () => {
|
||||
test('comandi: la molla si carica al centro e si lancia lasciando, ai lati le palette anche prima del lancio; annullare non lancia; due dita, pulsanti e tasti', () => {
|
||||
const c = m.newFlipper(8, { level: 'bona' });
|
||||
m.aimScreen(c, [440, 320]); assert.ok(m.press(c, 1)); run(c, 0.6);
|
||||
// A pallina ferma i lati alzano le palette, il centro carica la molla.
|
||||
m.aimScreen(c, [120, 300]); assert.ok(m.press(c, 5)); assert.ok(c.flippers.left.held.includes(5) && !c.holding, 'a sinistra, la paletta');
|
||||
m.aimScreen(c, [520, 300]); assert.ok(m.press(c, 6)); assert.ok(c.flippers.right.held.includes(6) && !c.holding, 'a destra, la paletta');
|
||||
m.release(c, 5); m.release(c, 6); assert.ok(m.waiting(c));
|
||||
m.aimScreen(c, [320, 320]); assert.ok(m.press(c, 1)); run(c, 0.6);
|
||||
assert.ok(c.holding && c.power > 0.4 && c.power < 0.6, `molla a ${c.power.toFixed(2)}`);
|
||||
assert.ok(!m.release(c, 2), 'un altro dito non lancia');
|
||||
m.cancel(c, 1); assert.ok(m.waiting(c) && !c.holding, 'annullata la carica: niente lancio');
|
||||
m.aimScreen(c, [440, 320]); m.press(c, 1); run(c, 0.6); assert.ok(m.release(c, 1)); assert.ok(!m.waiting(c));
|
||||
m.aimScreen(c, [300, 320]); m.press(c, 1); run(c, 0.6); assert.ok(m.release(c, 1)); assert.ok(!m.waiting(c));
|
||||
m.aimScreen(c, [250, 200]); assert.ok(m.press(c, 3)); assert.ok(c.flippers.left.held.includes(3));
|
||||
m.aimScreen(c, [400, 200]); assert.ok(m.press(c, 4)); assert.ok(c.flippers.right.held.includes(4));
|
||||
assert.ok(m.release(c, 3)); assert.ok(!c.flippers.left.held.length && c.flippers.right.held.includes(4));
|
||||
|
||||
@@ -13,18 +13,32 @@ async function tap(page, mode, selector) {
|
||||
if (mode === 'touch') { const r = await page.locator(selector).boundingBox(); await page.touchscreen.tap(r.x + r.width / 2, r.y + r.height / 2); }
|
||||
else await page.click(selector);
|
||||
}
|
||||
// Una battuta che compare proprio in quell'istante (le battute del giocatore partono dal ciclo del gioco) si prende il
|
||||
// tasto e la salta, come nel gioco: allora, come un giocatore, si ripreme. Al più tre volte.
|
||||
async function pressUntil(page, key, done, arg) {
|
||||
for (let i = 0; i < 3; i++) {
|
||||
await page.keyboard.press(key);
|
||||
if (await page.evaluate(done, arg)) return;
|
||||
await page.waitForFunction(() => !game.speech);
|
||||
}
|
||||
}
|
||||
async function playCard(page, mode, index, signal) {
|
||||
// Un tasto premuto mentre qualcuno parla salta la battuta e basta (come nel gioco): si aspetta che abbia finito.
|
||||
if (mode === 'keyboard') await page.waitForFunction(() => !game.speech);
|
||||
// Un tasto premuto mentre qualcuno parla salta la battuta e basta, e il segnale si sceglie solo quando tocca a noi
|
||||
// (come nel gioco): si aspetta che la battuta sia finita e che si possa giocare.
|
||||
if (mode === 'keyboard') {
|
||||
await page.evaluate(async () => { window.tressetteRules ??= await import('/src/engine/tressette.js'); });
|
||||
await page.waitForFunction(() => !game.speech && tressetteRules.canPlay(game.closeup));
|
||||
}
|
||||
if (signal) {
|
||||
if (mode === 'keyboard') await page.keyboard.press(signal[0]);
|
||||
if (mode === 'keyboard') await pressUntil(page, signal[0], s => game.closeup.signal === s, signal);
|
||||
else await tap(page, mode, `#tressette-${signal}`);
|
||||
assert.equal(await page.evaluate(() => game.closeup.signal), signal);
|
||||
}
|
||||
if (mode === 'keyboard') {
|
||||
await page.keyboard.press(String((index + 1) % 10));
|
||||
await pressUntil(page, String((index + 1) % 10), i => game.closeup.selected === i, index);
|
||||
assert.equal(await page.evaluate(() => game.closeup.selected), index);
|
||||
await page.keyboard.press('Enter');
|
||||
const held = await page.evaluate(() => game.closeup.hands[0].length);
|
||||
await pressUntil(page, 'Enter', n => game.closeup.hands[0].length < n || !!game.closeup.refused, held);
|
||||
return;
|
||||
}
|
||||
const at = await page.evaluate(async i => {
|
||||
|
||||
Reference in New Issue
Block a user