Pace was the missing dial, and the reachability test finally exists
"there are still balls which are basically not reachable with auto run.. please recheck" — and, asked twice: "did you write tests for the last issues we encountered?" The straight answer: no. The unreachable-balls issue only ever had config assertions, which is why it came back twice. Pace is the ladder's fourth dial. Width alone never fixed reachability because the returns left at ~27 m/s, crossing to the baseline in ~0.6s — less than auto-run needs from the far corner. matchOppPace 0.78 puts opponent one at ~20 m/s (measured live: twelve returns, 20.0-20.7), a quarter more flight time, and matchOppPacePer hands it back per rung. The vignette deepens: dmg x 0.8, cap 0.85, and the clean centre shrinks with damage instead of only the rim darkening. And the reachability regression the issue always deserved: a headless 90s autopilot soak asserting at least 10 returns sampled and at most 15% that never came within volley reach. Sabotage-verified. Its honest limit is recorded in PROJECT.md: the autopilot attends perfectly and taps frame-precisely, so it out-covers a human — it is a floor against catastrophic regressions, not a proxy for the thumb. Oliver's playtest stays the real gate. 46 tests, 15 seeds clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8ccf0a8fad
commit
fdbadce94d
6 files changed
+73
-4
No files matched your search
@@ -607,6 +607,43 @@ test('the placement mark fades on its own clock', () => {
|
||||
assert.equal(G.placeMark, null, 'gone within a second');
|
||||
});
|
||||
|
||||
test('REACHABILITY: an auto-run player can cover the first opponent\'s returns', () => {
|
||||
// The test this issue always deserved and never had — "unreachable balls" came back TWICE because
|
||||
// the suite only asserted the config dials, never the experience. This plays the match headless
|
||||
// with the same mediocre autopilot the browser uses (auto-run + a fixed tap window, no placement)
|
||||
// and asserts that the returns actually present themselves: a ball that never comes within volley
|
||||
// reach of an auto-run player is unreachable BY CONSTRUCTION, whatever the knobs claim.
|
||||
const assist = TUNE.autoAssist; TUNE.autoAssist = 1.15;
|
||||
try {
|
||||
startMatch();
|
||||
for (let i = 0; i < 2.2 * 60; i++) update(DT);
|
||||
const returns = [];
|
||||
let cur = null;
|
||||
for (let i = 0; i < 90 * 60 && G.mode !== 'eaten'; i++) {
|
||||
G.modal = null; G.modalQ.length = 0;
|
||||
if (G.phase === 'pretoss' && !(G.interlude && G.interlude.introT > 0)) { if (i % 40 === 0) keyPressed('Space'); }
|
||||
else if (G.phase === 'toss') { if (ball.vy < 0.4 && ball.y > 2.4) keyPressed('Space'); }
|
||||
else if (G.phase === 'rally' && ball.active && ball.lastHit === 'O') {
|
||||
const d = Math.hypot(ball.x - P.x, (ball.z - P.z) * 0.8);
|
||||
if (!cur) cur = { minD: 99 };
|
||||
cur.minD = Math.min(cur.minD, d);
|
||||
if (d < 2.9 && d > 2.2) keyPressed('Space');
|
||||
}
|
||||
if (cur && (!ball.active || ball.lastHit !== 'O')) { returns.push(cur.minD); cur = null; }
|
||||
update(DT);
|
||||
}
|
||||
assert.ok(returns.length >= 10, 'the soak saw a real rally sample: ' + returns.length + ' returns');
|
||||
const unreachable = returns.filter(d => d > 2.6).length; // never inside volley reach
|
||||
assert.ok(unreachable / returns.length <= 0.15,
|
||||
unreachable + ' of ' + returns.length + ' returns never came within reach of an auto-run player');
|
||||
} finally { TUNE.autoAssist = assist; }
|
||||
});
|
||||
|
||||
test('the ladder pace dial exists and starts below full pace', () => {
|
||||
assert.ok(TUNE.matchOppPace < 1, 'opponent one returns slower than the physics maximum');
|
||||
assert.ok(TUNE.matchOppPacePer > 0, 'and earns pace back per rung');
|
||||
});
|
||||
|
||||
test('THE REAL DEATH LOOP: a toss after their rally touch is not their passing shot', () => {
|
||||
// tossBall left ball.lastHit stale. After any rally the zombie touched last, the fresh toss still
|
||||
// said lastHit 'O' — and the match serves from BEHIND the baseline (z 24.3), past the passing-shot
|
||||
|
||||
Reference in new issue
Block a user