Revert splatter rapid-fire serve; fix horde pose + re-trigger
Oliver's feedback on the feel pass: 1. Rapid-fire serving was way too easy. Reverted splatter serving to the proper model: a tap does the toss ritual (apex timing = quality), a flick is a quick aimed serve. Dropped the multi-ball barrage and removed the extraBalls plumbing (array, update, render, hooks). Melee swish and zombie homing stay. If multi-ball is wanted back, it should require a proper serve per ball. 2. The player was stuck in the serve/swing pose when a horde started (the triggering shot's pose lingered) — startHorde now clears it. 3. A horde re-triggered immediately: machine-gun kills scored points, so games were won mid-horde and the next kill after it ended won another game → instant new horde. A horde is now survival: it doesn't score (splatPoint skipped while G.horde), so it can't chain. After a horde you must win a full game again to summon the next. Verified via window.T: a tap tosses (not an instant serve) and the full toss→serve→rally completes; melee still kills adjacent shamblers; pose is idle/-1 at horde start; no scoring during a horde and the next kill after scores 15 without restarting it; tennis 11/12, bomb consume, homing all still green; no console errors. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
38035738ac
commit
bfaafe6727
4 files changed
+25
-49
No files matched your search
+3
-28
@@ -13,7 +13,6 @@ export const gore = []; // lawn decals {x, z, r, a} — the flat ground laye
|
||||
export const piles = []; // 3D-ish gore mounds {x, z, size 1..4, seed} — grow where kills cluster
|
||||
export const parts = []; // splatter particles {x, y, z, vx, vy, vz, t, dark}
|
||||
export const pellets = []; // machine-gun rounds during a horde {x, y, z, vx, vz, t}
|
||||
export const extraBalls = []; // earlier serves still in flight while you fire the next {x,y,z,vx,vy,vz,g,pow,bomb,bounces}
|
||||
|
||||
let spawnT = 1.5, moanT = 3;
|
||||
|
||||
@@ -40,7 +39,7 @@ function killZombie(i, quiet) {
|
||||
}); }
|
||||
splat();
|
||||
sendBoy(zb.x, zb.z); // a boy sprints out to mop
|
||||
splatPoint('P', quiet); // horde kills rate-limit the umpire so he doesn't machine-gun scores
|
||||
if (!G.horde) splatPoint('P', quiet); // a horde is survival — it doesn't score, so it can't chain into itself
|
||||
}
|
||||
|
||||
// swishing the racket cleaves any shambler in reach (the racket-zombie boss shrugs melee off)
|
||||
@@ -54,14 +53,6 @@ export function meleeSwipe(x, z, range) {
|
||||
return hit;
|
||||
}
|
||||
|
||||
// serving again while a ball still flies: stash the current one so it keeps killing (a barrage)
|
||||
export function stashExtraBall() {
|
||||
if (!ball.active) return;
|
||||
extraBalls.push({ x: ball.x, y: ball.y, z: ball.z, vx: ball.vx, vy: ball.vy, vz: ball.vz,
|
||||
g: ball.g, pow: ball.pow, bomb: ball.bomb, bounces: ball.bounces });
|
||||
if (extraBalls.length > 6) extraBalls.shift(); // cap the barrage
|
||||
}
|
||||
|
||||
function splatter(i, fanfare = true) { // the MAIN ball hit a zombie
|
||||
killZombie(i, !!G.horde);
|
||||
ball.vx *= TUNE.zPierce; ball.vz *= TUNE.zPierce; // keep enough pace to plow through the next
|
||||
@@ -150,7 +141,7 @@ export function updateZombies(dt) {
|
||||
splat(1);
|
||||
voice('game_set_massacre', 0.8);
|
||||
G.mode = 'eaten'; ball.active = false; G.flash = null; // zombies keep shambling for ambience
|
||||
G.horde = null; pellets.length = 0; extraBalls.length = 0; // the swarm stops; the eaten screen takes over
|
||||
G.horde = null; pellets.length = 0; // the swarm stops; the eaten screen takes over
|
||||
}
|
||||
if (ball.active && ball.lastHit === 'P' && ball.y < 1.9) {
|
||||
const d = Math.hypot(ball.x - zb.x, ball.z - zb.z);
|
||||
@@ -165,7 +156,7 @@ export function updateZombies(dt) {
|
||||
ball.vx *= 0.6; ball.vz *= 0.6; ball.lastHit = 'X'; // spent — one stagger per ball
|
||||
}
|
||||
}
|
||||
if (zb.z >= COURT.L + 0.7) { zombies.splice(i, 1); if (G.mode !== 'eaten') splatPoint('O', !!G.horde); } // it reached your baseline
|
||||
if (zb.z >= COURT.L + 0.7) { zombies.splice(i, 1); if (G.mode !== 'eaten' && !G.horde) splatPoint('O'); } // it reached your baseline
|
||||
}
|
||||
|
||||
for (let i = pellets.length - 1; i >= 0; i--) { // machine-gun rounds: flat, fast, one-shot kills
|
||||
@@ -177,22 +168,6 @@ export function updateZombies(dt) {
|
||||
if (hit || pe.t <= 0) pellets.splice(i, 1);
|
||||
}
|
||||
|
||||
for (let i = extraBalls.length - 1; i >= 0; i--) { // earlier serves keep arcing and killing
|
||||
const b = extraBalls[i];
|
||||
b.vy -= (b.g || TUNE.gravity) * dt;
|
||||
b.x += b.vx * dt; b.y += b.vy * dt; b.z += b.vz * dt;
|
||||
let done = false;
|
||||
if (b.y <= 0 && b.vy < 0) { b.y = 0; b.vy = -b.vy * TUNE.bounceY; b.vx *= TUNE.bounceXZ; b.vz *= TUNE.bounceXZ; b.bounces++;
|
||||
if (b.bomb) { explode(b.x, b.z); done = true; } }
|
||||
if (!done && b.y < 1.9) for (let j = zombies.length - 1; j >= 0; j--) {
|
||||
if (zombies[j].variant === 'r' || Math.hypot(zombies[j].x - b.x, zombies[j].z - b.z) >= 0.55) continue;
|
||||
if (b.bomb) { explode(b.x, b.z); done = true; }
|
||||
else if ((b.pow || 0) >= TUNE.zSplatQ) { killZombie(j, !!G.horde); b.vx *= TUNE.zPierce; b.vz *= TUNE.zPierce; }
|
||||
break;
|
||||
}
|
||||
if (done || b.bounces >= 2 || b.z < -2 || b.z > 25.5 || Math.abs(b.x) > 7.5) extraBalls.splice(i, 1);
|
||||
}
|
||||
|
||||
for (let i = parts.length - 1; i >= 0; i--) {
|
||||
const p = parts[i];
|
||||
p.t -= dt; p.vy -= 14 * dt;
|
||||
|
||||
Reference in new issue
Block a user