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:
wuwiandClaude Opus 5 committed 2026-08-17 08:21:18 +02:00
1 parent 0c90337f2d
commit c613b6ceba
7 files changed
+147 -21

No files matched your search

+18
View File
@@ -313,6 +313,9 @@ export const TUNE = {
// court — so every downward pull picked the same body and the angle felt inert.
// 0.10 gives ±2.9 m out there: you have to actually point at a lane.
pullHintAfter: 1.5, // s of doing nothing in the serve stance before the pull gesture demos itself
flickHintAfter: 4, // returns hit with no aim at all before the flick demos itself. Not 2 like the
// tap lesson: hitting flat is a legal shot, not a failure, so it takes a RUN
// of them to read as "he does not know the gesture exists"
aimTie: 0.12, // how much worse-aimed a NEARER body may be and still win the lane (0..1 of the
// cone half-width). 0 = pure best-aligned wins; 1 = the old "nearest in the
// lane always wins", which is what made the magnet grab the wrong shambler.
@@ -506,6 +509,13 @@ export const TUNE = {
matchFlub: 0.08, // the match's own whiff base — the duel's 0.2 gives away a fifth of all
// returns, which across a game is an opponent that beats itself
matchFlubKeep: 0.76, // ...and it keeps only this much per rung — the ladder now that hp is flat
// THE WOUNDS PLAY, not just show. The score is the body, so the body it has left should be worth
// something at the racket: a one-armed opponent cannot cover as much, a headless one whiffs more.
// Deliberately SMALL per stage (Oliver: "not too pronounced") — the ladder is still the difficulty
// curve and this is the point-to-point texture under it, worth ~12% reach and ~35% more whiff at
// the LAST stage, which is one point from falling anyway. Read through racketStage, never hp.
matchWoundReach: 0.06, // reach lost per wound stage (1 arm off, 2 headless) — match only
matchWoundFlub: 0.175, // ...and extra whiff earned per stage, on top of the rung's own rate
matchReach: 1.35, // contact reach multiplier in the MATCH. The recorder showed swings missing by
// centimetres point after point — the assist parks you near the ball, not inside
// a 1.3 m reach. A rally mode lives on contact feeling fair. Match-only
@@ -1112,6 +1122,14 @@ export const racketStage = zb => {
const f = zb.hp / (zb.hpMax || TUNE.racketHp);
return f <= 0.34 ? 2 : f <= 0.67 ? 1 : 0; // 0 unhurt, 1 arm off, 2 headless
};
// ...and what that stage COSTS it at the racket. One place, because racketAI reads it twice and two
// copies of a threshold is how the boss's skins and its blood drifted apart before. An unhurt body
// gets exactly 1 and 1, so the gore duel's racket zombie is untouched by this (see the G.match gate
// at the call sites — the duel is one sudden-death point and has no wound arc to express).
export const matchWound = zb => {
const st = racketStage(zb);
return { reach: 1 - TUNE.matchWoundReach * st, flub: 1 + TUNE.matchWoundFlub * st };
};
const POSES = ['bounce', 'toss', 'serve', 'fall1', 'fall2', 'fall3', 'rise'];
export const famFrames = f => [
`z_${f}1`, `z_${f}2`, `z_${f}3`, `z_${f}4`, // stance, shuffle A, shuffle B, forehand