The flick shows itself, the width is a dial, the blood stays on
Three asks. The placement ring: an aimed rally hit stamps a gold ring that fades where the shot is going — flick, watch it bite the corner, learn the cause. Not stamped for unaimed hits (marking scatter would teach noise), gone in 0.8s (a permanent ring reads as a target rather than feedback). The opponent's width is the ladder's third dial. Its returns scatter off aimError x (1 - quality), which painted lines from game one. matchWideBase 2.1 keeps opponent one inside what an auto-run player can cover — measured, 25 returns all inside +-2.2m — and matchWidePer earns 0.4m per rung, so line-painting is the late ladder. Speed, reliability, width: three dials. The blood vignette replaces the temporary border. The old wash flashed 0.3s and vanished, so between hits the screen said you were fine. A radial vignette reads G.hp directly now — its depth is your damage fraction, permanent until healed, hit pulse riding on top. Global: the hp channel is global. Same no-HP-bar philosophy one layer out; at 1 hp the frame is properly blood-rimmed and the court centre stays legible. 44 tests, 12 seeds clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d6df582cd4
commit
8ccf0a8fad
7 files changed
+81
-9
No files matched your search
@@ -589,6 +589,24 @@ test('the match recovers to CENTRE between shots — a wide return must not stra
|
||||
} finally { TUNE.autoAssist = assist; }
|
||||
});
|
||||
|
||||
test('the first opponent cannot paint lines: its returns are width-clamped', () => {
|
||||
// aimError x (1 - 0.55 quality) scattered returns to +-3.5 m, which an auto-run player cannot
|
||||
// cover — "still a LOT of unreachable balls". Width is the ladder's third dial now.
|
||||
assert.ok(TUNE.matchWideBase < 2.5, 'opponent one is kept inside reachable width');
|
||||
assert.ok(TUNE.matchWidePer > 0, 'and the width is earned back per rung');
|
||||
});
|
||||
|
||||
test('the placement mark fades on its own clock', () => {
|
||||
// The stamp itself lives inside doHit (aimed match hits only) and is exercised by play; what the
|
||||
// state machine owes is that a mark never lingers — a permanent ring would read as a target the
|
||||
// player must hit rather than feedback on where the last shot went.
|
||||
startMatch();
|
||||
for (let i = 0; i < 2.0 * 60; i++) update(DT);
|
||||
G.placeMark = { x: 2, z: 4, t: 0.8 };
|
||||
for (let i = 0; i < 60; i++) update(DT);
|
||||
assert.equal(G.placeMark, null, 'gone within a second');
|
||||
});
|
||||
|
||||
test('THE REAL DEATH LOOP: a toss after their rally touch is not their passing shot', () => {
|
||||
// tossBall left ball.lastHit stale. After any rally the zombie touched last, the fresh toss still
|
||||
// said lastHit 'O' — and the match serves from BEHIND the baseline (z 24.3), past the passing-shot
|
||||
|
||||
Reference in new issue
Block a user