Commit Graph
29 Commits
Author SHA1 Message Date
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 f8dcceda5e fix(physics): restore binary record scan order
Interleave static ranges, type-three captures, type-four triggers, magnetic records, and dynamic ball records in exact ID order while tracking predicted position separately from mutable motion. Preserve type-three/dynamic broadphase and the raw stack quirk where fixed candidate slot one wins even when a later candidate is nearer; seal that behavior in both C and Rust harnesses.

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 original/MECHANICS_PROGRESS.md tdkpin-rs/CHANGELOG.md tdkpin-rs/RECONSTRUCTION.md tdkpin-rs/README.md
- git diff --check
2026-08-23 18:46:44 +02:00
ddidderr 742b8b7981 fix(physics): use predicted magnetic gate bounds
Correct the readable 1000:9b69 reconstruction to read DGROUP 07db/07df and name the helper for its predicted-position role. Rust magnetic rectangles now enter only from an old position inside the record and deactivate when the recomputed prediction exits any edge, replacing the prior swept approximation.

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
- git diff --check
2026-08-23 18:25:23 +02:00
ddidderr 8b99e9607c feat(reconstruction): complete binary-backed C recovery
Replace the partial mechanics transcriptions with a separate, readable C11
reconstruction of the complete Win16 image while preserving the original raw
Ghidra export as immutable evidence. Cover all ordinary and overlapping entry
points, Borland runtime behavior, Win16 imports, segmented data, callbacks,
resources, indirect control flow, physics, rendering, persistence, and
startup/shutdown lifecycles.

Add deterministic extraction and audit tooling plus address-linked ledgers for
functions, imports, DGROUP ranges and objects, relocations, resources, and
callbacks. The final gate records zero raw, partial, restored, unknown,
blocked, or unclassified required units. Keep the semantic-fidelity boundary
explicit: the portable C is not claimed to reproduce a byte-identical Borland
NE build.

Add strict focused harnesses for every reconstructed C unit, exact resource
round-trip checks, and a 16-bit Borland Real48 reference probe. No Rust source
or Cargo metadata is changed in this phase.

Test Plan:
- `bash original/tools/test_reconstructed_c.sh` -- passed
- `bash original/tools/probe_real48_reference.sh` -- passed bit-for-bit
- `python3 original/tools/audit_reconstruction.py --require-complete` -- passed
- `git diff --cached --check` -- passed
- `git diff HEAD -- '*.rs' Cargo.toml Cargo.lock` -- empty
2026-08-23 16:41:17 +02:00
ddidderr f2560ee2f7 fix(game): restore effect-seven multiball
Arm effect 7 after the wheel-reset target, select it on the next effect line,
and spawn a second visible live ball when record 149 is consumed. Advance the
second ball through recovered line, circle, ball-ball, magnetic, and scoring
collisions independently.

During multiball, draining one ball leaves the other active without consuming a
remaining player ball. Include secondary state in deterministic traces and
finite-state validation.

Test Plan:
- `cargo test --all-targets` -- 52 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- production build plus Windows GNU and macOS checks -- passed
- effect-seven spawn, movement, and single-drain lifecycle test -- passed
- `git diff --cached --check` -- passed
2026-08-22 22:02:50 +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 77c93ec36b fix(game): restore exact media thresholds
Replace the inferred exponential media progression with the four initialized
32-bit thresholds used by the original score-addition path: 140,000, 650,000,
1,300,000, and 4,000,000. Award exactly one media level and extra ball at each,
with no nonexistent fifth tier.

Test Plan:
- `cargo test --all-targets` -- 50 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- threshold boundary and four-extra-ball test -- passed
- `git diff --cached --check` -- passed
2026-08-22 21:53:11 +02:00
ddidderr b786a75544 fix(game): restore the six-way effect target
Implement the flagged object-84 selector and initially inactive type-4 object
149. Choose a different effect from 1-6, render the enabled target from its
original active-table rectangle, award its static 500 points, then apply the
recovered bonus or cashout action and disable it until reselected.

This replaces the final unimplemented help-screen target effect with its
original dispatcher values.

Test Plan:
- `cargo test --all-targets` -- 49 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- live object-84 probe activated record 149 and selected effect 3
- effect selection/consumption test -- passed
- `git diff --cached --check` -- passed
2026-08-22 21:50:50 +02:00
ddidderr 27749cb5f8 fix(game): correct every claw release velocity
Interpret the claw's 3800-unit release scalar per 10 ms physics substep rather
than per 30 ms animation frame. This removes a factor-of-three slowdown from all
four random terminals and restores terminal 18 to raw `(0,1000)`.

