The timing cues were match-only, and the walk cycles bounced
CLASSIC TENNIS, third time asked and this time actually found. Both cues open with a mode gate and I checked the wrong two features twice: drawApproachRing (the closing circles that show when to tap) and drawApexBand (the serve bar with the gold perfect window) each began `if (!G.match ...)`. So the mode whose whole pitch is "if the core tennis is good everything else is good" was the one mode with neither. They run on `G.match || G.mode === 'tennis'` now — the gore mode stays out on purpose, there is no rally there. A test reads both function bodies and fails if either is ever gated on the match alone again. (The two I kept pointing at — the landing ring and the placement ring — really are shared. They were just not the ones being asked about.) THE BOUNCING WAS IN THE ART, and measurable: the six generated families came back with the shuffle frame 30-44 px shorter than the stance it walks out of, against 9 px on the hand-made racket family. The game draws every frame at its own PNG height, so the body rose and dropped once per step. A walk cycle is one drawing with the legs moved and must be one height; _zsheet levels the stance and the stride pair now and leaves the forehand its own, exactly as the serve and the fall keep theirs. All seven families re-cut: spreads are 1-8 px. THE BENCH GETS BUTTONS. Arrow keys are not a control scheme on a phone, which is the device the walk has to be judged on — so every family and every wound stage was unreachable from the place the problem shows. Three on-screen pads: BODY, WOUND, POSE, the two-way ones split left/right. Geometry lives beside the drawing and input hit-tests the same function, the rule the rack established. THE FALL is quicker still (0.05/0.07/2.0/0.30): drop, lie there, get up. Three umpire lines pulled — ump_wound_you, ump_felled, ump_wound_opp2. Not funny enough to keep. Files deleted, call sites collapsed to the two that stay. 60 tests green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e1ce2486c0
commit
eb0e8775a4
46 files changed
+81
-8
No files matched your search
+3
-4
@@ -366,7 +366,7 @@ function matchReady() {
|
||||
// stumble; the beat only lands if it is down long enough to look beaten.
|
||||
// "fall quicker. lie there for 2s then stand up." The collapse is now a drop — two frames in a fifth
|
||||
// of a second — and the time is spent on the floor, where it reads.
|
||||
const FALL = [['fall1', 0.09], ['fall2', 0.11], ['fall3', 2.0], ['rise', 0.30]];
|
||||
const FALL = [['fall1', 0.05], ['fall2', 0.07], ['fall3', 2.0], ['rise', 0.30]];
|
||||
export const FALL_LEN = FALL.reduce((s, f) => s + f[1], 0);
|
||||
|
||||
function startFall(from) {
|
||||
@@ -473,7 +473,7 @@ function matchPoint(side) {
|
||||
// AFTER the score call, not under it. voice() drops any line that would start while the umpire
|
||||
// is still talking (one man, one microphone) — and matchPoint calls scoreKey() at 0.4 s with a
|
||||
// clip over a second long, so every one of these was being swallowed silently.
|
||||
aside(G.hp <= 2 ? 'ump_low_blood' : (score.pts[1] % 2 ? 'ump_wound_you2' : 'ump_wound_you'), 2.2);
|
||||
aside(G.hp <= 2 ? 'ump_low_blood' : 'ump_wound_you2', 2.2);
|
||||
if (G.hp <= 0) return killPlayer(); // eaten — the run summary, as ever
|
||||
}
|
||||
const over = advancePoint(side); // banks the game and resets the points itself
|
||||
@@ -484,7 +484,7 @@ function matchPoint(side) {
|
||||
// A LIMB IS WORTH A REMARK. Two lines, alternating on the stage taken, so the same sentence
|
||||
// never lands twice in one game — a repeated aside reads as a stuck HUD, the same reason the
|
||||
// praise words cycle rather than roll.
|
||||
aside(fellFrom ? 'ump_wound_opp2' : 'ump_wound_opp', 2.2); // ...after the score call, see above
|
||||
aside('ump_wound_opp', 2.2); // ...after the score call, see above
|
||||
return startFall(fellFrom); // it goes down, and gets up short of a limb
|
||||
}
|
||||
matchReady(); // next point, same opponent, both on their marks
|
||||
@@ -500,7 +500,6 @@ function matchGameWon(zb, banked = false) {
|
||||
G.runGames++; // the ladder metric, same as every mode
|
||||
G.hp = Math.min(G.hpMax, G.hp + TUNE.matchHeal); // a clean game is how you last
|
||||
voice('game_player', 0.3); cheer(2.4, 0.6);
|
||||
aside('ump_felled', 2.8); // ...after 'game', over the applause
|
||||
// GAME is the FLASH and the next opponent's name plate is the CARD. It used to be the other way
|
||||
// round and matchOpponent's plate landed on the same slot a frame later, so 'GAME.' never drew
|
||||
// once — and the plate is the better card anyway: it announces the win by replacing the loser.
|
||||
|
||||
Reference in new issue
Block a user