guts/web/js/combat/balance.js
jing 0a038582a7 [lane B] Round 1: flight controller, cannon, enemy framework on the stub
Flight (js/flight/): tube-mode controller in spline space (s,x,y) — flow-locked
forward motion, throttle as a spring-back lean, boost + i-frames, banking chase
cam on the parallel-transport frame, arcade wall response (shove + graze damage,
never a hard stop). Twin-stick input: WASD/left-stick moves the ship in the disc,
mouse/right-stick aims, Shift/Ctrl is throttle. Gamepad supported.

Combat (js/combat/): lysozyme cannon (pooled, instanced, heat-limited with
hysteresis lockout) + antacid torpedo emitting level:neutralize. Enemy framework
with floater/seeker/turret and turn-rate-limited homing darts, spawned from C's
level:event. Coat/hull model and the full bus surface E builds against.

Measured (deterministic stepper): flow-lock exact (3s at flow 14 -> s=44.0);
boost peak 30.8 u/s; heat 4s fire -> 2s lockout; wall slam 13.3 coat at 11.3 u/s
with forward speed untouched; 10 combat draws at 55 live enemies (budget <=80);
0.10 ms/frame CPU; 0 leaks over 20 create/dispose cycles. fps NOT claimed — rAF
does not run in the automated pane. Evidence: docs/shots/laneB/.

Three findings escalated in LANE_B_NOTES:
- qa.sh gate #1 is a no-op: node --check silently exits 0 on ESM, so the syntax
  gate has never checked anything. I shipped a real SyntaxError past a GREEN qa.
  Fix + verification handed to F.
- Surf is structurally broken: the peristalsis wave (13.64 u/s) is slower than
  the player (19.6 u/s), so level 2's signature mechanic loses to mashing
  throttle. Not tunable from this lane; escalated to A/F with options.
- Custom ShaderMaterials need #include <colorspace_fragment>, else ART_BIBLE's
  hostile amber reaches the display as rgb(255,26,6). Fixed here; stub/walls
  inherit it.

js/flight/dev.html is a dev harness (boot.js has no player wiring yet); it
retires once F pastes the snippet in LANE_B_NOTES.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 08:56:32 +10:00

60 lines
3.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// combat/balance.js (Lane B) — every combat number. Sibling of flight/tuning.js: that file
// decides how ENDO-1 handles, this one decides what the fight is worth.
//
// Sized against the stub esophagus (flow 14 u/s, playable disc radius ~7..10 u) and against
// the player's own numbers: disc top speed 13 u/s, coat 100 with 8/s regen after 2.5 s.
export const BALANCE = {
// Lysozyme cannon: infinite ammo, heat-limited (GDD). Heat is the whole design — the gun
// is free, so the cost has to be time. Sustained fire nets +25 heat/s (11 shots/s × 5.5,
// less 30/s cooling) => ~4 s of held fire before lockout, then ~2 s to recover to resumeAt.
// Burst and you never see the meter; hold and you're disarmed exactly when it's busiest.
cannon: {
rof: 11, // shots/s
speed: 95, // u/s in world space (closing speed ~75 with player flow)
life: 1.15, // s => ~109 u range, comfortably past the fog
damage: 12,
radius: 0.35,
heatPerShot: 5.5,
coolRate: 30, // /s
overheatAt: 100,
resumeAt: 40, // hysteresis — no stutter-firing on the edge of lockout
spread: 0.004, // rad, seeded — a hair of life, not a handicap
pool: 96, // rof × life = ~13 in flight; 96 covers spikes with room
},
// Antacid torpedo: the dual-use secondary (GDD). Also neutralizes an acid zone for ~10 s
// via the level:neutralize bus event — A/C consume it. Ammo-limited, pickup-fed (round 2).
torpedo: {
rof: 0.8, speed: 42, life: 3.2, damage: 45, splash: 9, radius: 0.7,
ammo: 6, ammoMax: 6,
neutralizeRadius: 14, neutralizeDuration: 10,
pool: 8,
},
enemies: {
// amylase droplet — slow floater with a corrosive contact aura. A soft obstacle: it
// doesn't chase, it taxes the lane it sits in. Aura ticks discretely (see enemies.js).
floater: { hp: 24, radius: 2.2, score: 100, drift: 1.6, bob: 0.5,
auraRadius: 4.2, auraDps: 18, auraTick: 0.2, pool: 24 },
// pepsin — small fast seeker, dissolves on contact. Chases in spline space (s,x,y), so
// a pursuit costs three floats. speed 19 > player flow 14: it WILL catch you from
// behind, and the answer is to shoot it or boost, not to outrun it at throttle 1.4.
seeker: { hp: 14, radius: 1.0, score: 150, speed: 19, turn: 2.4, contact: 16,
aggroS: 60, pool: 32 },
// antibody turret (Peyer's patch) — wall-mounted, fires homing darts. Dart turn radius
// is speed/turn = 24/1.8 = 13.3 u, wider than the tube itself: it can never corner you,
// only punish a straight line. Dodgeable by design (charter).
turret: { hp: 40, radius: 1.6, score: 250, fireEvery: 1.9, rangeS: 55,
dartSpeed: 24, dartTurn: 1.8, dartLife: 4.5, dartDamage: 14, pool: 12 },
},
darts: { pool: 48, radius: 0.45 },
// Chained kills feed the combo meter (GDD: score × style multiplier; E's music layer
// listens). Window is generous enough to cross a fold, tight enough to mean something.
combo: { window: 2.5 },
};