Add exact assertions for positions and raw velocities of terminals 1, 6, 7,
and 18, backed by repeated live original captures through release and the first
three gravity substeps.

Test Plan:
- `cargo test --all-targets` -- 48 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- all four live original terminal trajectories matched
- `git diff --cached --check` -- passed
2026-08-22 21:46:07 +02:00
ddidderr 4b56a23fb4 fix(game): restore one-shot magnetic fields
Replace the global timed magnet and drain teleport with the three recovered
field records. Map top targets 150-152 to center field 6 and outlane fields
153-154, apply upward pull only inside each registered rectangle, and deactivate
the field after it pulls the ball through its upper boundary.

Render each active field from its exact original active-table rectangle instead
of drawing invented yellow triangles.

Test Plan:
- `cargo test --all-targets` -- 48 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- production build plus Windows GNU and macOS checks -- passed
- live field-153 entry direction matched and Rust field lifecycle test passed
- `git diff --cached --check` -- passed
2026-08-22 21:43:13 +02:00
ddidderr b86810ebed fix(physics): restore the flipper downstroke
Represent press and release as distinct deferred flipper edges. Keep upward
position/velocity transfer unchanged, and apply the position-preserving
return-stroke velocity recovered from a live ball at `(125,390)`, mirrored for
the right flipper.

The downstroke now assigns raw `(3519,6302)` before the next physics clamp,
matching the original instead of moving geometry silently.

Test Plan:
- `cargo test --all-targets` -- 48 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- live downstroke transfer test -- passed within one raw unit
- `git diff --cached --check` -- passed
2026-08-22 21:36:24 +02:00
ddidderr cd27fc8404 docs(reverse): transcribe the fixed-point physics core
Add a standalone, syntax-checked C transcription of the recovered ball state,
10 ms substep, launcher repeat/release arithmetic, one-sided type-2 response,
swept type-1 response, and previous-position contact application. Link the
source to the authoritative raw function addresses and initialized object
ledger.

Keep unresolved persistent-contact and special-rule branches in the raw Ghidra
artifact rather than filling the readable reference with guesses.

Test Plan:
- strict C11 `clang -Wall -Wextra -Werror -fsyntax-only` -- passed
- `git diff --cached --check` -- passed
2026-08-22 21:29:41 +02:00
ddidderr 5e63772967 fix(game): restore wheel locks and reset target
Replace the inferred eight-sector wheel and central lock rectangle with the six
recovered type-3 records. Fill the five lock holes at their exact centers,
double each successive bonus from 10,000 through 160,000, transfer the complete
310,000 on the fifth, and return a launcher ball without consuming one.

Restore object 148 as the wheel-reset target and clear all filled-hole state on
contact. Keep these sensors on the same swept path and contact-latch machinery
as the claw and type-4 targets.

Test Plan:
- `cargo test --all-targets` -- 47 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- live five-hole bonus/score sequence matched exactly
- live object-148 reset cleared all five contact states
- `git diff --cached --check` -- passed
2026-08-22 21:26:20 +02:00
ddidderr 1ca8597080 fix(game): restore physical target-bank rules
Attach recovered score and rule flags to type-2 collision records. Deactivate
complete three-line groups through their contact owner, rearm all five
bumper-value groups after completion, and rearm all four central groups after
advancing the TDK diamond.

Remove the broad side and colored-target coordinate checks those physical
records replace. Preserve exact 5,000, 100,000, bank, and wheel-trigger scores
from the initialized object ledger.

Test Plan:
- `cargo test --all-targets` -- 46 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- target-bank deactivation, completion, and rearm test -- passed
- `git diff --cached --check` -- passed
2026-08-22 21:20:15 +02:00
ddidderr 20e751de80 fix(physics): resolve the earliest substep contact
Return exact path progress with each fixed-point line and circle candidate.
Evaluate the complete recovered physical object set and apply the nearest
contact, matching the selection logic in the original collision dispatcher
instead of stopping at the lowest matching object id.

This prevents dense assemblies from choosing a later wall or circle merely
because its record appears earlier in the table.

Test Plan:
- `cargo test --all-targets` -- 45 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- collision-progress ordering test -- passed
- `git diff --cached --check` -- passed
2026-08-22 21:15:45 +02:00
ddidderr bf5b855f44 fix(game): restore swept target sensors
Move claw contact and all eleven initially active type-4 circle records onto a
swept millipixel sensor test with per-object enter latching. Preserve the exact
left-bank and top-gate coordinates, radii, and scores from the initialized
object ledger.

