Skip to content

Game Objects Ships and Combat

LordBlacksun edited this page Sep 9, 2026 · 1 revision

Game Objects, Ships & Combat

The Game-Object ("GO") model [verified]

The world is a fixed array of 400 pointers at DAT_00587CE0; each points to a separately heap-allocated GO record of 0xB98 (2968) bytes (allocated in gameobj.cpp).

Item Value
pointer-table base 0x00587CE0
capacity 400 (table end 0x00588320)
record size 0xB98 bytes
high-water index DAT_00539AA0
player/AI count boundary DAT_0058832C
MP/arcade-mode flag DAT_00582E8C

Confirmed record offsets:

Offset Field
+0x00 object type id (< 0x100 = ships/weapons, geometry-backed; ≥ 0x100 = lightweight)
+0x04 self index
+0x08 flags (bit 0x20 = free slot, bit 0x400 = inactive)
+0x10 → per-type geometry/stat template &DAT_004FC670 (stride 0x30)
+0x14 → per-type template &DAT_004F9E70 (stride 0x28)
+0x84 position (vec3)
+0x59C bounding-sphere radius (float)
+0x5E8 hull / health
+0x640 / +0x644 AI vtable / behaviour id
+0x684 current-AI pointer
+0xB94 alive/in-use byte

Lifecycle: FUN_00466630 initialises the table (marks all slots free); FUN_00475DD0 is the constructor (gameobj.cpp); FUN_00466C10 is the factory (Create.cpp) — guards "create object: Overrun in GO arr" (index ≤ 399) and "Trying to create object %s twice" (+0xB94). Objects are destroyed by slot reuse (set free flag), not freed; iteration/collision skip slots with flags & 0x420.

Models (.SHP) & loading [verified]

FUN_00441AA0 (loadout preloader) loads model assets in batches: each is a 0x14-byte "OBJECT FILE" handle with the parsed .SHP at +0x0C, produced by the .SHP loader FUN_004A44D0. It walks fixed-width name tables (ships USLF.prd.SHP stride 0x22C; missiles stride 0x110; guns) and SetCurrentDirectorys into each asset folder. Assets are read as loose files by name after install; the .HOG (EA BIGF) is the distribution container. Weapon meshes are bound per weapon-type in FUN_0047D9A0.

Stat tables (SHIP/GUN/MISSILE/PILOTSTATS.BIN) [verified — corrects the format note]

All four loaders read with fread(buf, 0x160, 1, file) in a loop → 352-byte records, with a 64-byte name at +0x00 and stat fields beginning at +0x40. The 15 stat dwords are a mix of float32 and __ftol-converted int32 (so "15 floats" is only partly right). The trailing 0x7C..0x160 is not read by the loaders (preserved tail).

File Loader Fills
shipstats.bin 0x00466500 &DAT_004F9E74 (stride 10 dw) + &DAT_004FC678 (stride 0xC dw) — the same per-type templates the GO factory reads via +0x10/+0x14
gunstats.bin 0x004788F0 &DAT_00500CE8 (stride 0xB dw)
missilestats.bin 0x00494BC0 &DAT_005035E8 (stride 0x28 B)
pilotstats.bin 0x0049CAE0 &DAT_0058A968 (stride 0x12 dw)

The ship-stat → per-type-template → GO-factory link is now established: a record at table index type is reached by type * 0x30 / type * 0x28.

Combat systems [verified]

Addr Role
0x00468FA0 collision — sweep-and-prune on an axis, then narrow-phase squared-distance vs (r_a + r_b)² using position +0x84 and radius +0x59C; owner ids +0x618/+0x61C exclude self/parent.
0x0049F790 shields (shield.cpp) — "Capshield mesh"; capital-ship shields are an 8-section mesh-mapped HP grid (per-slot table 0x58FB70, stride 0x3C).
0x004A0310 shield-impact FX (shieldfx.cpp) — 12-byte hit-flash effect.
0x0046BF20 / 0x0046D090 explosions (explode.cpp) — debris burst + named subsystem-debris meshes (e.g. Kras_l_eng_block) for component-level destruction.
0x0040CA50 per-ship AI attach/detach — dispatch table &PTR_DAT_004E06E0 (stride 0x18: callback +8, priority +0x14, name +0x10); current AI at GO +0x684.
0x0041FE60 / 0x0041DD70 jump/warp gates (wgate.cpp) — 0x88-byte gate record in a 32-slot table 0x51D1A4; procedurally generates the ring/tunnel mesh with sin/cos.

Clone this wiki locally