La Condor al campone delle poste: la gara col Taglia con la pistola ad aria compressa coi pallini gialli (fiato trattenuto, il pallino che cala con la distanza, cartone, lattine, bottigliette, palloncino e la lattina in aria), sfondo di Codex (Andrea)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GiECd9KMfjthRUnujCGSzZ
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import * as m from '../src/engine/condor.js';
|
||||
import { drawCondor } from '../src/engine/condor-render.js';
|
||||
import { Game, MINIGAMES } from '../src/engine/game.js';
|
||||
import { story } from '../src/story/story.js';
|
||||
import { settle } from './helpers.mjs';
|
||||
|
||||
// Ferma il respiro (il mirino va dove si punta), spara e aspetta che il pallino arrivi.
|
||||
function shot(c, x, y) {
|
||||
c.skill = { ...c.skill, sway: 0 }; c.aim = { x, y };
|
||||
assert.ok(m.shoot(c));
|
||||
for (let i = 0; i < 200 && c.step === 'flying'; i++) m.update(c, 1 / 60);
|
||||
return c.line;
|
||||
}
|
||||
// Aspetta la ricarica.
|
||||
const reload = c => { for (let i = 0; i < 120 && !m.canThrow(c) && c.step !== 'result'; i++) m.update(c, 1 / 60); };
|
||||
// Mira sopra quanto cala il pallino a quella distanza.
|
||||
const over = (x, y) => [x, y - m.DROP * m.far(x) ** 2];
|
||||
|
||||
test('il pallino cala con la distanza: al cartone poco, alla porta di più; si mira sopra', () => {
|
||||
const c = m.newCondor(1, { level: 'seria' });
|
||||
assert.ok(m.far(m.CARTONE.x) < m.far(560));
|
||||
assert.match(shot(c, ...over(m.CARTONE.x, m.CARTONE.y)), /10 punti/);
|
||||
assert.equal(c.holes.length, 1); reload(c);
|
||||
const b = c.bottles[1];
|
||||
assert.match(shot(c, b.x, m.BAR - 6), /prato/, 'mirando dritto alla bottiglietta in fondo si va sotto');
|
||||
reload(c);
|
||||
assert.match(shot(c, ...over(b.x, m.BAR - 6)), /Bottiglietta giù/);
|
||||
assert.ok(b.down); reload(c);
|
||||
const k = c.cans[0];
|
||||
assert.match(shot(c, ...over(k.x, m.BENCH - 6)), /Lattina giù/);
|
||||
assert.equal(c.points, 10 + m.BOTTLE.points + m.CAN.points);
|
||||
});
|
||||
|
||||
test('il palloncino scoppia; la lattina in aria del Taglia c\'è solo a seria e a fassi male', () => {
|
||||
const c = m.newCondor(2, { level: 'bona' });
|
||||
const at = m.balloon({ visual: { time: c.visual.time + m.flight(m.BALLOON.x) } });
|
||||
assert.match(shot(c, ...over(at.x, at.y)), /palloncino/);
|
||||
assert.ok(c.balloon.popped);
|
||||
for (let i = 0; i < 60 * 20; i++) m.update(c, 1 / 60);
|
||||
assert.equal(c.volo, null, 'alla bona il Taglia non tira niente in aria');
|
||||
const s = m.newCondor(3, { level: 'seria' });
|
||||
while (!s.volo) m.update(s, 1 / 60);
|
||||
// Si mira dove sarà la lattina quando arriva il pallino (lì, vicina, non cala).
|
||||
while (s.volo.t < 0.6) m.update(s, 1 / 60);
|
||||
s.skill = { ...s.skill, sway: 0 };
|
||||
let v = m.voloAt(s, s.volo.t + 0.3);
|
||||
for (let i = 0; i < 3; i++) v = m.voloAt(s, s.volo.t + m.flight(v.x));
|
||||
s.aim = { x: v.x, y: v.y }; m.shoot(s);
|
||||
for (let i = 0; i < 200 && s.step === 'flying'; i++) m.update(s, 1 / 60);
|
||||
assert.match(s.line, /al volo/); assert.equal(s.points, m.VOLO.points);
|
||||
});
|
||||
|
||||
test('trattenere il fiato ferma il mirino; troppo e il colpo parte da solo; il tocco secco mira soltanto', () => {
|
||||
const c = m.newCondor(4, { level: 'male' });
|
||||
assert.ok(m.aimScreen(c, [300, 150])); assert.deepEqual(c.aim, { x: 300, y: 150 });
|
||||
assert.ok(m.press(c, 1)); m.update(c, 0.05); assert.equal(m.release(c, 1), true); assert.equal(c.step, 'aim');
|
||||
assert.equal(m.steady(c), 1);
|
||||
m.press(c, 1);
|
||||
for (let i = 0; i < 60 * m.STILL; i++) m.update(c, 1 / 60);
|
||||
assert.ok(m.steady(c) < 0.35, 'fermo');
|
||||
assert.ok(m.release(c, 1)); assert.equal(c.step, 'flying'); assert.equal(c.left, m.PELLETS - 1);
|
||||
reload(c);
|
||||
m.press(c, 2);
|
||||
for (let i = 0; i < 60 * (m.BREATH + m.GASP + 0.2); i++) m.update(c, 1 / 60);
|
||||
assert.equal(c.holding, false); assert.equal(c.left, m.PELLETS - 2, 'senza fiato il colpo è partito');
|
||||
assert.ok(m.key(c, 'ArrowUp', true));
|
||||
});
|
||||
|
||||
test('finiti i pallini si confronta col Taglia: vince chi ha di più, pari se uguali', () => {
|
||||
for (const [points, winner] of [[50, 'player'], [null, 'draw'], [0, 'cpu']]) {
|
||||
const c = m.newCondor(5, { level: 'seria' });
|
||||
c.left = 1; c.points = points ?? c.taglia;
|
||||
shot(c, 600, 340); reload(c);
|
||||
assert.equal(c.step, 'result'); assert.equal(c.result.winner, winner);
|
||||
}
|
||||
});
|
||||
|
||||
test('il disegno della Condor non cambia lo stato', () => {
|
||||
const calls = [], ctx = new Proxy({}, { get: (o, k) => k in o ? o[k] : (...args) => calls.push([k, ...args]) });
|
||||
const c = m.newCondor(6, { level: 'male' }), bg = {};
|
||||
while (!c.volo) m.update(c, 1 / 60);
|
||||
const draw = () => { const before = structuredClone(c); drawCondor(ctx, c, story.closeups.condor, bg); assert.deepEqual(c, before); };
|
||||
draw(); assert.ok(calls.some(([op, img]) => op === 'drawImage' && img === bg));
|
||||
assert.ok(calls.some(([op, t]) => op === 'fillText' && t === 'LA CONDOR'));
|
||||
c.step = 'result'; c.result = { winner: 'player', points: 50, taglia: 44 }; calls.length = 0; draw();
|
||||
assert.ok(calls.some(([op, t]) => op === 'fillText' && t === 'BATTUTO IL TAGLIA!'));
|
||||
assert.ok(MINIGAMES.condor);
|
||||
});
|
||||
Reference in New Issue
Block a user