Remove the inferred top-bank completion rule. Each original top target now
scores 500 and independently starts recovered magnetic-gate timing instead of
requiring all three for an invented bonus.

Test Plan:
- `cargo test --all-targets` -- 44 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- top sensor contact-latch and re-entry test -- passed
- 20-second deterministic launch remained in active table motion
- `git diff --cached --check` -- passed
2026-08-22 21:12:41 +02:00
ddidderr 9d91cc51c7 feat(reverse): ledger every initialized game object
Add a reproducible dump of all 175 initialized collision and rule records from
the unmodified traceable Wine process. Preserve geometry, bounds, activation,
all four decoded Borland Real48 response values, flags, contact state, score,
layer mask, and render rectangle in a reviewable TSV.

This extends the static function ledger with the runtime-built data table needed
to replace inferred target, lock, gate, and mechanism logic in Rust.

Test Plan:
- generated `OBJECTS.tsv` contains one header plus 175 records
- repeat dump compared byte-for-byte equal with `cmp`
- `ruff check` on all original tracing tools -- passed
- `git diff --cached --check` -- passed
2026-08-22 21:07:18 +02:00
ddidderr d813b5b9da fix(physics): restore upward flipper transfer
Apply flipper movement after the physics substep, matching the original timer
order. Replace the weak generic tangent kick with the recovered swept-body
position transfer and pre-clamp velocity curve fitted from three live left-edge
probes, then mirror that local transform for the right flipper.

The x=125 probe now reaches `(138.182,355)` with raw velocity within two units
of `(2217,-5889)`. Keep downstroke interaction listed as pending rather than
claiming the upward fit is the complete raw routine.

Test Plan:
- `cargo test --all-targets` -- 43 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- three live left-flipper transfer probes matched within documented tolerance
- `git diff --cached --check` -- passed
2026-08-22 21:05:02 +02:00
ddidderr e07a915277 fix(physics): restore live flipper geometry
Replace each invented centerline capsule with the original pair of moving line
records and moving tip circle. Use the exact asymmetric raised coordinates read
from live objects 66-68 and 81-83, while preserving their recovered type-1 and
type-2 fixed-point response coefficients in normal object traversal.

Remove the last generic segment overlap solver. Edge-time ball transfer remains
separate because the original applies it after physics while moving the records.

Test Plan:
- `cargo test --all-targets` -- 43 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- live left and right key-edge record dumps matched the Rust coordinates
- `git diff --cached --check` -- passed
2026-08-22 21:00:22 +02:00
ddidderr c886a93788 fix(physics): restore fixed-point circle responses
Replace the overlap-and-separate circle approximation with the original swept
ball-center entry test and radial/tangent fixed-point response. Preserve every
type-1 record's Real48 rebound and tangent coefficients, plus the bumper normal
kick derived from the 3800-unit speed scalar.

Unify line and circle traversal in original object-id order and remove the old
floating passive-circle and bumper impulses. Add exact tests for live object 155
and bumper 51 transitions, and keep moving flippers as the explicit remaining
collision approximation.

Test Plan:
- `cargo test --all-targets` -- 44 passed
- `cargo clippy --all-targets -- -D warnings` -- passed
- `cargo build --profile production` -- passed
- 20-second deterministic launch traversed bumpers and drained without rescue
- live object 155 and bumper 51 fixed-point transitions matched exactly
- `git diff --cached --check` -- passed
2026-08-22 20:52:58 +02:00
ddidderr 5c2a80cfa5 fix(reverse): avoid stopping Wine during probes
Repeated SIGSTOP-based injection can suspend Wine while its Win16 mutex is held
and eventually strand the timer callback. Make the short process-memory write
sequence the default between 30 ms callbacks, while retaining whole-process
stopping as an explicit single-probe diagnostic option.

Test Plan:
- `ruff check original/tools/trace_original_state.py original/tools/inject_original_state.py` -- passed
- live no-stop ball-state injection -- passed
- subsequent original timer updates remained observable
- `git diff --cached --check` -- passed
2026-08-22 20:52:03 +02:00
ddidderr c50ed39a35 feat(reverse): isolate original physics substeps
Expose the original detail-derived integration count, active-ball count,
gravity, maximum speed, and movement flags in live traces. Allow probes to
force one physics substep so a single collision response can be observed
without the default three-step timer batch obscuring intermediate state.

