Decode MPINIT stage terrain atlas

This commit is contained in:
gamer147
2026-07-23 21:31:43 -04:00
parent 3a46b2236a
commit 9646b23ae2
11 changed files with 703 additions and 25 deletions

View File

@@ -1359,6 +1359,96 @@ def test_voice_configuration() -> None:
)
def test_map_terrain_atlas() -> None:
scripts = paths.scripts()
script = sys4load.load(scripts["MPINIT.BIN"])
check(
extract_init.detect_mode(script) == "footer",
"MPINIT remains compatible with footer-mode auto-detection",
)
records, meta = extract_init.extract_map_terrain_atlas(script)
by_y = {record["grid_y"]: record for record in records}
check(
len(records) == 1472
and meta["footer_array_count"] == 1472
and meta["classified_instruction_count"] == 1473,
"MPINIT classifies every terrain-row footer copy and exit instruction",
)
check(
meta["atlas_base"] == "0xccc93"
and meta["row_stride"] == 53
and meta["first_authored_column"] == 1
and meta["authored_column_count"] == 50
and meta["tile_to_grid_scale"] == 2,
"MPINIT exposes its 53-cell row pitch and doubled tile coordinate system",
)
check(
meta["authored_grid_y_min"] == 2
and meta["authored_grid_y_max"] == 1600
and meta["implicit_zero_row_count"] == 127
and all(record["length"] == 50 for record in records),
"MPINIT preserves all authored rows and the omitted all-zero row gaps",
)
check(
by_y[2]["global_addr"] == "0xcccfe"
and by_y[1600]["global_addr"] == "0xe17d4"
and by_y[1199]["terrain_ids_used"] == [6]
and by_y[1199]["nonzero_cell_count"] == 25,
"MPINIT row coordinates recover directly from destination addresses",
)
definitions = {row["id"]: row for row in meta["terrain_definitions"]}
check(
definitions[1]["name"] == "通路"
and definitions[1]["layout_class_name"] == "passage"
and definitions[2]["name"] == "部屋"
and definitions[2]["area_fill_flag"] == 1
and definitions[3]["name"] == "隠し通路"
and definitions[3]["layout_class_name"] == "hidden"
and definitions[15]["name"] == "溶岩流"
and definitions[15]["texture_slot_index"] == 9,
"MPINIT terrain ids join to LAINIT names and layout/render classes",
)
stage_maps = {stage["id"]: stage for stage in meta["stage_maps"]}
stage1 = stage_maps[1]
check(
meta["stage_map_count"] == 66
and meta["unique_atlas_rectangle_count"] == 53
and stage1["name"] == "『庭園の地下空洞』"
and stage1["tile_bounds"]
== {"min_x": 9, "max_x": 17, "min_y": 1, "max_y": 8}
and stage1["grid_bounds"]
== {"min_x": 18, "max_x": 34, "min_y": 2, "max_y": 16},
"STINIT2 bounds join 66 stage definitions to their doubled atlas rectangles",
)
check(
stage1["grid_width"] == 17
and stage1["grid_height"] == 15
and stage1["terrain_ids_used"] == [1, 2, 4, 12]
and stage1["terrain_id_counts"]
== {"0": 212, "1": 12, "2": 13, "4": 2, "12": 16},
"stage joins expose complete terrain grids and value populations",
)
check(
any(
shared["stage_ids"] == [32, 33, 34]
for shared in meta["shared_atlas_rectangles"]
)
and any(
shared["stage_ids"] == [101, 104, 106, 107, 108]
for shared in meta["shared_atlas_rectangles"]
),
"MPINIT preserves intentional atlas sharing across stage variants",
)
check(
meta["nonzero_cell_count"] == 17126
and meta["stage_rectangle_nonzero_cell_count"] == 17079
and meta["outside_stage_rectangle_nonzero_cell_count"] == 47,
"MPINIT accounts for stage terrain and the raw border-context cells",
)
def test_condition_definitions() -> None:
scripts = paths.scripts()
script = sys4load.load(scripts["ILINIT.BIN"])
@@ -1573,6 +1663,7 @@ if __name__ == "__main__":
test_affinity_definitions()
test_name_entry_palette()
test_voice_configuration()
test_map_terrain_atlas()
test_condition_definitions()
test_field_semantics()
if FAILS: