The receiver stands where the serve can actually go
The trick: hard serve, slight slide, and the first ten opponents died where they stood. Measured headless — that serve was returned 0 times out of 24 at EVERY rung. Three things were wrong and all three were the same thing: he waited on the tennis mark 1.3 m off the centre line (covering the T, conceding the whole corner), he took no first step, and he chased the ball's LIVE position, which during a serve is still up by the server's baseline. Now: he waits on the bisector of the serves he has to cover, takes a returner's first step (serve-scoped — the rally is untouched), and runs at the bounce instead of at the ball. The slid serve comes back from rung one; a flush serve into the very corner of the box still aces the bottom of the ladder, which is the reward placement is supposed to earn. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ece27827e5
commit
86b8275f5d
6 files changed
+77
-10
No files matched your search
@@ -84,7 +84,7 @@ globalThis.getComputedStyle = () => ({ paddingTop: '0' });
|
||||
// ---- game modules (real code) ----------------------------------------------
|
||||
const state = await import('./src/state.js');
|
||||
const { G, P, O, score, ball, setupPoint } = state;
|
||||
const { update, forceZombies, startGore, splatPoint, restartRun, flickTarget, keyPressed, classicGame, serveApexY, assistK, rallyFeel, barrelGap, machCap } = await import('./src/gameplay.js');
|
||||
const { update, forceZombies, startGore, splatPoint, restartRun, flickTarget, keyPressed, classicGame, serveApexY, assistK, rallyFeel, barrelGap, machCap, hitServe } = await import('./src/gameplay.js');
|
||||
const { startDuel, resolveInterlude, startBossFight, endBossFight, startDrill: _startDrill, endDrill, startMatch: _startMatch, endMatch, FALL_LEN, startNetVs, endNetVs } = await import('./src/beats.js');
|
||||
const { mirror, netMsg, netTest, netTick } = await import('./src/net.js');
|
||||
// the drill's first-sight modal freezes the world (that is what modals do) — dismiss it the way a
|
||||
@@ -1083,6 +1083,37 @@ test('REACHABILITY: an auto-run player can cover the first opponent\'s returns',
|
||||
} finally { TUNE.autoAssist = assist; }
|
||||
});
|
||||
|
||||
test('a served ball with a slide on it is no longer a free kill', () => {
|
||||
// Oliver: "the moment you serve you can serve hard with a slight slide and almost all of them
|
||||
// fail to get the ball" — the first ten opponents died to one gesture. Measured before the fix:
|
||||
// a flush, hard, swayed serve was returned 0 times out of 24 at EVERY rung of the ladder, because
|
||||
// the receiver waited on the tennis mark (1.3 m off the centre line, covering the T and conceding
|
||||
// the whole corner) and then chased the ball's LIVE position, which during a serve is still up by
|
||||
// the server's baseline. Mark, first step and read are all dialled in config; this asserts the
|
||||
// EXPERIENCE, not the dials, exactly like the reachability soak above.
|
||||
// A serve into the very corner of the box is deliberately still an ace at the bottom of the
|
||||
// ladder — the trick that had to die is the one that needed no placement.
|
||||
const serve = sx => {
|
||||
freshSplatter();
|
||||
startMatch();
|
||||
for (let i = 0; i < 2.2 * 60; i++) update(DT);
|
||||
ball.active = true; ball.collected = false; ball.bounces = 0; ball.scored = false;
|
||||
ball.x = P.x + 0.12; ball.z = P.z; ball.y = 2.6; ball.vx = ball.vy = ball.vz = 0;
|
||||
G.wasServe = true;
|
||||
hitServe(P, 1, { sx, hard: 1 }); // flush timing, full pace, `sx` of slide
|
||||
for (let i = 0; i < 5 * 60; i++) {
|
||||
update(DT);
|
||||
if (ball.lastHit === 'O') return true; // he got a racket on it
|
||||
if (!ball.active || G.phase !== 'rally') break;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
let got = 0;
|
||||
const n = 10;
|
||||
for (let i = 0; i < n; i++) if (serve(-0.5)) got++;
|
||||
assert.ok(got >= n * 0.6, `opponent one returns a slid serve: ${got}/${n} (was 0)`);
|
||||
});
|
||||
|
||||
test('the match racket is longer, and only the match racket', () => {
|
||||
assert.ok(TUNE.matchReach > 1.2, 'match contact reach is widened — the recorder showed misses by centimetres');
|
||||
// the gore modes' contact stays untouched: matchReach only multiplies inside G.match
|
||||
|
||||
Reference in new issue
Block a user