fix(attract): use remainder-driven item phases

Raw 1000:061c-063b divides the idle tick by 144, copies the remainder from
CX:BX into AX:DX, and only then divides by 8. Readable C and Rust instead used
an unbounded quotient equivalent to tick/1152, making DAT801-809 advance far
too slowly and suggesting a nonexistent negative long-idle index.

Use `(tick % 144) / 8` to repeat item states 0,1..9,8..1 every 144 callbacks.
Remove the disproven long-idle status crops and restore the ten-minute simulator
ceiling. Extend the C and Rust phase tests across the forward, reverse, and wrap
boundaries.

Test Plan:
- raw instruction review at `1000:061c-063b` -- remainder transfer 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
- `rumdl check --flavor commonmark RECONSTRUCTION.md CHANGELOG.md` -- passed
- `git diff --cached --check` -- passed
This commit is contained in:
2026-08-23 20:50:05 +02:00
parent 5b8351ca1f
commit dd0299c30b
8 changed files with 45 additions and 41 deletions
+24 -1
View File
@@ -466,7 +466,7 @@ static void test_intro_tick_32_and_marquee(void)
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_present_calls == 3);
assert(g_item_calls == 1 && g_last_item == 0);
assert(g_item_calls == 1 && g_last_item == 4);
prepare_fixture();
win16_write_u8(win16_dgroup_pointer(0x07c9), 1);
@@ -485,6 +485,29 @@ static void test_intro_tick_32_and_marquee(void)
g_blits[3].x == 233 && g_blits[3].y == 372);
assert(g_select_calls == 5 && g_delete_object_calls == 1);
assert(g_delete_dc_calls == 2);
static const struct {
uint32_t before_tick;
int16_t expected_item;
} item_cases[] = {
{7, 1},
{71, 9},
{79, 8},
{135, 1},
{143, 0},
};
for (size_t index = 0;
index < sizeof(item_cases) / sizeof(item_cases[0]);
index++) {
prepare_fixture();
win16_write_u8(win16_dgroup_pointer(0x07c9), 1);
win16_write_u32(
win16_dgroup_pointer(0x0876), 0,
item_cases[index].before_tick);
tdkpin_timer_tick_with_frame(0x0300, g_window);
assert(g_item_calls == 1);
assert(g_last_item == item_cases[index].expected_item);
}
}
static void test_panel_and_game_initialization(void)