Difficoltà alle bocce e al biliardo, scelta nel dialogo con l'avversario: «Alla bona», «Seria», «A fassi male». Tarata con partite simulate contro un giocatore attento: al biliardo vince 9 su 12, circa 4 su 10 e quasi mai; alle bocce 72%, 50% e 35% delle mani. Battute nuove per Mariano e l'Ingegnere, test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ks2K99uqCZjAxvy7Rdj1R
This commit is contained in:
2026-10-25 23:46:46 +01:00
co-authored by Claude Opus 5.5
parent bd66ea45ad
commit 94e9da4009
25 changed files with 136 additions and 34 deletions
+1
View File
@@ -83,6 +83,7 @@ try {
game.go('circolo_4_maggio'); settle(game);
game.act('talk', 'ing_tozzi'); settle(game);
game.choose(game.options().findIndex(o => o.text.includes('una partita ai birilli'))); settle(game);
game.choose(game.options().findIndex(o => o.text === 'Seria.')); settle(game);
});
await page.waitForSelector('#bocce-controls:not([hidden])');
await page.waitForFunction(async () => {
+13
View File
@@ -251,7 +251,11 @@ test('al Circolo 4 Maggio: dal portone in piazza si entra nella sala, e al tavol
g.choose(g.options().findIndex(o => o.text === 'Ingegnere, una partita ai birilli?'));
const before = settle(g).map(s => s.text);
assert.ok(before.some(t => t.includes('Si va a venti')));
assert.deepEqual(g.options().map(o => o.text), ['Alla bona.', 'Seria.', 'A fassi male.'], 'prima si sceglie quanto fa sul serio');
g.choose(g.options().findIndex(o => o.text === 'A fassi male.'));
settle(g);
assert.equal(g.closeup?.id, 'biliardo');
assert.equal(g.closeup.level, 'male');
assert.equal(g.act('look', 'stecche'), false, 'durante la partita la scena non risponde');
const c = g.closeup;
assert.ok(g.closeupAim([VIEW.x + c.balls.cpu.x * VIEW.k, VIEW.y + c.balls.cpu.y * VIEW.k]), 'si mira sulla biglia avversaria');
@@ -270,7 +274,16 @@ test('al Circolo 4 Maggio: dal portone in piazza si entra nella sala, e al tavol
g.act('talk', 'ing_tozzi'); settle(g);
assert.ok(g.options().some(o => o.text === 'La rivincita?'), 'vinto, si chiede la rivincita');
g.choose(g.options().findIndex(o => o.text === 'La rivincita?')); settle(g);
g.choose(g.options().findIndex(o => o.text === 'Alla bona.')); settle(g);
assert.equal(g.closeup?.id, 'biliardo');
assert.equal(g.closeup.level, 'bona');
assert.ok(g.closeupClose());
assert.ok(settle(g).some(s => s.text.startsWith('Lasci a metà?')));
});
test('i livelli dell\'Ingegnere: «Alla bona» prova pochi colpi e trema, «A fassi male» li prova tutti', () => {
const bona = newBiliardo(1, { level: 'bona' }), male = newBiliardo(1, { level: 'male' }), none = newBiliardo(1);
assert.equal(none.level, 'seria', 'senza scelta si gioca sul serio');
assert.ok(bona.skill.wobble > male.skill.wobble * 3);
assert.ok(bona.skill.angles < male.skill.angles);
});
+14 -1
View File
@@ -1,6 +1,6 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { newBocce, press, release, update, powerAt, score, thrower, left, project, SWING, LANE, BALLS } from '../src/engine/bocce.js';
import { LEVELS, newBocce, press, release, update, powerAt, score, thrower, left, project, SWING, LANE, BALLS } from '../src/engine/bocce.js';
import { story } from '../src/story/story.js';
import { Game } from '../src/engine/game.js';
import { settle } from './helpers.mjs';
@@ -83,7 +83,11 @@ test('al pallaio: Mariano sfida, la mano si gioca nel primo piano; vincere vale
g.choose(g.options().findIndex(o => o.text.startsWith('Mariano! Facciamo')));
const before = settle(g).map(s => s.text);
assert.ok(before.some(t => t.includes('Brento Sanico')), 'la posta la dice prima');
assert.deepEqual(g.options().map(o => o.text), ['Alla bona.', 'Seria.', 'A fassi male.'], 'prima si sceglie quanto fa sul serio');
g.choose(g.options().findIndex(o => o.text === 'Seria.'));
settle(g);
assert.equal(g.closeup?.id, 'bocce');
assert.equal(g.closeup.level, 'seria');
assert.equal(g.act('look', 'pallaio'), false, 'durante la partita la scena non risponde');
// Si gioca la mano (le bocce di Andrea mirano al pallino); a mano finita il risultato si forza a favore.
const c = g.closeup;
@@ -108,7 +112,16 @@ test('al pallaio: Mariano sfida, la mano si gioca nel primo piano; vincere vale
assert.ok(g.options().some(o => o.text === 'La rivincita?') && g.options().some(o => o.text === 'Allora, Brento Sanico?'));
g.choose(g.options().findIndex(o => o.text === 'La rivincita?'));
settle(g);
g.choose(g.options().findIndex(o => o.text === 'A fassi male.'));
settle(g);
assert.equal(g.closeup?.id, 'bocce');
assert.equal(g.closeup.level, 'male');
assert.ok(g.closeupClose());
assert.ok(settle(g).some(s => s.text.startsWith('Già stanco?')));
});
test('i livelli di Mariano: alla bona si allarga, a fassi male boccia spesso', () => {
assert.equal(newBocce(1).level, 'seria');
assert.ok(LEVELS.bona.spread > LEVELS.seria.spread && LEVELS.seria.spread > LEVELS.male.spread);
assert.ok(LEVELS.male.attack > LEVELS.bona.attack);
});
+4
View File
@@ -375,6 +375,8 @@ try {
await clickScene(bocce, await hotspotCenter(bocce, 'mariano'));
await bocce.waitForFunction(() => game.dialogue && !game.busy, null, { timeout: 20000 });
await bocce.locator('#choices li', { hasText: 'Facciamo una partita' }).click();
await bocce.waitForFunction(() => game.options().some(o => o.text === 'Seria.'), null, { timeout: 30000 });
await bocce.locator('#choices li', { hasText: 'Seria.' }).click();
await bocce.waitForFunction(() => game.closeup?.id === 'bocce' && game.closeup.step === 'aim' && !game.speech, null, { timeout: 30000 });
const r = await bocce.locator('#scene').boundingBox();
await bocce.mouse.move(r.x + r.width / 2, r.y + r.height / 2);
@@ -405,6 +407,8 @@ try {
await clickScene(b, await hotspotCenter(b, 'ing_tozzi'));
await b.waitForFunction(() => game.dialogue && !game.busy, null, { timeout: 20000 });
await b.locator('#choices li', { hasText: 'una partita ai birilli' }).click();
await b.waitForFunction(() => game.options().some(o => o.text === 'Seria.'), null, { timeout: 30000 });
await b.locator('#choices li', { hasText: 'Seria.' }).click();
await b.waitForFunction(() => game.closeup?.id === 'biliardo' && game.closeup.step === 'aim' && !game.speech, null, { timeout: 30000 });
const r = await b.locator('#scene').boundingBox();
const [tx, ty] = await b.evaluate(async () => { const { VIEW } = await import('/src/engine/biliardo.js'); const V = game.closeup.balls.cpu; return [VIEW.x + V.x * VIEW.k, VIEW.y + V.y * VIEW.k]; });