-
If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.
|
The Adventure Map Data Structure
Page history
last edited
by Kert 5 years, 1 month ago
This wiki article was created largely as an extended answer to someone who asked about the format. It is still very incomplete, with no imminent plans to expand it. Talking to senior Ironfist team members remains the best way to learn more.
Overview
The main data structures in question are fullMap, SMapHeader, mapCell, and mapCellExtra. The raw reverse-engineered versions of the data structures are available in HEROES2W.h and EDITOR2W.h, but prettier versions are available in map.h . Some data structures are slightly different between the editor and the game; the editor's versions have extra data to support deleting.
Key concepts
- You know how in the map editor you can select a whole town or mountain object and place it as one? Well, in the game, there's no such concept of a larger object. All there is a bunch of tiles, each of which act independently. You can take the top-left corner of the Necromancer castle and put it in the middle of the ocean next to the bottom-right corner of a sulfur mine, and you can make it so that the ocean square next to it acts like a Faerie Ring.
- However, the concept of a larger object does exist in the editor, called an "overlay". In the editor, each mapCell and mapCellExtra has extra fields so that, when you delete one tile, it also deletes all other tiles placed at the same time.
-
The data structures make heavy use of bitfields. E.g.: there is a 1-bit field in mapCell declared "unsigned int isShadow : 1;". However, in the raw reverse-engineered data structure, it appears as part of a larger
field_4_1_1_isShadow_1_13_extraInfo field ("1 bit unknown, 1 bit isShadow, 1 bit unknown, 13 bits extraInfo"). All decompiled code that accesses the isShadow field will do so using bitops.
-
The mapCell field contains places to store the info of one object on that cell. However, cells may contain many overlapping objects. A single cell may contain a sulfur mine, the mountain it sits on, a visiting hero, the shadow of an object next to it, and the top part of a tall building on a cell beneath it. To support this, each cell also contains an embedded linked list of "cell extras," which store this information for other objects.
-
Some cells have extra gameplay information associated with them, e.g.: the cell with the entrance to a town is linked to the town object, a sign has text, etc. These are stored in an additional object, confusingly also called an "extra." (Yes, these names were used by the original game developers.) These are stored in the field extraInfo as an offset into the global array ppMapExtra, which contains these Extra objects. You can browse map.h to see a list of the various Extra objects (e.g.: TownExtra, SignExtra).
Information about specific fields
- mapCell->objType contains 8 bits: 7 bits are the location type (enum ADVENTURE_MAP_LOCATION); the 8th bit is "TILE_HAS_EVENT", and is only marked on the interactive tile (e.g.: all squares of a mine may have LOCATION_MINE, but only the flaggable square has LOCATION_MINE | TILE_HAS_EVENT). Note that, since Price of Loyalty features more than 126 distinct location types, several of them are actually stored under "LOCATION_ALCHEMIST_TOWER," with extraInfo used to disambiguate. (These are: Arena, Mermainds, Seer's Hut / Eyes, Sirens, and Stable.) See advManager::GenericSiteEvent for details.
- mapCell->objTileset is a value of enum OBJ_TILESET, which is an index into the gTilesetFiles array.
mapCell/mapCellExtra fields conversion tables
mapCell
mapCell decompiled |
|
mapCell ironfist |
Name |
Size (bits) |
Bit indexes |
|
Name |
Size (bits) |
Bit indexes |
groundIndex |
16 |
1-16 |
|
groundIndex |
16 |
1-16 |
objTileset |
8 |
17-24 |
|
hasObject |
1 |
17 |
objectIndex |
8 |
25-32 |
|
isRoad |
1 |
18 |
extraInfo |
16 |
33-48 |
|
objTileset |
6 |
19-24 |
overlayTileset |
8 |
49-56 |
|
objectIndex |
8 |
25-32 |
overlayIndex |
8 |
57-64 |
|
field_4_1 |
1 |
33 |
displayFlags |
8 |
65-72 |
|
isShadow |
1 |
34 |
objType |
8 |
73-80 |
|
field_4_3 |
1 |
35 |
extraIdx |
16 |
81-96 |
|
extraInfo |
13 |
36-48 |
|
|
|
|
hasOverlay |
1 |
49 |
|
|
|
|
hasLateOverlay |
1 |
50 |
|
|
|
|
overlayTileset |
6 |
51-56 |
|
|
|
|
overlayIndex |
8 |
57-64 |
|
|
|
|
flags |
8 |
65-72 |
|
|
|
|
objType |
8 |
73-80 |
|
|
|
|
extraIdx |
16 |
81-96 |
Conversion table
mapCell decompiled |
mapCell ironfist |
extraInfo & 1 |
field_4_1 |
(extraInfo >> 1) & 1 |
isShadow |
(extraInfo >> 2) & 1 |
field_4_3 |
(extraInfo >> 8) >> -5 |
extraInfo |
objTileset & 1 |
hasObject |
(objTileset >> 2) & 0x3F |
objTileset |
overlayTileset & 1 |
hasOverlay |
(overlayTileset >> 1) & 1 |
hasLateOverlay |
(overlayTileset >> 2) & 0x3F |
overlayTileset |
It's also very important to use casts for these fields
(unsigned char)overlayIndex
(unsigned char)objectIndex
mapCellExtra
mapCellExtra decompiled |
|
mapCellExtra ironfist |
Name |
Size (bits) |
Bit indexes |
|
Name |
Size (bits) |
Bit indexes |
nextIdx |
16 |
1-16 |
|
nextIdx |
16 |
1-16 |
_1_q_7_objTileset |
8 |
17-24 |
|
animatedObject |
1 |
17 |
objectIndex |
8 |
25-32 |
|
objTileset |
7 |
18-24 |
field_4_1_1_1_isShadow_5 |
8 |
33-40 |
|
objectIndex |
8 |
25-32 |
_1_q_1_hasLateOverlay_6_q |
8 |
41-48 |
|
field_4_1 |
1 |
33 |
field_6 |
8 |
49-56 |
|
field_4_2 |
1 |
34 |
|
|
|
|
field_4_3 |
1 |
35 |
|
|
|
|
field_4_4 |
5 |
36-40 |
|
|
|
|
animatedLateOverlay |
1 |
41 |
|
|
|
|
hasLateOverlay |
1 |
42 |
|
|
|
|
tileset |
6 |
43-48 |
|
|
|
|
overlayIndex |
8 |
49-56 |
Conversion table
mapCellExtra decompiled |
mapCellExtra ironfist |
_1_q_7_objTileset & 1 |
animatedObject |
(_1_q_7_objTileset >> 1) & 0x7F |
objTileset |
_1_q_1_hasLateOverlay_6_q & 1 |
animatedLateOverlay |
(_1_q_1_hasLateOverlay_6_q >> 1) & 1 |
hasLateOverlay |
(_1_q_1_hasLateOverlay_6_q >> 2) & 0x3F |
tileset |
field_4_1_1_1_isShadow_5 & 1 |
field_4_1 |
(field_4_1_1_1_isShadow_5 >> 1) & 1 |
field_4_2 |
(field_4_1_1_1_isShadow_5 >> 2) & 1 |
field_4_3 |
The Adventure Map Data Structure
|
Tip: To turn text into a link, highlight the text, then click on a page or file from the list above.
|
|
|
|
|
Comments (0)
You don't have permission to comment on this page.