HeroQuest Quest Format

From ModdingWiki
Jump to navigation Jump to search
HeroQuest Quest Format
HeroQuest Quest Format.png
Format typeMap/level
Map type2D cell-based
Layer countN/A
Viewport (pixels)320×200
Cell dimensions26×19 (isometric)
Viewport (cells)max 6×5 (one single room)
Games

This page describes the mapping of the QUEST##.BIN files in HeroQuest, which are used to describe one mission level. These files contain everything that is needed to generate a quest. The maps of the game, like in the board game, are always laid out as 26×19 squares.

In theory, with this information, it could be possible to create a mission editor for the game. The only known restrictions are to stick with the Special events list, since it is hard-coded, and that no new missions can be added (at the moment) to the 2-page in-game list. So to add missions, you need to overwrite the original quests. Since the second page is for the "Return of the Witch Lord" expansion, a new expansion (fan made, or based on official expansions like "Kellar's Keep") could be added as patch.

Format quirks

  • The game crashes if the file exceeds 2760h (10KB) in length.
  • Some special event are hard coded in the engine, and not in the file.

Overall structure

The overall structure of the file is the following:

Offset Description & Notes
0x000 Map layer for rooms layout
0x200 Map layer for walls layout
0x400 Hero positions for all four heroes
0x40C Special Events per room for treasures
0x437 Special Events per room for traps and hidden doors
0x462 Population block, with Monsters, Objects and Quest Text

The following sections will describe each of these in detail.

Map Layers

The file starts with two layers specifying different properties of the same map tiles; first the rooms layout, then the walls layout, with each block using one byte per tile. These blocks only need 26*19 bytes to contain all their data, but are padded to blocks of 0x200 bytes each.

Rooms Layout

This block starts at the beginning of the file. The rooms layout determines which area on the map is part of which room. Since the game is limited to showing rooms with a maximum dimension of 6x5, all paths are chopped up into different 'rooms' as well. Rooms have numbers from 0 to 42. A value of 0 means the room is not used. Rooms 1 to 20 (0x14) are the pathways. The remaining range, from 21 to 42 (0x15 to 0x2A), are the main rooms.

The default rooms layout with coordinates:

     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19
    
00   01 01 01 01 02 02 02 02 02 02 03 03 03 03 03 03 04 04 04 04 04 04 05 05 05 05
01   01 15 15 15 15 16 16 16 16 17 17 17 03 03 18 18 18 19 19 19 19 1A 1A 1A 1A 05
02   01 15 15 15 15 16 16 16 16 17 17 17 03 03 18 18 18 19 19 19 19 1A 1A 1A 1A 05
03   01 15 15 15 15 16 16 16 16 17 17 17 03 03 18 18 18 19 19 19 19 1A 1A 1A 1A 05
04   01 1B 1B 1B 1B 1C 1C 1C 1C 17 17 17 03 03 18 18 18 19 19 19 19 1A 1A 1A 1A 05
05   06 1B 1B 1B 1B 1C 1C 1C 1C 17 17 17 08 08 18 18 18 1D 1D 1D 1D 1E 1E 1E 1E 0A
06   06 1B 1B 1B 1B 1C 1C 1C 1C 07 08 08 08 08 08 08 09 1D 1D 1D 1D 1E 1E 1E 1E 0A
07   06 1B 1B 1B 1B 1C 1C 1C 1C 07 1F 1F 1F 1F 1F 1F 09 1D 1D 1D 1D 1E 1E 1E 1E 0A
08   06 1B 1B 1B 1B 1C 1C 1C 1C 07 1F 1F 1F 1F 1F 1F 09 1D 1D 1D 1D 1E 1E 1E 1E 0A
09   06 06 06 06 07 07 07 07 07 07 1F 1F 1F 1F 1F 1F 09 09 09 09 09 09 0A 0A 0A 0A
0A   0B 20 20 20 20 21 21 22 22 0C 1F 1F 1F 1F 1F 1F 0E 23 23 23 23 24 24 24 24 0F
0B   0B 20 20 20 20 21 21 22 22 0C 1F 1F 1F 1F 1F 1F 0E 23 23 23 23 24 24 24 24 0F
0C   0B 20 20 20 20 21 21 22 22 0C 0D 0D 0D 0D 0D 0D 0E 23 23 23 23 24 24 24 24 0F
0D   0B 20 20 20 20 26 26 26 26 27 27 27 0D 0D 28 28 28 28 23 23 23 24 24 24 24 0F
0E   0B 25 25 25 25 26 26 26 26 27 27 27 0D 0D 28 28 28 28 29 29 29 2A 2A 2A 2A 0F
0F   10 25 25 25 25 26 26 26 26 27 27 27 12 12 28 28 28 28 29 29 29 2A 2A 2A 2A 14
10   10 25 25 25 25 26 26 26 26 27 27 27 12 12 28 28 28 28 29 29 29 2A 2A 2A 2A 14
11   10 25 25 25 25 26 26 26 26 27 27 27 12 12 28 28 28 28 29 29 29 2A 2A 2A 2A 14
12   10 10 10 10 11 11 11 11 11 11 12 12 12 12 12 12 13 13 13 13 13 13 14 14 14 14

