Text tables (DICOS/<LANGUAGE>/*.BMD)
The game's text in four languages (French, German, Italian, Spanish): errors (DIC_ERR), race messages (DIC_GAM) and menus (DIC_MNU). There is no English table on this disc.
Reader: decoders/bmd.py. State: decoded completely on all 12 files (measured, 2026-10-23). The game's reader is load_dictionary (FUN_00474b4c).
Writer: crates/pod-formats/src/text.rs (decode, Table::encode, Table::set). Round-trip on all 12 files (measured). The pool is not in key order (measured), so it is kept as stored; a changed string is appended to it and its key pointed there. Section and key fields keep their bytes after the terminator (leftovers, INFOS\0G). Modded: the lap counter's "Tour" changed in DIC_GAM.BMD shows in the race (docs/modding.md).
Layout
In the block container, key 0xEA1E, block 0x200, one entry at 0xC.
| Read | Size | Content |
|---|---|---|
| counts | 12 | u32 sections, u32 strings, u32 pool size |
| pool | pool size | Zero-terminated strings, Latin-1 |
| — | 80 | A fixed-size read at 0x474c1f; meaning unknown |
| sections | sections × 0x14 | u32 count, char name[8], u32 (overwritten at load), u32 first string |
| strings | strings × 0xC | char key[8], u32 offset into the pool |
Observed: the loader turns each section's first-string index into a pointer (× 0xC) and each string's offset into a pointer into the pool. Measured on all 12 files: the section counts add up to the number of strings, and every offset starts a string.
A string is found by section and key, for example section CHRONO, key BSTLAP: "Tour Record" in French. Format strings use C printf codes (%s termine en position %ld).
Open questions
- The 80 bytes after the pool: they start with a small number (3 in
DIC_GAM) and end with a few words; a hash table or leftovers? - Where the game picks the language folder.