You aim it yourself now, and no two rounds are dealt alike
Oliver played it: "the auto aim just mean no skills involved at all. this should just go away.. there is no penalty at the moment.. make some variations of the position on the court and the color". The first two notes are one finding. With the shot locked to the called body it was unmissable, so the fault could never fire — there was no penalty because there was no way to earn one. Both snaps are deleted. What replaced them is one line: aimTie is 0 during a drill. That is not auto-aim, it is removing the guess — the ordinary magnet lets a nearer body inside the same cone steal a shot aimed past it, which is right for a crowd you are mowing down and exactly wrong where hitting the wrong body IS the failure. An unaimed tap now lands on grass. And the variation: - six colours (purple, white) with the court dealt three to five of them, so which colours turn up and how many decoys there are are live questions. At four out of four every round dealt every colour and only the order moved. - PLACEMENTS: fan, cluster, column, stagger, wing — weighted, mirrored per round, lanes shuffled against the bib order. column stacks bodies in one lane, and the ball hits the first thing it touches, so feet matter. - pips are dice faces now, shared by bib and HUD chip. A row of five dots has to be counted; a die is recognised. Measured over 30 deals: all five shapes, counts even, all six colours, and the first target screened by another body in ~10% of rounds. Verified end to end in the browser that FAULT and DOUBLE FAULT both fire. 26 tests, including a named regression for the auto-aim staying gone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
22df96cc1d
commit
ef8a413031
10 files changed
+173
-64
No files matched your search
+8
-19
@@ -5,7 +5,7 @@ import { P, O, ball, score, crowd, G, court, other, deuceSide, setupPoint, sendB
|
||||
import { audio, pock, swish, whoosh, applause, voice, sfx, aww, zombieMusic, zombieDuck, menuDuck, splat, shriek, boom } from './audio.js';
|
||||
import { axisX, axisZ, takeFlickAim, touchPX, resetInput } from './input.js';
|
||||
import { W } from './render.js'; // runtime-only cycle (render imports gameplay), same pattern as input/zombies
|
||||
import { updateDrill, drillTarget } from './drill.js';
|
||||
import { updateDrill } from './drill.js';
|
||||
import { updateZombies, updateParts, spawnZombie, spawnRacketZombie, spawnMachine, spawnChapterBoss, zombies, gore, explode, meleeSwipe, extras, parts, pellets, shots, playerGore, eatenBleed, resetZombies , firePellet , spawnBarrel , fireBeam , pops, popText } from './zombies.js';
|
||||
import { proceedAfterClear, startDuel, startHorde, warnHorde, resolveInterlude, watchdog } from './beats.js'; // runtime-only cycle: beats calls back into cheer/aside/endBurst/deliverTin/showModal/logSwing
|
||||
|
||||
@@ -73,16 +73,12 @@ function dustPuff(x, z, n = 5, sp = 1) {
|
||||
export function flickTarget(ch, aim) { // exported: render draws the live reticle with it
|
||||
const q = pullQuality(aim.mag), f = pullFrac(aim.mag);
|
||||
if (aim.mag < TUNE.pullMin) return { q, f }; // barely drawn: no lane yet, so no target
|
||||
// THE DRILL SNAPS. Ordinary splatter wants a forgiving magnet (one thumb, a moving crowd); the
|
||||
// drill's whole subject is WHICH body, so the magnet must never pick one for you — it locks to
|
||||
// the called target and to nothing else. The shot can still be BLOCKED by a body standing in the
|
||||
// lane (updateZombies hits the first thing the ball touches), which is the footwork half of the
|
||||
// mode and is deliberately left alone: sidestep to open the angle.
|
||||
if (G.drill) {
|
||||
const zt = drillTarget();
|
||||
if (!zt) return { q, f, tx: ch.x + aim.fx * TUNE.aimReach, tz: ch.z + aim.fy * TUNE.aimReach };
|
||||
return { q, f, zt, tx: zt.x, tz: zt.z };
|
||||
}
|
||||
// NO AUTO-AIM IN THE DRILL. This used to lock the shot to the called body wherever you pointed,
|
||||
// and Oliver's verdict was the only one it could be: "no skills involved at all" — and with the
|
||||
// shot unmissable the fault could never fire either, so the mode had no penalty in it. You aim.
|
||||
// What DOES change is the tie-break: aimTie lets a nearer body inside the same cone steal a shot
|
||||
// aimed past it, which is right for a crowd you are mowing down and exactly wrong here, where
|
||||
// hitting the wrong body IS the failure. Zero slack — the body you are pointing at wins, always.
|
||||
const ax = aim.fx, az = aim.fy; // unit vector; input already inverted the pull. screen up = -z
|
||||
let zt = null, near = 1e9, bestErr = 1e9;
|
||||
for (const zb of zombies) {
|
||||
@@ -97,7 +93,7 @@ export function flickTarget(ch, aim) { // exported: render draws the live reticl
|
||||
// clearly aimed past it — the magnet Oliver felt. Range only breaks ties between equally
|
||||
// well-aimed targets (TUNE.aimTie of slack), so a deliberate far shot still beats a sloppy
|
||||
// near one while a genuine straight-ahead lane still eats the nearest body first.
|
||||
const tie = TUNE.aimTie;
|
||||
const tie = G.drill ? 0 : TUNE.aimTie; // the drill never guesses for you — see the note above
|
||||
if (err < bestErr - tie || (Math.abs(err - bestErr) <= tie && along < near)) {
|
||||
bestErr = Math.min(bestErr, err); near = along; zt = zb;
|
||||
}
|
||||
@@ -112,13 +108,6 @@ export function flickTarget(ch, aim) { // exported: render draws the live reticl
|
||||
// anywhere on the court — including your own side of the net.
|
||||
function zombieTarget(aim) {
|
||||
if (!zombies.length) return null;
|
||||
// THE DRILL SNAPS HERE TOO. flickTarget (the slingshot) and this (the plain tap) are the two ways
|
||||
// a splatter shot ever picks a body, and they are separate functions — snapping only the first one
|
||||
// left every tap-fired serve in the drill aiming at whatever zombieTarget liked, which in practice
|
||||
// was nothing at all: fifteen serves in a row scored zero. Unconditional, and ABOVE the
|
||||
// no-direction guard: in this mode a bare tap is a legal shot at the called body, because the
|
||||
// subject is which body comes next and not which lane you can find it in.
|
||||
if (G.drill) return drillTarget();
|
||||
const none = !aim || (!aim.ax && !aim.az);
|
||||
if (none) return null; // no direction, no lock. Free predictive auto-aim was the reason a
|
||||
// bare rhythm of taps could clear the court without any aiming at all.
|
||||
|
||||
Reference in new issue
Block a user