Skip to content

Modding: how the game finds its files, and how to load a changed one ​

A mod for the original WINPOD.EXE needs no patch to the game and no new disc. The game looks for every data file in the folder named by Ubi.ini before it looks on the CD, so a changed file placed there is loaded instead of the disc's copy. Four mods were loaded this way on 2026-10-23 (measured, in the emulated PC, run/vm): a string, a menu image, a track texture and a car's grip. The writers that make them are in crates/pod-formats (tests/writers.rs), and examples/make_mod.rs makes each one.

Where the game looks ​

At start-up FUN_00479954 reads C:\WINDOWS\UbiSoft\Ubi.ini (observed: GetPrivateProfileStringA):

Key in [POD2_0]Kept atUse
Directory0x578c5cThe installation folder, C:\POD\ in run/vm/inside.sh
Language0x57905cThe language folder for text and localised images (French); from GetLocaleInfoA when missing

The CD drive's root is kept at 0x57884c. open_data_file (FUN_0047ba70) finds the drive by trying every letter from A: for a drive of type 5 (CD-ROM) labelled POD2_0 (observed).

Every data file is opened through open_data_file with a folder number. folder_path (FUN_0047aeb4) builds two names from it (observed: one switch on the folder number, two string copies per case): the first under Directory, the second under the CD's root.

FolderPath under the rootFilesOn the CD too
1Data\Binary\Voitures\Cars .BV3/.BV4, CHROME.CH3/.CH4yes
2Data\Binary\Circuits\Tracks .BL3/.BL4yes
3Data\Binary\Polices\Fonts .BP3, effects .BI2yes
4Data\Binary\Dicos\<Language>\Text .BMDyes
5Data\Binary\MIMG\Menu images .IMGyes
6Data\Binary\MIMG\<Language>\Localised menu imagesyes
7Data\Binary\Scripts\Lists .BINyes
8Data\Records\Best times .BRTno
9Data\ChShip\Championship saves POD<n>.NS and others (formats/chship.md)no
10Data\Params\Car setups .prbno
11Scope\(not seen in use)no
12Data\Com\modem.annno
13Data\Binary\Video\Stills .BBM, CREDITS.BVB, videosyes
14Data\Binary\resson\Sounds .MEG, music lists .TXTyes

Then open_data_file does this (observed):

  1. CreateFileA on the name under Directory. If it opens, that file is used.
  2. If it fails and the file is opened for writing, the game reports "impossible to write file".
  3. Folders 8 to 12 (the game's own saves) stop here: no CD copy is looked for.
  4. Otherwise, when the CD has been found (0x578858 set), the name under the CD's root (inferred: folder_path writes that name into the buffer passed in EBX, which Ghidra's pseudocode drops; that the CD copy is read is measured, since unchanged files still load).
  5. If that fails too, the game searches the drives for the POD2_0 disc again and asks for it (message 0x436 to its window); Cancel quits.

So a mod is a file at the same path under Directory: for example C:\POD\Data\Binary\Circuits\BELTANE.BL3. Wine finds the folder names in any case. Only the files that change need to be there; the rest still come from the CD.

The four mods (2026-10-23) ​

Each was made with cargo run --release -p pod-formats --example make_mod, copied into the VM's C:\POD\ with run/vm/mods.sh install, and seen in the running game (screenshots in the diary, 2026-10-23, "The first mods"). The 8-bit build reads the .BL3 tracks and .BV3 cars (docs/hardware/3d-cards.md).

ModFileCommandSeen in the game
A stringDicos\French\DIC_GAM.BMDtext … LAPCNT LAPESP "MOD " (and CHRONO LAP, AFFICH LAPX, AFFICH LASTLAP)The lap counter reads "MOD 1/3" instead of "Tour 1/3"
A menu imageMIMG\BELTANE.IMGimage … 0The track screen's map of Beltane carries a frame and "MOD"
A track textureCircuits\BELTANE.BL3texture … 0Texture page 0 (route2l2, murco4, Cellule, stone2) is a yellow and grey chequerboard on the tunnel walls and ceiling
A car valueVoitures\GAMMA.BV3setting … 2 5The car screen shows "Adhérence 5" instead of 95; the race car's grip falls from 3.67 to 1.33 (read from memory); lap times below

Notes from the mods (measured):

  • Colours come from the palette. A changed 8-bit picture keeps its palette, so the writer picks the nearest palette colour. Beltane's palette has no magenta: the chequerboard's magenta squares came out grey, and the menu image's yellow came out green.
  • A longer string is fine. The text writer appends the new string to the pool and points the key at it; the pool and the file grow (text.rs, Table::set).
  • The game checks the container. Every changed container file is written through pod_container::encode, which recomputes each block's checksum; a wrong sum stops the game (docs/formats/container.md).

Grip: the garage setting, not the parameters ​

A first grip mod changed the parameters' side_grip and traction_grip (carparams.rs) on all four wheels to 1.2. The changed values were in the car's slot in memory (0x61757c + slot × 0x63c, parameters +0x94), so the file loaded; but the race car (0x61aad0, +0x94) held 3.67 on every wheel, as it does with the disc's file (measured). The race uses the garage setup: setup_defaults (FUN_004436c8) computes one grip for all four wheels, side and traction alike, from the car's third garage setting, and car_from_setup (FUN_00442f04) writes it over the parameters (observed). The setup lives at 0x50769c + car × 0x1a8, the grip at +0x13c.

