21 Commits
Author SHA1 Message Date
ddidderr 26b7a9ecf3 fix(input): match original low-byte key scans
The Win16 handlers mask the keyboard scan to its low byte. Main and keypad
Enter therefore both produce the right-flipper scan 0x1c, both Ctrl keys
produce the left-flipper scan 0x1d, and scan 0x1b is the physical
main-keyboard plus/right-bracket position accepted alongside keypad plus. Rust
omitted main Enter and scan 0x1b, and incorrectly assigned Right Ctrl to the
right flipper.

Map the native keys to those recovered scan semantics. Keep A/D, arrows, and
Equal only as explicit modern aliases and document the distinction.

Test Plan:
- `cargo test --workspace --all-targets --all-features` -- 125 passed
- `cargo clippy --workspace --all-targets --all-features -- -D warnings` -- passed
- `rumdl check --flavor commonmark README.md RECONSTRUCTION.md CHANGELOG.md` -- passed
- `git diff --cached --check` -- passed
2026-08-23 20:37:45 +02:00
ddidderr c84df73857 fix(ui): restore effect and player display assets
Load and render DAT400-407 effect panels with the preserved wheel overlap, and add deterministic effect-7 coverage. Restore exact 1008:0996/0b9e score fields, configured-player rows, current/status indicators, signed status thresholds, and six 5x5 per-player ball-marker slots.

Test Plan:
- cargo test --all-targets
- cargo clippy --all-targets --all-features -- -D warnings
- rumdl check CHANGELOG.md RECONSTRUCTION.md README.md
- cargo run --quiet -- --simulate effect-7 --step 0 --screenshot /tmp/tdkpin-effect7.png
- cargo run --quiet -- --simulate launcher --step 0 --screenshot /tmp/tdkpin-display.png
- git diff --check
2026-08-23 19:21:28 +02:00
ddidderr 0e7208e03a fix(config): import original INI semantics
Load case-insensitive Language, Speed, and singular Sound values from an adjacent or embedded TDKPIN.INI before portable JSON exists, preserving Win16 defaults and clamps. Separate runtime playback from stored settings so F12 remains a silent, non-persistent toggle exactly like the original.

Test Plan:
- cargo test --all-targets
- cargo clippy --all-targets --all-features -- -D warnings
- rumdl check CHANGELOG.md RECONSTRUCTION.md README.md
- git diff --check
2026-08-23 19:12:31 +02:00
ddidderr fae322bb91 fix(ui): restore original high-score windows
Replace modern overlays with the reconstructed HighScore child and DIALOG 32514 topology, exact DAT993 background, row coordinates, original strings, unpadded scores, and 21-character edit behavior. Restore OK/Cancel semantics, including Escape preserving the prefilled name and allowing an accepted empty name, with deterministic screenshot scenarios.

Test Plan:
- cargo test --all-targets
- cargo clippy --all-targets --all-features -- -D warnings
- rumdl check CHANGELOG.md RECONSTRUCTION.md README.md
- cargo run --quiet -- --simulate highscores --step 0 --screenshot /tmp/tdkpin-highscores.png
- cargo run --quiet -- --simulate name-entry --step 0 --screenshot /tmp/tdkpin-name-entry.png
- git diff --check
2026-08-23 19:09:28 +02:00
ddidderr c80f5e2136 fix(ui): restore staged loading progress
Correct raw 1000:531e's Pascal-order BitBlt to destination (202,328), height 13, and width (stage-1)*7 from original DAT994. Render stages 2 through 35 over DAT995, add deterministic loading screenshots, and update the C harness and evidence ledger for the corrected 237x13 source.

Test Plan:
- bash original/tools/test_reconstructed_c.sh
- python3 original/tools/audit_reconstruction.py --require-complete
- cargo test --all-targets
- cargo clippy --all-targets --all-features -- -D warnings
- rumdl check original/C_RECONSTRUCTION_FINAL_AUDIT.md tdkpin-rs/CHANGELOG.md tdkpin-rs/RECONSTRUCTION.md tdkpin-rs/README.md
- cargo run --quiet -- --simulate loading --at 0.55 --screenshot /tmp/tdkpin-loading-mid.png
- git diff --check
2026-08-23 19:03:09 +02:00
ddidderr 8168d9dc23 fix(ui): restore original attract animation
Advance idle mode on the selected detail callback and reproduce the reconstructed target, word-quad, magnetic, record-strip, point-chase, item, and BITMAP500 marquee phases from original assets. Add a deterministic attract screenshot scenario and correct DAT801-809 item placement to y=300.

