The marker stops lying, and the rule announces itself
"the marker flips all the time even during a ball being midair.. i am not sure that a player would get the mechanic intuitively let alone without the marker". The flip had a specific cause and it was a design bug, not jitter. With lanes held and speeds constant, arrival differences never change while bodies walk — the queue only reorders on a kill or an arrival. The marker flipped because it showed only q[0] while the rule accepts any near-tie within the slack: every kill made it jump between tied bodies, so the marker was stricter than the rule it was explaining. drillLegal() marks the whole slack set now, bright head and dim ties, which is stable by construction. Measured: zero head-changes across 12s of walking with no kills. Learnability, two answers. The rule gets one modal, once per run, on the mode's own calm court — CLEARANCE DRILL / DROP WHOEVER WOULD REACH YOU FIRST / FAST BEATS CLOSE / STREAKS PAY — because "most urgent first" is not guessable from a chevron alone. And the markers are training wheels that take themselves off: hidden at streak >= 8 (the streak is the evidence you can read the court), back on any fault. The teacher steps in exactly when you demonstrably need it. 31 tests, 15 seeds clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6a16e77480
commit
be191dba82
6 files changed
+100
-24
No files matched your search
+23
-16
@@ -4,7 +4,7 @@ import { cv, ctx } from './dom.js';
|
||||
import { TUNE, UI, EATEN_BURST, EATEN_SUMMARY, EATEN_RESTART, COURT, P_BOUNDS, PLAYER_H, BOY_H, UMP_H, UMP_X, MACH_H, BOSS_ART, ZWOUND, woundStage, BOUNCE_IDLE, SPRITE_H, zombieH , WEAPONS, RACK_ROW, TOSS } from './config.js';
|
||||
import { P, O, ball, score, crowd, G, court, tour } from './state.js';
|
||||
import { predictLanding, previewServe, slotId, slotStock } from './gameplay.js';
|
||||
import { drillQueue, drillMult } from './drill.js';
|
||||
import { drillQueue, drillLegal, drillMult } from './drill.js';
|
||||
import { zombies, gore, piles, parts, pellets, extras, shots, pops } from './zombies.js';
|
||||
|
||||
// ---------------------------------------------------------------- palette ----
|
||||
@@ -696,21 +696,28 @@ function drawDrillHud() {
|
||||
ctx.font = F(8);
|
||||
shadowText('BEST ' + Math.max(d.best, d.score), W / 2, y + 44, UI.dim);
|
||||
if (d.msg && d.msg.t > 0) { ctx.font = B(20); shadowText(d.msg.text, W / 2, y + 60, d.msg.bad ? UI.bad : UI.pick); }
|
||||
// THE CALIBRATION MARKER (TUNE.drillMark): a chevron over the body the rule says is next. For the
|
||||
// playtest only — it exists so Oliver can check the game's read against his own, and it answers
|
||||
// the exact question the mode is asking, so it must be OFF in anything shipped.
|
||||
if (TUNE.drillMark >= 0.5) {
|
||||
const head = drillQueue()[0];
|
||||
if (head) {
|
||||
const p = proj(head.x, zombieH(head) + 0.5, head.z);
|
||||
if (p.s > 0) {
|
||||
const bob = Math.sin(G.idleT * 6) * 2;
|
||||
const px = Math.round(p.x), py = Math.round(p.y + bob);
|
||||
ctx.fillStyle = UI.warm;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(px - 5, py - 7); ctx.lineTo(px + 5, py - 7); ctx.lineTo(px, py);
|
||||
ctx.closePath(); ctx.fill();
|
||||
}
|
||||
// THE MARKERS ARE TRAINING WHEELS THAT TAKE THEMSELVES OFF. Every LEGAL kill is marked — the
|
||||
// whole slack set, not the bare head: the rule accepts any near-tie, so a single chevron was
|
||||
// stricter than the rule it explained and every kill made it jump between tied bodies. Marking
|
||||
// the set is also stable by construction (arrival differences never change while bodies walk;
|
||||
// the set only moves on a kill or an arrival).
|
||||
// They HIDE once the streak shows you have the read (drillMarkOff) and come back on any fault —
|
||||
// which answers "would a player get this without the marker": the marker teaches, the streak
|
||||
// decides when you have learned it, and unlearning (a fault) brings the teacher back.
|
||||
if (TUNE.drillMark >= 0.5 && d.streak < TUNE.drillMarkOff) {
|
||||
const legal = drillLegal();
|
||||
for (let i = 0; i < legal.length; i++) {
|
||||
const zb = legal[i];
|
||||
const p = proj(zb.x, zombieH(zb) + 0.5, zb.z);
|
||||
if (p.s <= 0) continue;
|
||||
const bob = Math.sin(G.idleT * 6) * 2;
|
||||
const px = Math.round(p.x), py = Math.round(p.y + bob);
|
||||
ctx.globalAlpha = i === 0 ? 1 : 0.45; // the head is bright; a tied body is a quiet "also fine"
|
||||
ctx.fillStyle = UI.warm;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(px - 5, py - 7); ctx.lineTo(px + 5, py - 7); ctx.lineTo(px, py);
|
||||
ctx.closePath(); ctx.fill();
|
||||
ctx.globalAlpha = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user