From 22c5b6235d16ee4873fa0e976cdac72fb1a7de2e Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Sat, 17 Mar 2018 04:16:14 +0000 Subject: [PATCH] Document maps findings and start moving things out of README.md --- README.md | 147 +++++----------- doc/formats/index.md | 122 +++++++++++++ doc/formats/maps.md | 399 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 566 insertions(+), 102 deletions(-) create mode 100644 doc/formats/index.md create mode 100644 doc/formats/maps.md diff --git a/README.md b/README.md index 524d3fc..0a57238 100644 --- a/README.md +++ b/README.md @@ -1,116 +1,25 @@ # WH40K: Chaos Gate -Re-implementation of the WH40K binary using SDL. +Re-implementation of the WH40K binary. **You must have a copy of the original game data to use this project** -Files: - -``` -Anim/ - WarHammer.ani # Doesn't seem to be a RIFF file. 398M so very important. - * There's a pcx image header at `dd ... bs=1 skip=213` but it seems to be a false alert - * Hits for "AmigaOS bitmap font"... probably a false positive - * Lots of 8-byte reads when loading stuff in the mission editor - * Some ~4K reads, havent found one corresponding to a known format yet -Assign/ - *.asn # Unknown, seems to be related to .obj files -Cursor/ - *.ani # RIFF data - *.cur # Presumably standard windows-format non-animated cursors -Data/ - *.dat # plaintext files defining properties of objects. No single format - PARSED: - Accounting.dat # key = value => internal/data/accounting.go - AniObjDef.dat # animated object definitions - GenericData.dat # Generic Game Settings - IN PROGRESS: - - 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 - Random_AI.dat # contains the percentage of the different AI types for each of the different Chaos Squad Types - RandomPlanets.dat # Campaign Primary and Secondary Objectives - Sounds.dat # Sound Effect Data - SpellDef.dat # SPELL DEFINITIONS - StdWeap.dat # SQUAD STANDARD WEAPONS - Ultnames.dat # List of names for ultramarines - VehicDef.dat # VEHICLE DEFINITIONS - WeapDef.dat # Weapon definitions - PROBABLY NOT NEEDED: - BugHunt.dat # Contains SMF text for Bug hunt random missions - Credits.dat # list of credits - GenArm.dat # "Random campaign armory levels - space marine" - HeroArm.dat # "Random campaign armory levels - Veteran" - MHeroArm.dat # "Random campaign armory levels - Veteran" - PlanetDesc.dat # well-documented params. random mission generator params per planet. - RandChar.dat # Random character matrix. Information on what goes into a character matrix. - RandSMFtext.dat # SuperMacro Objectives for Campaign Random Mission Generator. - SpArm.dat # "RANDOM CAMPAIGN ARMORY LEVELS - Veteran" - VetArm.dat # "RANDOM CAMPAIGN ARMORY LEVELS - Veteran" - - *.chk # checksums? Mentions all the .dat files - *.cyc # ColorCycle DataFile. - *.dta # localized strings and things - Encyclopedia.dta # encyclopedia entries - KeyMap.dta # unknown - Keymap.dta # unknown - USEng.dta # Localized strings - -EquipmentMenuData # gzip-compressed, presumably to do with (initial?) squad configuration -Filters/ - wh40k.flt # Audio filter(s?) -Fonts/ - cboxfont # unknown - *.fnt # ASCII text. Map keycodes to sprites? - *.spr # sprites, presumably -Idx/ - WarHammer.idx # unknown, 1.8M -Maps/ - *.MAP # gzip-compressed, must be map definition, contains `WHMAP` constant and character names - *.TXT # scenario text -Menu/ - *.mnu # plain text, linked to .obj file, contains definitions - *.obj # unknown, not 3D .obj format -Misc/ - occlusio.lis # plain text, presumably occlusion mappings? -MultiMaps/ - *.MAP # Like Maps/ - *.TXT -Obj/ - *.obj # must be visual data of some sort, one per placeable map object? -Pic/ - *.pcx # Standard .pcx format -RandomMaps/ - *.chk # multiplayer. worry about these another day - *.dat -Save_G/ - *.sav # savedata, gzip-compressed, custom format - *.txt # Seems to be a copy of one of Maps/*.txt -Sets/ - Data.chk # checksums? Mentions all the .set files - *.set # plain text, related to maps, lists a set of .obj files for that map? -SMK/ - *.smk # Videos: RAD Game Tools Smacker Multimedia version 2 -Sounds/ - wh40k.ds # 0xffffffff then a list of .wav file names. Some sort of index? -Wav/ - *.wav # normal WAV files, all mentioned in Sounds/wh40k.ds -``` - WH40K.exe is the existing game engine WH40K_TD.exe is the map editor. Allows things to be saved as .MAP or as .SMF ("Super Macro File") -"Mission Setup" includes information about available squad types +This README is a grab-bag of miscellaneous information about file formats at +present. This is being migrated to the [Formats overview](doc/formats/index.md) +as a precursor to making this file useful! +No game yet, nothing even close. I'm in the very early stages of trying to +understand the various file formats. Until then, you can play WH40L: Chaos Gate +in a WinXP VM, disconnected from the internet. It doesn't need 3D rendering! + + + +"Mission Setup" includes information about available squad types From EquipDef.cpp Dumo: CEquipment we learn the following object types: @@ -404,4 +313,38 @@ Perhaps we have 24 bytes of header and that's the header-exclusive pixel data si Last 8 bits would then actually be the start of the image, but there's a lot of similarity between them... +It smells a bit like a DIB: + +| Offset | Size | Example | Purpose | +| 0 | 2 | D1 00 (209) | ? +| 2 | 2 | 41 01 (321) | ? +| 4 | 2 | 80 00 (128) | Width? | +| 6 | 2 | 3F 00 (63) | Height? +| 8 | 4 | 00 00 00 00 | Could be pitch / stride? +| 12 | 4 | D1 10 00 00 | Size of pixel data +| 16 | 4 | 00 00 00 00 | ? +| 20 | 4 | 00 00 00 00 | ? + + Now, how to convert the pixel data to an image?!?! + +Average bits per pixel seems to be less-than-1, e.g. for crates.obj: + +``` +2018/03/16 21:21:37 CFrame 0: w=76 h=57 sz=3008 w*h=4332 bpp=0.6943674976915974 +2018/03/16 21:21:37 CFrame 1: w=76 h=57 sz=2988 w*h=4332 bpp=0.6897506925207756 +2018/03/16 21:21:37 CFrame 2: w=108 h=73 sz=5185 w*h=7884 bpp=0.6576610857432775 +2018/03/16 21:21:37 CFrame 3: w=107 h=73 sz=5208 w*h=7811 bpp=0.6667520163871463 +2018/03/16 21:21:37 CFrame 4: w=109 h=95 sz=7639 w*h=10355 bpp=0.7377112506035731 +2018/03/16 21:21:37 CFrame 5: w=109 h=95 sz=7620 w*h=10355 bpp=0.7358763882182521 +2018/03/16 21:21:37 CFrame 6: w=76 h=57 sz=2996 w*h=4332 bpp=0.6915974145891043 +2018/03/16 21:21:37 CFrame 7: w=76 h=57 sz=2964 w*h=4332 bpp=0.6842105263157895 +2018/03/16 21:21:37 CFrame 8: w=108 h=73 sz=5148 w*h=7884 bpp=0.6529680365296804 +2018/03/16 21:21:37 CFrame 9: w=107 h=73 sz=5153 w*h=7811 bpp=0.659710664447574 +2018/03/16 21:21:37 CFrame 10: w=109 h=95 sz=7423 w*h=10355 bpp=0.7168517624336069 +2018/03/16 21:21:37 CFrame 11: w=109 h=95 sz=7487 w*h=10355 bpp=0.7230323515210043 +``` + +So some form of compression? RLE? + +How does WH40K_TD.EXE draw these? diff --git a/doc/formats/index.md b/doc/formats/index.md new file mode 100644 index 0000000..9f9b635 --- /dev/null +++ b/doc/formats/index.md @@ -0,0 +1,122 @@ +# Formats + +Chaos Gate has over 700MB of data, organized (seemingly) logically into files in +directories. Being able to parse, display, and use that data is paramount to any +remake. + +## Filesystem layout + +* `Anim/` + * `WarHammer.ani` # Doesn't seem to be a RIFF file. 398M so very important. + * There's a pcx image header at `dd ... bs=1 skip=213` but it seems to be a false alert + * Hits for "AmigaOS bitmap font"... probably a false positive + * Lots of 8-byte reads when loading stuff in the mission editor + * Some ~4K reads, havent found one corresponding to a known format yet + * foo +* `Assign/` + * `*.asn` # Unknown, seems to be related to .obj files +* `Cursor/` + * `*.ani` # RIFF data + * `*.cur` # Presumably standard windows-format non-animated cursors +* `Data/` + * `*.dat` # plaintext files defining properties of objects. No single format + * **PARSED** + * `Accounting.dat` # key = value => internal/data/accounting.go + * `AniObjDef.dat` # animated object definitions + * `GenericData.dat` # Generic Game Settings + * **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 + * `Random_AI.dat` # contains the percentage of the different AI types for each of the different Chaos Squad Types + * `RandomPlanets.dat` # Campaign Primary and Secondary Objectives + * `Sounds.dat` # Sound Effect Data + * `SpellDef.dat` # SPELL DEFINITIONS + * `StdWeap.dat` # SQUAD STANDARD WEAPONS + * `Ultnames.dat` # List of names for ultramarines + * `VehicDef.dat` # VEHICLE DEFINITIONS + * `WeapDef.dat` # Weapon definitions + * **PROBABLY NOT NEEDED** + * `BugHunt.dat` # Contains SMF text for Bug hunt random missions + * `Credits.dat` # list of credits + * `GenArm.dat` # "Random campaign armory levels - space marine" + * `HeroArm.dat` # "Random campaign armory levels - Veteran" + * `MHeroArm.dat` # "Random campaign armory levels - Veteran" + * `PlanetDesc.dat` # well-documented params. random mission generator params per planet. + * `RandChar.dat` # Random character matrix. Information on what goes into a character matrix. + * `RandSMFtext.dat` # SuperMacro Objectives for Campaign Random Mission Generator. + * `SpArm.dat` # "RANDOM CAMPAIGN ARMORY LEVELS - Veteran" + * `VetArm.dat` # "RANDOM CAMPAIGN ARMORY LEVELS - Veteran" + * `*.chk` # checksums? Mentions all the .dat files + * `*.cyc` # ColorCycle DataFile. + * `*.dta` # localized strings and things + * `Encyclopedia.dta` # encyclopedia entries + * `KeyMap.dta` # unknown + * `Keymap.dta` # unknown + * `USEng.dta` # Localized strings +* `EquipmentMenuData` # gzip-compressed, presumably to do with (initial?) squad configuration +* `Filters/` + * `wh40k.flt` # Audio filter(s?) +* `Fonts/` + * `cboxfont` # unknown + * `*.fnt` # ASCII text. Map keycodes to sprites? + * `*.spr` # sprites, presumably +* `Idx/` + * `WarHammer.idx` # unknown, 1.8M +* [`Maps/`](maps.md) + * `*.MAP` + * `*.TXT` +* `Menu/` + * `*.mnu` # plain text, linked to .obj file, contains definitions + * `*.obj` # unknown, not 3D .obj format +* `Misc/` + * `occlusio.lis` # plain text, presumably occlusion mappings? +* [`MultiMaps/`](maps.md#multimaps) + * `*.MAP` + * `*.TXT` +* `Obj/` + * `*.obj` # must be visual data of some sort, one per placeable map object? +* `Pic/` + * `*.pcx` # Standard .pcx format +* `RandomMaps/` + * `*.chk` # multiplayer. worry about these another day + * `*.dat` +* `Save_G/` + * `*.sav` # savedata, gzip-compressed, custom format + * `*.txt` # Seems to be a copy of one of Maps/*.txt +* `Sets/` + * `Data.chk` # checksums? Mentions all the .set files + * `*.set` # plain text, related to maps. Editor has a concept of map sets, which these must be +* [✓] `SMK/` + * `*.smk` # Videos: RAD Game Tools Smacker Multimedia version 2 +* `Sounds/` + * `wh40k.ds` # 0xffffffff then a list of .wav file names. Some sort of index? +* [✓] `Wav/` + * `*.wav` # Normal WAV files + +Phew. + +## General notes + +* For binary formats, integers seem to be stored in little-endian +* *Almost everything* seems to be in a data file somewhere. Helpful! +* `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 + formats and the parsers I'm writing. Ensure you're in a `GOPATH`! + +## Cross-links / associations + +(Just some noticed so far) + +* [`Assign/*.asn`](assign.md): + * [`Obj/*.obj`](obj.md). +* [`Maps/*.map`](maps.md): + * [`Maps/*.txt`](maps.md#associated-txt-file) + * [`Sets/*.set`](sets.md) +* [`Sounds/wh40k.ds`](sounds.md) + * `Wav/*.wav` \ No newline at end of file diff --git a/doc/formats/maps.md b/doc/formats/maps.md new file mode 100644 index 0000000..3659353 --- /dev/null +++ b/doc/formats/maps.md @@ -0,0 +1,399 @@ +# Map format information + +## Overview + +The `Map/` directory contains linked pairs of files: a `.TXT` and a `.MAP`. +The former appears to be structured text, with tilde-separated sections. +The latter is a custom format of some kind, GZip-compressed, with a `WHMAP` +constant and character names embedded + +WH40K_TD.exe can read in and write out maps for us, for investigation \o/. + +I update [structure](#structure) with details as I work them out, and put the +working in appropriately-named subsections *below* that section. + +## Directory listing + +``` +total 1.5M +-rw-r--r-- 1 65K Nov 4 1998 Chapter01.MAP +-rw-r--r-- 1 429 Nov 7 1998 Chapter01.TXT +-rw-r--r-- 1 81K Nov 4 1998 Chapter02.MAP +-rw-r--r-- 1 587 Nov 7 1998 Chapter02.TXT +-rw-r--r-- 1 88K Nov 4 1998 Chapter03.MAP +-rw-r--r-- 1 597 Nov 7 1998 Chapter03.TXT +-rw-r--r-- 1 100K Jan 26 1999 Chapter04.MAP +-rw-r--r-- 1 538 Jan 26 1999 Chapter04.TXT +-rw-r--r-- 1 42K Jan 26 1999 Chapter05.MAP +-rw-r--r-- 1 1.3K Nov 7 1998 Chapter05.TXT +-rw-r--r-- 1 56K Nov 4 1998 Chapter06.MAP +-rw-r--r-- 1 572 Nov 7 1998 Chapter06.TXT +-rw-r--r-- 1 63K Jan 26 1999 Chapter07.MAP +-rw-r--r-- 1 750 Jan 26 1999 Chapter07.TXT +-rw-r--r-- 1 66K Nov 20 1998 Chapter08.MAP +-rw-r--r-- 1 638 Nov 7 1998 Chapter08.TXT +-rw-r--r-- 1 98K Jan 26 1999 Chapter09.MAP +-rw-r--r-- 1 656 Jan 26 1999 Chapter09.TXT +-rw-r--r-- 1 100K Nov 5 1998 Chapter10.MAP +-rw-r--r-- 1 622 Nov 7 1998 Chapter10.TXT +-rw-r--r-- 1 110K Nov 4 1998 Chapter11.MAP +-rw-r--r-- 1 396 Nov 7 1998 Chapter11.TXT +-rw-r--r-- 1 118K Jan 26 1999 Chapter12.MAP +-rw-r--r-- 1 593 Nov 7 1998 Chapter12.TXT +-rw-r--r-- 1 133K Nov 4 1998 Chapter13.MAP +-rw-r--r-- 1 1.1K Nov 7 1998 Chapter13.TXT +-rw-r--r-- 1 137K Jan 26 1999 Chapter14.MAP +-rw-r--r-- 1 641 Nov 7 1998 Chapter14.TXT +-rw-r--r-- 1 140K Nov 5 1998 Chapter15.MAP +-rw-r--r-- 1 338 Nov 7 1998 Chapter15.TXT + +``` + +## Multimaps + +There are also maps in the `MultiMaps/` directory. I guess they're reworks of +the `Maps/` entries for multiplayer with differing numbers of players - +`Chapter1_3P.MAP` would be the chapter1 map, just modified for 3-player +multiplayer. Ignore for now, but here's the directory listing: + +``` +total 1.4M +-rw-r--r-- 1 93K Nov 5 1998 Chapter10_2P.MAP +-rw-r--r-- 1 21 Nov 4 1998 Chapter10_2P.TXT +-rw-r--r-- 1 103K Nov 5 1998 Chapter11_4P.MAP +-rw-r--r-- 1 36 Nov 4 1998 Chapter11_4P.TXT +-rw-r--r-- 1 111K Jan 26 1999 Chapter12_2P.MAP +-rw-r--r-- 1 198 Nov 4 1998 Chapter12_2P.TXT +-rw-r--r-- 1 125K Jan 26 1999 Chapter13_4P.MAP +-rw-r--r-- 1 394 Nov 4 1998 Chapter13_4P.TXT +-rw-r--r-- 1 64K Nov 5 1998 Chapter1_3P.MAP +-rw-r--r-- 1 168 Nov 4 1998 Chapter1_3P.txt +-rw-r--r-- 1 127K Nov 4 1998 Chapter14_4P.MAP +-rw-r--r-- 1 21 Nov 4 1998 Chapter14_4P.TXT +-rw-r--r-- 1 127K Nov 7 1998 Chapter15_2P.MAP +-rw-r--r-- 1 21 Nov 4 1998 Chapter15_2P.TXT +-rw-r--r-- 1 75K Nov 4 1998 Chapter2_4P.MAP +-rw-r--r-- 1 109 Nov 4 1998 Chapter2_4P.txt +-rw-r--r-- 1 83K Nov 5 1998 Chapter3_2P.MAP +-rw-r--r-- 1 119 Nov 4 1998 Chapter3_2P.txt +-rw-r--r-- 1 92K Jan 26 1999 Chapter4_2P.MAP +-rw-r--r-- 1 21 Nov 4 1998 Chapter4_2P.txt +-rw-r--r-- 1 35K Nov 4 1998 Chapter5_3P.MAP +-rw-r--r-- 1 416 Nov 4 1998 Chapter5_3P.txt +-rw-r--r-- 1 48K Nov 5 1998 Chapter6_2P.MAP +-rw-r--r-- 1 357 Nov 4 1998 Chapter6_2P.txt +-rw-r--r-- 1 56K Nov 7 1998 Chapter7_2P.MAP +-rw-r--r-- 1 233 Nov 4 1998 Chapter7_2P.txt +-rw-r--r-- 1 59K Nov 4 1998 Chapter8_2P.MAP +-rw-r--r-- 1 240 Nov 4 1998 Chapter8_2P.txt +-rw-r--r-- 1 91K Nov 4 1998 Chapter9_4P.MAP +-rw-r--r-- 1 367 Nov 4 1998 Chapter9_4P.TXT +``` + +## Structure + +The .MAP files are compressed with gzip. All offsets are on the uncompressed +size. + +(Incomplete) parser can be found [here](../../internal/maps/) + +The start of Chapter01.MAP. It's header then per-map-coordinate data. Must +remember that maps have 7 height levels (7), so the volume we're describing is +actually WxLxH in all cases + +``` +00000000 01 00 00 00 .... # IsCampaignMap +00000004 1A 00 00 00 .... # MinWidth +00000008 14 00 00 00 .... # MinLength +0000000C 68 00 00 00 h... # MaxWidth +00000010 50 00 00 00 P... # MaxLength +00000014 01 00 00 00 .... # Unknown1 +00000018 00 00 00 00 .... # Unknown2 +0000001C 00 00 00 00 .... # Unknown3 +00000020 00 00 00 00 .... # Unknown4 +00000024 08 00 57 48 ..WH # Magic value +00000028 4D 41 50 00 MAP. # ... +0000002C 00 00 00 00 .... # Unknown +00000030 91 09 00 00 .... # Unknown - varies between maps of the same size +00000034 6D 61 70 30 map0 # Name of object set to load from `Sets/` +00000038 31 00 00 00 1... # ... +0000003C 00 00 00 00 .... # Unknown from here.... +00000040 00 00 00 00 .... +00000044 00 00 00 00 .... +00000048 00 00 00 00 .... +0000004C 00 00 00 00 .... +00000050 00 00 00 00 .... +00000054 00 00 00 00 .... +00000058 00 00 00 00 .... +0000005C 00 00 00 00 .... +00000060 00 00 00 00 .... +00000064 00 00 00 00 .... +00000068 00 00 00 00 .... +0000006C 00 00 00 00 .... +00000070 00 00 00 00 .... +00000074 00 00 00 00 .... +00000078 00 00 00 00 .... +0000007C 00 00 00 00 .... +00000080 00 00 00 00 .... +00000084 00 00 00 00 .... +00000088 00 00 00 00 .... +0000008C 00 00 00 00 .... +00000090 00 00 00 00 .... +00000094 00 00 00 00 .... +00000098 00 00 00 00 .... +0000009C 00 00 00 00 .... +000000A0 00 00 00 00 .... +000000A4 00 00 00 00 .... +000000A8 00 00 00 00 .... +000000AC 00 00 00 00 .... +000000B0 00 00 00 00 .... +000000B4 38 00 30 00 8.0. +000000B8 00 00 3F 00 ..?. +000000BC 32 00 00 00 2... +000000C0 00 00 00 00 .... +000000C4 00 00 00 00 .... +000000C8 00 00 00 00 .... +000000CC 00 00 00 00 .... +000000D0 00 00 3F 00 ..?. +000000D4 32 00 01 00 2... +000000D8 00 00 0F 00 .... +000000DC 05 00 00 00 .... +000000E0 01 00 00 00 .... +000000E4 A2 FF 80 00 .... +000000E8 17 00 00 00 .... +000000EC FF FF FF FF .... +000000F0 FF FF FF FF .... +000000F4 FF FF FF FF .... +000000F8 FF FF FF FF .... +000000FC FF FF FF FF .... +00000100 FB 00 00 00 .... # It's plausible that per-coord data begins here + +``` + +Comparing some values across all maps bundled with the game: + +* `Maps/` + * `Chapter10.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map10 + * `Chapter12.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map12 + * `Chapter15.MAP`: IsCampaignMap=1 W=0:130 L=0:100 SetName=map15 + * `Chapter04.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map04 + * `Chapter08.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map08 + * `Chapter09.MAP`: IsCampaignMap=1 W=13:117 L=10:90 SetName=map09 + * `Chapter03.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map03 + * `Chapter11.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map11 + * `Chapter13.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map13 + * `Chapter02.MAP`: IsCampaignMap=1 W=13:117 L=10:90 SetName=map02 + * `Chapter06.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map06 + * `Chapter07.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map07 + * `Chapter14.MAP`: IsCampaignMap=1 W=13:117 L=10:90 SetName=map14 + * `Chapter01.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map01 + * `Chapter05.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map05 +* `MultiMaps/` + * `Chapter13_4P.MAP`: IsCampaignMap=0 W=26:104 L=20:80 SetName=map13 + * `Chapter1_3P.MAP`: IsCampaignMap=0 W=26:104 L=20:80 SetName=map01 + * `Chapter5_3P.MAP`: IsCampaignMap=0 W=26:104 L=20:80 SetName=map05 + * `Chapter8_2P.MAP`: IsCampaignMap=0 W=26:104 L=20:80 SetName=map08 + * `Chapter11_4P.MAP`: IsCampaignMap=0 W=26:104 L=20:80 SetName=map11 + * `Chapter9_4P.MAP`: IsCampaignMap=0 W=13:117 L=10:90 SetName=map09 + * `Chapter12_2P.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map12 + * `Chapter15_2P.MAP`: IsCampaignMap=0 W=0:130 L=0:100 SetName=map15 + * `Chapter2_4P.MAP`: IsCampaignMap=0 W=13:117 L=10:90 SetName=map02 + * `Chapter4_2P.MAP`: IsCampaignMap=1 W=26:104 L=20:80 SetName=map04 + * `Chapter10_2P.MAP`: IsCampaignMap=0 W=26:104 L=20:80 SetName=map10 + * `Chapter14_4P.MAP`: IsCampaignMap=0 W=13:117 L=10:90 SetName=map14 + * `Chapter3_2P.MAP`: IsCampaignMap=0 W=26:104 L=20:80 SetName=map03 + * `Chapter6_2P.MAP`: IsCampaignMap=0 W=26:104 L=20:80 SetName=map06 + * `Chapter7_2P.MAP`: IsCampaignMap=0 W=26:104 L=20:80 SetName=map07 + +## IsCampaignMap + +This is just a theory, but every map that forms part of the single-player +campaign has a value of 0x01 for 0x0000 - 0x0003. + +Most of the MP maps and the maps I generate for myself have the value of 0x0 +instead. Perhaps `Chapter4_2P.MAP` and `Chapter12_2P.MAP` have it set by +accident? Or maybe it's another thing entirely. + +TODO: try to trace what WH40K.exe does with this flag, if anything. + +## Width and Length + +Maximum allowed size by WH40K_TD.exe is 130x100. Minimum is 20x20. + +To investigate this, I created maps of different sizes **only**, and observed +what differences this made in the putative header: + +| Offset | 20x20 | 20x21 | 21x20 | 21x21 | 100x100 | 130x100 | +| ------ | ----- | ----- | ----- | ----- | ------- | ------- | +| 0x04 | 0x37 | 0x37 | 0x36 | 0x36 | 0x0F | 0x00 | +| 0x08 | 0x28 | 0x27 | 0x28 | 0x27 | 0x00 | 0x00 | +| 0x0C | 0x4B | 0x4B | 0x4B | 0x4B | 0x73 | 0x82 | +| 0x10 | 0x3C | 0x3C | 0x3C | 0x3C | 0x64 | 0x64 | + +WH40K_TD.exe gives us coordinates for each point on each of these maps: + +| Size | North | East | South | West | 0x04 | 0x08 | 0x0c | 0x10 | +| ------- | ----- | ------ | ------ | ----- | ---- | ---- | ---- | ---- | +| 20x20 | 55,40 | 74,40 | 74,59 | 55,59 | 55 | 40 | 75 | 60 | +| 20x21 | 55,39 | 74,39 | 74,59 | 55,59 | 55 | 39 | 75 | 60 | +| 21x20 | 54,40 | 74,40 | 74,59 | 54,59 | 54 | 40 | 75 | 60 | +| 100x100 | 15, 0 | 114, 0 | 114,99 | 15,99 | 15 | 0 | 115 | 100 | +| 130x100 | 0, 0 | 129, 0 | 129,99 | 0,99 | 0 | 0 | 130 | 100 | + + +So our valid coordinates range in width from `(*0x04, (*0x0c)-1)`, and for +length, from `(*0x08, (*0x10)-1)` + +We're specifying a viewport on a statically-defined area with a width of 130, +and a length of 100. The viewport is centered on the middle of that area and +anything outside it is clipped away. + +## Per-coordinate data + +All .MAP files are the same size once uncompressed, regardles of width and +length parameters, suggesting that they each have fixed-sized records for every +possible coordinate, regardless. + +Skipping the header we know about, we have data like this: + +``` +00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00000080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00000090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +000000A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +000000B0 00 00 00 00 1F 00 2C 00 00 00 00 00 00 00 00 00 ......,......... +000000C0 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ +000000D0 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 ................ +000000E0 01 00 FC FF F3 FF 1C 00 10 00 00 00 FF FF FF FF ................ +000000F0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF ................ +00000100 FB 00 00 00 24 FF FF FF 51 02 00 00 00 06 00 FF ....$...Q....... +00000110 3F 00 00 00 82 01 00 00 00 00 00 FF 00 00 00 00 ?............... +00000120 39 00 00 00 87 01 00 00 00 00 00 FF 00 00 00 00 9............... +00000130 38 00 00 00 89 01 00 00 00 00 00 FF 00 00 00 00 8............... +00000140 38 00 00 00 85 01 00 00 00 00 00 FF 00 00 00 00 8............... +00000150 38 00 00 00 88 01 00 00 00 00 00 FF 00 00 00 00 8............... +00000160 38 00 00 00 89 01 00 00 00 00 00 FF 00 00 00 00 8............... +00000170 38 00 00 00 84 01 00 00 00 00 00 FF 00 00 00 00 8............... +00000180 38 00 00 00 89 01 00 00 00 00 00 FF 00 00 00 00 8............... +00000190 38 00 00 00 85 01 00 00 00 00 00 FF 00 00 00 00 8............... +000001A0 38 00 00 00 8A 01 00 00 00 00 00 FF 00 00 00 00 8............... +000001B0 38 00 00 00 82 01 00 00 00 00 00 FF 00 00 00 00 8............... +000001C0 38 00 00 00 8A 01 00 00 00 00 00 FF 00 00 00 00 8............... +000001D0 38 00 00 00 83 01 00 00 00 00 00 FF 00 00 00 00 8............... +000001E0 38 00 00 00 83 01 00 00 00 00 00 FF 00 00 00 00 8............... +000001F0 38 00 00 00 88 01 00 00 00 00 00 FF 00 00 00 00 8............... +``` + +It would be very neat if the per-coordinate data started at 0x100 and took 16 +bytes per coordinate. + +Total number of possible coordinates is 100x130x7 = 91,000 = 1,456,000 bytes. + +Uncompressed file size is always 1,458,915 bytes, leaving 2,915 bytes over for +header and any trailing data. + +Looking at the data around 0x163890, we see: + +``` +00163800 38 00 00 00 00 01 00 00 00 00 00 FF 00 00 00 00 8............... +00163810 38 00 00 00 00 01 00 00 00 00 00 FF 00 00 00 00 8............... +00163820 38 00 00 00 00 01 00 00 00 00 00 FF 00 00 00 00 8............... +00163830 38 00 00 00 00 01 00 00 00 00 00 FF 00 00 00 00 8............... +00163840 38 00 00 00 00 01 00 00 00 00 00 FF 00 00 00 00 8............... +00163850 38 00 00 00 00 01 00 00 00 00 00 FF 00 00 00 00 8............... +00163860 38 00 00 00 00 01 00 00 00 00 00 FF 00 00 00 00 8............... +00163870 38 00 00 00 00 01 00 00 00 00 00 FF 00 00 00 00 8............... +00163880 38 00 00 00 00 01 00 00 00 00 00 FF 00 00 00 00 8............... +00163890 38 00 00 68 00 00 00 50 00 00 00 1A 00 00 00 14 8..h...P........ +001638A0 00 00 00 3A 00 00 00 00 38 25 00 04 00 00 00 00 ...:....8%...... +001638B0 00 00 00 1A 00 00 00 00 00 00 00 00 00 00 00 00 ................ +001638C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +001638D0 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 00 ................ +001638E0 00 00 00 32 00 00 00 00 00 00 00 00 00 00 00 00 ...2............ +001638F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00163900 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00163910 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00163920 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00163930 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00163940 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00163950 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00163960 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00163970 00 00 00 00 00 00 00 00 00 00 00 00 00 17 4D 61 ..............Ma +00163980 6E 69 61 00 00 00 00 00 00 00 00 00 00 00 00 00 nia............. +``` + +So this looks like a good working theory. + +Wherever they start, these rows must refer to the object sets somehow. We also +need to work out how they're arranged. + +## Trailer + +Assuming the theory above is correct, we have trailer data starting at +`0x163890`. Browsing through the `Chapter01.MAP` data, I see: + +* Names: + * `0x163970`: Mania + * Dagon + * Nihasa + * Samnu + * Gigamen + * Valefor + * Apollyon + * Vassago + * Diabolus + * Asmodee + * Gamigin + * Beherit + * Marbas + * Lucifer + * Ahpuch + * Gorgon + * Loki + * Lucifer + * Mammon + * Baphomet + * Magot + * Belial + * Mamon + * ... + +So we must have enemy characters placed on the map, although I don't remember +Chapter01 having *this many*... + +At 0017C9DF we see the start of scenario text: + +``` +0017C9A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +0017C9B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +0017C9C0 00 00 00 02 00 00 00 00 00 00 00 32 00 00 00 01 ...........2.... +0017C9D0 03 FF FF 00 00 00 00 00 00 00 00 00 00 00 00 59 ...............Y +0017C9E0 6F 75 20 68 61 76 65 20 73 70 6F 74 74 65 64 20 ou have spotted +0017C9F0 61 6D 6D 75 6E 69 74 69 6F 6E 20 63 72 61 74 65 ammunition crate +0017CA00 73 20 77 69 74 68 20 49 6D 70 65 72 69 61 6C 20 s with Imperial +0017CA10 6D 61 72 6B 69 6E 67 73 2E 00 00 00 00 00 00 00 markings........ +0017CA20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +``` + +Several records like this. + +Around 001841A0: mission objectives! + +``` +00184190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +001841A0 00 00 00 00 00 00 4D 69 73 73 69 6F 6E 20 4F 62 ......Mission Ob +001841B0 6A 65 63 74 69 76 65 3A 0A 0A 45 6E 74 65 72 20 jective:..Enter +001841C0 74 68 65 20 74 65 6D 70 6C 65 20 6F 66 20 74 68 the temple of th +001841D0 65 20 43 68 61 6F 73 20 43 75 6C 74 69 73 74 20 e Chaos Cultist +001841E0 61 6E 64 20 72 65 74 72 69 65 76 65 20 74 68 65 and retrieve the +001841F0 20 72 65 6C 69 63 2E 20 0A 0A 52 65 63 6F 6D 6D relic. ..Recomm +00184200 65 6E 64 65 64 20 45 71 75 69 70 6D 65 6E 74 3A ended Equipment: +00184210 20 0A 0A 4B 72 61 6B 20 47 72 65 6E 61 64 65 73 ..Krak Grenades +00184220 20 0A 0A 41 6E 74 69 2D 50 6C 61 6E 74 20 47 72 ..Anti-Plant Gr +00184230 65 6E 61 64 65 73 0A 00 00 00 00 00 00 00 00 00 enades.......... +00184240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +``` + +Since all the files are exactly the same length uncompressed, I'm going to +assume these are all a fixed number of fixed-size records when looking into it. \ No newline at end of file