Test Plan:
- cargo test --all-targets
- cargo clippy --all-targets --all-features -- -D warnings
- rumdl check CHANGELOG.md RECONSTRUCTION.md README.md
- cargo run --quiet -- --simulate attract --step 24 --screenshot /tmp/tdkpin-attract-24.png
- cargo run --quiet -- --simulate attract --step 192 --screenshot /tmp/tdkpin-attract-192.png
- cargo run --quiet -- --simulate attract --step 4608 --screenshot /tmp/tdkpin-attract-4608.png
- git diff --check
2026-08-23 18:59:19 +02:00
ddidderr 096d923c79 fix(game): restore six-state target rotation
Replace the free-running 68x60 wheel animation with the original six-callback
91x90 DAT600 mechanism. Start WAVE 2011 at state one, advance once per selected
detail timer, and rotate the five per-player lock contact/item values exactly at
state six.

Decode the 17x17 DAT600 target image/mask pair and render all six recovered
position sets over the correct atlas or overlay-B base. Preserve filled targets
in their resting state after rotation and add a deterministic `targets` scenario
for trace and framebuffer validation.

Test Plan:
- `cargo test --all-targets` -- passed, 74 tests
- `cargo clippy --all-targets -- -D warnings` -- passed
- `rumdl check CHANGELOG.md README.md RECONSTRUCTION.md` -- passed
- rendered all six target-rotation states -- visually verified
- `git diff --cached --check` -- passed
2026-08-23 17:53:40 +02:00
ddidderr 4b84460c93 fix(game): restore the 281-frame panel sequence
Replace the immediate five-hole cleanup with the original 281-callback panel
state machine. Suspend physics, clear contact/item state at the recovered
boundaries, and emit WAVE 2013, WAVE 2012, and stop events at frames
1/45/58/66/129/159/222/230/238 before resuming after cleanup.

Decode DAT600's four AND/OR mask-image pairs into transparent native textures
and render all nine phase formulas with the original source rectangles,
destination offsets, variable heights, and opaque wheel copies. Add a `panel`
simulation scenario for deterministic trace and framebuffer validation.

Test Plan:
- `cargo test --all-targets` -- passed, 72 tests
- `cargo clippy --all-targets -- -D warnings` -- passed
- `rumdl check CHANGELOG.md README.md RECONSTRUCTION.md` -- passed
- rendered panel frames 1, 66, 159, 238, and completion -- visually verified
- `git diff --cached --check` -- passed
2026-08-23 17:49:04 +02:00
ddidderr 6337291461 fix(ui): preserve original idle view and function keys
Remove the invented attract-screen instruction panel so idle mode presents the
original table artwork without a modern overlay. Keep the original plus-key
start flow and automatic high-score presentation.

Stop assigning F2 and F3 to modern screens; those keys are normally inactive in
the original executable outside dormant debug paths. Retain optional portable
settings and high-score viewers on F10 and F9, documenting them as additional
host controls rather than original behavior.

Test Plan:
- `cargo test --all-targets` -- passed, 70 tests
- `cargo clippy --all-targets -- -D warnings` -- passed
- `rumdl check CHANGELOG.md README.md RECONSTRUCTION.md` -- passed
- `git diff --cached --check` -- passed
2026-08-23 17:43:44 +02:00
ddidderr 2549eaa459 fix(timing): batch state on original detail callbacks
Replace the host-frame 10 ms publication loop with the original timer matrix:
50/40/30/20/10 ms callbacks execute exactly 5/4/3/2/1 internal physics
substeps. Ball state, claw progression, and flipper geometry are now visible only
at the selected callback boundary rather than leaking intermediate substeps.

Separate flipper input flags from flipper position. Key changes are sampled by
the timer, then produce one delta edge, WAVE 2021, collision response, and
rendered position update after physics, matching the Win16 callback order. Clear
both input and position state on turn reset and keep tilt decay on the same timer
cadence.

Test Plan:
- `cargo test --all-targets` -- passed, 70 tests
- `cargo clippy --all-targets -- -D warnings` -- passed
- `rumdl check CHANGELOG.md README.md RECONSTRUCTION.md` -- passed
- `git diff --cached --check` -- passed
2026-08-23 17:41:18 +02:00
ddidderr aae4671586 fix(input): restore original nudge and tilt behavior
Replace the float nudge direction, cooldown, and decaying meter with the
scan-code-specific Win16 behavior. Left Shift and keypad 3 now use the original
random directional impulse, while Space uses the reconstructed random horizontal
and vertical formulas with scalar 15 and wrapping millipixel velocities.

