Clear the court of everything that is neither the puzzle nor the threat
"remove the mob boy - make the normal zombies rarer and not so close to the color gang". sendBoy refuses during a drill, guarded at the function rather than at the call sites — same shape as its existing G.interlude guard, so every present and future caller inherits it. He is one more body crossing the lanes you are reading colours down, and unlike everything else out there he is neither the puzzle nor the threat. Measured: 0 boy-frames in 90 seconds. Gore no longer gets mopped in this mode; the existing 40/30 caps are what bound it. The eaters are rarer — every 12s falling to 5s, capped at 3 on court. At the old rate they were a second crowd rather than an interruption, and a threat you break off to deal with only works if breaking off is occasional. 8 arrivals in 90s where the old numbers gave ~13. And they enter wide of the colour gang: best-of-9 lane sampling against the bibbed bodies, the same trick the batch uses. Narrowest clearance measured across 8 spawns was 0.91 m. They still converge on you afterwards — that is what they are for — this only decides where they walk in, so they stop screening the bodies you are trying to read. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d775ac40ec
commit
3379e83efc
5 files changed
+45
-8
No files matched your search
+8
-3
@@ -360,9 +360,14 @@ export const TUNE = {
|
||||
drillSpeed: 0.80, // m/s a bibbed body walks at the bottom of the ramp...
|
||||
drillSpeedMax: 1.9,// ...and at the top. Stamped per body AT SPAWN, so the ramp shows up as new
|
||||
// arrivals outpacing the ones already walking, not the court accelerating
|
||||
drillEaterEvery: 7.0, // s between unbibbed eaters at the bottom of the ramp...
|
||||
drillEaterMin: 2.2, // ...and at the top. THE difficulty dial now that the puzzle plays fair
|
||||
drillEaterMax: 4, // eaters allowed on court at once — past this the puzzle is unreadable
|
||||
// The eaters are RARE on purpose. At every 7 s / 2.2 s they were a second crowd rather than an
|
||||
// interruption, and the puzzle is the point of the mode — a threat you have to break off and deal
|
||||
// with only works if breaking off is occasional. They also enter wide of the colour gang
|
||||
// (spawnEater), because the one body out there that is neither the puzzle nor worth anything has
|
||||
// no business standing in front of the puzzle.
|
||||
drillEaterEvery: 12.0, // s between unbibbed eaters at the bottom of the ramp...
|
||||
drillEaterMin: 5.0, // ...and at the top. Still THE difficulty dial, just a slower one
|
||||
drillEaterMax: 3, // eaters allowed on court at once — past this the puzzle is unreadable
|
||||
drillEaterSpeed: 1.15,// they walk a touch faster than the batch: the batch is a list, this is a threat
|
||||
drillRampT: 210, // s to go from the bottom of every curve above to the top
|
||||
drillRingR: 0.62, // m — radius of the colour disc a bibbed body walks on. Big enough to read at
|
||||
|
||||
+13
-2
@@ -101,8 +101,19 @@ function spawnBatch(d) {
|
||||
// mode was missing.
|
||||
function spawnEater(d) {
|
||||
if (zombies.filter(z => z.bib === undefined).length >= TUNE.drillEaterMax) return;
|
||||
spawnZombie((Math.random() * 2 - 1) * TUNE.drillSpread, TUNE.drillSpawnZ + Math.random() * 0.8,
|
||||
Math.random() < 0.3 ? 'b' : 'a');
|
||||
// THEY ENTER WIDE OF THE COLOUR GANG. An eater walking in on top of the batch screens the very
|
||||
// bodies you are trying to read, and it is the one body on court that is neither the puzzle nor
|
||||
// worth points — so it has no business standing in front of the puzzle. Best-of-N: sample lanes
|
||||
// across the width and take the one furthest from every coloured body. They still converge on you
|
||||
// afterwards (that is what they are for); this only decides where they come IN.
|
||||
const gang = bibs();
|
||||
let bx = 0, bs = -1;
|
||||
for (let k = 0; k < 9; k++) {
|
||||
const x = -TUNE.drillSpread + (2 * TUNE.drillSpread) * (k / 8) + (Math.random() - 0.5) * 0.4;
|
||||
const s = gang.length ? Math.min(...gang.map(z => Math.abs(z.x - x))) : 1e9;
|
||||
if (s > bs) { bs = s; bx = x; }
|
||||
}
|
||||
spawnZombie(bx, TUNE.drillSpawnZ + Math.random() * 0.8, Math.random() < 0.3 ? 'b' : 'a');
|
||||
const zb = zombies[zombies.length - 1];
|
||||
zb.v = drillSpeed(d) * TUNE.drillEaterSpeed * (0.9 + Math.random() * 0.2);
|
||||
}
|
||||
|
||||
+6
-2
@@ -104,8 +104,9 @@ export const G = {
|
||||
interlude: false, // sudden-death duel vs the racket zombie: falsy, or {introT} while announcing
|
||||
duelLerp: 0, // 0..1 — how far the court has returned to tennis colors for the duel
|
||||
horde: null, // active horde wave {t, spawnT, mgT} — machine-gun racket, no serving
|
||||
drill: null, // the coaching drill (src/drill.js): {seq, step, faults, callT, beat, rush, won, lost, msg}.
|
||||
// Owns the court like every other mode — see beats.startDrill.
|
||||
drill: null, // the coaching drill (src/drill.js): {seq, step, faults, t, eaterT, rounds, lost, msg}.
|
||||
// Owns the court like every other mode — see beats.startDrill. `t` is time
|
||||
// survived and it is the whole difficulty curve; there is no round clock.
|
||||
killCount: 0, // splatter: kills banked toward the next point (see TUNE.killsPerPoint)
|
||||
runGames: 0, // games finished this run (either side) — the difficulty director
|
||||
sets: [0, 0], // splatter sets won [you, them]; 6 games = a set = a horde
|
||||
@@ -181,6 +182,9 @@ const mopWorthIt = () => gore.some(d => d.a >= 0.15 && d.z >= COURT.netZ - 2);
|
||||
|
||||
export function sendBoy(tx = ball.x, tz = ball.z, mop = G.mode === 'splatter') {
|
||||
if (G.interlude) return; // the sudden-death duel is clean tennis: nobody mops through it
|
||||
if (G.drill) return; // ...and nobody walks onto a drill. He is one more body crossing the
|
||||
// lanes you are reading colours down, and unlike everything else out
|
||||
// there he is not part of the puzzle OR the threat — pure noise.
|
||||
if (mop && !mopWorthIt()) return; // no job, no boy
|
||||
if (tz < -3 || tz > 27) return; // target left the field lengthwise, let it go
|
||||
// ONE boy, one slot. Every kill used to call this and teleport him back to the wing mid-stride,
|
||||
|
||||
Reference in new issue
Block a user