From 148da4713c62eab4e67e0f26667919f5c7e14894 Mon Sep 17 00:00:00 2001 From: Oliver Rieger Date: Mon, 13 Jul 2026 22:32:44 +0200 Subject: [PATCH] Zombies: organic approach, honest eaten radius; restore CPU strength MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Personal lane offset (homeOff ±0.8m) + a per-zombie shamble wobble so on your half they fan around you instead of stacking into one column. - Eaten check weights depth by 0.75 (z is foreshortened in the projection), so a head-on shambler kills you when it LOOKS on top of you — fixes "they touch me and I don't die." Lateral reach unchanged. - Revert aiFlub 0.14 -> 0.09 (undo the CPU weakening). Co-Authored-By: Claude Opus 4.8 --- config.js | 2 +- zombies.js | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/config.js b/config.js index cf3c775..08a9f22 100644 --- a/config.js +++ b/config.js @@ -14,7 +14,7 @@ export const TUNE = { serveSpeed: 21, serveQualitySpeed: 7, aimError: 2.4, // m of scatter at quality 0 perfectMs: 45, // |offset from window center| for PERFECT - aiQualityMin: 0.45, aiQualityMax: 0.85, aiFlub: 0.14, // ~86% of returns land (was 0.09) — a touch easier to beat + aiQualityMin: 0.45, aiQualityMax: 0.85, aiFlub: 0.09, aiReaction: 0.45, // s before the CPU reads your shot — well-aimed corners are winners autoAssist: matchMedia('(pointer: coarse)').matches ? 1.15 : 0, // auto-run speed factor (mobile) zSpeed: 0.7, // zombie shamble speed m/s diff --git a/zombies.js b/zombies.js index 6f8f60c..efb5612 100644 --- a/zombies.js +++ b/zombies.js @@ -19,7 +19,8 @@ let spawnT = 1.5, moanT = 3; export function spawnZombie(x, z, variant) { const ramp = 1 + Math.min(1.5, G.splatT / 70); // they get faster the longer you survive - const zb = { x, z, v: TUNE.zSpeed * ramp * (0.8 + Math.random() * 0.4), walkT: Math.random() * 9, variant }; + const zb = { x, z, v: TUNE.zSpeed * ramp * (0.8 + Math.random() * 0.4), walkT: Math.random() * 9, + homeOff: (Math.random() * 2 - 1) * 0.8, variant }; // personal lane offset so they don't stack into a column if (variant === 'f') { zb.v = Math.min(TUNE.runnerVMax, zb.v * TUNE.runnerSpeed); shriek(); } // shriek = the fairness contract; capped so late runners stay reactable if (variant === 'g') { zb.v *= 0.55; zb.hp = TUNE.bruteHp; } // slow, but soaks hits if (variant === 's') zb.shieldT = 0; // chair up; > 0 = seconds of stagger left @@ -184,11 +185,13 @@ export function updateZombies(dt) { zb.z += zb.v * dt; if (zb.shieldT > 0) zb.shieldT -= dt; // staggered chair comes back up when this runs out if (zb.variant === 'r') { /* the racket boss holds station — its AI owns its x */ } - else if (G.mode === 'splatter' && zb.z > COURT.netZ) // on YOUR half they home in on you - zb.x += Math.sign(P.x - zb.x) * Math.min(Math.abs(P.x - zb.x), zb.v * 0.7 * dt); - else + else if (G.mode === 'splatter' && zb.z > COURT.netZ) { // on YOUR half they close in — each on its own lane, not a column + const tx = P.x + zb.homeOff; + zb.x += Math.sign(tx - zb.x) * Math.min(Math.abs(tx - zb.x), zb.v * 0.7 * dt) + + Math.sin(zb.walkT * 2.3) * 0.25 * dt; // shamble wobble — the approach reads organic, not tracked + } else zb.x += Math.sin(zb.walkT * 1.7) * 0.15 * dt; // far half: aimless shamble - if (G.mode === 'splatter' && Math.hypot(zb.x - P.x, zb.z - P.z) < TUNE.eatenR + (zb.variant === 'g' ? 0.2 : 0)) { // it got you — touch is HONEST now: sprite overlap = eaten + if (G.mode === 'splatter' && Math.hypot(zb.x - P.x, (zb.z - P.z) * 0.75) < TUNE.eatenR + (zb.variant === 'g' ? 0.2 : 0)) { // z weighted down: depth is foreshortened, so a head-on shambler eats you when it LOOKS on top of you gore.push({ x: P.x, z: P.z, r: 0.9, a: 0.9 }); for (let k = 0; k < 30; k++) parts.push({ x: P.x, y: 1.1, z: P.z,