Skip to content

The track world ​

The track as POD 2.8's WINPOD.EXE keeps it in memory for the car physics, and how Un-POD lays it out from the player's disc (crates/pod-world). The physics reads it through pod_physics::World at the original's addresses (physics.md, "The track"). Each finding is observed (read in POD's code), measured (against a snapshot of the running game, derived/physics/pod-beltane.world), inferred or unknown.

WhatIn memoryFrom the file (load_track_file, POD FUN_0046a1e8)
Sector tablecount [0x57bf74], records of 0x3c at [0x57bf78]one per sector, in order
Sector record+0 mesh; +0x10 .. +0x24 bounds; +0x28 neighbours (-1 out of play); +0x2c their records; +0x34 = 1the bounds after the sector's mesh, the floor 2 lower and the top 10 higher (measured); the sector's visibility list, in order; an empty list gives -1 (measured, sector 68)
Mesh (read_object, POD FUN_00466898)+0 vertices, +2 triangles, +4 quads (u16); +0xc vertices; +0x14 triangles; +0x18 quadsthe object's counts and its vertex words as they stand
Quad (read_face, POD FUN_00465d54), 0x3c+0 normal; +0xc and +0x18 the halves' normals; +0x2c corners (u16); +0x34 render kind; +0x35, +0x36, +0x37 the flags word's bytes 1, 0, 2the file's normal and corners; the halves a b c and c d a by FUN_004247f8 (measured: all 2,615 quads); the render kind from the render type's name (0x60 TEXGOU, 0x20 GOURAUD measured; 0x40 TEX, 0x10 FLAT inferred); the trailing flags word split (observed, 0x46650f .. 0x466538): byte 0 the flags (bit 3 ground, bit 5 wall), byte 2 the surface
Triangle, 0x20+0 normal; +0x14 corners; +0x1a render kind; +0x1b, +0x1c, +0x1d the flags word's bytes 1, 0, 2as for quads
Surfaces, 0x62bc0c16 records of 12 bytes, the grip firstFUN_004985e8's defaults (grip 1, 50000, 40000, 25000, … in 16.16); FUN_00498584 reads 16 "%ld %ld" lines over them from a file when one opens (not ported; the running game holds the defaults)

A .BL4 sector face carries one more word before the flags word (pod-formats car::face). Read past it, POD's .BL4 files give the same world as their .BL3 twins on 13 of 14 tracks. On LOON the .BL4 faces lack flag bits 0x40 and 0x80, which is the file's own data (measured, tests/snapshot.rs).

tests/snapshot.rs compares every field the physics reads, for all 141 sectors and 2,837 faces of POD's Beltane, with the snapshot: all match. Not laid out: the texture and colour words of the faces (+0x24, +0x28), the vertex normals (+0x10), the second list at +0x30, which the physics does not read; the race paths (putback.rs reads them when a car is put back).

The race cars and the grid ​

Each racer's race car comes from its car file (crates/pod-world, racer.rs), as POD builds it when a race starts:

StepOriginalIn the port
The car file's parameters into the race car, field for fieldcar_to_racer 0x47161cracer::copy
The garage set-up from the five settings (acceleration, brakes, grip, steering, top speed)setup_from_car 0x434b94; top speed 0x4351c0, acceleration 0x435068 (the torque curve as a Bézier through 0x434e0c), grip 0x43542c, brakes 0x435390, steering 0x435324; car_from_setup 0x434cc8racer::setup_from_car and the five setting functions
The settingsthe player's from the car file; the computer cars' 80, 80, 75, 35, 30 (HARD 85 and 100; time attack 120) in place_racersSettings::from_file, Settings::computer
The difficulty factor on the top speed, for every car0.8 EASY, 0.9 MEDIUMrace_car's factor
Inertias, weights and the body inertia from the half extents of body set 0's six objects and the four wheelscar_physics_setup 0x41c780, then car_resetracer::physics, half_extents
The grid slot: the track's start record (0x24 bytes: position, then heading); a point outside every sector takes the first sector that holds itFUN_004236f0, FUN_00423538, FUN_0045ccd8racer::grid
The settling: steps of 3 × the step unit until 0x20000, each car's input 0x10, its controller, the car step, the wheels' roll, the stuck timer clearedrace_setup 0x49b9d4 (FUN_004155b8, FUN_0041e0d0)pod_game::live settle

Measured: crates/pod-world/tests/racer.rs compares every set-up field of the eight cars of POD's Beltane (EASY) with the first step of the step log, and crates/pod-game/tests/start.rs starts the race from the disc (pod_game::start::from_disc: the world from the track file, each car from its file on its grid slot, the drivers fresh), settles it and compares every word of each race car, the pointers aside, with the same step: all match. The computer drivers' first line point is found as FUN_00455ed0 finds it.

