More file format musing

This commit is contained in:
2020-04-15 22:18:53 +01:00
parent 32fd9f9aa9
commit 87c0aae54b
3 changed files with 201 additions and 147 deletions

View File

@@ -1,18 +1,71 @@
# `Anim/WarHammer.ani` # `Anim/WarHammer.ani`
This turns out to simply be an [`obj`](obj.md#WarHammer.ani) file. However, some This turns out to simply be an [`obj`](obj.md) file.
other files are implicated in its interpretation:
- `Data/AniObDef.dat` The first 1,064 sprites are all of the same Ultramarine, carryng a bolter. There
are eight "facing" orientations:
* North
* Northeast
* East
* Southeast
* South
* Southwest
* West
* Northwest
For each orientation, an action is pictured in a variable number of frames. The
final frame for each action appears to be "stationary".
* Walk (13 frames)
* Run (9 frames)
* Crouch down (8 frames)
* Stand up (8 frames)
* Take aim (standing) (6 frames)
* Fire (standing) (6 frames)
* Relax aim (standing) (6 frames)
* Throw grenade (standing) (18 frames)
* Take aim (crouched) (5 frames)
* Fire (crouched) (5 frames)
* Relax aim (crouched) (5 frames)
* Throw grenade (crouched) (17 frames)
* Draw melee weapon (standing) (10 frames)
* Strike down with melee weapon (standing) (8 frames)
* Stab with melee weapon (standing) (9 frames)
Added together and multiplied by 87, that's 1064.
The next sprite is a walking-north action for an ultramarine with a flamer. The
total number of frames for this character is 1120 - 56 additional frames, or 7
per orientation. Could be an extra action, or an extra frame per action.
Also notable is that while the bolter showed muzzle flash in the animation, the
flamer only showed a tiny hint of fire. I think the animation for spewing flame
is held elsewhere.
I strongly suspect the actions and the number of frames in each action are
configurable. So, what other files are implicated in its interpretation? Here's
a few possibilities:
* `Data/AniObDef.dat`
* `Data/Coordinates.dat`
* `Data/HasAction.dat`
* `Data/VehicDef.dat`
* `Data/WeapDef.dat`
- `Idx/WarHammer.idx` - `Idx/WarHammer.idx`
Including comments, the former is 4098 lines, giving approx. 45 lines for each ## `Data/AniObDef.dat`
Including comments, this is 4098 lines, giving approx. 45 lines for each
of the ~188 characters in the `ani`. That doesn't seem many, and there's no of the ~188 characters in the `ani`. That doesn't seem many, and there's no
obvious correspondence between the commented-on names (`SMOKE01`?) and the obvious correspondence between the commented-on names (`SMOKE01`?) and the
viewed frames... but then, I've not viewed all the frames. viewed frames... but then, I've not viewed all the frames.
Still, I think a focus in `WarHammer.idx` (1,880,078 bytes, binary, so around
10KiB per character, in theory) is more reasonable. ## `Idx/WarHammer.idx`
`WarHammer.idx` (1,880,078 bytes, binary, so around 10KiB per character, in
theory) is more reasonable.
Here's a list of operations on the file when `WH40K_TD.EXE` is instructed to Here's a list of operations on the file when `WH40K_TD.EXE` is instructed to
place an Ultramarine squad: place an Ultramarine squad:
@@ -310,22 +363,15 @@ read(<WarHammer.ani>, "\xbe\xe5\xb6\x09\x0c\x0f\x00\x00", 8) = 8
</details> </details>
Notable is that we still load 5 type 2 records, even though there's just a Notable is that we read from `idx` **before** we read from `ani` - so it does
single librarian, and 8 compass points. Why 5? seem like the former should tell us where to pull from the latter.
Also notable is that we read from `idx` **before** we read from `ani`. We still load 5 type 2 records, even though there's just a single librarian, and
8 compass points. Why 5? After looking in `idx`, we load 10 sprites from `ani`,
which is at least a multiple. Do any of the records we load from `idx` specify
sprite directory offsets that match?
Other data may be loaded at program start, of course. What other files seem ## `Data/HasAction.dat`
relevant?
* `Data/AniObDef.dat`
* `Data/HasAction.dat`
* `Data/VehicDef.dat`
* `Data/WeapDef.dat`
These all reference animations in one way or another.
## `HasAction.dat`
This file seems relevant as it says whether or not particular animations exist This file seems relevant as it says whether or not particular animations exist
for the different types of character, which maps directly to what is stored in for the different types of character, which maps directly to what is stored in

View File

@@ -9,7 +9,7 @@ remake.
* [✓] [`Anim/`](obj.md#WarHammer.ani) * [✓] [`Anim/`](obj.md#WarHammer.ani)
* [`WarHammer.ani`](obj.md#WarHammer.ani) * [`WarHammer.ani`](obj.md#WarHammer.ani)
* [`Assign/`](obj.md#assign) * [`Assign/`](obj.md#assign)
* `*.asn` # Unknown, seems to be related to .obj files * `*.asn` # Specify properties for frames in .obj files
* `Cursor/` * `Cursor/`
* `*.ani` # RIFF data, standard ANI format \o/ * `*.ani` # RIFF data, standard ANI format \o/
* [`Cursors.cur`](obj.md) # `obj` file containing pointers and drag elements * [`Cursors.cur`](obj.md) # `obj` file containing pointers and drag elements
@@ -23,6 +23,7 @@ remake.
* **TODO** * **TODO**
* `ChaNames.dat` # list of character names * `ChaNames.dat` # list of character names
* `Coordinates.dat` # Weapon Firing Coordinates * `Coordinates.dat` # Weapon Firing Coordinates
* `Credits.dat` # list of credits
* `Defs.dat` # defines properties for objects and tiles, each of which seems to have an id * `Defs.dat` # defines properties for objects and tiles, each of which seems to have an id
* `GDestroy.dat` # table of what destroys what? * `GDestroy.dat` # table of what destroys what?
@@ -39,7 +40,6 @@ remake.
* `WeapDef.dat` # Weapon definitions * `WeapDef.dat` # Weapon definitions
* **PROBABLY NOT NEEDED** * **PROBABLY NOT NEEDED**
* `BugHunt.dat` # Contains SMF text for Bug hunt random missions * `BugHunt.dat` # Contains SMF text for Bug hunt random missions
* `Credits.dat` # list of credits
* `GenArm.dat` # "Random campaign armory levels - space marine" * `GenArm.dat` # "Random campaign armory levels - space marine"
* `HeroArm.dat` # "Random campaign armory levels - Veteran" * `HeroArm.dat` # "Random campaign armory levels - Veteran"
* `MHeroArm.dat` # "Random campaign armory levels - Veteran" * `MHeroArm.dat` # "Random campaign armory levels - Veteran"
@@ -49,11 +49,9 @@ remake.
* `SpArm.dat` # "RANDOM CAMPAIGN ARMORY LEVELS - Veteran" * `SpArm.dat` # "RANDOM CAMPAIGN ARMORY LEVELS - Veteran"
* `VetArm.dat` # "RANDOM CAMPAIGN ARMORY LEVELS - Veteran" * `VetArm.dat` # "RANDOM CAMPAIGN ARMORY LEVELS - Veteran"
* `*.chk` # checksums? Mentions all the .dat files * `*.chk` # checksums? Mentions all the .dat files
* `*.cyc` # ColorCycle DataFile. * `Cycle.cyc` # ColorCycle DataFile.
* `*.dta` # localized strings and things
* `Encyclopedia.dta` # encyclopedia entries * `Encyclopedia.dta` # encyclopedia entries
* `KeyMap.dta` # unknown * `keymap.dta` # unknown
* `Keymap.dta` # unknown
* `USEng.dta` # Localized strings * `USEng.dta` # Localized strings
* `EquipmentMenuData` # gzip-compressed, presumably to do with (initial?) squad configuration * `EquipmentMenuData` # gzip-compressed, presumably to do with (initial?) squad configuration
* `Filters/` * `Filters/`
@@ -105,7 +103,7 @@ Phew.
* *Almost everything* seems to be in a data file somewhere. Helpful! * *Almost everything* seems to be in a data file somewhere. Helpful!
* `make loader` creates a `load` binary that will try to load various bits * `make loader` creates a `load` binary that will try to load various bits
of data from `investigation/` and `orig/`. I use it to investigate file of data from `investigation/` and `orig/`. I use it to investigate file
formats and the parsers I'm writing. Ensure you're in a `GOPATH`! formats and the parsers I'm writing.
## Cross-links / associations ## Cross-links / associations

View File

@@ -6,80 +6,6 @@ be placed on it - a `SURFACE`, `LEFT`, `RIGHT`, and `CENTER`. Maps reference
objects in a space-efficient way via sets, which seem to be a kind of object objects in a space-efficient way via sets, which seem to be a kind of object
palette. palette.
## Assign
The `Assign/` directory contains a matching `.asn` file for each `Obj/*.obj`.
It's a plain-text format which seems to assign properties to frames, and has
references to a `<name>.flc` file which does not exist in the tree.
Theory: .obj files were originally generated from `.flc` files. This is an
AutoDesk format for visual data, so this suggests the .obj files contain pixels
\o/
`blank.asn` references 6 frames (0-5):
```
# single pixel tile
# transpix.obj/.asn
#/--> transpix.flc
#
0-5:DEF 1;
0-5:TYPE 13;
END OF FILE
```
`jungtil.asn` references 18 frames (0-17):
```
# jungle floor
# jungtil.obj/.asn
# /--> d:\warflics\missions\jungtil.flc
#
0:DEF 2;
1-11:DEF 454;
#damaged frames!!!!
12:DEF 2;
13-16:DEF 454;
17:DEF 454;
0:TYPE 2;
1-11:TYPE 0;
12:TYPE 2;
13-16:TYPE 0;
17:TYPE 0;
0:DESTROY 12;
1-3:DESTROY 13;
4-6:DESTROY 14;
7-9:DESTROY 15;
10-11:DESTROY 16;
17:DESTROY 15;
1-11:Dmg1Lnk 17;
END OF FILE
```
So it seems this visual data can have quite complicated attributes. At a minimum
we see:
* `TYPE`
* `DEF`
* `DESTROY`
* `Dmg1Lnk`
The `type` field **may** tell us what format each sprite is in.
## OBJ container structure ## OBJ container structure
`.obj` files represent visual data. They contain a number of sprites, which are `.obj` files represent visual data. They contain a number of sprites, which are
@@ -512,60 +438,144 @@ break *0x41DD10
This lets me focus very narrowly on what happens when loading sprites, and This lets me focus very narrowly on what happens when loading sprites, and
might give clues. might give clues.
## Assign
The `Assign/` directory contains a matching `.asn` file for each `Obj/*.obj`.
It's a plain-text format which seems to assign properties to frames, and has
references to a `<name>.flc` file which does not exist in the tree.
Theory: .obj files were originally generated from `.flc` files. This is an
AutoDesk format for visual data, so this suggests the .obj files contain pixels
\o/
`blank.asn` references 6 frames (0-5):
```
# single pixel tile
# transpix.obj/.asn
#/--> transpix.flc
#
0-5:DEF 1;
0-5:TYPE 13;
END OF FILE
```
`jungtil.asn` references 18 frames (0-17):
```
# jungle floor
# jungtil.obj/.asn
# /--> d:\warflics\missions\jungtil.flc
#
0:DEF 2;
1-11:DEF 454;
#damaged frames!!!!
12:DEF 2;
13-16:DEF 454;
17:DEF 454;
0:TYPE 2;
1-11:TYPE 0;
12:TYPE 2;
13-16:TYPE 0;
17:TYPE 0;
0:DESTROY 12;
1-3:DESTROY 13;
4-6:DESTROY 14;
7-9:DESTROY 15;
10-11:DESTROY 16;
17:DESTROY 15;
1-11:Dmg1Lnk 17;
END OF FILE
```
So it seems this visual data can have quite complicated attributes. We see:
* `DEF`
* `DESTROY`
* `Dmg1Lnk`
* `MacroLnk`
* `TYPE`
Each command takes the form:
```
<sprite-spec>:<command> <args>;
```
The sprite-spec can either be a single number, or a range of n-m.
### `DESTROY`
### `DEF`
I wonder if this `DEF`ines sprites an object, represented by an integer. In
`Data/Defs.dat`, we see sections that `EDIT <integer>`. Perhaps the two point to
the same thing?
`Assign/cabbage.asn` has `DEF 17` and `DEF 20`, covering two ranges of sprites.
`Data/Defs.dat` has `EDIT 17 # TREE LEAVES` and `EDIT 20 # NON-CENTERED CENTER
BUSHES`.
`Assign/TZEENTCH.asn` has `DEF 24` and `DEF 25`. `Data/Defs.dat` has `EDIT 24 #
SWITCHES & HOSES AS CENTER OBJS...RIGHT` and `EDIT 25 # SWITCHES & HOSES AS
CENTER OBJS...LEFT`.
`Assign/altar.asn` has `DEF 232`, and `Data/Defs.data` has `EDIT 232 # MRS
BUILDING PIECES - POOL TABLE`.
These all seem really close.
Then we have `EDIT 19 #big rocks` and these instances of `DEF 19;`:
```
Assign/grayroks.asn:5:0-7:DEF 19;
Assign/grayroks.asn:9:8-15:DEF 19;
Assign/sn_roks.asn:6:0-7:DEF 19;
Assign/sn_roks.asn:10:8-15:DEF 19;
```
The sprites for `grayroks` depicts some grey rocks, while `sn_roks` depicts
the same, but with snow on them. So this seems correct to me.
Does each object ID represent a unique thing? Or is it an index for a set of
characteristics that may be shared across multiple things? A set could quite
easily specify both `grayroks` and `sn_roks` for a map...
### `Dmg1Lnk`
This command is fairly easy. It takes a sprite-spec and says "if damage has been
sustained and you would normally display these sprites, display this sprite
instead". This is particularly obvious for the `cabbage` pair.
### `MacroLnk`
### `TYPE`
## WarHammer.ani ## WarHammer.ani
This 400MiB file appears to be a standard object file, it's just very large. This 400MiB file appears to be a standard object file, it's just very large.
The directory contains 188,286 sprites! The directory contains 188,286 sprites!
The first 1,064 sprites are all of the same Ultramarine, carryng a bolter. There The field at 0x10 in each sprite header is set in `WarHammer.ani`, but not in
are eight "facing" orientations:
* North
* Northeast
* East
* Southeast
* South
* Southwest
* West
* Northwest
For each orientation, an action is pictured in a variable number of frames. The
final frame appears to be "stationary".
* Walk (13 frames)
* Run (9 frames)
* Crouch down (8 frames)
* Stand up (8 frames)
* Take aim (standing) (6 frames)
* Fire (standing) (6 frames)
* Relax aim (standing) (6 frames)
* Throw grenade (standing) (18 frames)
* Take aim (crouched) (5 frames)
* Fire (crouched) (5 frames)
* Relax aim (crouched) (5 frames)
* Throw grenade (crouched) (17 frames)
* Draw melee weapon (standing) (10 frames)
* Strike down with melee weapon (standing) (8 frames)
* Stab with melee weapon (standing) (9 frames)
Added together and multiplied by 87, that's 1064.
The next sprite is a walking-north action for an ultramarine with a flamer. The
total number of frames for this character is 1120 - 56 additional frames, or 7
per orientation. Could be an extra action, or an extra frame per action.
Also notable is that while the bolter showed muzzle flash in the animation, the
flamer only showed a tiny hint of fire. I think the animation for spewing flame
is held elsewhere.
I strongly suspect the actions and the number of frames in each action are
configurable. But where?
The field at 0x10 in the sprite header is set in `WarHammer.ani`, but not in
the other object files encountered so far. However, it seems to be the other object files encountered so far. However, it seems to be
set statically to the bytes `[212 113 59 1]` for all of them. set statically to the bytes `[212 113 59 1]` for all of them.
Assuming ~1000 sprites per character, `WarHammer.ani` contains 188 characters. Assuming ~1000 sprites per character, `WarHammer.ani` contains 188 characters.
Two other files have been implicated in animation - `Data/AniObDefs.dat` and Two other files have been implicated in animation - `Data/AniObDefs.dat` and
`Idx/WarHammer.idx`. More on those in `ani.md`. `Idx/WarHammer.idx`. More on those in [ani.md](ani.md)