Skip to content

Best times (RECORDS/*.BRT) ​

One file per circuit, named after the circuit's file stem in CIRCUITS.BIN (lists.md). Each holds the circuit's best races, best laps and best sector times, with the drivers' names. The game writes these files: they are save state as well as data.

Reader: decoders/brt.py, crates/pod-formats/src/records.rs. State: decoded and round-trip for all 17 files (measured, 2026-10-23: every byte is accounted for, and writing the decoded tables gives the original file). Not yet tested in the game.

Container ​

One block of the block container (container.md), key 0xEAFA, block 0x1000: a 4,096-byte file, 4,092 bytes of stream. The stream starts with the usual header (raw size 0x1000, one entry, at 0xC). Observed: load_records (FUN_004b2300) opens the file with pod_file_open (FUN_004694b8, EDX = 0xEAFA, EBX = 0x1000) and reads 0xE5C bytes with pod_read_small (FUN_0046846c) into 0x693A84. save_records (FUN_004b23f4) creates the file with FUN_00468fa4 (block 0x1000, one entry, key 0xEAFA in EBX), writes the same 0xE5C bytes from 0x693A84 with FUN_0046859c and closes it with FUN_00469a1c.

After the 0xE5C bytes, the stream is zero to its end (measured, 17 files).

Layout ​

Offsets from the start of the 0xE5C bytes (stream offset 0xC, memory 0x693A84). All measured on 17 files; the meanings are observed in the functions named.

OffsetSizeContent
0x00015 × 0x38Race table, best first: char name[20], i32 total, i32 lap[8]
0x3481Rows in use (15)
0x3491Laps per race (3 in every file; 0x693DCD)
0x34A26Zero
0x3643 × 0x38Splits of the best race: lap k at 0x364 + k × 0x38, i32 sector[5]; the rest of each slot is zero
0x3F415 × 0x38Lap table, best first: char name[20], i32 lap time, i32 sector[8]
0x73C1Rows in use (15; 0x6941C0)
0x73D1Timing sectors per lap (2 to 4; 0x6941C1)
0x73E2Zero
0x7405 × 0x16CSector tables, one per sector slot: 15 × (char name[20], i32 time), then u8 rows in use and 3 zero bytes

Only the first laps lap words of a race row and the first sectors sector words of a lap row are used; the others are zero. Sector slots past the sector count have 0 rows in use and all their bytes zero. Names are zero-padded; no file has bytes after a name's zero.

Who reads which part ​

  • FUN_004b28c8 finds the rank of a race time in the race table (count at +0x348, times at +0x14 of each 0x38 row). FUN_004b286c does the same for one sector table (count at +0x168, 0x18-byte rows).
  • FUN_004b2924 and FUN_004b2978 search the lap table by time and by name.
  • FUN_004b2a34 stores a new best race's splits at 0x693DE8, 0x693E20 and 0x693E58 (+0x364, +0x39C, +0x3D4) when its total beats row 1.
  • FUN_0045fd58 shows the gap to the record during a race: it adds the record's lap times (+0x14 + 4 × lap) and the split of the current lap and sector.

Times ​

A time is seconds in 16.16 fixed point (observed: FUN_0047e4d0 multiplies it by 1 / (65,536 × 60) for the minutes, takes the seconds from what is left, and the hundredths as the fraction × 100 / 65,536, then prints %02u'%02u"%02u). For example 0x00F85EB7 is 248.37 s, shown as 04'08"37.

File names ​

load_records and save_records build the name from the circuit's file stem (build_data_path, FUN_004ae91c, folder 8 = Data\Records\) and then change two characters (observed, not yet seen on disk):

  • The last character becomes the mode: T when bit 2 of 0x61D5B8 is set (time attack), else the difficulty from 0x61D5CC: E (1), H (4), M (anything else). The disc has only the .BRT files.
  • The first character of the name becomes - for the mirrored circuit (save_records: when 0x61D5E8 > 0; load_records: when its second argument is non-zero).

So a race on a mirrored circuit at hard difficulty would write a file such as -ELTANE.BRH (inferred). In POD (observed, 0x4ad09c, docs/systems/front-end.md "Best times"): the same rules with the mode 0x633320 & 4 and the difficulty 0x633334; the extension is set by 0x4a9b98. How the game writes a file, row by row, is in that section, measured under the emulator against the port (crates/pod-ui/src/best_times/).

When a file is missing ​

FUN_004b1d84 fills the tables when the file cannot be opened (observed): 15 rows with names drawn at random from 21 built-in names (0x4F7CAC, 20 bytes each) and times rising from a base time (0x693A50) in steps of base / 60. The shipped files look made the same way: in every file each race row's laps are equal and rows rise by a constant step (measured).

Measured cross-check with CIRCUITS.BIN ​

15 of the 17 files have as many sector tables as their circuit has timing sectors in CIRCUITS.BIN. BANK.BRT and SPECIAL.BRT have 3 where CIRCUITS.BIN gives 4 (measured): the files may come from an older circuit list. What the game does with such a file is open.

Modding ​

Write the file with brt.py's encode() or records::write. Names longer than 19 characters do not fit. Keep the zero bytes the layout lists as zero: the readers here refuse a file that has data there, because the game's own writer never puts any.

Open questions ​

  • A changed .BRT loading in the game, and the game writing one (needs a writable copy of DATA/RECORDS under Wine).
  • The - and E/M/H file names seen on disk.
  • What the game does when the sector count in the file differs from CIRCUITS.BIN.

Prose CC0 1.0, code Apache 2.0. POD: Planet of Death is © Ubi Soft; none of its files are on this site.