Commit Graph

2 Commits

Author SHA1 Message Date
m3ultra
7347ec4db7 Pinball: Rules, Juice, HUD, a table probe — and the three bugs it found
Four lanes built in parallel onto the data-driven spine:

- Rules.gd (509) — score with a decaying combo multiplier, 3 balls, ball save,
  escalating drop-bank bonuses, lit rollover lanes that level up when swept,
  saucer-lock multiball, two-warning tilt, end-of-ball bonus, per-table high
  scores in user://pinball_scores.cfg.
- Juice.gd (784) — 12 procedural voices synthesized at boot, no assets. The
  spinner ratchet is timed to Table.gd bleeding spin_left at 6.0/s so the ticking
  stops exactly when the blade does. Pooled voices/lights/sparks, quadratic-falloff
  shake, and a damped spring for nudge. Palette-tinted lights with a value floor,
  because a light the colour of a near-black saucer illuminates nothing.
- Hud.gd (935) — score that ROLLS UP rather than snapping, combo, award callouts,
  plunger meter, tilt banner, ball save, game over panel.
- dev/probe_tables.gd (480) — the gate: builds every table and checks parts, part
  overlaps, playfield bounds, flipper swing, that the ball actually DRAINS, and
  that everything settles.

The probe immediately found three real bugs the flipper autotest could not see:

1. The drain sat 3 cm PAST the playfield lip, so on four of five tables the ball
   rolled off the end into the void and the trigger never fired. A table you cannot
   lose a ball on is not a table. Moved inside the slab.
2. Inlane posts were level with the slingshots and interpenetrated them on three
   tables — on a real table the posts sit below. Moved down-table.
3. THE DIG's counter ramp ran through the crate bank, and a 15 deg yaw over a 28 cm
   ramp swings its far end 7 cm sideways, which then walked it through the left rail.
   Less yaw, tucked in, crates slid right.

PROBE_TABLES: PASS 5/5. AUTOTEST: ALL TABLES OK.

Still open, and it is an ENGINE finding not a table one: godot-box3d does not enforce
HingeJoint3D angular limits — flippers swing 147-160 deg against a 62 deg limit. The
probe reports it as a NOTE per table. Worth an upstream issue alongside the motor-sign
inversion already in the README.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-09 18:18:15 +10:00
m3ultra
2f1a1250cc Pinball: data-driven table spine (3 tables, 11 part kinds)
Replaces the single hand-built .tscn table with the Floorplan/Levels pattern from
Destroyulator: Table.gd builds a playfield from a spec, Tables.gd holds the specs,
Main.gd orchestrates. A table is now a Dictionary you can diff and hot-swap (T),
parallel work doesn't collide in one scene file, and a headless autotest builds
every table and proves the flippers swing.

Part vocabulary: flipper, bumper, sling, target, drop (banked, with cleared
detection), spinner (scores per revolution), saucer (captures + ejects), rollover
(lit lanes/glyphs), ramp (speed-gated, scores only at the top), wall, post.

Three ORIGINAL tables — NEON ARCADE (wide open, 3-bank, spinner lane), THE GROTTO
(narrow, open outlanes, a 5-bank guarding the only ramp), THE FOUNDRY (long, twin
ramps, upper flipper, 2x3 target array). Not traced from the vendored decomp.

Main also centralises the engine divergence: Box3D's hinge motor runs opposite to
Jolt/GodotPhysics, so flip_sign is resolved once at boot from the engine name
rather than authoring two sets of tables.

Caught by the new autotest: Godot's HingeJoint3D spins about its own local Z, so a
flipper built in code needs the joint stood on end to swing about world Y. Commanded
correctly and utterly motionless until fixed. AUTOTEST now: 3 tables, 7 flippers,
68-84 deg swing, ALL TABLES OK.

Rules/Juice/Hud are spawned by class name if present, so those lanes land independently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-09 17:24:07 +10:00