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:
@@ -464,7 +464,7 @@ static void test_intro_tick_32_and_marquee(void)
|
||||
assert(g_restore_a_ids[2] == 153 &&
|
||||
g_restore_a_ids[3] == 154 && g_restore_a_ids[4] == 6);
|
||||
assert(g_restore_b_id_count == 1 && g_restore_b_ids[0] == 1002);
|
||||
assert(g_region_a_calls == 2 && g_region_b_calls == 1);
|
||||
assert(g_region_a_calls == 1 && g_region_b_calls == 2);
|
||||
assert(g_present_calls == 3);
|
||||
assert(g_item_calls == 1 && g_last_item == 4);
|
||||
|
||||
@@ -510,6 +510,41 @@ static void test_intro_tick_32_and_marquee(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void test_intro_remainder_driven_cycles(void)
|
||||
{
|
||||
prepare_fixture();
|
||||
win16_write_u8(win16_dgroup_pointer(0x07c9), 1);
|
||||
win16_write_u32(win16_dgroup_pointer(0x0876), 0, 3);
|
||||
tdkpin_timer_tick_with_frame(0x0300, g_window);
|
||||
assert(g_restore_a_id_count == 2);
|
||||
assert(g_restore_a_ids[0] == 142 && g_restore_a_ids[1] == 1002);
|
||||
assert(g_restore_b_id_count == 1 && g_restore_b_ids[0] == 1001);
|
||||
assert(g_region_a_calls == 2 && g_region_b_calls == 1);
|
||||
assert(g_item_calls == 0);
|
||||
|
||||
prepare_fixture();
|
||||
win16_write_u8(win16_dgroup_pointer(0x07c9), 1);
|
||||
win16_write_u32(win16_dgroup_pointer(0x0876), 0, 15);
|
||||
tdkpin_timer_tick_with_frame(0x0300, g_window);
|
||||
assert(g_restore_a_id_count == 1 && g_restore_a_ids[0] == 1005);
|
||||
assert(g_restore_b_id_count == 5);
|
||||
assert(g_restore_b_ids[0] == 140 && g_restore_b_ids[1] == 1004);
|
||||
assert(g_restore_b_ids[2] == 153 &&
|
||||
g_restore_b_ids[3] == 154 && g_restore_b_ids[4] == 6);
|
||||
assert(g_region_a_calls == 2 && g_region_b_calls == 1);
|
||||
assert(g_item_calls == 1 && g_last_item == 2);
|
||||
|
||||
prepare_fixture();
|
||||
win16_write_u8(win16_dgroup_pointer(0x07c9), 1);
|
||||
win16_write_u32(win16_dgroup_pointer(0x0876), 0, 39);
|
||||
tdkpin_timer_tick_with_frame(0x0300, g_window);
|
||||
assert(g_restore_a_id_count == 2);
|
||||
assert(g_restore_a_ids[0] == 144 && g_restore_a_ids[1] == 1003);
|
||||
assert(g_restore_b_id_count == 1 && g_restore_b_ids[0] == 1002);
|
||||
assert(g_region_a_calls == 2 && g_region_b_calls == 1);
|
||||
assert(g_item_calls == 1 && g_last_item == 5);
|
||||
}
|
||||
|
||||
static void test_panel_and_game_initialization(void)
|
||||
{
|
||||
prepare_fixture();
|
||||
@@ -556,6 +591,7 @@ int main(void)
|
||||
test_multiball_promotion();
|
||||
test_multiball_spawn();
|
||||
test_intro_tick_32_and_marquee();
|
||||
test_intro_remainder_driven_cycles();
|
||||
test_panel_and_game_initialization();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user