The game only seems to accept 32 different rooms on one quest map. If a map exceeds this amount, the higher ones after 32 are used are displayed on the overhead map, and you can enter them, but no tiles are displayed. This is probably an engine limitation. Because of this, any inaccessible areas in the quest map are cleared to room 0. The numbers of the used rooms don't need to be consecutive, though, so the actual layout of the numbers is generally not changed. The few changes to room layout definitions that exist in the files all seem to be map errors. Some maps do have corridors that are shortened because of an obstruction, and in such cases the room type is generally also cleared to cut it off at that point.

Example of the first level, "The Maze". 00 bytes have been replaced by "--" to more clearly show the layout. You can see that room 0x12 was cut off towards the north.

01 01 01 01 02 02 02 02 02 02 03 03 03 03 03 03 04 04 04 04 04 04 05 05 05 05
01 -- -- -- -- 16 16 16 16 17 17 17 03 03 -- -- -- -- -- -- -- -- -- -- -- 05
01 -- -- -- -- 16 16 16 16 17 17 17 03 03 -- -- -- -- -- -- -- -- -- -- -- 05
01 -- -- -- -- 16 16 16 16 17 17 17 03 03 -- -- -- -- -- -- -- -- -- -- -- 05
01 1B 1B 1B 1B 1C 1C 1C 1C 17 17 17 03 03 -- -- -- -- -- -- -- -- -- -- -- 05
06 1B 1B 1B 1B 1C 1C 1C 1C 17 17 17 08 08 -- -- -- 1D 1D 1D 1D 1E 1E 1E 1E 0A
06 1B 1B 1B 1B 1C 1C 1C 1C 07 08 08 08 08 08 08 09 1D 1D 1D 1D 1E 1E 1E 1E 0A
06 1B 1B 1B 1B 1C 1C 1C 1C 07 1F 1F 1F 1F 1F 1F 09 1D 1D 1D 1D 1E 1E 1E 1E 0A
06 1B 1B 1B 1B 1C 1C 1C 1C 07 1F 1F 1F 1F 1F 1F 09 1D 1D 1D 1D 1E 1E 1E 1E 0A
06 06 06 06 07 07 07 07 07 07 1F 1F 1F 1F 1F 1F 09 09 09 09 09 09 0A 0A 0A 0A
0B 20 20 20 20 21 21 22 22 -- 1F 1F 1F 1F 1F 1F 0E 23 23 23 23 -- -- -- -- 0F
0B 20 20 20 20 21 21 22 22 -- 1F 1F 1F 1F 1F 1F 0E 23 23 23 23 -- -- -- -- 0F
0B 20 20 20 20 21 21 22 22 -- -- -- -- -- 0D 0D 0E 23 23 23 23 -- -- -- -- 0F
0B 20 20 20 20 26 26 26 26 -- -- -- -- -- 28 28 28 28 23 23 23 -- -- -- -- 0F
0B -- -- -- -- 26 26 26 26 -- -- -- -- -- 28 28 28 28 -- -- -- -- -- -- -- 0F
10 -- -- -- -- 26 26 26 26 -- -- -- -- -- 28 28 28 28 -- -- -- -- -- -- -- 14
10 -- -- -- -- 26 26 26 26 -- -- -- -- -- 28 28 28 28 -- -- -- -- -- -- -- 14
10 -- -- -- -- 26 26 26 26 -- -- -- -- -- 28 28 28 28 -- -- -- -- -- -- -- 14
10 10 10 10 11 11 11 11 11 11 12 12 12 12 12 12 13 13 13 13 13 13 14 14 14 14

