Splatter: ball economy — one ball, fetch it back, no more toss-spam
The slingshot serve didn't fix the gameplay because four things were free at once: pure-hold auto-target with predictive lead, a hardcoded 0.62 serve quality, infinite ammo with an instant mid-rally re-toss, and a melee swish on every single tap that cleaved the whole cluster. Perfecting the pretoss/toss rhythm beat the game; no skill required. The ball is scarce now. A spent ball LIES where it died (G.loose, ringed on court) and there is no serve until it's back in your hand: walk it down (instant, and the only reason to leave the baseline), let a boy scoop it, wait out TUNE.looseMax, or watch a shambler swallow it — the one real punishment. Fire rate is a positioning decision instead of a thumb-tempo one. Also: the far backstop rebounds a ball with pace left, still lethal on the way home and volleyable (trySwing lets P re-hit their own ball in splatter); melee drops to nearest-one-only on a 1s cooldown; and the mid-rally re-toss is gone. With no ball in hand the thumb-drag steers your legs instead of the reticle — without that, walking your ball down is impossible on touch. TUNE.looseMax is the fire-rate knob. Measured: ~4s per serve standing still, ~0.4s if you go and get it. 600 taps in 10s now yield exactly one serve. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
013fe8152d
commit
2787778ad2
6 files changed
+95
-35
No files matched your search
@@ -396,6 +396,7 @@ export function render() {
|
||||
if (l) drawRing(l.x, l.z, 'rgba(255,255,255,0.85)');
|
||||
}
|
||||
if (G.outMarker) drawRing(G.outMarker.x, G.outMarker.z, G.outMarker.out ? '#ff5050' : '#f8e048');
|
||||
if (G.loose) drawRing(ball.x, ball.z, '#f8e048'); // your ball is down there — go and get it
|
||||
// slingshot serve aim: an angry-birds dotted trajectory from the racket to the aim point;
|
||||
// red = the magnet has a zombie locked, yellow = a free spot on the court
|
||||
if (G.aim && G.mode === 'splatter' && !G.interlude && (G.phase === 'pretoss' || G.phase === 'toss' || G.phase === 'rally')) {
|
||||
@@ -434,14 +435,14 @@ export function render() {
|
||||
zombies.filter(zb => zb.z > COURT.netZ).sort((a, b) => a.z - b.z).forEach(drawZombie);
|
||||
|
||||
// server idly bouncing the ball while waiting
|
||||
if (G.phase === 'pretoss') {
|
||||
if (G.phase === 'pretoss' && !(G.mode === 'splatter' && (G.loose || G.fetchT > 0))) { // empty-handed = no ball to bounce
|
||||
const sv = score.server === 'P' ? P : O;
|
||||
const bx = sv.x - BOUNCE_IDLE.dx * (sv.side === 'P' ? 1 : -1);
|
||||
const by = Math.abs(Math.sin(G.idleT * BOUNCE_IDLE.tempo)) * BOUNCE_IDLE.apex;
|
||||
drawBall(bx, by, sv.z);
|
||||
}
|
||||
// the match ball (and any triple-serve side balls in flight)
|
||||
if ((ball.active || G.phase === 'over') && !ball.collected) drawBall(ball.x, ball.y, ball.z, true, ball.bomb, ball.flame);
|
||||
if ((ball.active || G.phase === 'over' || G.loose) && !ball.collected) drawBall(ball.x, ball.y, ball.z, true, ball.bomb, ball.flame);
|
||||
for (const e of extras) drawBall(e.x, e.y, e.z);
|
||||
// splatter particles (fire embers ride the same array)
|
||||
for (const pt of parts) {
|
||||
@@ -529,7 +530,9 @@ export function render() {
|
||||
const touch = IS_TOUCH, switchHint = touch ? 'TAP THE RACK TO SWITCH' : '1-5 TO SWITCH';
|
||||
const sel = ['PLAIN', 'BOMB', 'TRIPLE', 'FIRE', 'GUN'][G.weapon];
|
||||
const txt = G.mode === 'splatter'
|
||||
? (G.weapon === 4 ? (touch ? 'TAP TO UNLOAD THE GUN' : 'SPACE UNLOADS THE GUN')
|
||||
? (G.loose ? 'RUN YOUR BALL DOWN'
|
||||
: G.fetchT > 0 ? 'NEW BALLS PLEASE...'
|
||||
: G.weapon === 4 ? (touch ? 'TAP TO UNLOAD THE GUN' : 'SPACE UNLOADS THE GUN')
|
||||
: G.aim ? 'PULL BACK TO AIM · RELEASE TO FIRE'
|
||||
: G.weapon > 0 ? `SERVE FIRES: ${sel} · ${switchHint}`
|
||||
: touch ? 'TAP TO SERVE · PULL BACK TO AIM' : 'SPACE SERVES · ARROWS AIM')
|
||||
|
||||
Reference in new issue
Block a user