fix(attract): restore all remainder-driven cycles

The same raw Div32 pattern used by the item animation appears in every nested
idle phase: after division by 32, 40, or 16, the binary copies the remainder
from CX:BX before the second division. Readable C and Rust used quotients for
targets, word quads, the record strip, and the four-point chase, turning short
repeating chases into slow one-shot progressions.

Use `%32/2`, `%32/4`, `%40/4`, and `%16/4` for those cycles alongside the
already corrected `%144/8` items. Preserve the first-cycle phase-zero delay,
then repeat each incremental overlay state exactly. Add C and Rust coverage at
phase activation, reversal, deactivation, and wrap boundaries.

Test Plan:
- raw instruction review at `1000:01b7-063b` -- all remainder transfers confirmed
- `cargo test --workspace --all-targets --all-features` -- 125 passed
- `cargo clippy --workspace --all-targets --all-features -- -D warnings` -- passed
- `bash original/tools/test_reconstructed_c.sh` -- passed
- `python3 original/tools/audit_reconstruction.py --require-complete` -- passed with zero incomplete or unclassified units
- `cargo run -- --simulate attract --step 145 --screenshot /tmp/tdkpin-attract-remainder.png` -- passed; visually inspected at 640x460
- `rumdl check --flavor commonmark RECONSTRUCTION.md CHANGELOG.md` -- passed
- `git diff --cached --check` -- passed
This commit is contained in:
2026-08-23 20:53:12 +02:00
parent dd0299c30b
commit 7633ef9990
7 changed files with 82 additions and 39 deletions
+4 -4
View File
@@ -378,7 +378,7 @@ static void active_ball_tick(uint16_t frame_bp, Win16FarPtr window)
static void update_intro_collision_visibility(uint16_t frame_bp, int32_t tick)
{
if (remainder_i32(tick, 2) == 0) {
int32_t phase = quotient_i32(quotient_i32(tick, 32), 2);
int32_t phase = quotient_i32(remainder_i32(tick, 32), 2);
if (phase >= 0 && phase <= 7) {
tdkpin_restore_record_or_item_a(
frame_bp, (uint16_t)(phase + 140));
@@ -388,7 +388,7 @@ static void update_intro_collision_visibility(uint16_t frame_bp, int32_t tick)
}
}
if (remainder_i32(tick, 4) == 0) {
int32_t phase = quotient_i32(quotient_i32(tick, 32), 4);
int32_t phase = quotient_i32(remainder_i32(tick, 32), 4);
if (phase == 0) {
tdkpin_restore_record_or_item_a(frame_bp, 1001);
tdkpin_restore_record_b(frame_bp, 1002);
@@ -424,7 +424,7 @@ static void update_intro_record_strip(
if (remainder_i32(tick, 4) != 0) {
return;
}
int32_t phase = quotient_i32(quotient_i32(tick, 40), 4);
int32_t phase = quotient_i32(remainder_i32(tick, 40), 4);
bool background_b = phase >= 5;
int32_t normalized = background_b ? phase - 5 : phase;
uint16_t id = (uint16_t)(normalized * 3 + 90);
@@ -450,7 +450,7 @@ static void update_intro_four_point_chase(
}
static const INT16 y[4] = {209, 214, 219, 224};
static const INT16 x[4] = {150, 164, 178, 192};
int32_t phase = quotient_i32(quotient_i32(tick, 16), 4);
int32_t phase = quotient_i32(remainder_i32(tick, 16), 4);
if (phase < 0 || phase > 3) {
return;
}