The body plays the wounds it wears, and the flick finally has a teacher
Score-is-the-body was a picture: the opponent lost an arm and swung exactly as far, lost its head and missed exactly as often. Two dials now read the same racketStage the SKINS are picked with, so what you watch it lose is what it loses — deliberately small (6% reach, 17.5% whiff per stage), texture under the ladder rather than a second difficulty curve, with a test on that ceiling. An unhurt body still returns exactly 1 and 1, and the whole thing is gated on G.match: the gore duel's racket zombie is untouched. And the placement flick, the mode's one act of skill, was taught nowhere on touch — the placement ring is a receipt, not a lesson, and you only get one if you already knew to swipe. The ghost hand teaches it now, in the same register as PULL DOWN and TAP AS IT ARRIVES, riding the failure it answers: a run of returns that left with no aim on them. The tap lesson still wins when both qualify — placement is the wrong thing to teach someone who cannot reach the ball. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0c90337f2d
commit
c613b6ceba
7 files changed
+147
-21
No files matched your search
+35
-3
@@ -2136,6 +2136,32 @@ function drawHitHint() {
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// ---- ...and the lesson AFTER that one. The tap gets the ball back; the FLICK decides where it
|
||||
// goes, and wrong-footing the body across the net is how points are actually won. It was taught
|
||||
// nowhere on touch: the placement ring shows the result of a flick, which is a receipt, not a
|
||||
// lesson — if you never happen to swipe you never get one, so you never learn there was anything
|
||||
// to learn. Same ghost hand as every other gesture in this game, over the same shoulder, riding
|
||||
// the same failure it answers (a run of returns hit flat — doHit resets flatStreak the moment one
|
||||
// leaves with an aim on it). It mimes BOTH ways in turn or it teaches one corner.
|
||||
function drawFlickHint() {
|
||||
const cyc = 1.4, t = G.idleT % cyc;
|
||||
const dir = (((G.idleT / cyc) | 0) % 2) ? -1 : 1;
|
||||
const slide = Math.min(1, t / 0.8), gone = t > 0.95; // stroke, held a beat, lifted, repeat
|
||||
if (gone) return;
|
||||
const p0 = proj(P.x, 0, P.z);
|
||||
const hx = Math.round(p0.x), hy = Math.round(p0.y) - 52;
|
||||
ctx.save(); ctx.globalAlpha = 0.9;
|
||||
ctx.fillStyle = UI.dim; // the track the thumb travels
|
||||
for (let d = 10; d <= 38; d += 7) ctx.fillRect(hx + dir * d - 1, hy, 2, 2);
|
||||
drawGhostHand(hx + dir * (10 + 28 * slide), hy, 1); // starts clear of his own sprite
|
||||
ctx.font = F(10); ctx.textAlign = 'center'; ctx.textBaseline = 'top';
|
||||
// ...and the words sit ABOVE the stroke and OPPOSITE it: below is the player's own feet and the
|
||||
// BASELINE, and 10px type across a bright white line is the one place on this court it cannot be
|
||||
// read. Clamped off the screen edges too — this rides the player and he stands in the corners.
|
||||
shadowText('SWIPE AS YOU HIT', Math.max(52, Math.min(W - 52, hx - dir * 22)), hy - 26, UI.warm);
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
// The modal: drawn LAST, over everything, and the world behind it is frozen (gameplay.update
|
||||
// early-returns). Unlike drawCard this is a wall — nothing moves until it is tapped away.
|
||||
// easeOutBack: overshoots past the target and settles. The arcade snap — nothing in a cabinet
|
||||
@@ -2703,9 +2729,15 @@ export function render() {
|
||||
if (txt) shadowText(txt, W / 2, METER_Y(), UI.warm); // same slot the draw meter uses
|
||||
if (demo) drawPullHint(); // show the gesture instead of only naming it
|
||||
}
|
||||
// the one surviving tennis struggle hint: rides the exact failure it answers
|
||||
if (G.mode === 'tennis' && G.phase === 'rally' && G.passStreak >= 2 && ball.active && ball.lastHit === 'O')
|
||||
drawHitHint();
|
||||
// the tennis struggle hints: both ride the exact failure they answer, and only one at a time —
|
||||
// teaching the flick to someone who cannot get a racket on the ball is the wrong lesson, so the
|
||||
// tap always wins. The flick lesson also runs in the MATCH (G.match plays under splatter's
|
||||
// permanent interlude, not mode 'tennis') and on touch only: on a keyboard the aim is held keys,
|
||||
// and 'SWIPE' would be an instruction for a gesture that does not exist there.
|
||||
const inRally = G.phase === 'rally' && ball.active && ball.lastHit === 'O';
|
||||
if (G.mode === 'tennis' && inRally && G.passStreak >= 2) drawHitHint();
|
||||
else if (IS_TOUCH && inRally && (G.mode === 'tennis' || G.match) && G.flatStreak >= TUNE.flickHintAfter)
|
||||
drawFlickHint();
|
||||
// The free-floating register: no panel, one fixed slot, shouted. PERFECT, GAME N, DOUBLE KILL,
|
||||
// RETURNED, CHANGEOVER, weapon labels — everything that used to be plain white 12px text sitting
|
||||
// directly on the crowd. It keeps its 1px jitter; the shadow is what makes it legible anywhere.
|
||||
|
||||
Reference in new issue
Block a user