Walls layout

This block starts at offset 0x200, and, like the room IDs, is one byte per tile. The values determine the walls around each tile, any doors set in them, and any special properties of these walls or doors. South and East walls and doors are not defined, since you can get the same effect by placing a North or West ones in the adjacent room, and the southern and eastern border of the entire map are automatically walls.

Note that the perspective is isometric, so only the west (top left) and north (top right) walls are visible while playing. Because of this, some maps have errors where there are missing walls on openings that seem to lead to unused areas with room ID 00 when going to the east or south. In reality, the game will never indicate openings towards room 00 as passable, so the lack of wall makes no difference.

Each byte in this block is made up of bit flags that can be combined. Here are the meanings of each separate bit:

Bin value Hex Value Effect
00000000 0x00 None
00000001 0x01 Do not draw this wall. Doors show up as a frame only. This is done with walls when the area goes around a corner behind the walls, to prevent them from overlapping the floor tiles.
00000010 0x02 Unknown (only appears once in Quest 3)
00000100 0x04 The door is Open (can't be applied if secret)
00001000 0x08 The door is Secret (can't be applied if open)
00010000 0x10 Door to the West
00100000 0x20 Door to the North
01000000 0x40 Wall to the West
10000000 0x80 Wall to the North

Example of the first level "The Maze". 00 bytes have been replaced by "--" to more clearly show the layout:

C0 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80
40 C0 80 80 80 C0 80 80 80 C0 20 80 41 -- C0 80 80 80 80 80 80 80 80 80 80 41
40 40 -- -- -- 40 -- -- -- 40 -- -- 41 -- 40 -- -- -- -- -- -- -- -- -- -- 41
40 40 -- -- -- 40 -- -- -- 10 -- -- 41 -- 40 -- -- -- -- -- -- -- -- -- -- 41
40 C0 80 80 80 C0 80 80 80 40 -- -- 41 -- 40 -- -- -- -- -- -- -- -- -- -- 41
40 40 -- -- -- 40 -- -- -- 18 -- -- 40 -- 40 -- -- C0 80 80 80 90 80 80 80 40
40 40 -- -- -- 10 -- -- -- C0 80 80 -- -- 81 81 80 40 -- -- -- 40 -- -- -- 10
40 40 -- -- -- 40 -- -- -- 40 C0 80 80 80 80 80 40 40 -- -- -- 40 -- -- -- 40
40 40 -- -- -- 40 -- -- -- 40 40 -- -- -- -- -- 40 40 -- -- -- 40 -- -- -- 40
40 81 81 29 80 80 80 80 80 -- 10 -- -- -- -- -- 10 81 81 21 81 81 80 80 80 00
40 C0 80 80 80 68 80 C0 80 C0 40 -- -- -- -- -- 40 C0 80 80 20 C0 80 80 80 40
40 40 -- -- -- 40 -- 10 -- 40 40 -- -- -- -- -- 40 18 -- -- -- 40 -- -- -- 40
40 10 -- -- -- 40 -- 40 -- 40 80 80 80 80 C0 80 -- 40 -- -- -- 40 -- -- -- 40
40 40 -- -- -- 60 80 80 80 40 -- -- -- -- C0 80 80 20 41 -- -- 40 -- -- -- 40
40 C0 80 80 80 40 -- -- -- 40 -- -- -- -- 40 -- -- -- C0 80 80 -- -- -- -- 40
40 40 -- -- -- 40 -- -- -- 40 -- -- -- -- 40 -- -- -- 40 -- -- -- -- -- -- 40
40 40 -- -- -- 40 -- -- -- 40 -- -- -- -- 40 -- -- -- 40 -- -- -- -- -- -- 40
40 40 -- -- -- 40 -- -- -- 40 -- -- -- -- 40 -- -- -- 40 -- -- -- -- -- -- 40
40 81 81 81 80 80 20 80 80 80 80 80 80 80 80 20 80 80 80 80 80 80 80 80 80 00

Visualised as image, you get this:

HeroQuest-Quest1.png

Different rooms are indicated in different colours. Doors are shown as white, secret doors as purple, and walls with the draw-suppression bit enabled are dark grey instead of black.

Hero Positions

At 0x400, after the two map layers, starts the hero positioning info. This gives the following structure for each hero:

Offset Data type Block Name Description & Notes
0x00 UINT8 HeroX Cell position X-coordinate of the barbarian
0x01 UINT8 HeroY Cell position Y-coordinate of the barbarian
0x02 UINT8 HeroFacing Animation frame for the hero, determining the facing.

This structure occurs four times, in this order: Barbarian, Dwarf, Elf, Wizard.

This table gives the facing frames for each hero:

Hero North East South West
Barbarian 0x23 0x1D 0x20 0x26
Dwarf 0x2F 0x29 0x2C 0x32
Elf 0x3B 0x35 0x38 0x3E
Wizard 0x47 0x41 0x44 0x4A

Special Events

The next sections, starting at 0x040C, are the Special Events. There are two of these: one for treasure searching (at 0x040C), and one for searching for traps and hidden doors (at 0x0437). They each take up 43 bytes, one for each of the room numbers specified in the Rooms Layout. The lists seem to include the unused room 0.

The list of special events:

Hex ID Dec ID Where Event
0x00 00 None No event.
0x01 01 Chest Trapped, you disarm it
0x02 02 Chest Trapped, -1 body point
0x03 03 Cupboard 30 coins + potion of healing
0x04 04 Chest Trapped, -1 body point, +100 coins
0x05 05 Weapon rack Spear
0x06 06 Chest 50 coins + potion of healing
0x07 07 Chest 250 coins of prince magnus, the weight slows you
0x08 08 Throne Melar's key
0x09 09 Generic Talisman of lore
0x0A 10 Generic Borin's armour
0x0B 11 Chest Karlen's 200 coins
0x0C 12 Chest 150 coins + wand of recall
0x0D 13 Chest 100 coins (and the chest vanishes)
0x0E 14 Generic Shield
0x0F 15 Chest Trapped, beware
0x10 16 Chest Trapped, gargoyle awakes
0x11 17 Generic Spirit blade
0x12 18 Chest 200 coins
0x13 19 2 Chests 200 coins x2
0x14 20 Chest 300 coins
0x15 21 Chest 100 coins + potion of healing
0x16 22 Chest Trapped, -1 body point
0x17 23 Chest Trapped, you disarm it
0x18 24 Table Agrain's keys (100 coins)
0x19 25 Chest 200 coins
0x1A 26 Chest 350 coins
0x1B 27 Chest 250 coins
0x1C 28 Throne 500 coins
0x1D 29 Chest Potion of healing
0x1E 30 Generic Mine entrance + 5000 coins, cannot attack (Coins are fake only in the "Castle of Mystery" mission)

For example, in QUEST17.BIN, the (hexadecimal) event contents are the following. Again, 00 bytes have been replaced by "--" to more clearly show the data.

Room ID:  00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A
Treasure  -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 15 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 16 -- -- -- -- -- -- -- -- --
Traps     -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 17 -- -- -- -- -- -- -- -- --

Population

The population block, starting at 0x462, takes up the rest of the file. It has a header that specifies for each section where the data can be found. All pointers in this section are relative to the start of the population block.

Offset Data type Block Name Description & Notes
0x00 UINT16LE TextBlockStart Relative pointer to where the Quest Text Block starts. This is normally put at the end of the file.
0x02 UINT16LE TextBlockSize Size of the text block.
0x04 UINT16LE MonstersBlockStart Relative pointer to the Monsters Block. Each block is 10 bytes. This is normally put directly behind this header, at offset 0C.
0x06 UINT16LE MonstersBlockSize Size of the Monsters block. Divide by 10 to get the amount of monsters.
0x08 UINT16LE ObjectsBlockStart Relative pointer to the Objects Block.
0x0A UINT16LE NrOfObjects Number of objects in the Objects Block.

After this come the sections, normally in the following order:

  • Monsters Block
  • Objects block
  • Quest Text Block
  • A padding byte. This is sometimes two bytes. Might be needed to serve as end of the last text item.

Monsters Block

Typically starts at offset 0x46E. Each monster block takes 10 bytes. The length of the full block is specified in the header in MonstersBlockSize. Divide it by 10 to know the amount of monsters.

Layout

The monster layout is the following:

Offset Data type Description & Notes
00 UINT8 Seems to be a set of bit flags. It apparently needs to be 0x81 to have a properly functioning monster. If it is set to 0x00, the monster does not appear on the map at all. If it is set to just 0x80 or just 0x01, the monster can't be attacked except by spells. Only the Death Mist on Quest 17 uses value 0x01, but its special scripted code means it can not be interacted with at all.
01 UINT8 X position, from 0x00 to 0x19.
02 UINT8 Y position, from 0x00 to 0x12.
03 UINT8 Unknown, seems to mostly be 00.
04 UINT8 Unknown, seems to mostly be 00.
05 UINT8 Unknown, seems to mostly be 00.
06 UINT8 Unknown. Usually 01. Only the Death Mist on Quest 17 has the highest bit of this enabled.
07 UINT8 Unknown. Generally 10, 12, or 13.
08 UINT8 Monster type; see table below.
09 UINT8 Monster type, again. Changing this duplicate value seems to have no effect.

The first monster in the list is used as the "wandering monster" that might show up when you search a room. Its first byte is usually put to 0, so it won't show up on the map and acts purely as wandering monster template. However, it is perfectly possible to have a monster both serve as wandering monster and appear as physical entity on the map.

Monster Types

Original Monsters
Hex ID Dec ID Monster Notes
0x00 00 Goblin
0x01 01 Orc
0x02 02 Fimir
0x03 03 Chaos Warrior
0x04 04 Skeleton
0x05 05 Zombie
0x06 06 Mummy
0x07 07 Gargoyle
0x08 08 Orc Warlord Ulag Uses the Gargoyle graphics
0x09 09 Orc Lord Grak Uses the Orc graphics
0x0A 10 Balur the Fire Mage Uses the Gargoyle graphics
0x0B 11 Stone Chaos Warrior Uses the Gargoyle graphics
0x0C 12 The Witch Lord Uses the Gargoyle graphics
Dummy Monsters

The next range, which are the indices between the original game's monsters and the expansion's monsters, seems to be filled with dummy / junk data. Despite their name, they all show up as Gargoyle.

Hex ID Dec ID Monster Notes
0x0D 13 The Witch Lord
0x0E 14 Goblin
0x0F 15 Orc
0x10 16 Fimir
0x11 17 Chaos Warrior
0x12 18 Chaos Warrior
0x13 19 Zombie Defeating this in Quest 1 gave the message that it dropped the Star of the West.
Expansion Monsters

Then follow the expansion pack monsters.

Hex ID Dec ID Monster Notes
0x14 20 Spirit Rider Uses the Gargoyle graphics
0x15 21 Death Mist Has no graphics, can be passed through, and does not show up on the minimap. Only seems to work on Quest 17, even when its data is configured identical to Quest 17.
0x16 22 Bellthor Uses the Gargoyle graphics
0x17 23 Skulmar Uses the Gargoyle graphics
0x18 24 Doomguard Uses the Gargoyle graphics
0x19 25 Witch Kessandria Uses the Gargoyle graphics
0x1A 26 The Witch Lord Specific expansion version, probably with different stats. Uses the Gargoyle graphics

Going beyond this first gives a monster which identifies as "Orc", and even higher values produce junk monsters with strange names (e.g. those of spells) which tend to crash the game when attacked or when defeated. It is unknown whether the Orc is an actual dummy entry like the ones in between, or if it is already junk data that coincidentally references the Orc's name.

Objects Block

Each object block takes 3 bytes. The length of the list of objects is specified in the header in NrOfObjects. The full block length is NrOfObjects * 3.

The object layout is the following:

Offset Data type Description & Notes
00 UINT8 X position, from 0x00 to 0x19.
01 UINT8 Y position, from 0x00 to 0x12.
02 UINT8 Object type; see table below.

Objects appear to be stored in order of their ID, though it is unknown if this is a requirement.

Multi-cell objects are made up of a defining indicator on the north-west origin-cell of the object, and filler objects on the other cells. These fillers are technically invisible objects, but they are important to ensure the entire object is considered impassable by the game. Each type has its own filler type; e.g. the tables in both directions both use the "table filler block". It is important to use the correct type, since this determines the name that shows up when holding your mouse over these cells on the minimap. For example, Quest 5 has an Alchemy Table with Fireplace filler blocks, and the minimap will indeed show the wrong name on all tiles except the top left one.

The Stairs that indicate the end (and sometimes start) of the Quest map are a special case in this; each of the cells is specifically defined.

Here is the full list of known object types. Types indicated with (*) are unused in the game levels, but might exist in-game for other reasons (e.g. sprung traps).

IDs outside the range indicated in this list usually spawn bugged monsters which won't move or attack, and can't be attacked with normal weapons because they are always deemed "out of range".

Hex ID Dec ID Object
30 48 Rock
31 49 Rock(*)
32 50 Pit Trap - Hidden
33 51 Pit Trap - Opened(*)
34 52 Falling Rock Trap
35 53 ?
36 54 Spear Trap
37 55 Teleport
38 56 Stairs Block 1 (NW)
39 57 Stairs Block 2 (SW)
3A 58 Stairs Block 3 (NE)
3B 59 Stairs Block 4 (SE)
3C 60 ?
3D 61 ?
3E 62 ?
3F 63 ?
40 64 ?
41 65 ?
42 66 Table (Filler)
43 67 ?
44 68 Torture Table (Filler)
45 69 Tomb (Filler)
46 70 Alchemy Table (Filler)
47 71 Fireplace (Filler)
48 72 Closet (Filler)
49 73 Library (Filler)
4A 74 Armour Rack (Filler)
4B 75 Table 2x3 (Origin)
4C 76 Table 3x2 (Origin)
4D 77 Torture 3x2 (Origin)
4E 78 Torture 2x3 (Origin)
4F 79 Alchemy 2x3 (Origin)
50 80 Alchemy 3x2 (Origin)
51 81 ?
52 82 ?
53 83 Tomb 3x2 (Origin)
54 84 Closet 1x3 (Origin)
55 85 Armour Rack 3x1 (Origin)
56 86 Library 1x3 (Origin)
57 87 Fireplace 3x1 (Origin)
58 88 Library 3x1 (Origin)
59 89 Fireplace 1x3 (Origin)
5A 90 Closet 3x1 (Origin)
5B 91 Armour Rack 1x3 (Origin)
5C 92 Chest (South)
5D 93 Chest (East)
5E 94 Throne (South)
5F 95 Throne (East)

Quest Text Block

This block contains the briefing at the start of the Quest. Its X and Y positions are offsets on the scroll on which the text is shown.

The full block consists of any number of text chunks, without any bytes in between the chunks. The 00 byte behind the last text chunk seems to serve as end point. If this 00 byte is not present, the game will ignore the length set in the header and will keep on reading and interpreting text entries. The 00 byte is not included in the text block length in the header.

Each text chunk contained in this block is preceded by a small header consisting of an entry separator value and the X and Y coordinates.

Offset Data type Description & Notes
UINT8 Separator Always 0x11. Is probably used to detect where the previous entry ends.
UINT8 Y position Y position in the scroll's matrix offsets; effectively the line number.
UINT8 X position X position in the scroll's matrix offsets, to nicely center the text.

This header is immediately followed by the text.