Exact touchdown, the boy finishes his shift, healing announces itself, 4K heads

Five of Oliver's six (the sixth is a play-mode discussion):
- THE DOUBLE FAULTS WERE FRAME QUANTIZATION: the bounce registered a full
  integration step after true contact — ~0.75 m of travel at serve pace — so
  serves aimed half a metre safe were judged long. Classic enforces the
  service box, the match only the court, hence 'zombie tennis does not'.
  The bounce now rewinds to y=0 before anything reads the position.
  Measured in-pane: 30/40 faults on good taps before, 0/40 after (mistimed
  and smudged taps also 0/40; aimed hard serves keep their scatter risk).
  Also: the strike flick dead zone is 44 px so a smudged tap stays a tap,
  and the aim base clamps 0.18 m inside the lines — scatter, not the aim,
  is what faults.
- The mop beat holds the walk-on until the boy actually LEAVES the court
  (ordered off at beat end, 6 s cap).
- A match game win that restores blood shows the duel's WOUNDS TREATED
  popup; full-blood wins stay silent.
- The opponent walk-on card holds 4.0 s (was 2.4).
- Card heads are cut from the 4K sheets at 144 px (assets/_heads.py,
  z_<fam>head.png, HEAD_CROP stays as fallback) — the old 65 px crops were
  the 'very low res' heads.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-13 21:09:04 +02:00
1 parent c847bcbfa1
commit c6218a6284
17 files changed
+178 -23

No files matched your search

+12 -5
View File
@@ -505,9 +505,13 @@ test('endDrill hands the court back', () => {
const startMatch = () => { const r = _startMatch(); G.modal = null; G.modalQ.length = 0; return r; };
const oppOf = () => zombies.find(z => z.variant === 'r');
// a won game now opens the MOP BEAT (TUNE.matchMopT) before the next opponent walks on —
// tests that play across a game boundary step through it here
const passMopBeat = () => { for (let i = 0; i < (TUNE.matchMopT + 1) * 60; i++) update(DT); };
// a won game now opens the MOP BEAT (TUNE.matchMopT) before the next opponent walks on — plus
// the boy's walk-off hold (he must LEAVE the court) and possibly the WOUNDS TREATED popup, which
// freezes the world until tapped. Tests that play across a game boundary step through all of it,
// dismissing popups the way a player would.
const passMopBeat = () => { // ...stopping at the walk-on: past it, the next opponent PLAYS
for (let i = 0; i < (TUNE.matchMopT + 8) * 60 && !oppOf(); i++) { G.modal = null; G.modalQ.length = 0; update(DT); }
};
test('a match owns the court like every other mode', () => {
assert.ok(startMatch(), 'a match starts on a clean court');
@@ -540,7 +544,10 @@ test('a point won tears a wound stage off the body; only the game point fells it
assert.ok(!oppOf(), 'no fresh opponent on the kill frame — the mop beat owns the court');
assert.ok(G.match.mopT > 0, 'the beat is armed');
assert.ok(G.interlude && G.interlude.introT > 0, 'and serving is barred for its whole length');
for (let i = 0; i < (TUNE.matchMopT + 1) * 10; i++) update(0.1);
// ...and the beat now also WAITS FOR THE BOY TO LEAVE the court before the walk-on
for (let i = 0; i < (TUNE.matchMopT + 2) * 10 && G.boy && Math.abs(G.boy.x) < 6.5; i++) update(0.1);
assert.ok(!oppOf(), 'still no opponent while the boy is on the court');
passMopBeat();
const next = oppOf();
assert.ok(next && next !== zb, 'a fresh opponent shambled on after the mop beat');
assert.equal(next.hpMax, TUNE.matchOppHp, 'same flat pool — the ladder escalates in speed/flub, not hp');
@@ -766,7 +773,7 @@ test('service alternates by game, and the opponent actually serves', () => {
for (let i = 0; i < 2 * 60 && G.matchFall; i++) update(DT); // let each collapse finish
}
assert.equal(score.server, 'O', 'their serve next game');
for (let i = 0; i < (TUNE.matchMopT + 1) * 60; i++) update(DT); // the mop beat holds the court first
passMopBeat(); // the mop beat (and the boy's exit) come first
// the opponent stands behind ITS baseline to serve, not on the receiving mark
const rz = zombies.find(z => z.variant === 'r');
assert.ok(rz.z < 1.0, 'it steps back to serve: z=' + rz.z.toFixed(2));