After the settling, each car's race tracker (the driver's +0x2c link and +0x30 point, which FUN_004b0ec0 then moves along) is put on the path point nearest the car's body by FUN_004aa8a0's distance: the larger of |dx| and |dy|, or |4 dz| when larger (observed). Measured: all eight trackers are the original's at the first step (tests/start.rs). Deviation: the original places them with FUN_004af830, not ported. After a put-back the car's tracker is found again from its last one by FUN_004aa8a0 (pod-race's Paths::place, ported by the controllers session), as the original does (Cars::retrack).

The race paths ​

When a car falls through the track or lies upside down for 2.5 s, the physics puts it back (FUN_00415730, pod-physics putback.rs) heading along the race path at the driver's tracker. It reads the paths in memory; pod_world::paths::build lays them out from pod-race's graph:

WhatIn memory (measured on POD's Beltane)
[0x543254]non-zero when the track has paths (a link's address here)
Node, 0x24 bytes+0 the position, +0xc the links out, +0x14 their list, +0x1c the value
Link, 0x1c bytes+8 the end node, +0xc the start node, +0x10 the points (12 bytes each), +0x14 the values, +0x18 how many

Past a link's last point the put-back's step (FUN_004abae8) goes to the end node's position when it has several links out, else to the first point of its only link. pod-race's tracker (FUN_004b0ec0, FUN_004b0b98) always takes the node's position.

Measured: crates/pod-world/tests/paths.rs reads the step at every point of Beltane's paths from the laid-out memory, and at the eight drivers' trackers compares it with the running game's records: all match. The live race gives the step the race's tracker as the driver's, so a put-back on the disc's world heads along the path (tests/start.rs).

The cars' drawn objects ​

The collisions and the damage (physics.md, "Car against car" and "Damage") read each car's drawn object, the driver's +4. pod_world::object::build lays out the fields they read:

WhatIn memoryFrom the file
Body parts18 objects, three sets of six; +0x34 the hull, +0x38 the macro chain, +0x3c the healthFUN_0046aabc (observed): each object's hull is the seven words after it in the file (half sizes, radius, centre); health [0x61ea68], set to 2,000,000 at start-up; sets 0 and 1 each get a chain of one element, FUN_004545a8 with the same part of the next set, so a broken part becomes its damaged version; set 2 has none
Wheels4 objects, +0x34 the hullas for the body, no health and no chain
The race object+0 10 parts, +4 their list (body set 0, then the wheels), +0x44 the hull of the whole carFUN_004203c8, "Prisme" (observed): each of the ten parts gets a new hull from its own vertices (FUN_00420300); the whole car's hull is the box of all ten parts' vertices
A hull, 0x1c bytes+0 half sizes, +0xc radius, +0x10 centrethe vertices' box (FUN_004713c8, from 0x7fffffff and 0x80000001): half sizes (max − min) >> 1, centre (max + min) >> 1; radius FUN_00423b48, √(x² + y²) of the x and y half sizes through FUN_004d3e90

Measured: crates/pod-world/tests/object.rs compares every one of these fields, for all eight cars of POD's Beltane, with the running game's objects (snapshot and step log): the ten parts' hulls and health, their chains and the damaged parts two sets down, and the whole car's hull. All match.

The live race (pod_game::live) runs the collision pass (cars::collisions) after every car's step, with the frame's time, and follows the damage when the menus' option is on (Setup::damage, [0x63334c]). Not ported: the wheels' part offsets (+0x98, which the physics takes from the car) and the drawn meshes; the damage record for the race display (FUN_0047ed1c). A push joins the car's move of that step (Deviation: the original tests the beacons again after each push).

Props ​

The props of a track's .env (cones, drums, boxes, signs) that cars knock about are its global list, the "Objets Collisionnables" at [0x62129c], [0x621298] of them (pod-physics props.rs). POD's environment reader FUN_00468cfc (pod-formats read_environment) builds them; the lists per sector are decoration and stay in the sectors (+4, +8). pod_world::props::build lays them out (observed in the disassembly):

StepOriginalIn the port
A type: its object, then the hull's seven words (+0x34), the mass +0x1c, the inertia +0x24, the health +0x3c, the friction +0x20 and the contact points (+0x30 the count, +0xb8 the records, 0x40 bytes each), each point's sector the first sectorFUN_0046a780 (0x46a804 .. 0x46a8aa)props::kind. pod-formats' frames are these points; the word it reads as the object's tail is the hull's first
The centre of mass, Σ point offset × point mass (+0x1c), scaled by 2³² / the mass, taken off the points' offsets and the hull's centre (and the vertices)FUN_00454654props::centre
A prop: a copy of its type's record, its macro list (+0xb0), its position (+0x98) and matrix (+0x40, row by row) from the file; every point in the first sector in play whose bounds hold the position (FUN_0045ccd8), else the first sectorFUN_00468cfcprops::build

Measured: crates/pod-world/tests/props.rs compares every field the physics reads of Canyon's 20 props with POD's running game (pod-canyon.world): mass, friction, inertia, points, hull, health, chain, matrix, position, the motion state, and every contact point, its sector by number. All match. The live race reads them at the start and runs the props' collision pass (props::collisions) after the cars' pairs each step. Not laid out: the props' meshes and macro lists (the renderer's and the track macros').

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