Skip to content

Championship saves (Data\ChShip\POD<n>.<kind>) ​

POD saves a championship under way into one of sixteen slots. The game makes these files; the disc has none. Everything here is observed in POD 2.8's WINPOD.EXE unless marked; no file made by the original has been checked yet (unknown: whether a real save matches byte for byte; the layout below is read from the code that writes and reads it).

Reader and writer: crates/pod-formats/src/chship.rs (round-trip tests in the module). The menus that save and load them: docs/systems/front-end.md, "Championship saves (POD)".

Where and what ​

  • Folder: folder 9 of open_data_file (0x4765f8): folder_path (0x475a10) gives Directory (0x58e1b0) plus Data\ChShip\ (0x4e5f64). As for the other save folders, no copy on the CD is looked for (docs/modding.md).
  • Name (0x46b598): POD and the slot ("%s%d", the slot 0 to 15 as a signed 16-bit number), then an extension chosen from the mode bits (0x633320), tested in this order:
Mode bitsExtensionChampionship
2, 0x800 and 0x1000.RSrandom (action 21, mode 0x180a)
2 and 0x80.CScustom (action 20, mode 0x8a)
2 and 0x1000.VSunknown
2 and 0x800.TSunknown
2.NSstandard (action 19, mode 10)

Without bit 2 the name gets whatever the stack buffer held (not a championship; never called so).

  • Written by 0x46b70c (slot in AX): CreateFileA for writing, then one WriteFile per block below, each checked for its full length; a short write closes the file and returns 0.
  • Read by 0x46bc60 (slot in AX, keep in DL): nothing when the slot's menu text is empty; else 0x46b200 keeps the globals, each block is read and stored back where it came from, and any short read restores them (0x46b3cc) and returns 0. With DL = 0 (a probe) the state is restored after a good read too.
  • Names only (0x46c2d8): for each of the 16 slots, the first 32 bytes are read into the current menu's item text (AL = 1) or field (AL = 0); a slot with no file gets an empty field.

Layout ​

All values little-endian; i32 unless said. Offsets for one player and eight racers with no driver entries; the racers' part grows with their lists.

OffsetSizeContentMemory (POD)
0x000032The slot's name: the menu item's field (+0x88) as typed, its zero, then whatever the field helditem +0x88
0x00208POD Cshp (0x4e4e74, strncpy of 8: no zero). Not checked by the reader—
0x00284Tracks in the championship0x633340
0x002c4The race being run, from 00x633344
0x00304Human racers0x633324
0x00344Computer racers0x633328
0x00384Mode bits0x633320
0x003c4Laps per race0x633330
0x00404Difficulty (1, 2, 4)0x633334
0x00444Damage (0, 1, 2)0x63334c
0x004816 × 4The tracks by circuit number; action 19 writes -1 past the last0x634594
0x00880xd40Player 1's garage set-ups: eight car slots of 0x1a8 (layout not traced)0x4fe2e8
0x0dc88Player 1's kept flag per car slot0x4ffd68
0x0dd00xd40Player 2's set-ups0x4ff028
0x1b108Player 2's kept flags0x4ffd70
0x1b181Racer 0's gearbox (4 automatic)0x6339b8 (racer entry +0xc4)
0x1b191Racer 1's gearbox0x633a94
0x1b1aper racerThe racers, below, as many as the low words of 0x633324 and 0x633328 added (signed 16 bits)
end − 22Mirror mask: bit n set, race n is mirrored (0x4284a8 sets the race's flag 0x633350 from it)0x4fdf16

The reader reads nothing after the mask.

A racer (0x18c bytes, then two lists) ​

Built on the stack by 0x46b70c from several tables, racer r:

OffsetSizeContentMemory (POD)
+0x0000x40Name0x6338f4 + r × 0xdc
+0x0400x40The racer entry's text at +0x80 (start-up, 0x4986a4, copies a string from 0x6341cc into it; use unknown)0x633974 + r × 0xdc
+0x0801A byte 0x473534 subtracts from the racer count to put a race record's place back (inferred: the count less the last race's place)0x58b6d0 + r
+0x0813Never set: stale stack bytes—
+0x0844The racer's car (entry +0xc0)0x6339b4 + r × 0xdc
+0x0884Never set: stale stack bytes—
+0x08c4Entry +0xc8 (start-up sets the racer's number from 1; use unknown)0x6339bc + r × 0xdc
+0x0906 × 4Computer driver's state after the last race (0x456408, 0x4564b0 copy word +0x3c of six objects the AI record at 0x5a8e34 + r × 0xb8 points to)0x5a9828 + r × 0x7c
+0x0a86 × 4The same, kept from the race before (0x4565a4 copies the table)0x5a9448 + r × 0x7c
+0x0c04Championship points0x58b6b0 + 4r
+0x0c44Race times added up0x58b690 + 4r
+0x0c84Entries in the second list0x5a9824 + r × 0x7c
+0x0cc4Entries in the first list0x5a9444 + r × 0x7c
+0x0d00xbcThe race record (crates/pod-race/src/record.rs)0x4f8d84 + r × 0xbc
+0x18c8 × count +0xccFirst list (none when the count is 0 or less)0x5a93f4 + r × 0x7c
then8 × count +0xc8Second list0x5a97d4 + r × 0x7c

The two 0x7c-byte tables per racer (0x5a93f4, 0x5a97d4) hold up to ten 8-byte entries, the count at +0x50 and the six words at +0x54; they are copied from the computer drivers' records after a race (observed in 0x456408, 0x4564b0; what the entries mean is unknown).

After a good read, 0x46bc60 also: rebuilds the order table (0x4f9360, by the place in the high nibble of each race record's byte +4); checks the mirror mask: a non-zero mask needs the difficulty's flag (0x6345d4, 0x6345d5, 0x6345d6 for 1, 2, 4), else the load fails and the mask is cleared; loads the best times of the current track (load_records, 0x4ad118, with the bit 1 << track number of the mask: by the track's number, where 0x4284a8 uses the race's, observed); then calls 0x421bb0 (unknown).

Size ​

0x1b1c + 0x18c × racers + 8 × (all list entries): 0x277c (10,108) bytes for one player and seven computers with empty lists.

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