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: resource layouts and documented ordinary-fight playback rules recovered. All 520 mesh records validate against the decoded header, vertices, polygons and moving-part layout. The scene, motion, raster, clock and audio source rules are documented below. Native commands now establish ordinary cross-fight phase retention. No identified algorithm gap remains for the documented parameterized paths. One particle integration input producer remains unbound, as described below; native visual, audio and cadence conformance is also incomplete.
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
Runtime
4 fields · 38 bytes
data
databehaviour
databehaviour
data
| slot | world_position | object_rotation |
|---|---|---|
| A | 0x24 | 0x2a |
| B | 0x26 | 0x2c |
| C | 0x28 | 0x2e |
Reserved
1 field · 10 bytes
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
Runtime
4 fields · 12 bytes
databehaviour
databehaviour
databehaviour
Serialized nonzero values remain unexplained.
databehaviour
| slot | containing_part_ids | anchor_indices |
|---|---|---|
| A | 0x0a | 0x18 |
| B | 0x0b | 0x19 |
Colour
3 fields · 5 bytes
0, 32, 64, 96, 128, 160 - the polygon's colour: a base index into the fight palette, see Colour
datarender
databehaviour
-8..+8; ordinary shade step, or anchor key/effect-model selector in the special material path.
See Colour.
datarenderbehaviour
Drawing
3 fields · 3 bytes
1 also participates in anchor preparation.
Mode 1 uses the separate segment path; 0xff checkerboards, 0xfe/0xfd use row bands, and 0 fills. Material 2/-1 takes precedence. Line clipping/stepping is source-backed; native conformance remains partial.
databehaviour
databehaviour
Wider authoring meaning remains partial.
databehaviour
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.
FTTAB1 common part/rate and optional anchor-driven commands are source-backed; ordinary cross-fight phase retention and Y-only common commands are captured live
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
Colour
2 fields · 4 bytes
databehaviour
databehaviour
Placements
2 fields · 2 bytes
data
datarender
Reserved
1 field · 12 bytes
data
Position
4 fields · 8 bytes
object_ids
datarender
datarender
datarender
databehaviour
Drawing
1 field · 2 bytes
0, -1 or -2 in these files; copied unchanged to staged controls.
Runtime scans admit -2, -1 and 1 in separate batches; zero joins the per-side dynamic batch.
databehaviour
Rotation
1 field · 6 bytes
databehaviour
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.
- lead_1c◐Zero on disk; runtime role not established here. ObjectHeader
- lead_30◐Zero on disk; runtime role not established here. ObjectHeader
- raster_mode◐Selects raster dispatch; mode
1also participates in anchor preparation. PolygonRecord - face_group_control◐Positive reuses the prior lighting term, negative sets it to zero; also controls face-list traversal and culling. PolygonRecord
- normal_control◐Nonzero bypasses ordinary normal rotation and takes the zero lighting-term path; also bypasses one backface test. PolygonRecord
- lighting_mode◐Selects ordinary, ambient-only, direct-bias and special normal/material paths. PolygonRecord
- anchor_indices◐Initialization zeros this word; the conditional anchor pass writes two counter bytes consumed as signed anchor indices. PolygonRecord