King's Bounty Index Tables

From ModdingWiki
Jump to navigation Jump to search

As indicated in King's Bounty Saved game Format, some of the values that define King's Bounty's world and mission are hardcoded within the main executable (KB.EXE). Specifically, assuming

constexpr int kAlphabet = 26; // 'Z' - 'A' + 1
constexpr int kAlphaExt = kAlphabet + 1; // extra element at the end is the king's castle

the following index tables exist (sample locations provided):

Offset 1990 Data Type Description
0x183f8 BYTE x[kAlphaExt], y[kAlphaExt] Castle gate locations (27 X values, then 27 Y values)
0x1867d BYTE c[kAlphabet] Continent of the castle (0-3).[1] 26 values (the king's continent is always 0)
0x165cb BYTE c[kAlphabet] An identical copy of the above, with unclear purpose.[2]
0x169d6 BYTE c[kAlphabet] A THIRD identical copy of the above, used e.g. for villain contracts.
0x18481 BYTE x[kAlphabet], y[kAlphabet] Town square coordinates (26 X values, then 26 Y values), *in corresponding castle order*.[3]
0x1852d BYTE x[kAlphabet], y[kAlphabet] Harbor coordinates (where the boat appears); 26 X values, then 26 Y values
0x18649 BYTE x[kAlphabet], y[kAlphabet] "Airport" coordinates (where Town Gate lands the hero); 26 X values, then 26 Y values
0x18697 BYTE m[kAlphabet] town letter -> castle letter mapping for Town Gate (26 indices). E.g. m[0] (town of A-Anomaly) is 0x3 (castle of D-Duvock).

Notes

  1. Used for Castle Gate and for castle entry detection.
  2. Possibly a rudiment of an early design allowing town placement on a different continent from its castle?
  3. The game treats castle-town pairs as, essentially, castle objects with town properties. All town data, except (obviously) for the Town Gate lookup table, are arranged in castle order, i.e. Riverton is #0 because of Azram, Underfoot is #1 because of Basefit, etc. Even the town name strings appear in the file in corresponding castle alphabetical order (Riverton, Underfoot...) instead of their own alphabetical order (Anomaly, Bayview...)

Obviously, all of the offsets apply to the uncompressed file.

The Castle Gate spell always places the hero south of the actual castle gate (the Y coordinate is less by 1).

Stepping on a Castle Gate tile (0x85) that does not correspond to a recognized castle freezes the game.

Stepping on a Town tile (0x8a) that does not correspond to a recognized town immediately returns the hero one step back.

Stepping onto a registered map location (one that's present in the tables) that's not marked by a corresponding interactive tile (town walls or castle gate) on the map does not by itself result in an interaction. In other words, coordinate matching only occurs after tile code matching.

Original geography

The offsets to index tables vary between released game builds. It is, however, possible to locate those tables in the game file by value by using the original castle and town coordinates to build canonical representations of the original index tables and then searching for representative byte sequences.

Modena (the KB modding tool) uses the following castle/town coordinates (the first pair being the castle entry, the second the town square, the first directional vector offset to the "Rent Boat" harbor and the second offset to the Town Gate "airfield"):

       {{30,	27},	{{29,	12},	se,	ss}},
       {{47,	6}, 	{{58,	4},	ne,	ww}},
       {{36,	49},	{{38,	50},	ee,	ss}},
       {{30,	18},	{{34,	23},	ss,	ee}},
       {{11,	46},	{{5,	50},	sw,	ss}},
       {{22,	49},	{{17,	44},	ee,	ww}},
       {{41,	36},	{{13,	60},	ee,	ww}},
       {{43,	27},	{{9,	39},	se,	ss}},
       {{11,	30},	{{14,	27},	ss,	ww}},
       {{41,	34},	{{58,	33},	ss,	ww}},
       {{57,	58},	{{51,	28},	ss,	nn}},
       {{52,	57},	{{57,	57},	se,	ss}},
       {{25,	39},	{{3,	37},	sw,	ss}},
       {{22,	24},	{{17,	21},	ee,	ww}},
       {{6, 	57},	{{41,	58},	ss,	ww}},
       {{58,	23},	{{50,	13},	sw,	nn}},
       {{42,	56},	{{58,	60},	ee,	ss}},
       {{54,	6}, 	{{57,	5},	sw,	ww}},
       {{17,	39},	{{9,	60},	ee,	ss}},
       {{9, 	18},	{{13,	7},	ww,	nn}},
       {{41,	12},	{{7,	3},	ee,	ww}},
       {{40,	5}, 	{{12,	3},	ww,	nn}},
       {{40,	41},	{{46,	35},	ne,	ee}},
       {{45,	6}, 	{{49,	8},	ne,	ee}},
       {{19,	19},	{{3,	8},	nw,	nn}},
       {{46,	43},	{{58,	48},	ee,	ss}},
       {{11,	7},     {}} // Washington, D.C.

...and the following castle/continent breakdown:

C-index Continent Castles Castle initials (for Info)
0 Continentia 11 ACFIKNOPRVW
1 Forestria 6 BDJMQY
2 Archipelia 6 EGHLTX
3 Saharia 3 SUZ
= (total) 26

You can use the ham (name shortened from "Hamming") tool from the Royal Reward project to analyze a binary file. Sample output:

conts: 0x165cb # (hamming=0 confidence=100.00%)
conts: 0x169d6 # (hamming=0 confidence=100.00%)
conts: 0x1867d # (hamming=0 confidence=100.00%)
forts[X]: 0x183f8 # (hamming=0 confidence=100.00%)
forts[Y]: 0x18413 # (hamming=0 confidence=100.00%)
ports[X]: 0x18481 # (hamming=0 confidence=100.00%)
ports[Y]: 0x1849b # (hamming=0 confidence=100.00%)
p_bay[X]: 0x1852d # (hamming=0 confidence=100.00%)
p_bay[Y]: 0x18547 # (hamming=0 confidence=100.00%)
p_air[X]: 0x18649 # (hamming=0 confidence=100.00%)
p_air[Y]: 0x18663 # (hamming=0 confidence=100.00%)
ptofs: 0x18697 # (hamming=0 confidence=100.00%)

The tool has been tested on three different versions of KB.EXE and successfully located all the 6 kinds of lookup tables (4 of them broken down by X and Y) in each.

By editing all the correlated tables simultaneously it is then possible to move the castles and towns both within and across continents. However, placement of a castle and its corresponding town on two different continents has not yet been achieved and is most probably impossible.