The five garage settings at the end of the car file are the car screen's five figures, in order: acceleration, brakes, grip ("adhérence"), steering, speed (measured: GAMMA's 49, 25, 95, 82, 49 on screen; a changed third value shows there). make_mod setting FILE OUT 2 N changes the grip.

GAMMA driven by the line follower (run/vm/follow.py, the same recorded line, Beltane, 3 laps, EASY); progress from its log (--log), lap ends counted along the line:

Grip settingRace car's grip (memory)Laps completed at (s after the follower starts)
95 (the disc)3.67 (240517)159, 317, 472 (the game's best lap 2:33.38); a second run 154, 323, 482 (best 2:37.39)
502.50 (163840)202, 506 (the game's lap times 3:28.38 and 5:00.79); wedged in a dark corner in lap 3
51.33 (87162)none: 0.69 of a lap in 625 s, 418 s of them standing against walls

The three values fit grip = 1.2 + 0.026 × setting exactly in 16.16 (measured at three points; the code computes it in x87 floating point, which Ghidra's pseudocode hides). The computer's cars race with 3.15 (206438) whatever the player's car file says.

Track edits (2026-10-24) ​

The track editor (apps/viewer, feature editor; pod-viewer edit) writes over the fields the reader found, so an edited track keeps its size and every other byte. Three edits were loaded in the 8-bit build in the emulated PC and compared with a stock race run the same way (screenshots in the diary, 2026-10-24, "The track editor"):

EditFileCommandSeen in the game (measured)
A changed textureCircuits\BELTANE.BL3--sector-page 35 1 --sector-page 36 1The road after the grid shows page 1's red and orange pictures; the stock race shows the brown road there
A raised roadCircuits\BELTANE.BL3--raise 601.5 48.2 35 6The cars drive over it: at x ≈ 596 the player's car is at z 55.2 against 52.3 in the stock race, at x ≈ 613 at 54.7 against 49.4, and the seven computer cars rise the same way (racerec.py); past the crest they stay above the old road to x ≈ 650, beyond the bump's end at 636, so they jump; the camera tilts over the crest at 222 km/h
Moved propsCircuits\ALDERON.BL3--move-prop on two signs and three cones, onto the road 40 and 60 units after the gridThe signs and cones stand on the road in the race; the stock race shows the bend empty

Beltane has no environment props (its .env name is NEANT), so the props were moved on Alderon. The game takes the new heights for its physics as well as its drawing: the raised road needs no change outside the sector geometry, given the face normals and the sector bounds that the editor writes again (docs/formats/tracks.md, "After the sectors").

Edited tracks in Un-POD (POD, 2026-10-24) ​

The editor installs an edited track into a game folder (pod-viewer edit ... --install GAME_DIR, apps/viewer/README.md), and Un-POD reads it from there with unpod --live --content GAME_DIR/Data, as the original reads its install folder before the CD. --as NEW installs a copy under a new name with its own CIRCUITS.BIN row (pod_extras::install::add_circuit). Compared with the same race on POD's own files (measured with the probe, car 0 every 10 passes, holding accelerate only):

EditTrackSeen in Un-POD
--sector-page 35 1 --sector-page 36 1BELTANE.BL3The road after the grid shows page 1, as in the original
--raise 601.5 48.2 35 6BELTANE.BL3The player's car is higher from x ≈ 570: +3.5 at x 600, +4.8 at x 620; it stays above the old road to x ≈ 650, past the bump's end, and lands (Un-POD at d4fa3b4; repeatable byte for byte). The original (first edition, racerec.py) gave +2.9 at x 596 and +5.3 at x 613
--sector-page 72 6 --as MAGVOLTMAGNETIC.BL3 (new in POD), installed as a new trackUn-POD races MAGVOLT; the grid's sector shows page 6
--move-beacon 35 0 0 50BELTANE.BL3: the lap line (beacon 35, its chain runs "P-Chrono Tour") lifted 50 unitsThe cars pass under it: after 3:20 the computer's racer 1 has crossed it 0 times and has no lap, against 2 crossings and a lap of 111.2 s on POD's track; every car waits for checkpoint 0
--move-path all 600 48 80 0 25 0BELTANE.BL3: the racing line moved 25 units across the downhill straightThe seven computer cars follow it: their mean y on their first pass is +24.2 at x 595 and +23.8 at x 610, falling off on both sides as the move does (+7.7 at x 550 and 655)
--add-prop 4 -380 -21.5 6.8 and three --add-prop 7 across the lane at x −360ALDERON.BL3The sign and three cones stand on the road; the player's car, holding accelerate, passes between the cones with its path and speed unchanged (whether the cone in its way moved is not measured)

Make your own ​

sh
cargo run --release -p pod-formats --example make_mod -- text  DIC_GAM.BMD OUT.BMD SECTION KEY "TEXT"
cargo run --release -p pod-formats --example make_mod -- image BELTANE.IMG OUT.IMG ENTRY
cargo run --release -p pod-formats --example make_mod -- pages BELTANE.BL3
cargo run --release -p pod-formats --example make_mod -- texture BELTANE.BL3 OUT.BL3 PAGE
cargo run --release -p pod-formats --example make_mod -- car GAMMA.BV3 OUT.BV3 FIELD VALUE

Put the result under Directory at the path in the table above, with the original file's name. To undo a mod, delete the file: the game goes back to the CD's copy.

Open ​

  • Whether the 3D-card builds use the same two roots (they share open_data_file's strings; not checked).
  • What folder 11, Scope\, holds.
  • A changed track's race paths and beacons in the game: geometry, textures and props load (above); the race data is still kept as bytes (track/layout.rs).

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