Author: Mirex, JWP, random_npc, myst6re, HobbitDur
Header
DAT file is divided into 11 sections (except for c0m127.dat, which contains only 2 sections : 7th and 8th).
Offset | Length | Description |
---|---|---|
0 | 4 bytes | Number of sections (always =11, except for c0m127.dat) |
4 | nbSections * 4 bytes | Section Positions |
4 + nbSections * 4 | 4 bytes | File size |
Section 1: Skeleton
More info on OpenVIII
Offset | Length | Description |
---|---|---|
0 | 2 bytes | Number of bones |
2 | 6 bytes | Unknown |
8 | s16f (divide by 4096f) | scaleX |
10 | s16f (divide by 4096f) | scale -Z |
12 | s16f (divide by 4096f) | scale Y |
14 | 2 bytes | Unknown |
16 | Number of bones * 48 bytes | Bones |
Bone struct
Offset | Length | Description |
---|---|---|
0 | 2 bytes | Parent id |
2 | s16f (divide by 4096f) | Bone size (?) |
4 | s16f (divide by 4096f) | unknown, multiplied by 360f |
6 | s16f (divide by 4096f) | unknown, multiplied by 360f |
8 | s16f (divide by 4096f) | unknown, multiplied by 360f |
10 | s16f (divide by 4096f) | unknown |
12 | s16f (divide by 4096f) | unknown |
14 | s16f (divide by 4096f) | unknown |
16 | 28 bytes | Unknown (often empty) |
Section 2: Model geometry
Header (data sub table)
Offset | Length | Description |
---|---|---|
0 | 4 bytes | Number of objects |
4 | nbObjects * 4 bytes | Object Positions |
4 + nbObjects * 4 | Varies | Object Data (see below) |
Varies | 4 bytes | Total count of vertices |
Object Data
Offset | Length | Description |
---|---|---|
0 | 2 bytes | Number of Vertices Data |
2 | Varies * NbVerticesData | Vertices Data (see below) |
Varies | 4 - (absolutePosition % 4) | Padding (0x00) |
Varies | 2 bytes | Num triangles |
Varies | 2 bytes | Num quads |
Varies | 8 bytes | Always empty |
Varies | numTriangles * 16 bytes | Triangles |
Varies | numQuads * 20 bytes | Quads |
Vertice Data
Offset | Length | Description |
---|---|---|
0 | 2 bytes | Bone id |
2 | 2 bytes | Number of vertices |
4 | nbVertices * 6 bytes | Vertices (nbVertices * 3 shorts) |
Useful structures
struct vertice {
sint16 x, y, z;
};
(sizeof = 6)
struct triangle {
uint16 vertex_indexes[3]; // vertex_indexes[0] &= 0xFFF, other bits are unknown
uint8 texCoords1[2];
uint8 texCoords2[2];
uint16 textureID_related;
uint8 texCoords3[2];
uint16 u; // textureID_related2
};
(sizeof = 16)
struct quad {
uint16 vertex_indexes[4]; // vertex_indexes[0] &= 0xFFF, other bits are unknown
uint8 texCoords1[2];
uint16 textureID_related;
uint8 texCoords2[2];
uint16 u; // textureID_related2
uint8 texCoords3[2];
uint8 texCoords4[2];
};
(sizeof = 20)
Section 3: Model animation
More info on OpenVIII
Header (data sub table)
Offset | Length | Description |
---|---|---|
0 | 4 bytes | Number of animations |
4 | nbAnimations * 4 bytes | Animations Pointers |
AnimPointer | Varies | Animation |
Animation
Offset | Length | Description |
---|---|---|
0 | 1 byte | Number of frames |
1 | Varies | Animation frame |
Animation frame
Each frame is one vector location and BonesCount*RotationVectorData. Vector location is used to manipulate the model in world space, where all the animation is rotating each bone. The frames work accumulatively, so in order to get the final rotation at in example frame 5, you have to add all rotations from frames 0,1,2,3 and 4.
Offset | Length | Description |
---|---|---|
0 | LocationVectorData | LocationVectorData |
Varies | 1 BIT | Mode bit (contains additional info check) |
Varies | RotationVectorData * bonesCount | Rotation Vector data per bone |
Location vector data
Offset | Length | Description |
---|---|---|
0 | PositionType | Location X |
Varies | PositionType | Location Y |
Varies | PositionType | Location Z |
Rotation vector data
Offset | Length | Description |
---|---|---|
0 | RotationType | Rotation X |
Varies | RotationType | Rotation Y |
Varies | RotationType | Rotation Z |
Varies | 1 BIT | bUnk1 |
Varies | 0 if bUnk1==0, else 16 BITs | Unk1 data |
Varies | 1 BIT | bUnk2 |
Varies | 0 if bUnk2==0, else 16 BITs | Unk2 data |
Varies | 1 BIT | bUnk3 |
Varies | 0 if bUnk3==0, else 16 BITs | Unk3 data |
We don’t know what the Unk1, Unk2 and Unk3 do. Enemies works without them, but as it’s important to keep up with the current bit position, we need to read it anyway
Position type
Position is BIT length. First we read the count of bits to read by reading first 2 bits.
Offset | Length | Description |
---|---|---|
0 | 2 BITs | PositionTypeBits |
0+0b11 | PositionTypeBits | Vector axis |
PositionTypeBits
PositionTypeBits value | Bits to read for one vector axis |
---|---|
0b00 | 3 |
0b01 | 6 |
0b10 | 9 |
0b11 | 16 |
Rotation type
Rotation is also BIT length. First read first bit to see, if there’s rotation data. If no, continue. If yes, then read the rotation data similar to Position Type
Offset | Length | Description |
---|---|---|
0 | 1 BIT | IsRotationTypeAvailable |
0+0b1 | 2 BIT | RotationTypeBits |
0+0b100 | RotationTypeBits | Rotation vector axis (pitch/yaw/roll) |
RotationTypeBits
PositionTypeBits value | Bits to read for one vector axis |
---|---|
0b00 | 3 |
0b01 | 6 |
0b10 | 8 |
0b11 | 12 |
Section 4: Texture animation data
Optional section, often empty. It contains info on animated texture (like blink-eyes) It starts with a list of offset followed by data that look like this:
struct texAnim
{
uint8 textureNum;
uint8 originalUCoord; //All UV coords here are for the upper left corner
uint8 originalVCoord;
uint8 regionUSize;
uint8 regionVSize;
uint8 copiedRegionCount; //1 less than the actual number
uint8 unknown1;
uint8 unknown2;
//Insert remaining UV coords here
};
Refer to this message for more info: Qhimm message
Section 5: Animation sequences
Contain sequence of animation. Not much known yet, all info are found here: Qhimm message
Header
Offset | Length | Description |
---|---|---|
0 | 2 bytes | Number of sequences |
2 | nbSequences * 2 bytes | Sequences Positions |
Section 6: Camera sequence
Not analysed, but defined camera work.
Section 7: Informations & stats
Offset | Length | Description |
---|---|---|
0 | 24 bytes | Monster name in FF8 String |
24 | 4 bytes | HP values |
28 | 4 bytes | Str values |
32 | 4 bytes | Vit values |
36 | 4 bytes | Mag values |
40 | 4 bytes | Spr values |
44 | 4 bytes | Spd values |
48 | 4 bytes | Eva values |
52 | 16*4 bytes | Abilities, low level |
116 | 16*4 bytes | Abilities, med level |
180 | 16*4 bytes | Abilities, high level |
244 | 1 byte | Med level start |
245 | 1 byte | High level start |
246 | 1 byte | Unknown (flags, 3 bits used) |
247 | 1 byte | [LSB] Zombie / Fly / zz1 / LvUp-Down Immunity / HP Hidden / Auto-Reflect / Auto-Shell / Auto-Protect [MSB] |
248 | 3 bytes | Card (drop/mod/rare mod) |
251 | 3 bytes | Devour (low/med/high) |
254 | 1 byte | [LSB] zz1 / zz2 / unused / unused / unused / unused / Gravity Immunity / Always obtains card [MSB] |
255 | 1 byte | Unknown (flags, 4 bits used) |
256 | 2 bytes | Extra EXP |
258 | 2 bytes | EXP |
260 | 8 bytes | Draw (low) |
268 | 8 bytes | Draw (med) |
276 | 8 bytes | Draw (high) |
284 | 8 bytes | Mug(low) |
292 | 8 bytes | Mug(med) |
300 | 8 bytes | Mug(high) |
308 | 8 bytes | Drop (low) |
316 | 8 bytes | Drop (med) |
324 | 8 bytes | Drop (high) |
332 | 1 byte | Mug rate |
333 | 1 byte | Drop rate |
334 | 1 byte | Padding (0x00) |
335 | 1 byte | APs |
336 | 16 bytes | Renzokuken data |
352 | 8 bytes | Elemental resistance (Fire, Ice, Thunder, Earth, Poison, Wind, Water, Holy) |
360 | 20 bytes | Status resistance (Death, Poison, Petrify, Darkness, Silence, Berserk, Zombie, Sleep, Haste, Slow, Stop, Regen, Reflect, Doom, Slow Petrify, Float, Confuse, Drain, Expulsion, VIT0(but unused by the game)) |
Abilities
Abilities are composed of:
Length | Description |
---|---|
1 byte | AbilityTypeID |
1 byte | AnimationSequenceID |
2 byte | AbilityID |
AnimationSequenceID
Refer to a sequence in the Section 5
Renzokuken data
The data is 8*2 bytes, each 2 bytes corresponding to an ID on the Special Action list
Draw Mug Drop
Each section is composed of 8 bytes corresponding to 4 id (magic for draw, Item for mug & drop) and 4 quantity. Quantity is not used for draw (always 0 but no impact on game when changing it)
Length | Description |
---|---|
1 byte | ID 1 |
1 byte | Quantity 1 |
1 byte | ID 2 |
1 byte | Quantity 2 |
1 byte | ID 3 |
1 byte | Quantity 3 |
1 byte | ID 4 |
1 byte | Quantity 4 |
Elemental resistance
The % def value follow the formula: value% = 900 - value_hex * 10
and to revert back: value_hex = floor((900 - value%) / 10))
Status resistance
The % def value follow the formula: value% = value_hex - 100
and to revert back: value_hex = value% + 100
Rate value
The % def value follow the formula: value% = value_hex * 100 / 255
and to revert back: value_hex = value% * 255 / 100
Section 8: Battle scripts/AI
Offset | Length | Description |
---|---|---|
0 | 4 bytes | Number of sub-sections |
4 | 4 bytes | Offset to AI sub-section |
8 | 4 bytes | Offset to text offsets |
12 | 4 bytes | Offset to text sub-section |
AI
Offset | Length | Description |
---|---|---|
0 | 4 bytes | Offset to init code |
4 | 4 bytes | Offset to code executed at ennemy’s turn |
8 | 4 bytes | Offset to counterattack code |
12 | 4 bytes | Offset to death code |
16 | 4 bytes | Offset to “before dying or taking a hit” |
Texts
Text offsets is a list of text positions (2 bytes each) in the text sub-section.
Section 9: Sounds
Contains AKAO sequences (can be empty).
Offset | Length | Description |
---|---|---|
0 | 2 bytes | Number of AKAOs |
2 | nbAKAOs * 2 bytes | AKAOs Positions |
2 + nbAKAOs * 2 | 2 bytes | End of section 9 |
4 + nbAKAOs * 2 | Varies * nbAKAOs | AKAOs |
Section 10: Sounds/Unknown
Contains AKAO sequence + unknown data (can be empty).
Section 11: Textures
Contains some TIMs.
Offset | Length | Description |
---|---|---|
0 | 4 bytes | Number of TIMs |
4 | nbTIMs * 4 bytes | TIMs Positions |
4 + nbTIMs * 4 | 4 bytes | End of file |
8 + nbTIMs * 4 | Varies * nbTIMs | TIMs |