More investigation into animation

This commit is contained in:
2020-04-15 21:11:01 +01:00
parent 80c65f68ca
commit 32fd9f9aa9
9 changed files with 515 additions and 124 deletions

View File

@@ -9,6 +9,7 @@ import (
"code.ur.gs/lupine/ordoor/internal/data"
"code.ur.gs/lupine/ordoor/internal/fonts"
"code.ur.gs/lupine/ordoor/internal/idx"
"code.ur.gs/lupine/ordoor/internal/maps"
"code.ur.gs/lupine/ordoor/internal/menus"
"code.ur.gs/lupine/ordoor/internal/sets"
@@ -33,13 +34,15 @@ func main() {
loadSets()
loadMenus()
loadFonts()
loadIdx()
}
func loadData() {
dataPath := filepath.Join(*gamePath, "Data")
accountingPath := filepath.Join(dataPath, "Accounting.dat")
genericDataPath := filepath.Join(dataPath, "GenericData.dat")
aniObDefPath := filepath.Join(dataPath, "AniObDef.dat")
genericDataPath := filepath.Join(dataPath, "GenericData.dat")
hasActionPath := filepath.Join(dataPath, "HasAction.dat")
i18nPath := filepath.Join(dataPath, data.I18nFile)
log.Printf("Loading %s...", accountingPath)
@@ -73,6 +76,12 @@ func loadData() {
}
log.Printf("%s: len=%v", i18nPath, i18n.Len())
ha, err := data.LoadHasAction(hasActionPath)
if err != nil {
log.Fatalf("Failed to parse %s: %v", hasActionPath, err)
}
ha.Print()
}
func loadObj() {
@@ -189,3 +198,11 @@ func loadFonts() {
fmt.Printf(" * `%s`: obj=%v entries=%v\n", font.Name, font.ObjectFile, font.Entries())
}
}
func loadIdx() {
idxPath := filepath.Join(*gamePath, "Idx", "WarHammer.idx")
_, err := idx.Load(idxPath)
if err != nil {
log.Fatalf("Failed to parse %s as idx: %v", idxPath, err)
}
}

View File

@@ -162,6 +162,7 @@ how many type 2 records there are.
| 0 | 2? | `02 06` - ??? |
| 2 | 2? | `n xx` - ??? `n` counts from 1 to 8 |
| 4 | 4 | Position of type 3 record |
| 8 | 4 | ??? |
The two type 3a and 3b records are identical to each other, it's hard to know
what's what.
@@ -169,137 +170,219 @@ what's what.
None of the unknown numbers, however sliced, seem to be sprite indices for
`Anim/WarHammer.ani`.
Here's a trace of both `idx` (fd 34) and `ani` (fd 14) files when placing a
single librarian for me to dig into in more detail.
Here's a trace of both `idx` and `ani` files when placing a single librarian for
me to dig into in more detail. No other files are touched when doing this.
<details>
```
read(14, "~\337\2\0 \0\0\0\360\373\26\0\20\374\26\0\245J\303\30\0\0\0\0\0\0\0\0(\222R\0", 32) = 32
_llseek(<WarHammer.idx>, 132, [132], SEEK_SET) = 0
read(<WarHammer.idx>, "\x30\x7c\x09\x00\x98\x00\x00\x00\x88\xf8\x00\x00", 12) = 12
_llseek(34, 132, [132], SEEK_SET) = 0
read(34, "0|\t\0\230\0\0\0\210\370\0\0", 12) = 12
_llseek(<WarHammer.idx>, 132, [132], SEEK_SET) = 0
read(<WarHammer.idx>, "\x30\x7c\x09\x00\x98\x00\x00\x00\x88\xf8\x00\x00", 12) = 12
_llseek(34, 132, [132], SEEK_SET) = 0
read(34, "0|\t\0\230\0\0\0\210\370\0\0", 12) = 12
_llseek(<WarHammer.idx>, 621616, [621616], SEEK_SET) = 0
read(<WarHammer.idx>, "\x02\x01\x01\x33\x50\x83\x09\x00\x0d\x00\x00\x00", 12) = 12
_llseek(34, 621616, [621616], SEEK_SET) = 0
read(34, "\2\1\0013P\203\t\0\r\0\0\0", 12) = 12
_llseek(34, 621628, [621628], SEEK_SET) = 0
read(34, "\2\1\0023\262\203\t\0\r\0\0\0", 12) = 12
_llseek(34, 621640, [621640], SEEK_SET) = 0
read(34, "\2\1\0033\24\204\t\0\r\0\0\0", 12) = 12
_llseek(34, 621652, [621652], SEEK_SET) = 0
read(34, "\2\1\0043v\204\t\0\r\0\0\0", 12) = 12
_llseek(34, 621664, [621664], SEEK_SET) = 0
read(34, "\2\1\0053\330\204\t\0\r\0\0\0", 12) = 12
_llseek(<WarHammer.idx>, 621628, [621628], SEEK_SET) = 0
read(<WarHammer.idx>, "\x02\x01\x02\x33\xb2\x83\x09\x00\x0d\x00\x00\x00", 12) = 12
_llseek(34, 623832, [623832], SEEK_SET) = 0
read(34, "4\0@\0@\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
_llseek(<WarHammer.idx>, 621640, [621640], SEEK_SET) = 0
read(<WarHammer.idx>, "\x02\x01\x03\x33\x14\x84\x09\x00\x0d\x00\x00\x00", 12) = 12
_llseek(14, 509440, [509440], SEEK_SET) = 0
read(14, "\fM\266\th\16\0\0", 8) = 8
_llseek(14, 509448, [509448], SEEK_SET) = 0
read(14, "t[\266\t\376\16\0\0", 8) = 8
_llseek(14, 509456, [509456], SEEK_SET) = 0
read(14, "rj\266\tg\17\0\0", 8) = 8
_llseek(14, 509464, [509464], SEEK_SET) = 0
read(14, "\331y\266\t\251\17\0\0", 8) = 8
_llseek(14, 509472, [509472], SEEK_SET) = 0
read(14, "\202\211\266\t\273\17\0\0", 8) = 8
_llseek(14, 509480, [509480], SEEK_SET) = 0
read(14, "=\231\266\t\10\20\0\0", 8) = 8
_llseek(14, 509488, [509488], SEEK_SET) = 0
read(14, "E\251\266\t\321\17\0\0", 8) = 8
_llseek(14, 509496, [509496], SEEK_SET) = 0
read(14, "\26\271\266\t\1\17\0\0", 8) = 8
_llseek(14, 509504, [509504], SEEK_SET) = 0
read(14, "\27\310\266\t\304\16\0\0", 8) = 8
_llseek(14, 509512, [509512], SEEK_SET) = 0
read(14, "\333\326\266\t\343\16\0\0", 8) = 8
_llseek(14, 509520, [509520], SEEK_SET) = 0
read(14, "\276\345\266\t\f\17\0\0", 8) = 8
_llseek(14, 509528, [509528], SEEK_SET) = 0
read(14, "\312\364\266\tA\17\0\0", 8) = 8
_llseek(14, 509536, [509536], SEEK_SET) = 0
read(14, "\v\4\267\t\246\17\0\0", 8) = 8
_llseek(14, 509440, [509440], SEEK_SET) = 0
read(14, "\fM\266\th\16\0\0", 8) = 8
_llseek(<WarHammer.idx>, 621652, [621652], SEEK_SET) = 0
read(<WarHammer.idx>, "\x02\x01\x04\x33\x76\x84\x09\x00\x0d\x00\x00\x00", 12) = 12
_llseek(14, 164448540, [164448540], SEEK_SET) = 0
read(14, "\367\0\n\0015\0T\0\0\0\0\0P\16\0\0\324q;\1\0\0\0\0\200\23\207**+*+"..., 3688) = 3688
_llseek(14, 509448, [509448], SEEK_SET) = 0
read(14, "t[\266\t\376\16\0\0", 8) = 8
_llseek(14, 164452228, [164452228], SEEK_SET) = 0
read(14, "\365\0\10\0017\0W\0\0\0\0\0\346\16\0\0\324q;\1\0\0\0\0\200\25\3*\212+*,"..., 3838) = 3838
_llseek(14, 509456, [509456], SEEK_SET) = 0
read(14, "rj\266\tg\17\0\0", 8) = 8
_llseek(14, 164456066, [164456066], SEEK_SET) = 0
read(14, "\364\0\10\19\0Z\0\0\0\0\0O\17\0\0\324q;\1\0\0\0\0\200\30\201*\5+\200\33"..., 3943) = 3943
_llseek(14, 509464, [509464], SEEK_SET) = 0
read(14, "\331y\266\t\251\17\0\0", 8) = 8
_llseek(14, 164460009, [164460009], SEEK_SET) = 0
read(14, "\356\0\7\1B\0[\0\0\0\0\0\221\17\0\0\324q;\1\0\0\0\0\200\"\201*\200\37\0\200"..., 4009) = 4009
_llseek(14, 509472, [509472], SEEK_SET) = 0
read(14, "\202\211\266\t\273\17\0\0", 8) = 8
_llseek(14, 164464018, [164464018], SEEK_SET) = 0
read(14, "\356\0\n\1C\0\\\0\0\0\0\0\243\17\0\0\324q;\1\0\0\0\0\200#\3)\3+\200\32"..., 4027) = 4027
_llseek(14, 509480, [509480], SEEK_SET) = 0
read(14, "=\231\266\t\10\20\0\0", 8) = 8
_llseek(14, 164468045, [164468045], SEEK_SET) = 0
read(14, "\354\0\t\1C\0Z\0\0\0\0\0\360\17\0\0\324q;\1\0\0\0\0\200$\201*\200\36\0\200"..., 4104) = 4104
_llseek(14, 509488, [509488], SEEK_SET) = 0
read(14, "E\251\266\t\321\17\0\0", 8) = 8
_llseek(14, 164472149, [164472149], SEEK_SET) = 0
read(14, "\356\0\t\1?\0V\0\0\0\0\0\271\17\0\0\324q;\1\0\0\0\0\200\35\212&&H)*"..., 4049) = 4049
_llseek(14, 509496, [509496], SEEK_SET) = 0
read(14, "\26\271\266\t\1\17\0\0", 8) = 8
_llseek(14, 164476198, [164476198], SEEK_SET) = 0
read(14, "\366\0\10\0015\0[\0\0\0\0\0\351\16\0\0\324q;\1\0\0\0\0\200\20\201*\4+\206*"..., 3841) = 3841
_llseek(14, 509504, [509504], SEEK_SET) = 0
read(14, "\27\310\266\t\304\16\0\0", 8) = 8
_llseek(14, 164480039, [164480039], SEEK_SET) = 0
read(14, "\367\0\7\0013\0[\0\0\0\0\0\254\16\0\0\324q;\1\0\0\0\0\200\33\210+,+,,"..., 3780) = 3780
_llseek(14, 509512, [509512], SEEK_SET) = 0
read(14, "\333\326\266\t\343\16\0\0", 8) = 8
_llseek(14, 164483819, [164483819], SEEK_SET) = 0
read(14, "\370\0\7\1A\0_\0\0\0\0\0\313\16\0\0\324q;\1\0\0\0\0\200\34\203,,*\200\""..., 3811) = 3811
_llseek(14, 509520, [509520], SEEK_SET) = 0
read(14, "\276\345\266\t\f\17\0\0", 8) = 8
_llseek(14, 164487630, [164487630], SEEK_SET) = 0
read(14, "\370\0\7\1H\0`\0\0\0\0\0\364\16\0\0\324q;\1\0\0\0\0\200\35\201,\200*\0\200"..., 3852) = 3852
_llseek(14, 509528, [509528], SEEK_SET) = 0
read(14, "\312\364\266\tA\17\0\0", 8) = 8
_llseek(14, 164491482, [164491482], SEEK_SET) = 0
read(14, "\373\0\10\1;\0Z\0\0\0\0\0)\17\0\0\324q;\1\0\0\0\0\200\36\202+,\200\33\0"..., 3905) = 3905
_llseek(14, 509536, [509536], SEEK_SET) = 0
read(14, "\v\4\267\t\246\17\0\0", 8) = 8
_llseek(14, 164495387, [164495387], SEEK_SET) = 0
read(14, "\366\0\n\18\0Y\0\0\0\0\0\216\17\0\0\324q;\1\0\0\0\0\200\32\t+\205*\4,"..., 4006) = 4006
_llseek(<WarHammer.idx>, 621664, [621664], SEEK_SET) = 0
read(<WarHammer.idx>, "\x02\x01\x05\x33\xd8\x84\x09\x00\x0d\x00\x00\x00", 12) = 12
_llseek(34, 623832, [623832], SEEK_SET) = 0
read(34, "4\0@\0@\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
read(34, "\0\0\6\0\4\0\0\0\6\0\4\0\0\0\6\0\4\0\0\0\5\0\4\0\0\0\5\0\4\0\0\0"..., 78) = 78
_llseek(<WarHammer.idx>, 623832, [623832], SEEK_SET) = 0
read(<WarHammer.idx>, "\x34\x00\x40\x00\x40\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 20) = 20
_llseek(34, 132, [132], SEEK_SET) = 0
read(34, "0|\t\0\230\0\0\0\210\370\0\0", 12) = 12
_llseek(<WarHammer.idx>, 0, [623852], SEEK_CUR) = 0
_llseek(<WarHammer.idx>, 623852, [623852], SEEK_SET) = 0
_llseek(<WarHammer.idx>, 623930, [623930], SEEK_SET) = 0
_llseek(34, 621616, [621616], SEEK_SET) = 0
read(34, "\2\1\0013P\203\t\0\r\0\0\0", 12) = 12
_llseek(34, 621628, [621628], SEEK_SET) = 0
read(34, "\2\1\0023\262\203\t\0\r\0\0\0", 12) = 12
_llseek(34, 621640, [621640], SEEK_SET) = 0
read(34, "\2\1\0033\24\204\t\0\r\0\0\0", 12) = 12
_llseek(34, 621652, [621652], SEEK_SET) = 0
read(34, "\2\1\0043v\204\t\0\r\0\0\0", 12) = 12
_llseek(34, 621664, [621664], SEEK_SET) = 0
read(34, "\2\1\0053\330\204\t\0\r\0\0\0", 12) = 12
_llseek(<WarHammer.ani>, 509440, [509440], SEEK_SET) = 0
read(<WarHammer.ani>, "\x0c\x4d\xb6\x09\x68\x0e\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509448, [509448], SEEK_SET) = 0
read(<WarHammer.ani>, "\x74\x5b\xb6\x09\xfe\x0e\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509456, [509456], SEEK_SET) = 0
read(<WarHammer.ani>, "\x72\x6a\xb6\x09\x67\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509464, [509464], SEEK_SET) = 0
read(<WarHammer.ani>, "\xd9\x79\xb6\x09\xa9\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509472, [509472], SEEK_SET) = 0
read(<WarHammer.ani>, "\x82\x89\xb6\x09\xbb\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509480, [509480], SEEK_SET) = 0
read(<WarHammer.ani>, "\x3d\x99\xb6\x09\x08\x10\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509488, [509488], SEEK_SET) = 0
read(<WarHammer.ani>, "\x45\xa9\xb6\x09\xd1\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509496, [509496], SEEK_SET) = 0
read(<WarHammer.ani>, "\x16\xb9\xb6\x09\x01\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509504, [509504], SEEK_SET) = 0
read(<WarHammer.ani>, "\x17\xc8\xb6\x09\xc4\x0e\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509512, [509512], SEEK_SET) = 0
read(<WarHammer.ani>, "\xdb\xd6\xb6\x09\xe3\x0e\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509520, [509520], SEEK_SET) = 0
read(<WarHammer.ani>, "\xbe\xe5\xb6\x09\x0c\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509528, [509528], SEEK_SET) = 0
read(<WarHammer.ani>, "\xca\xf4\xb6\x09\x41\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509536, [509536], SEEK_SET) = 0
read(<WarHammer.ani>, "\x0b\x04\xb7\x09\xa6\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 509440, [509440], SEEK_SET) = 0
read(<WarHammer.ani>, "\x0c\x4d\xb6\x09\x68\x0e\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 164448540, [164448540], SEEK_SET) = 0
read(<WarHammer.ani>, "\xf7\x00\x0a\x01\x35\x00\x54\x00\x00\x00\x00\x00\x50\x0e\x00\x00\xd4\x71\x3b\x01\x00\x00\x00\x00\x80\x13\x87\x2a\x2a\x2b\x2a\x2b"..., 3688) = 3688
_llseek(<WarHammer.ani>, 509448, [509448], SEEK_SET) = 0
read(<WarHammer.ani>, "\x74\x5b\xb6\x09\xfe\x0e\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 164452228, [164452228], SEEK_SET) = 0
read(<WarHammer.ani>, "\xf5\x00\x08\x01\x37\x00\x57\x00\x00\x00\x00\x00\xe6\x0e\x00\x00\xd4\x71\x3b\x01\x00\x00\x00\x00\x80\x15\x03\x2a\x8a\x2b\x2a\x2c"..., 3838) = 3838
_llseek(<WarHammer.ani>, 509456, [509456], SEEK_SET) = 0
read(<WarHammer.ani>, "\x72\x6a\xb6\x09\x67\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 164456066, [164456066], SEEK_SET) = 0
read(<WarHammer.ani>, "\xf4\x00\x08\x01\x39\x00\x5a\x00\x00\x00\x00\x00\x4f\x0f\x00\x00\xd4\x71\x3b\x01\x00\x00\x00\x00\x80\x18\x81\x2a\x05\x2b\x80\x1b"..., 3943) = 3943
_llseek(<WarHammer.ani>, 509464, [509464], SEEK_SET) = 0
read(<WarHammer.ani>, "\xd9\x79\xb6\x09\xa9\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 164460009, [164460009], SEEK_SET) = 0
read(<WarHammer.ani>, "\xee\x00\x07\x01\x42\x00\x5b\x00\x00\x00\x00\x00\x91\x0f\x00\x00\xd4\x71\x3b\x01\x00\x00\x00\x00\x80\x22\x81\x2a\x80\x1f\x00\x80"..., 4009) = 4009
_llseek(<WarHammer.ani>, 509472, [509472], SEEK_SET) = 0
read(<WarHammer.ani>, "\x82\x89\xb6\x09\xbb\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 164464018, [164464018], SEEK_SET) = 0
read(<WarHammer.ani>, "\xee\x00\x0a\x01\x43\x00\x5c\x00\x00\x00\x00\x00\xa3\x0f\x00\x00\xd4\x71\x3b\x01\x00\x00\x00\x00\x80\x23\x03\x29\x03\x2b\x80\x1a"..., 4027) = 4027
_llseek(<WarHammer.ani>, 509480, [509480], SEEK_SET) = 0
read(<WarHammer.ani>, "\x3d\x99\xb6\x09\x08\x10\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 164468045, [164468045], SEEK_SET) = 0
read(<WarHammer.ani>, "\xec\x00\x09\x01\x43\x00\x5a\x00\x00\x00\x00\x00\xf0\x0f\x00\x00\xd4\x71\x3b\x01\x00\x00\x00\x00\x80\x24\x81\x2a\x80\x1e\x00\x80"..., 4104) = 4104
_llseek(<WarHammer.ani>, 509488, [509488], SEEK_SET) = 0
read(<WarHammer.ani>, "\x45\xa9\xb6\x09\xd1\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 164472149, [164472149], SEEK_SET) = 0
read(<WarHammer.ani>, "\xee\x00\x09\x01\x3f\x00\x56\x00\x00\x00\x00\x00\xb9\x0f\x00\x00\xd4\x71\x3b\x01\x00\x00\x00\x00\x80\x1d\x8a\x26\x26\x48\x29\x2a"..., 4049) = 4049
_llseek(<WarHammer.ani>, 509496, [509496], SEEK_SET) = 0
read(<WarHammer.ani>, "\x16\xb9\xb6\x09\x01\x0f\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 164476198, [164476198], SEEK_SET) = 0
read(<WarHammer.ani>, "\xf6\x00\x08\x01\x35\x00\x5b\x00\x00\x00\x00\x00\xe9\x0e\x00\x00\xd4\x71\x3b\x01\x00\x00\x00\x00\x80\x10\x81\x2a\x04\x2b\x86\x2a"..., 3841) = 3841
_llseek(<WarHammer.ani>, 509504, [509504], SEEK_SET) = 0
read(<WarHammer.ani>, "\x17\xc8\xb6\x09\xc4\x0e\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 164480039, [164480039], SEEK_SET) = 0
read(<WarHammer.ani>, "\xf7\x00\x07\x01\x33\x00\x5b\x00\x00\x00\x00\x00\xac\x0e\x00\x00\xd4\x71\x3b\x01\x00\x00\x00\x00\x80\x1b\x88\x2b\x2c\x2b\x2c\x2c"..., 3780) = 3780
_llseek(<WarHammer.ani>, 509512, [509512], SEEK_SET) = 0
read(<WarHammer.ani>, "\xdb\xd6\xb6\x09\xe3\x0e\x00\x00", 8) = 8
_llseek(<WarHammer.ani>, 164483819, [164483819], SEEK_SET) = 0
read(<WarHammer.ani>, "\xf8\x00\x07\x01\x41\x00\x5f\x00\x00\x00\x00\x00\xcb\x0e\x00\x00\xd4\x71\x3b\x01\x00\x00\x00\x00\x80\x1c\x83\x2c\x2c\x2a\x80\x22"..., 3811) = 3811
_llseek(<WarHammer.ani>, 509520, [509520], SEEK_SET) = 0
read(<WarHammer.ani>, "\xbe\xe5\xb6\x09\x0c\x0f\x00\x00", 8) = 8
_llseek(34, 623832, [623832], SEEK_SET) = 0
read(34, "4\0@\0@\0\1\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) = 20
```
</details>
Notable is that we still load 5 type 2 records, even though there's just a
single librarian, and 8 compass points. Why 5?
Notable is that we still load 5 type 2 records, even though there's just a
single librarian, and 8 compass points. Why 5?
Also notable is that we read from `idx` **before** we read from `ani`.
Other data may be loaded at program start, of course. What other files seem
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
for the different types of character, which maps directly to what is stored in
the .ani file - and so must affect lookups thereof.
Fortunately, it's commented extensively. For each "Character Type", there are
36 different possible animations.
Here's a table representation of the data:
```
Tac Ass Dev Term Apo Tech Chp Lib Cpt CMar CLrd CChp CSrc CTrm Kbz BTh BL FHnd LoC Flm PHr BHr Cult
00 x x x x x x x x x x x x x x x x x x x x x x x
01 x x x x x x x x x x x x x x x x x x x x x x x
02 x x x x x x x x x x x x x x x x x x x x x x x
03
04
05
06 x x x x x x x x x x x x x x x x x x x x
07 x x x x x x x x x x x x x x x x x x x x x x x
08 x x x x x x x x x x x x x x x x
09
10
11
12
13
14 x x x x x x x x x x x x x
15 x x x x x x x x x x x x x
16 x x x x x x x x x x x x x
17 x x x x x x x x x x x x x
18 x x x x x x x x x x x x x
19 x x x x x x x x x x x x x
20 x x x x x x x x x x x x x
21 x x x x x x x x x x x x x
22 x x x x x x x x x x x x x x
23 x x x x x x x x x x x x x
24 x x x x x x x x x x x x x x x x
25 x x x x x x x x x x x x x x x x x x x x x x
26 x x x x x x x x x x x x x x x x x
27 x x x x x x x x x x x x x x x x x x x x x
28 x x x x x x x x x x x x x x
29 x x x
30 x
31 x
32 x x x
33 x x x x x x x x x x x x x x x x x x x x x
34 x x x x x x x x x x x x x x x x x x x x x x x
35 x x x x x x x
```
`WarHammer.ani` doesn't have blank sprites for the unchecked cells, so this must
surely be used to map between set-of-sprites and `AnimAction`.
I think we still need the data in `.idx` for a full picture, though. Things we
still need:
* Mapping of character type to sprite directory index in `WarHammer.ani`
* Number of frames in each AnimAction
Either of these could be hardcoded, or dynamic.

View File

@@ -17,14 +17,15 @@ remake.
* `*.dat` # plaintext files defining properties of objects. No single format
* **PARSED**
* `Accounting.dat` # key = value => internal/data/accounting.go
* [`AniObjDef.dat`](ani.mnu) # animated object definitions
* `AniObjDef.dat` # animated object definitions
* `GenericData.dat` # Generic Game Settings
* [`HasAction.dat`](ani.md) # "Are there animation for each of the character" - list of booleans
* **TODO**
* `ChaNames.dat` # list of character names
* `Coordinates.dat` # Weapon Firing Coordinates
* `Defs.dat` # defines properties for objects and tiles, each of which seems to have an id
* `GDestroy.dat` # table of what destroys what?
* `HasAction.dat` # "Are there animation for each of the character" - list of booleans
* `MiniMap.dat` # lots of seemingly random numbers. IDs?
* `MissionBriefing.dat` # Contains all Campaign Mission Briefing Text. Sections: "CAMPAIGN MISSION X ... END CAMPAIGN MISSION X"
* `PWeight.dat` # Personality weights for the individual character types
@@ -75,8 +76,9 @@ remake.
* [`MultiMaps/`](maps.md#multimaps)
* [`*.MAP`](maps.md)
* [`*.TXT`](maps.md)
* [✓] [`Obj/`](obj.md)
* [`*.obj`](obj.md)
* [`Obj/`](obj.md)
* [ ] `cpiece.rec` # "Rects for various cursor piece types..."
* [✓] [`*.obj`](obj.md)
* [✓] `Pic/`
* `*.pcx` # Standard .pcx format
* `RandomMaps/`

1
go.mod
View File

@@ -4,6 +4,7 @@ go 1.12
require (
github.com/BurntSushi/toml v0.3.1
github.com/emef/bitfield v0.0.0-20170503144143-7d3f8f823065
github.com/hajimehoshi/ebiten v1.11.0-alpha.2.0.20200101150127-38815ba801a5
github.com/jfreymuth/oggvorbis v1.0.1 // indirect
github.com/kr/text v0.2.0 // indirect

2
go.sum
View File

@@ -3,6 +3,8 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/emef/bitfield v0.0.0-20170503144143-7d3f8f823065 h1:7QVNyw2v9R1qOvbe9vfeVJWWKCSnd2Ap+8l8/CtG9LM=
github.com/emef/bitfield v0.0.0-20170503144143-7d3f8f823065/go.mod h1:uN4GbWHfit2ByfOKQ4K6fuLy1/Os2eLynsIrDvjiDgM=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72 h1:b+9H1GAsx5RsjvDFLoS5zkNBzIQMuVKUYQDmxU3N5XE=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=

178
internal/data/has_action.go Normal file
View File

@@ -0,0 +1,178 @@
package data
import (
"fmt"
"github.com/emef/bitfield"
"code.ur.gs/lupine/ordoor/internal/util/asciiscan"
)
// AnimAction represents an animation that is stored in WarHammer.ani
type AnimAction int
// CharacterType represents one of the different types of character in the game.
//
// TODO: can we load the list of character types anywhere or is it hardcoded in
// the original too?
type CharacterType int
const (
AnimActionNone AnimAction = 0
AnimActionAnim AnimAction = 1
AnimActionWalk AnimAction = 2
AnimActionExplosion AnimAction = 3
AnimActionProjectile AnimAction = 4
AnimActionSmoke AnimAction = 5
AnimActionStandingShoot AnimAction = 6
AnimActionStandingDeath AnimAction = 7
AnimActionPain AnimAction = 8
AnimActionSpellFx1 AnimAction = 9
AnimActionSpellFx2 AnimAction = 10
AnimActionSpellFx3 AnimAction = 11
AnimActionSpellFx4 AnimAction = 12
AnimActionSpellFx5 AnimAction = 13
AnimActionRun AnimAction = 14
AnimActionCrouch AnimAction = 15
AnimActionStand AnimAction = 16
AnimActionStandingRead AnimAction = 17
AnimActionStandingUnready AnimAction = 18
AnimActionCrouchingReady AnimAction = 19
AnimActionCrouchingUnready AnimAction = 20
AnimActionCrouchingShoot AnimAction = 21
AnimActionStandingGrenade AnimAction = 22
AnimActionCrouchingGrenade AnimAction = 23
AnimActionDrawMelee AnimAction = 24
AnimActionSlash AnimAction = 25
AnimActionStab AnimAction = 26
AnimActionBlown AnimAction = 27
AnimActionCrouchingDeath AnimAction = 28
AnimActionJump AnimAction = 29
AnimActionHeal AnimAction = 30
AnimActionTechWork AnimAction = 31
AnimActionCast AnimAction = 32
AnimActionShoot AnimAction = 33
AnimActionDeath AnimAction = 34
AnimActionFromWarp AnimAction = 35
AnimActionStart = AnimActionNone
AnimActionEnd = AnimActionFromWarp
AnimActionCount = AnimActionEnd - AnimActionStart + 1
// FIXME: indexed from 1, very annoying
CharacterTypeTactical CharacterType = 1
CharacterTypeAssault CharacterType = 2
CharacterTypeDevastator CharacterType = 3
CharacterTypeTerminator CharacterType = 4
CharacterTypeApothecary CharacterType = 5
CharacterTypeTechmarine CharacterType = 6
CharacterTypeChaplain CharacterType = 7
CharacterTypeLibrarian CharacterType = 8
CharacterTypeCaptain CharacterType = 9
CharacterTypeChaosMarine CharacterType = 10
CharacterTypeChaosLord CharacterType = 11
CharacterTypeChaosChaplain CharacterType = 12
CharacterTypeChaosSorcerer CharacterType = 13
CharacterTypeChaosTerminator CharacterType = 14
CharacterTypeKhorneBerserker CharacterType = 15
CharacterTypeBloodThirster CharacterType = 16
CharacterTypeBloodLetter CharacterType = 17
CharacterTypeFleshHound CharacterType = 18
CharacterTypeLordOfChange CharacterType = 19
CharacterTypeFlamer CharacterType = 20
CharacterTypePinkHorror CharacterType = 21
CharacterTypeBlueHorror CharacterType = 22
CharacterTypeChaosCultist CharacterType = 23
CharacterTypeStart = CharacterTypeTactical
CharacterTypeEnd = CharacterTypeChaosCultist
CharacterTypeCount = CharacterTypeEnd - CharacterTypeStart + 1
)
// HasAction tells us whether a character has an animation or not.
type HasAction struct {
bits bitfield.BitField
}
func LoadHasAction(filename string) (*HasAction, error) {
scanner, err := asciiscan.New(filename)
if err != nil {
return nil, err
}
defer scanner.Close()
out := &HasAction{
bits: bitfield.New(int(CharacterTypeCount) * int(AnimActionCount)),
}
// Reuse this for every loop
var actions [AnimActionCount]bool
ptrs := make([]*bool, len(actions))
for i, _ := range actions {
ptrs[i] = &actions[i]
}
for c := CharacterTypeStart; c <= CharacterTypeEnd; c++ {
if err := scanner.ConsumeBoolPtrs(ptrs...); err != nil {
return nil, err
}
for j, value := range actions {
a := AnimActionStart + AnimAction(j)
out.set(c, a, value)
}
}
return out, nil
}
func (h *HasAction) Check(c CharacterType, a AnimAction) bool {
return h.bits.Test(h.offset(c, a))
}
func (h *HasAction) offset(c CharacterType, a AnimAction) uint32 {
// Best to view this as a 2D array with CharacterTypeCount * AnimActionCount elements
i := uint32(c - CharacterTypeStart)
j := uint32(a - AnimActionStart)
return (i * uint32(AnimActionCount)) + j
}
func (h *HasAction) set(c CharacterType, a AnimAction, value bool) {
if value {
h.bits.Set(h.offset(c, a))
} else {
h.bits.Clear(h.offset(c, a))
}
}
// Actions returns the list of animations that a character type has
func (h *HasAction) Actions(c CharacterType) []AnimAction {
var out []AnimAction
for j := AnimActionStart; j < AnimActionCount; j++ {
if h.Check(c, j) {
out = append(out, j)
}
}
return out
}
func (h *HasAction) Print() {
fmt.Println(" Tac Ass Dev Term Apo Tech Chp Lib Cpt CMar CLrd CChp CSrc CTrm Kbz BTh BL FHnd LoC Flm PHr BHr Cult")
for a := AnimActionStart; a <= AnimActionEnd; a++ {
fmt.Printf("%.2d", int(a))
for c := CharacterTypeStart; c <= CharacterTypeEnd; c++ {
if h.Check(c, a) {
fmt.Print(" x ")
} else {
fmt.Print(" ")
}
}
fmt.Println("")
}
}

73
internal/idx/idx.go Normal file
View File

@@ -0,0 +1,73 @@
// package idx parses the Idx/WarHammer.idx file.
//
// No, I don't know what it's for yet.
package idx
import (
"encoding/binary"
//"fmt"
"log"
"os"
//"strings"
)
type Type1Record struct {
Offset1 uint32 // Where the type2 for this type1 is to be found
Unknown1 uint32 // ???
Offset2 uint32 // Another offset? But what to?
}
type Type2Record struct {
Unknown1 [4]byte // ???
Offset uint32 // Where the type3 for this type2 is to be found
Unknown2 [4]byte // ??
}
type Type3Record struct {
First20 [20]byte
Last78 [78]byte
}
type Idx struct {
Filename string
Type1Records [512]Type1Record // Experimentally, there seem to be 512 of these
Type2Records []Type2Record
Type3Records []Type3Record
}
func Load(filename string) (*Idx, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
out := &Idx{Filename: filename}
if err := binary.Read(f, binary.LittleEndian, &out.Type1Records); err != nil {
return nil, err
}
for i, rec := range out.Type1Records {
var off1diff uint32
var off2diff uint32
if i > 0 && rec.Offset1 > 0 {
lastRec := out.Type1Records[i-1]
off1diff = rec.Offset1 - lastRec.Offset1
off2diff = rec.Offset2 - lastRec.Offset2
}
log.Printf(
"%.3d: 0x%.6x diff=%.6d %.4d 0x%.6x diff=%.6d",
i, rec.Offset1, off1diff, rec.Unknown1, rec.Offset2, off2diff,
// i,
// rec.Unknown1[0], rec.Unknown1[1], rec.Unknown1[2], rec.Unknown1[3],
// rec.Unknown1[4], rec.Unknown1[5], rec.Unknown1[6], rec.Unknown1[7],
)
}
return out, nil
}

View File

@@ -201,12 +201,18 @@ func loadProperties(menu *Menu, scanner *asciiscan.Scanner) error {
return err
}
// DeBrief.mnu misspells these
parts := strings.SplitN(strings.ToUpper(k), " ", 3)
if len(parts) > 2 {
k = strings.Join(parts[0:2], " ")
}
switch strings.ToUpper(k) {
case "BACKGROUND COLOR 0..255..-1 TRANS":
case "BACKGROUND COLOR":
menu.BackgroundColor = data.ColorPalette[vInt]
case "HYPERTEXT COLOR 0..255":
case "HYPERTEXT COLOR":
menu.HypertextColor = data.ColorPalette[vInt]
case "FONT TYPE 0..5":
case "FONT TYPE":
menu.FontType = vInt
default:
return fmt.Errorf("Unhandled menu property in %v: %q=%q", menu.Name, k, v)

View File

@@ -123,6 +123,15 @@ func (s *Scanner) ConsumeInt() (int, error) {
return strconv.Atoi(str)
}
func (s *Scanner) ConsumeBool() (bool, error) {
integer, err := s.ConsumeInt()
if err != nil {
return false, err
}
return (integer > 0), nil
}
// Reads a list of non-property lines, skipping any that match the given strings
func (s *Scanner) ConsumeStringList(skip ...string) ([]string, error) {
skipper := make(map[string]bool, len(skip))
@@ -166,6 +175,16 @@ func (s *Scanner) ConsumeIntPtr(to *int) error {
return nil
}
func (s *Scanner) ConsumeBoolPtr(to *bool) error {
val, err := s.ConsumeBool()
if err != nil {
return err
}
*to = val
return nil
}
func (s *Scanner) ConsumeIntPtrs(ptrs ...*int) error {
for _, ptr := range ptrs {
if err := s.ConsumeIntPtr(ptr); err != nil {
@@ -175,3 +194,13 @@ func (s *Scanner) ConsumeIntPtrs(ptrs ...*int) error {
return nil
}
func (s *Scanner) ConsumeBoolPtrs(ptrs ...*bool) error {
for _, ptr := range ptrs {
if err := s.ConsumeBoolPtr(ptr); err != nil {
return err
}
}
return nil
}