Fight 3D resources
FGT/*.LIB, FGT/*.DAT
Everything that draws a close-combat scene: 3D meshes, scenery lists, palettes, movement and camera tables, and the sine table.
Close-combat scenes in Battle Isle 2 are drawn with small 3D meshes rather than sprites. Everything that draws them lives in the FGT/ directory: the meshes (three archives sharing a 3DOB magic), the scenery and ground lists, the palettes, the backdrops, the movement and camera tables, a sine/tangent table and the sound banks. This page describes each in turn.
Status: header, vertices, polygon topology, per-face normals, per-face colour and the moving-part table recovered and validated against all 520 records - enough to render the meshes as the game does, including the per-face shade bias, and to know which polygons are a turret and where it pivots. Every byte of the file is now accounted for. The 3DLD scene lists that place the scenery are decoded too, and groupSize records a unit's strategic member count. The conversion from strength to visible members still needs a runtime trace. The layout is accounted for; the light term, some angle drivers and three inline polygon fields remain unresolved.
Archives
| Archive | Records | Contents |
|---|---|---|
FGT/UN3D000.LIB | 240 | units (UNIT###), animations (ANIT###) |
FGT/LAND000.LIB | 288 | terrain objects (LAND###) |
FGT/LAND300.LIB | 288 | terrain objects |
FGT/PAL000.LIB | 41 | the fight palettes the meshes are coloured from |
FGT/LAYR000.LIB, LAYR300.LIB | 96 each | 3DLD scenery layer lists |
FGT/GRND000.LIB, GRND300.LIB | 24 each | 3DLD ground lists |
FGT/BACK000.LIB | 20 | the raster horizon backdrops and their moons - not meshes; see Where the mountains go |
520 of the entries carry the 3DOB magic; the remaining 296 are 8-byte LEER__ (German *leer*, "empty") placeholders for unused slots.
FGT/SCHOSS.DAT (German *Schuss*, "shot") is a twelfth archive in a container of its own, and it holds the ammunition. Its own layout is simple: a u32 at 0x00 gives the offset of the directory, TCT and an entry count follow at 0x04, and the directory is 40 records of an 8-byte name and a u32 offset. The 40 slots are ten AMMO### groups in A/B/C/S form, of which 11 hold real 3DOB objects - the ten A models plus AMMO005S - and the other 29 are LEER__.
They obey the object layout above (face_offset - vertex_offset == vertex_count * 6 and so on) and none has parts:
| Object | Size | Reads as |
|---|---|---|
AMMO001A | 2 vertices, 1 two-vertex face, steel | a tracer: a bare 320-unit line |
AMMO002A | 7 vertices, 8 faces, steel and olive | a shell, 420 units long and 30 wide |
AMMO005A | 9 vertices, 2 faces, all sky, y = 0 throughout | a flat water splash |
AMMO006A | 16 vertices, 10 faces, steel and gold | a 110-unit ball with gold octagon caps |
AMMO050A | 12 vertices, 8 faces, entirely gold | a 120-unit ball of flame - a muzzle or impact flash |
The rest of FGT/ is not 3D. FGTEXPLO.LIB and FGTSHOOT.LIB are Creative Voice (.VOC) samples, named by where the explosion happens (LAND, WATER, UWATER, AIR) and by weapon type (MG, KAN, ARI, RAK, BOMBE, WBOMB, TORP, GTORP, with LEER in the unused slots); FGTWIN.LIB and FGTLOS.LIB are eight XMIDI stings each for winning and losing a fight.
Object layout
All multi-byte integers are little-endian.
Tables
4 fields · 8 bytes
databehaviour
trailing_offset on the 410 objects that have no parts
databehaviour
databehaviour
databehaviour
Counts
3 fields · 6 bytes
+ 1
data
+ 1
data
Reserved
2 fields · 48 bytes
0 across the corpus
data
0 across the corpus
data
Position
3 fields · 6 bytes
datarender
-Y
datarender
datarender
Normal
3 fields · 6 bytes
16384 = 1.0)
datarender
x
datarender
x
datarender
Layout
1 field · 2 bytes
26 + 2*vertex_count - the fixed fields run +0x00..+0x19, then one word per vertex.
Holds for all 16480 polygons in the 520 records
datarender
Vertices
3 fields · 4 bytes
vertex_ptrs
data
+ 1 vertices
datarender
vertex_count words
datarender
Colour
2 fields · 4 bytes
0, 32, 64, 96, 128, 160 - the polygon's colour: a base index into the fight palette, see Colour
datarender
Reserved
2 fields · 10 bytes
data
0 across the corpus
data
Unknown
3 fields · 6 bytes
data
data
0 on 92% of faces; undecoded
data
Geometry
4 fields · 8 bytes
datarender
+ 1 consecutive polygons
datarender
datarender
+ 1 entries
datarender
Pivot
3 fields · 6 bytes
datarender
-Y, as everywhere else in the format
datarender
datarender
Runtime
2 fields · 12 bytes
0 on disk; runtime X/Y/Z translation added after pivot rotation
databehaviour
0 on disk.
Per-class drivers remain open
datarenderbehaviour
| slot | translation | angles |
|---|---|---|
| A | 0x0e | 0x14 |
| B | 0x10 | 0x16 |
| C | 0x12 | 0x18 |
Reserved
1 field · 6 bytes
0 on disk; runtime role unresolved
data
Objects
1 field · 12 bytes
LAND objects this record may place; 0xffff/0xfffe mark unused slots
datarender
Placements
2 fields · 2 bytes
data
datarender
Reserved
1 field · 16 bytes
LDF005G.3DL
data
Position
3 fields · 6 bytes
object_ids
datarender
datarender
datarender
Unknown
1 field · 2 bytes
0, 0xffff or 0xfffe; undecoded
data
Reserved
1 field · 8 bytes
data
Still to investigate
Every field marked unknown or partial above, and every bit that is set without a name or named without ever being set.
- unknown_10○packed small byte pair; undecoded PolygonRecord
- unknown_12○packed small byte pair; undecoded PolygonRecord
- unknown_18○
0on 92% of faces; undecoded PolygonRecord - unknown_02○
0,0xffffor0xfffe; undecoded Placement