HARD hunts the corner you are not standing in

"the hard mode is still too easy — make it really challenging." The dial that
was missing is aim: the CPU rolled a random lane on every shot, so a third of
everything came politely back to your racket regardless of the other six
numbers. DIFFS grows `smart` — the probability the CPU plays the OPEN court,
the corner away from P.x — and HARD sets it to 0.8: four shots in five now
make you run. EASY and MEDIUM keep random aim (MEDIUM pinned by test), so
the shipped classic is untouched below the top chip.

The rest of HARD tightened in the same pass: reaction 0.22 s, speed 1.30,
reach 1.85 m, quality floored at 0.70 under a cap of 1.0, serve 1.15, flub
one ball in a hundred. It reads your shot almost instantly, covers what it
reads, and places its reply where you are not.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-14 12:02:49 +02:00
1 parent 77bc68043d
commit 1facc954e2
4 files changed
+18 -5

No files matched your search

+8 -1
View File
@@ -1174,8 +1174,15 @@ function trySwing(ch, isAI, qCap = TUNE.aiQualityMax) {
if (Math.abs(t - center) * 1000 < TUNE.perfectMs) q = 1;
ch.facing = dx >= 0 ? 1 : -1; // forehand right (righty), backhand left → mirrored sprite
const flick = isAI ? null : takeFlickAim();
// SMART AIM (G.diff.smart, classic difficulty): with this probability the CPU plays the OPEN
// COURT — the corner away from where you stand — instead of rolling a random lane. Random aim
// sends a third of everything straight back to your racket; hunting the open corner is what
// makes a hard CPU feel like it is PLAYING you. ax is an absolute court lane (see doHit).
const smart = isAI && G.diff && Math.random() < (G.diff.smart || 0);
const aim = isAI
? { ax: [ -1, 0, 1 ][Math.floor(Math.random() * 3)], az: Math.random() < 0.25 ? -1 : 0 }
? { ax: smart ? (P.x > 0.6 ? -1 : P.x < -0.6 ? 1 : (Math.random() < 0.5 ? -1 : 1))
: [ -1, 0, 1 ][Math.floor(Math.random() * 3)],
az: Math.random() < 0.25 ? -1 : 0 }
: flick || { ax: axisX(), az: axisZ() * (ch.side === 'P' ? 1 : -1) };
// G.diff (classic difficulty) moves the FLOOR too: a raised qMin is what makes HARD's every
// ball arrive with pace, where a cap alone just trims the best ones. Null outside classic, so