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/data"
"code.ur.gs/lupine/ordoor/internal/fonts" "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/maps"
"code.ur.gs/lupine/ordoor/internal/menus" "code.ur.gs/lupine/ordoor/internal/menus"
"code.ur.gs/lupine/ordoor/internal/sets" "code.ur.gs/lupine/ordoor/internal/sets"
@@ -33,13 +34,15 @@ func main() {
loadSets() loadSets()
loadMenus() loadMenus()
loadFonts() loadFonts()
loadIdx()
} }
func loadData() { func loadData() {
dataPath := filepath.Join(*gamePath, "Data") dataPath := filepath.Join(*gamePath, "Data")
accountingPath := filepath.Join(dataPath, "Accounting.dat") accountingPath := filepath.Join(dataPath, "Accounting.dat")
genericDataPath := filepath.Join(dataPath, "GenericData.dat")
aniObDefPath := filepath.Join(dataPath, "AniObDef.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) i18nPath := filepath.Join(dataPath, data.I18nFile)
log.Printf("Loading %s...", accountingPath) log.Printf("Loading %s...", accountingPath)
@@ -73,6 +76,12 @@ func loadData() {
} }
log.Printf("%s: len=%v", i18nPath, i18n.Len()) 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() { func loadObj() {
@@ -189,3 +198,11 @@ func loadFonts() {
fmt.Printf(" * `%s`: obj=%v entries=%v\n", font.Name, font.ObjectFile, font.Entries()) 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` - ??? | | 0 | 2? | `02 06` - ??? |
| 2 | 2? | `n xx` - ??? `n` counts from 1 to 8 | | 2 | 2? | `n xx` - ??? `n` counts from 1 to 8 |
| 4 | 4 | Position of type 3 record | | 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 The two type 3a and 3b records are identical to each other, it's hard to know
what's what. what's what.
@@ -169,137 +170,219 @@ what's what.
None of the unknown numbers, however sliced, seem to be sprite indices for None of the unknown numbers, however sliced, seem to be sprite indices for
`Anim/WarHammer.ani`. `Anim/WarHammer.ani`.
Here's a trace of both `idx` (fd 34) and `ani` (fd 14) files when placing a Here's a trace of both `idx` and `ani` files when placing a single librarian for
single librarian for me to dig into in more detail. me to dig into in more detail. No other files are touched when doing this.
<details> <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 _llseek(<WarHammer.idx>, 132, [132], SEEK_SET) = 0
read(34, "0|\t\0\230\0\0\0\210\370\0\0", 12) = 12 read(<WarHammer.idx>, "\x30\x7c\x09\x00\x98\x00\x00\x00\x88\xf8\x00\x00", 12) = 12
_llseek(34, 132, [132], SEEK_SET) = 0 _llseek(<WarHammer.idx>, 621616, [621616], SEEK_SET) = 0
read(34, "0|\t\0\230\0\0\0\210\370\0\0", 12) = 12 read(<WarHammer.idx>, "\x02\x01\x01\x33\x50\x83\x09\x00\x0d\x00\x00\x00", 12) = 12
_llseek(34, 621616, [621616], SEEK_SET) = 0 _llseek(<WarHammer.idx>, 621628, [621628], SEEK_SET) = 0
read(34, "\2\1\0013P\203\t\0\r\0\0\0", 12) = 12 read(<WarHammer.idx>, "\x02\x01\x02\x33\xb2\x83\x09\x00\x0d\x00\x00\x00", 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(34, 623832, [623832], SEEK_SET) = 0 _llseek(<WarHammer.idx>, 621640, [621640], 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(<WarHammer.idx>, "\x02\x01\x03\x33\x14\x84\x09\x00\x0d\x00\x00\x00", 12) = 12
_llseek(14, 509440, [509440], SEEK_SET) = 0 _llseek(<WarHammer.idx>, 621652, [621652], SEEK_SET) = 0
read(14, "\fM\266\th\16\0\0", 8) = 8 read(<WarHammer.idx>, "\x02\x01\x04\x33\x76\x84\x09\x00\x0d\x00\x00\x00", 12) = 12
_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(14, 164448540, [164448540], SEEK_SET) = 0 _llseek(<WarHammer.idx>, 621664, [621664], 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 read(<WarHammer.idx>, "\x02\x01\x05\x33\xd8\x84\x09\x00\x0d\x00\x00\x00", 12) = 12
_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(34, 623832, [623832], SEEK_SET) = 0 _llseek(<WarHammer.idx>, 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(<WarHammer.idx>, "\x34\x00\x40\x00\x40\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 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(34, 132, [132], SEEK_SET) = 0 _llseek(<WarHammer.idx>, 0, [623852], SEEK_CUR) = 0
read(34, "0|\t\0\230\0\0\0\210\370\0\0", 12) = 12 _llseek(<WarHammer.idx>, 623852, [623852], SEEK_SET) = 0
_llseek(<WarHammer.idx>, 623930, [623930], SEEK_SET) = 0
_llseek(34, 621616, [621616], SEEK_SET) = 0 _llseek(<WarHammer.ani>, 509440, [509440], SEEK_SET) = 0
read(34, "\2\1\0013P\203\t\0\r\0\0\0", 12) = 12 read(<WarHammer.ani>, "\x0c\x4d\xb6\x09\x68\x0e\x00\x00", 8) = 8
_llseek(34, 621628, [621628], SEEK_SET) = 0
read(34, "\2\1\0023\262\203\t\0\r\0\0\0", 12) = 12 _llseek(<WarHammer.ani>, 509448, [509448], SEEK_SET) = 0
_llseek(34, 621640, [621640], SEEK_SET) = 0 read(<WarHammer.ani>, "\x74\x5b\xb6\x09\xfe\x0e\x00\x00", 8) = 8
read(34, "\2\1\0033\24\204\t\0\r\0\0\0", 12) = 12
_llseek(34, 621652, [621652], SEEK_SET) = 0 _llseek(<WarHammer.ani>, 509456, [509456], SEEK_SET) = 0
read(34, "\2\1\0043v\204\t\0\r\0\0\0", 12) = 12 read(<WarHammer.ani>, "\x72\x6a\xb6\x09\x67\x0f\x00\x00", 8) = 8
_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>, 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> </details>
Notable is that we still load 5 type 2 records, even though there's just a Notable is that we still load 5 type 2 records, even though there's just a
single librarian, and 8 compass points. Why 5? 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 * `*.dat` # plaintext files defining properties of objects. No single format
* **PARSED** * **PARSED**
* `Accounting.dat` # key = value => internal/data/accounting.go * `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 * `GenericData.dat` # Generic Game Settings
* [`HasAction.dat`](ani.md) # "Are there animation for each of the character" - list of booleans
* **TODO** * **TODO**
* `ChaNames.dat` # list of character names * `ChaNames.dat` # list of character names
* `Coordinates.dat` # Weapon Firing Coordinates * `Coordinates.dat` # Weapon Firing Coordinates
* `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?
* `HasAction.dat` # "Are there animation for each of the character" - list of booleans
* `MiniMap.dat` # lots of seemingly random numbers. IDs? * `MiniMap.dat` # lots of seemingly random numbers. IDs?
* `MissionBriefing.dat` # Contains all Campaign Mission Briefing Text. Sections: "CAMPAIGN MISSION X ... END CAMPAIGN MISSION X" * `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 * `PWeight.dat` # Personality weights for the individual character types
@@ -75,8 +76,9 @@ remake.
* [`MultiMaps/`](maps.md#multimaps) * [`MultiMaps/`](maps.md#multimaps)
* [`*.MAP`](maps.md) * [`*.MAP`](maps.md)
* [`*.TXT`](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/` * [✓] `Pic/`
* `*.pcx` # Standard .pcx format * `*.pcx` # Standard .pcx format
* `RandomMaps/` * `RandomMaps/`

1
go.mod
View File

@@ -4,6 +4,7 @@ go 1.12
require ( require (
github.com/BurntSushi/toml v0.3.1 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/hajimehoshi/ebiten v1.11.0-alpha.2.0.20200101150127-38815ba801a5
github.com/jfreymuth/oggvorbis v1.0.1 // indirect github.com/jfreymuth/oggvorbis v1.0.1 // indirect
github.com/kr/text v0.2.0 // 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/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/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/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 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-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= 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 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) { switch strings.ToUpper(k) {
case "BACKGROUND COLOR 0..255..-1 TRANS": case "BACKGROUND COLOR":
menu.BackgroundColor = data.ColorPalette[vInt] menu.BackgroundColor = data.ColorPalette[vInt]
case "HYPERTEXT COLOR 0..255": case "HYPERTEXT COLOR":
menu.HypertextColor = data.ColorPalette[vInt] menu.HypertextColor = data.ColorPalette[vInt]
case "FONT TYPE 0..5": case "FONT TYPE":
menu.FontType = vInt menu.FontType = vInt
default: default:
return fmt.Errorf("Unhandled menu property in %v: %q=%q", menu.Name, k, v) 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) 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 // Reads a list of non-property lines, skipping any that match the given strings
func (s *Scanner) ConsumeStringList(skip ...string) ([]string, error) { func (s *Scanner) ConsumeStringList(skip ...string) ([]string, error) {
skipper := make(map[string]bool, len(skip)) skipper := make(map[string]bool, len(skip))
@@ -166,6 +175,16 @@ func (s *Scanner) ConsumeIntPtr(to *int) error {
return nil 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 { func (s *Scanner) ConsumeIntPtrs(ptrs ...*int) error {
for _, ptr := range ptrs { for _, ptr := range ptrs {
if err := s.ConsumeIntPtr(ptr); err != nil { if err := s.ConsumeIntPtr(ptr); err != nil {
@@ -175,3 +194,13 @@ func (s *Scanner) ConsumeIntPtrs(ptrs ...*int) error {
return nil return nil
} }
func (s *Scanner) ConsumeBoolPtrs(ptrs ...*bool) error {
for _, ptr := range ptrs {
if err := s.ConsumeBoolPtr(ptr); err != nil {
return err
}
}
return nil
}