The leagues, phase 4: the duel learns, tin tiers by league, level buffs, the board wears the badge

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Fable 5 committed 2026-08-29 12:53:12 +02:00
1 parent 76d88030e5
commit 787877bce6
10 files changed
+175 -24

No files matched your search

+4 -4
View File
@@ -11,7 +11,7 @@ import { drillKill, drillCaught } from './drill.js';
import { splatPoint, cheer, spentBall, aside, grantWeapon, endBurst, sliceCarom } from './gameplay.js';
import { resolveInterlude, endBossFight } from './beats.js'; // runtime-only cycle, like the gameplay one
import { tally, multiKill, endRun, MODE_MATCH } from './stats.js';
import { award } from './profile.js';
import { award, bonus } from './profile.js';
export const zombies = []; // {x, z, v, walkT, variant: 'a'|'b'|'c'}
export const gore = []; // lawn decals {x, z, r, a} — the flat ground layer
@@ -267,7 +267,7 @@ export function hurtPlayer(n) {
// it beats this channel and the eat test below, which is the only reason to spend a dodge.
if (G.mode !== 'splatter' || G.hurtT > 0 || G.dodgeI > 0 || G.mode === 'eaten') return;
G.hp -= n;
G.hurtT = TUNE.hurtGrace; G.hurtFlash = 0.3;
G.hurtT = TUNE.hurtGrace * bonus().grace; G.hurtFlash = 0.3; // the grace rides the level (the leagues)
haptic('heavy'); // taking one is rare (hurtGrace gates it) and is the loudest thing the hand gets
G.shake = { t: 0.22, mag: 4 };
splat(0.7); aww(0.5);
@@ -1383,14 +1383,14 @@ export function updateZombies(dt) {
const dP = Math.hypot(s.x - P.x, (s.z - P.z) * 0.8);
const dHit = Math.hypot(s.x - P.x, s.z - P.z);
if (!done && P.swingT >= 0 && P.swingT <= TUNE.parryWindow
&& dP < TUNE.parryReach && s.y < CONTACT.maxY) {
&& dP < TUNE.parryReach * bonus().parry && s.y < CONTACT.maxY) {
// the parry: it becomes an `extras` clone — that array is already ballistic and already kills
// zombies, so "returned shot is a live weapon" costs nothing to build.
// It is a GLANCING blow, not a mirror. Reversing the incoming line sent every return straight
// back up the line it arrived on — which is where the thrower is standing — so a boss was a
// free wound per throw. Where you meet the ball across the racket face now sets the angle:
// hitting it back INTO him is a shot you have to place your feet for.
const off = Math.max(-1, Math.min(1, (s.x - P.x) / TUNE.parryReach)); // -1..1 across the face
const off = Math.max(-1, Math.min(1, (s.x - P.x) / (TUNE.parryReach * bonus().parry))); // -1..1 across the face
const ang = (off * TUNE.parryDeflect + (Math.random() * 2 - 1) * TUNE.parryJitter) * Math.PI / 180;
const sp = Math.hypot(s.vx, s.vz) * 1.15;
extras.push({ x: s.x, y: s.y, z: s.z, g: TUNE.gravity, pow: TUNE.parryPow, t: 2.5,