King's Bounty Map Format

From ModdingWiki
Jump to navigation Jump to search
King's Bounty Map Format
King's Bounty Map Format.png
Format typeMap/level
Map type2D tile-based
Layer countUnknown
Games

This format is used to store the world map for King's Bounty in both it's initial state (LAND.ORG file) and in modified, randomized state (in the *.DAT save files at offset 0xFC5). Consequently, there are minor format differences, described below.

File format

The map always takes exactly 16384 bytes. As there are 4 continents 64 x 64 tiles each, and each tile takes 1 byte, all continents start at a convenient offset - 0x0000, 0x1000, 0x2000 or 0x3000.

Data type Description
BYTE map[4][64][64] Map data

Coordinates

The game is consistent with it's map coordinate system, which goes in the bottom-to-top, left-to-right order. That means top left corner has coordinate X=0, Y=63.

Salting

When a new game is first created, the initial map data is read and then the following values are replaced:

0xFF - continent start           -> 0x20 - sea tile
0x8B - put something random here -> 0x8B - 0x93 , but not 0x90
0x8E - archmage's alcove         -> 0x00 (for mages) / 0x8E (for rest)

Note, that the 0x8B index is used in both initial and salted data with different meanings - it stands for random object in LAND.ORG, and a treasure chest in the save files.

Tileset

The tileset is kept inside the tileseta.* and tilesetb.* graphic files. Each file contains 36 tiles, making 72 in total. Additionally, tilesalt.* contains replacements graphics for tiles 0x11-0x13 for continents 2-4. Each level byte with it's most significant bit cleared maps directly into that range (0x00-0x47). The high bit signifies if the tile is interactive, and those high-bit versions are always used instead of the regular indexes:

0x80 - magic barrier (blocks followers)
0x85 - castle gate
0x8A - town
0x8B - treasure chest
0x8C - plains dwelling
0x8D - forest dwelling
0x8E - cave dwelling (multiple purposes)
0x8F - dungeon dwelling
0x90 - sign
0x91 - follower
0x92 - artifact 1
0x93 - artifact 2

Constant Locations

Those locations are hard-coded into the game and can not be changed from within the map:

X=11 Y=7  - King's Castle
X=11 Y=6  - Retreat location
X=11 Y=5  - Starting Location
X=11 Y=3  - Continent 1 starting location
X=1  Y=37 - Continent 2 starting location
X=14 Y=62 - Continent 3 starting location
X=9  Y=1  - Continent 4 starting location
X=11 Y=19 - Archmage's Alcove

The king's castle coordinates are the last extra element of the castle location table.

Constraints

Remember that while it's possible to place any combination of the tiles on the map, not all of those combinations will be consistent:

  1. Town square and castle gate locations need to be placed in the game's lookup tables to be interactive.
  2. If a desert tile is placed near the ocean tile, it's possible to pull the boat onto the beach and row it across the desert. Each step still takes a day. If this is not a desired effect, separate the desert from the sea with any other terrain (typically, road).
  3. Of terrain tiles, only the road tile (0x0) can "seamlessly neighbor" both its own and all other terrains. Other terrain types (sea, desert, mountains and woods) have a "solid" tile (0x20 for the sea, 0x2d for the woods, 0x3a for the desert and 0x47 for the mountains) that can only neighbor its own terrain and 12 border tiles.

The following code example creates the tile code correction table for border tiles. The correction is added to the code of the respective solid tile:

       constexpr int lb = 1, rb = 2, lt = 4, rt = 8;
       cor_sea.resize(0x10, 0); // all 16 combinations, though only 13 are supported
       cor_sea[lt | rt] = -1; // ▀
       cor_sea[lb | rb] = -2; // ▄
       cor_sea[rt | rb] = -3; // ▐
       cor_sea[lt | lb] = -4; // ▌
       cor_sea[rt | rb | lb] = -5; // ▟
       cor_sea[lt | rt | rb] = -6; // ▜
       cor_sea[rb | lb | lt] = -7; // ▙
       cor_sea[rt | lt | lb] = -8; // ▛
       cor_sea[lt] = -9;  // ▘
       cor_sea[lb] = -12; // ▖
       cor_sea[rt] = -10; // ▝
       cor_sea[rb] = -11; // ▗
       cor_for = cor_sea; // sea tiles have a special ordering
       cor_for[lb] = -10; // ▖
       cor_for[rt] = -11; // ▝
       cor_for[rb] = -12; // ▗
       cor_snd = cor_mnt = cor_for; // sands, mountains, and forest follow a common order

Generally, every tile of a special terrain (sands, mountains, woods or sea) must be a part of at least one 2x2 patch of the same terrain — i.e., e.g., an isolated 1x1 patch of desert can't be displayed correctly. In addition, diagonal combinations (e.g. a sea tile that's neighboring a sea — i.e. is a part of a 2x2 sea square — to the northeast and southwest, but not to the northwest and southeast, *and has to be a part of both*[1]) can't be displayed correctly, either. E.g. consider the following screen:

sea1 sea1 land
sea1 sea* sea2
land sea2 sea2

The sea* tile can be a part of either the 2x2 sea1 patch or the 2x2 sea2 patch. If sea1 is a part of a greater ocean, then sea1 tiles can be displayed as its border tiles and sea* form a block with sea2 (ditto if sea2 is a larger sea). If the sea tiles on the screen show a complete lake, there is no way to take the central tile out of either part of the lake without breaking the 2x2 rule.

With narrow diagonal straits the limitation can be mitigated by displaying one of the corners cut off; it looks less crappy than displaying a solid tile (e.g. the sea* tile above can have either a northeast or a southwest land corner, but not both). With forest tiles, ignoring inconsistent bottom corners produces slightly better looks than ignoring the top ones. Ideally, however, your generator and/or map editor should not allow graphically inconsistent tiles to border each other.

Note that while original maps don't have narrow forest/mountain passages that only allow a diagonal move, such passages are possible. Followers know how to navigate them, and do.

There is no practical limit on treasure chests ("loot boxes"), since what's in them is determined at random when they are open. However, limited numbers of followers and dwellings are allowed per continent, and these limits are smaller than the nominal array dimensions in the save file.

  1. Adjacent tiles of the same terrain can still be displayed as if they belonged to disconnected spans of it — look at the fractured desert between Nyre and Xoctan to see what I mean

Modding

Note that there is no land.org in the 1990 game edition -- to play on a custom map, you have to modify the save file itself, possibly also modifying the lookup tables in KB.EXE.

Credits

Originally devised by the openkb project, with best regards to the modding community. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)

The constraints have been contributed by the Royal Reward project.