Record the dynamically verified type-2 rail response: resolve velocity in the
registered line's normal/tangent basis, apply the two original Real48
coefficients, then advance from the previous position using that response.

Test Plan:
- `ruff check original/tools/trace_original_state.py original/tools/inject_original_state.py` -- passed
- one-substep probes against both vertical shooter walls -- passed
- ordinary rail responses matched 0.6 normal rebound and 0.1 tangent coupling
- `git diff --cached --check` -- passed
2026-08-22 20:27:56 +02:00
ddidderr 65ee3c5355 fix(reverse): trace active injected ball states
The tracer could only rediscover the game object while all original position
copies agreed, which is normally true at the waiting launcher but not during an
active controlled probe. Accept the injector-reported object base explicitly so
one process can be sampled through an entire sequence of collision tests.

Test Plan:
- `ruff check original/tools/trace_original_state.py original/tools/inject_original_state.py` -- passed
- active live trace with `--object-base 0xadc2b0` -- passed
- `git diff --cached --check` -- passed
2026-08-22 20:23:06 +02:00
ddidderr d24ef6612f feat(reverse): inject controlled original ball states
Add an atomic live-state injector for the traceable Wine process. It updates
all recovered global and object copies of ball position and velocity while the
process is stopped, clears pending impulses, and re-enables normal collision
processing before resuming the unmodified executable.

This makes individual walls, circles, gates, and mechanisms reachable without
relying on random gameplay. Document the first controlled claw probe, including
its original terminal-18 animation, exact release state, and three-substep
gravity behavior.

Test Plan:
- `ruff check original/tools/trace_original_state.py original/tools/inject_original_state.py` -- passed
- controlled `(289,94)` injection and one-second live claw trace -- passed
- terminal-18 release matched `(325000,92000)` and `(0,1000)` -- passed
- `shellcheck original/tools/run_traceable_original.sh` -- passed
- `git diff --cached --check` -- passed
2026-08-22 20:20:26 +02:00
ddidderr dcc664346c feat(reverse): trace the live original physics state
WineDbg changes the Win16 exception path and cannot capture continuous game
state reliably. Add a Linux-only launcher that opts the normally running Wine
process into same-user tracing without modifying TDKPIN.EXE, plus a sampler
that locates the loaded DGROUP and game object from recovered signatures.

The CSV trace exposes original millipixel positions, predicted positions,
velocities, flipper state, and claw state whenever they change. This provides
an external oracle for reconstructing and differentially testing the fixed-
point mechanics instead of tuning the Rust approximation against screenshots.

Test Plan:
- `shellcheck original/tools/run_traceable_original.sh` -- passed
- `ruff check original/tools/trace_original_state.py` -- passed
- strict shared-library compile with `cc` warnings as errors -- passed
- live Wine smoke trace and four-second charged launch capture -- passed
- `git diff --cached --check` -- passed
2026-08-22 20:16:14 +02:00
ddidderr 9e74745fde docs(testing): record live original comparison
Document the Wine-backed original start and charged-launch captures, the matching deterministic Rust states, and the remaining boundary that a chosen claw terminal was not forced in the live original.

Test Plan:
- Launch original/TDKPIN.EXE with Wine 11.15 staging
- Send keypad plus, hold Down for 1.1 seconds, release, and inspect captures
- Compare original started state with Rust launcher step zero
- git diff --cached --check
2026-08-22 18:55:41 +02:00
ddidderr 75c2464e72 docs(reverse): decode claw release arithmetic
Correct the coordinate model from guessed 16.16 values to the millipixel arithmetic shown by the 16-bit division routine.

Decode the Borland Real48 direction constants and record the exact position and velocity tables used by every claw terminal.

Test Plan:
- git diff --cached --check
- Compare constants against segment 1 disassembly at 9bca and eab1
2026-08-22 18:44:50 +02:00
ddidderr e1dc644c76 docs(reverse): restore named mechanism state machines
Transcribe the claw and flipper control flow into an address-mapped readable companion while preserving unresolved fixed-point projection as an explicit boundary.

Correct the reconstruction ledger so the current Rust claw is not described as proven parity.

Test Plan:
- git diff --cached --check
- Review restored constants and branches against TDKPIN_GHIDRA_RAW.c
2026-08-22 18:38:07 +02:00
ddidderr 54061f1eb7 init 2026-08-22 15:52:52 +02:00