Keep the praise word on screen, and take the cliff out of the groundstroke
Oliver on v371: the praise word is cut off on the left on the iPhone. It is centred under the player's feet, so out wide it ran past the edge; every pop is now clamped to the canvas by its measured width. Step 4, measured first. The rally sim gets a human bot (taps on the timed ring with a timing spread), a Climb mode and a lost-point breakdown. At level 26 the ladder falls over six rungs and then goes flat: nearly every lost point is the player's own early whiff, the CPU barely ever misses, and the auto-run reaches everything, so no opponent dial decides points. A quality ramp, a follow-through and CPU put-aways were each measured and reverted; the options go to Oliver in PROJECT.md. Shipped: in the rally modes q no longer drops from 1 to 0.43 one ms past PERFECT; it falls smoothly to the window's edge (TUNE.qSeamless). A tap 30 ms early is q 0.86 instead of 0.61. Same window, same whiff edge. v372. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d561050af8
commit
5dd5d71c33
7 files changed
+170
-9
No files matched your search
@@ -153,6 +153,9 @@ export const TUNE = {
|
||||
// screen: a short swipe is a safe half-court ball, and only a committed
|
||||
// one goes hunting the line, which is what makes going OUT a chosen risk.
|
||||
perfectMs: 45, // |offset from window center| for PERFECT
|
||||
qSeamless: 1, // rally modes: past perfectMs, q falls from 1 to the window edge with no step.
|
||||
// 0 = the old curve, 1 - off/half, which dropped a groundstroke 1 ms past
|
||||
// PERFECT straight to q 0.43 (step 4, 2026-10-14 — see gameplay.trySwing)
|
||||
// The tennis CPU only exists in the OPENING match (after the transition, tennis never comes
|
||||
// back — duels use racket* dials), so these three are the "how long until the first game is won"
|
||||
// knobs. Testers needed several games to get past him: softer cap, twice the whiffs, and
|
||||
|
||||
@@ -1687,6 +1687,15 @@ function trySwing(ch, isAI, qCap = TUNE.aiQualityMax) {
|
||||
const center = TUNE.swingWindup + win / 2;
|
||||
const off = Math.abs(t - center) / (win / 2);
|
||||
let q = Math.max(0.05, 1 - off);
|
||||
// ...WITHOUT A CLIFF in the rally modes (step 4, 2026-10-14). The line above runs from the centre, so
|
||||
// q was 1 inside perfectMs and 0.43 a millisecond outside it: a groundstroke's half-window is ~80 ms
|
||||
// and PERFECT owns 45 of them. The volley's 1.8x window used to hide that (q 0.69 at the edge); step
|
||||
// 1 made the rally groundstrokes, and a 30 ms early tap came back at q 0.6 (0.89 now). Same window,
|
||||
// same PERFECT, same whiff edge — only the step between them is gone. It does NOT move the ring bot's
|
||||
// win rate: points are decided by whiffs, not weak balls (see PROJECT.md, step 4's measurement).
|
||||
const p = TUNE.perfectMs / 1000, half = win / 2;
|
||||
if (rallyFeel() && !isAI && TUNE.qSeamless && half > p)
|
||||
q = Math.max(0.05, 1 - (Math.abs(t - center) - p) / (half - p));
|
||||
if (Math.abs(t - center) * 1000 < TUNE.perfectMs) q = 1;
|
||||
ch.facing = dx >= 0 ? 1 : -1; // forehand right (righty), backhand left → mirrored sprite
|
||||
// the LIVE swipe outranks the released one: since the crossing fires the swing (input.js), the
|
||||
|
||||
+5
-1
@@ -2883,7 +2883,11 @@ export function render() {
|
||||
ctx.save();
|
||||
ctx.globalAlpha = Math.min(1, f * 3); // holds, then a quick fade at the end
|
||||
ctx.font = B(13); ctx.textAlign = 'center'; ctx.textBaseline = 'top';
|
||||
shadowText(p.text, Math.round(pr.x), Math.round(pr.y - (p.still ? 0 : (1 - f) * 14)), p.col || '#ffffff');
|
||||
// kept on screen: a word under a player out wide (the rally's praise, v371) is centred on his feet,
|
||||
// and "SHOT OF THE DAY" off a man near the left tramline lost its first letters on the iPhone
|
||||
const hw = ctx.measureText(p.text).width / 2 + 3;
|
||||
const x = hw * 2 < W ? Math.min(W - hw, Math.max(hw, pr.x)) : W / 2;
|
||||
shadowText(p.text, Math.round(x), Math.round(pr.y - (p.still ? 0 : (1 - f) * 14)), p.col || '#ffffff');
|
||||
ctx.restore();
|
||||
}
|
||||
// (a PERFECT-contact spark ring lived here for one build — Oliver's verdict: too much. The
|
||||
|
||||
Reference in new issue
Block a user