Track the original 16-bit tilt counter: each nudge adds 25, compares against
30 + Random(10), and the selected detail timer decrements a nonzero counter once
per callback. Allow the same input while a ball waits in the launcher, retain
bonus state when tilt latches, clear flippers immediately, and keep Right Shift
only as a documented modern alias for keypad 3.

Test Plan:
- `cargo test --all-targets` -- passed, 57 tests
- `cargo clippy --all-targets -- -D warnings` -- passed
- `rumdl check tdkpin-rs/CHANGELOG.md tdkpin-rs/README.md tdkpin-rs/RECONSTRUCTION.md` -- passed
- `git diff --cached --check` -- passed
2026-08-23 16:55:02 +02:00
ddidderr aef404c834 fix(ui): restore original presentation scale
The recovered client enlarged the 640x460 canvas to 960x690 and shrank the
score glyphs, so artwork and numeric displays no longer matched the original
pixel presentation. Restore the native window dimensions and title, render
score digits at their recovered 16x28 size, and align the score fields to the
original layout. Update the user and reconstruction documentation accordingly.

Test Plan:
- `cargo test --workspace --all-targets --all-features` -- passed, 52 tests
- `cargo clippy --workspace --all-targets --all-features -- -D warnings` -- passed
- `rumdl check --flavor commonmark CHANGELOG.md README.md RECONSTRUCTION.md` -- passed
- `git diff --cached --check` -- passed
- `cargo +nightly fmt --all -- --check` -- baseline fails on existing import formatting in touched and untouched Rust files
- `prettier --check CHANGELOG.md README.md RECONSTRUCTION.md --prose-wrap always --print-width 80` -- baseline fails on existing whole-file formatting in README.md and RECONSTRUCTION.md
2026-08-23 06:08:11 +02:00
ddidderr 25e32b2c06 fix(game): honor original mechanism timer choices
Map detail levels 1-5 to the recovered 50, 40, 30, 20, and 10 ms callback
periods for claw animation while retaining the invariant 10 ms physics step.
This removes the hard-coded default cadence from non-default configurations.

Keep repaint batching documented separately because Rust exposes intermediate
physics states instead of reproducing Win16 GDI callback batching.

Test Plan:
- `cargo test --all-targets` -- 51 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- all five claw cadence boundary tests -- passed
- `git diff --cached --check` -- passed
2026-08-22 21:55:21 +02:00
ddidderr 7d28818e23 test(game): exercise two minutes of autoplay
Add a seeded autoplay scenario that performs a deliberate full-strength charge
for every launcher ball and operates both flippers from live ball position.
Turn the two-minute run into an end-to-end test covering repeated launches,
flipper edges, bumpers, targets, lock holes, claw capture/release, and drains
while rejecting non-finite state.

Document autoplay as the long-run validation entry point and record the expanded
runtime coverage boundary.

Test Plan:
- `cargo test --all-targets` -- 48 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- Windows GNU and macOS x86_64 `cargo check` -- passed
- `git diff --cached --check` -- passed
2026-08-22 21:33:29 +02:00
ddidderr 7caf460022 fix(physics): restore fixed-point rail movement
Replace the guessed variable-rate floating integration with the original 10 ms
millipixel step, 15-unit gravity, and 3800-unit speed limit. Restore every
registered type-2 Real48 response pair, one-sided start-to-end orientation, and
the original normal/tangent velocity transform validated against live shooter
wall traces.

Restore repeat-driven plunger charging and its release-time randomized clamp.
The shooter route now follows table orientation instead of coordinate-specific
gate exceptions. Remove the synthetic ball-search impulse so future stuck balls
remain visible reconstruction failures, and include collision ids in deterministic
traces for differential work on circles and triggers.

Test Plan:
- `cargo test --all-targets` -- 42 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- charged launcher scenario cleared the shooter lane -- passed
- all recovered rails accepted front-side and rejected back-side probes
- `git diff --cached --check` -- passed
2026-08-22 20:42:47 +02:00
ddidderr b7326f7a13 fix(input): require plus to start players
Remove the Enter shortcut so the start flow matches the original plus-key handler. Use the recovered player-add sound resource for both the first and subsequent players.

Test Plan:
- cargo fmt --check
- cargo test
- cargo clippy --all-targets --all-features -- -D warnings
- git diff --cached --check
2026-08-22 18:50:55 +02:00
ddidderr 16c055eec6 feat(testing): add deterministic mechanics capture
Add named launcher, flipper, and claw scenarios that advance at exact 120 Hz steps with stable seeds. Emit per-step JSON state/event traces and optionally capture the logical 640x460 framebuffer at any requested time or step.

