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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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