Tighten the returns, give each chapter its own boss, and let the umpire talk
Five reports from Oliver's second playtest. The parry was too generous — at 6 m of arm with a 0.34 s window the shot flew into reach on its own, so any tap once it was vaguely close worked. 3.4 m / 0.2 s / 1.7 m reach now: a tap at 4.5 m is rejected and costs blood, 3.2 m and in returns. The boss telegraphs in 0.5 s against the machine's 0.9 and throws harder, because a boss should be worse than furniture. His three balls were decoration: fanned ±1.9 m across space, so only the middle one could ever reach you. They are a timed salvo now — three shots 0.42 s apart, each aimed at where you are at that moment. hurtGrace still caps a whole volley at one point of damage, which is what it is for. Every chapter was the same boss. Three designs cycling now, each with its own sheet, stride, throw pose, wrecked skin and wrecked-throw skin: the GROUNDSKEEPER, the LINE JUDGE, the CHAIR UMPIRE with his chair strapped on. The chapter card names them. Designs are data in BOSS_ART, so a fourth is a sheet plus a row. Healing announces itself with a first-aid tin and a red cross instead of a 1.4 s flash. And 14 new umpire lines: ten sarcastic asides on a jittered timer, four hooked to specific beats. He still has not acknowledged that the match became a massacre, so he keeps officiating it. Two traps found and written into the pipeline notes. Sprite loads now carry ?v=SPRV, because python http.server sends no cache headers and the browser caches 404s — a name added before its PNG exists stays permanently missing for that browser. And a scripted replace that silently didn't match left drawZombie on the old hardcoded boss names while everything else moved to BOSS_ART; the built-in fallback hid it perfectly, all four designs rendering as design 1 with no error. Assert your rewiring edits matched. Tennis untouched: 30 tapped points, 50 hits / 0 whiffs. 45-game soak clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
295470b73c
commit
8bc57e9358
34 files changed
+180
-40
No files matched your search
@@ -72,9 +72,13 @@ export const TUNE = {
|
||||
// intended answer, on a phone, with one thumb, against something aimed at you — it has to be
|
||||
// forgiving. parryWindow must stay <= swingWindup + swingWindow*VOLLEY.window (0.348 s) or the
|
||||
// swing clock in update() expires before the window closes.
|
||||
parryArm: 6.0, // m — an incoming shot this close makes the next tap a SWING instead of a serve
|
||||
parryReach: 2.4, // m — how far off the racket a return still connects (normal volley reach is 1.82)
|
||||
parryWindow: 0.34, // s the return window stays open after the tap
|
||||
// TIGHTENED after Oliver's second playtest: "I can tap pretty early and it returns the ball".
|
||||
// At parryArm 6.0 / window 0.34 / reach 2.4 the shot flew INTO reach during the window, so any tap
|
||||
// once it was vaguely close worked and the timing stopped mattering. At 13 m/s a 3.4 m arm is about
|
||||
// 0.26 s of "the tap counts", which is a real reaction test and still landable one-thumbed.
|
||||
parryArm: 3.4, // m — an incoming shot this close makes the next tap a SWING instead of a serve
|
||||
parryReach: 1.7, // m — how far off the racket a return still connects (normal volley reach is 1.82)
|
||||
parryWindow: 0.2, // s the return window stays open after the tap
|
||||
// ---- chapter bosses: one every bossEvery games, escalating. The racket zombie is demoted to an
|
||||
// occasional opponent (racketEvery) so the boss is the only thing that reads as a wall.
|
||||
bossEvery: 10, // games between chapter bosses
|
||||
@@ -85,9 +89,17 @@ export const TUNE = {
|
||||
bossScalePer: 0.18, // ...growing per chapter, so chapter 4 towers
|
||||
bossSpeed: 0.42, // m/s it advances — slow, deliberate, unstoppable
|
||||
bossCycle: 2.6, // s between its ranged attacks (it uses the machine's projectile)
|
||||
bossVolley: 3, // shots per attack, fanned
|
||||
bossVolley: 3, // shots per attack — STAGGERED IN TIME, not fanned across space. Fanning them
|
||||
// +-1.9 m meant only the middle ball could ever reach you and the other two were
|
||||
// decoration; Oliver called that out. Three real threats in a rhythm instead.
|
||||
bossSalvoGap: 0.42, // s between the shots of one volley
|
||||
bossWind: 0.5, // s of telegraph before a boss throws — shorter than the machine's 0.9 on purpose:
|
||||
// he asked for a tighter reaction time, and a boss should be harder than furniture
|
||||
bossShotSpeed: 15.5, // m/s a boss throws at (the machine's is machSpeed 13)
|
||||
racketEvery: 3, // games between racket-zombie (plain opponent) spawns — was EVERY won game, which
|
||||
// is why he read as "the boss" and why a real boss would not have stood out
|
||||
asideEvery: 26, // s between the umpire's sarcastic asides in splatter (jittered +-40%). He never
|
||||
// acknowledged that the match had changed; now he comments on it, disapprovingly.
|
||||
racketHpPerGame: 0.12, // the racket zombie stiffens as the run goes on (floored into whole hp)
|
||||
// ---- damage. Bodies with hp (racket boss 'r', brute 'g') take damage in these units, so a big
|
||||
// boss is just a bigger hp number and every weapon stays proportional. Fractions are legal: they
|
||||
@@ -218,6 +230,24 @@ COURT.svcNear = COURT.netZ + 6.4; // near service line
|
||||
|
||||
// world sizes (meters)
|
||||
export const PLAYER_H = 1.88;
|
||||
// The chapter-boss ROSTER. One design per chapter, cycling — chapter 5 gets design 1 again, but at
|
||||
// far more hp and much bigger, so it still escalates. Each entry is pure DATA so adding a design is a
|
||||
// sheet plus a row here, never a change to drawZombie.
|
||||
// walk: two frames, stepped off DISTANCE COVERED (never time — see the animation invariant)
|
||||
// wounds: damage skins, healthiest first. However many there are, they are spread evenly over hp.
|
||||
// throws: the same states mid-throw, used while windT > 0. Index is clamped, so a design with
|
||||
// fewer throw frames than wound stages simply reuses its last one.
|
||||
// Every name must be ALL LOWERCASE and a whole word — see the case-collision note in the pipeline.
|
||||
export const BOSS_ART = [
|
||||
{ name: 'THE GROUNDSKEEPER', walk: ['z_boss1', 'z_boss2'],
|
||||
wounds: ['z_bossw1', 'z_bossw2', 'z_bossw3'],
|
||||
throws: ['z_bosst0', 'z_bosst1', 'z_bosst2', 'z_bosst3'] },
|
||||
{ name: 'THE LINE JUDGE', walk: ['z_judge1', 'z_judge2'],
|
||||
wounds: ['z_judgew'], throws: ['z_judget', 'z_judgewt'] },
|
||||
{ name: 'THE CHAIR UMPIRE', walk: ['z_chair1', 'z_chair2'],
|
||||
wounds: ['z_chairw'], throws: ['z_chairt', 'z_chairwt'] },
|
||||
];
|
||||
|
||||
export const MACH_H = 1.15; // a ball machine stands about waist high — it must read as furniture, not as a body
|
||||
export const BOY_H = 1.5; // was 1.2 — the mopping boy read as a distant speck at that scale
|
||||
// how far off-court a boy starts. The mop boy comes in from just off-screen (he is slow, and
|
||||
|
||||
Reference in new issue
Block a user