Cover parser behavior, deterministic replay, launcher timing, flipper edges, and complete capture/release/idle cycles for all claw terminals.

Test Plan:
- cargo fmt --check
- cargo test
- cargo clippy --all-targets --all-features -- -D warnings
- cargo run -- --simulate claw-6 --at 0.15 --screenshot /tmp/tdkpin-sim-validation/claw-6-after-flush.png --trace /tmp/tdkpin-sim-validation/claw-6.json
- Inspect both generated 640x460 PNGs and JSON traces
- git diff --cached --check
2026-08-22 18:50:25 +02:00
ddidderr 95760b9940 fix(input): start games with the plus key
Match the recovered Win16 registration flow: the first plus press creates Player 1 and additional presses add Players 2 through 4 until the initial launch. Down now belongs only to charging and releasing the plunger.

Test Plan:
- cargo fmt --check
- cargo test
- cargo clippy --all-targets --all-features -- -D warnings
- live: verify Down cannot leave attract mode
- live: start with plus, add Player 2, hold Down through partial/full plunger frames, and release onto the table
- git diff --check
2026-08-22 18:24:29 +02:00
ddidderr 91ae8cdfd8 fix(game): restore the original plunger launch
Start each ball at the recovered right-lane coordinates and charge the
plunger while Down is held, firing only on release. Render all eleven frames
of resource 901, preserve object 25 as the returning-ball catch, and use the
object table's center-contact extents without adding the art radius twice.

Test Plan:
- cargo fmt --all -- --check
- cargo test
- cargo clippy --all-targets --all-features -- -D warnings
- runtime smoke: start, hold Down, release, and inspect the right shooter lane
2026-08-22 17:37:28 +02:00
ddidderr e815391980 fix(ui): preserve the original canvas and display styling
High-DPI sizing and a resizable client allowed the 640x460 canvas to be placed
inside a much taller window, producing the large internal black band captured in
the gameplay recording. Open an aspect-correct fixed 960x690 client with high-DPI
framebuffer scaling disabled, giving every platform a predictable 1.5x canvas.

Use exact active-table patches for the cyan score fields and derive transparent
numeral glyphs from the recovered Win16 bitmap font. Fill the complete display
slots, move the KBytes readout clear of its border, and place shortcuts on a
readable footer so no dynamic text is clipped or left over an inactive panel.

Test Plan:
- `cargo fmt -- --check` -- passed
- `cargo test --all-targets` -- passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- launched the Linux window and confirmed a 960x690 client with no letterbox,
  full-width cyan fields, recovered score digits, and readable footer -- passed
- `git diff --check` -- passed
2026-08-22 17:03:46 +02:00
ddidderr f817b63683 feat: rebuild TDK Pinball Machine in Rust
Replace the empty Rust scaffold with a playable native reconstruction of the
1995 Win16 game. Embed the complete decoded asset set, retain the original
640x460 presentation and localized help, and implement a resizable letterboxed
Macroquad frontend for Linux, macOS, and Windows.

Recreate the multiplayer ball flow, flippers, nudging, target banks, wheel,
robot, lock, magnets, bumper progression, TDK diamond multiplier, media extra
balls, sound dispatch, settings, and high-score entry. The physics engine uses
a fixed time step and 101 static collision segments transcribed from the
original 175-object table. Portable JSON persistence imports and decodes the
original XOR-obfuscated high-score file on first run.

Document the evidence boundary explicitly: artwork and PCM samples are exact,
static geometry is recovered, and several numeric scoring/impulse values remain
best-evidence behavioral tuning rather than bit-identical Win16 arithmetic.
Add a native three-OS CI matrix and retain every decoded resource for future
fidelity work.

Test Plan:
- `diff -qr original/assets/decoded tdkpin-rs/assets/original` with the two
  intentionally added legacy root files excluded -- passed
- `cargo fmt --all -- --check` -- passed
- `cargo check --all-targets` -- passed
- `cargo test --all-targets` -- passed, 8 tests
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- `cargo check --all-targets --target x86_64-pc-windows-gnu` -- passed
- `cargo check --all-targets --target x86_64-apple-darwin` -- passed
- `cargo run` graphical start, launch, collision, and score smoke test -- passed;
  audible output was unavailable because the host has no ALSA device
2026-08-22 16:12:11 +02:00