This page lists all internal gameplay mechanics and is VERY SPOILERISH. For non-spoiler version, consider reading the [Manual] page instead.
YOU HAVE BEEN WARNED! SPOILERS AHEAD!
The game world consists of large map, separated into 4 isolated continents. The basic layout is predetermined, but it gets "salted" for each new game.
Each continent takes exactly 64 x 64 tiles and is surrounded by water. When player travels between continents, he always enters them at predetermined locations (see below).
A scepter is hidden somewhere on the map. Finding it is winning the game. The location is picked at random, as per "salting".
Coordinates start from the bottom of the screen, so '0,0' is a bottom-left corner. Note, that player is allowed to stand on corner tiles, at which point the missing tiles are depicted as water.
X=27 Y=11 Plains dwelling at continent 0
All towns and castles
max_grass 0 1 2 3 table 644 844 465 600
Table: villains per continent 06 04 04 03
Creatures and their numbers are:
TROOP TYPES (hex) Villain 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Slot 0 00 0B 01 03 02 01 02 09 07 04 04 16 06 08 17 17 18 1 03 02 01 07 02 0D 08 14 0F 05 05 18 10 0A 15 18 18 2 02 02 04 08 08 0E 0A 13 11 0D 0D 0F 16 12 14 12 18 3 00 00 05 11 09 14 12 0A 16 15 15 07 0B 0E 06 0E 17 4 00 00 0F 0C 10 14 0E 01 03 17 17 06 00 18 00 14 15 TROOP NUMBERS (dec) Villain 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Slot 0 50 10 70 30 50 250 100 30 150 500 600 30 300 35 30 50 100 1 20 30 50 20 50 10 20 30 20 100 200 5 40 100 50 10 25 2 25 20 20 10 10 10 20 10 10 30 50 30 20 80 100 200 25 3 30 60 20 2 10 4 15 30 5 10 25 200 100 60 500 250 100 4 25 40 4 6 5 4 15 300 80 6 10 200 700 5 5000 60 100
Each continent has a number of pre-defined dwellings, and generates the
rest randomly.
Predefined dwellings are:
Continent 0 00 01 07 04 03 06 1 0C 05 0B 09 0F 09 2 0D 10 11 13 3 16 15 14 18 17
Note: different continents have different numbers of troops (6, 6, 4, 5).
When this list is exhausted, troop type is randomly picked within those ranges:
Continent 0 0x00 - 0x0e (peasant-knight) 1 0x01 - 0x0e (sprites-knight) 2 0x02 - 0x0e (militia-knight) 3 0x14 - 0x18 (archmag-dragon)
Note: as troop type is returned, and not dwelling type, a conversion must
be performed to figure appropriate map tile.
All dwellings start fully populated.
1. Set spells for all towns to 0xFF 2. Set spell for town[0x15] to 0x07 // huntersville sells bridge! 3. Foreach Spell (except 0x07): A. Pick random Town with spell == 0xFF B. Set spell for that Town = Spell 4. Foreach Town that still sells 0xFF: A. Town.spell = rand(0, 0x0D) // random spell
Dwelling-to-troop table:
Dwelling 0-PLAINS 1-FOREST 2-HILL 3-DUNGEON Index 0 00 peasant 01 sprite 07 orc 04 skeleton 1 03 wolf 06 gnome 0c dwarf 05 zombie 2 0b nomad 09 elf 0f ogre 0d ghost 3 10 barbarian 11 troll 16 giant 15 vampire 4 14 archmage 13 druid 18 dragon 17 demon
When generating armies, a "difficulty curve" is used. It determines
the chances to get higher order troop for a given dwelling.
Difficulty ranges from 0 to 3.
Castles have their own preset difficulty value (see table in "Castle").
Foes have their value equal to the continent they are on (so, 0-3).
Troop chance table:
Difficulty 0 1 2 3 Index 0 3C 14 0A 03 1 5A 46 14 06 2 62 5F 32 0A 3 65 63 5A 28
Note: for difficulty 3
, it's very easy to get index "4", as 1d100 will likely roll something > 0x28, however, for difficulty 0
, it is impossible, as 1d100 can never roll anything > 0x65.
Troop numbers table:
Difficulty 0 1 2 3 Troop Peasants 0A 14 32 64 Sprites 14 32 64 7F Militia 0A 14 32 64 Wolves 05 0F 1E 50 Skeletons 05 0A 19 32 Zombies 05 0A 19 4B Gnomes 0A 19 32 64 Orcs 05 0F 1E 50 Archers 00 00 00 00 Elves 05 0A 19 32 Pikemen 00 00 00 00 Nomads 04 08 0F 1E Dwarves 04 0A 14 32 Ghosts 02 04 0A 14 Knights 00 00 00 00 Ogres 02 04 08 0F Barbarians 02 04 0A 14 Trolls 02 04 08 0F Cavalry 00 00 00 00 Druids 01 03 06 0A Archmages 01 02 04 08 Vampires 02 04 0A 19 Giants 01 02 05 0A Demons 01 02 04 08 Dragons 01 01 01 02
1. Each castle has it's own difficulty (see table in "Castle") from 0 to 3. 2. All 5 slots are populated. 3. First, dwelling type is picked (0-3). 4. Then, chance is rolled (1d100). 5. Following the chance table, while `chance` > value, increase index. 6. Pick troop type based on dwelling type and chosen index (see dwelling-to-troop table above). 7. Troop numbers are picked from the "troop numbers table" (see above). A. If picked number is 0x01, use rand(1, number) + rand(1, number) instead (always 2!).
1. Difficulty = continent this foe is on (0-3) 2. 3 slots are populated. 3. Dwelling = rand(0, 3) 4. Chance = rand(1, 100) // roll 1d100 5. Index = lowest row from the "chance table" with value <= Chance 6. Pick troop type based on Dwelling type and Index (see "dwelling-to-troop" table above). A. If troop type was already picked in previous slots, re-run step 3. 7. Pick troop number from the "troop numbers table" (see above). A. If picked number is 0x01, use rand(1, number) + rand(1, number) instead (always 2!).
In both DOS versions (and probably all else, verify!), the orb for the first continent could never be found. This happens due to a bug in nav map salting, where the algorithm goes something like:
if (continent != 03) { map[continent].x = x } map[continent].y = y //code probably lacked braces, that make this clear //or indentation?
Instead of silently ignoring last continent (what should happen), the out-of-bound array write is performed, and next memory-adjacent array (the orbs!) gets overwritten.
Specifically, the Y value for Orb 0 becomes incorrect. Thus, Orb 0 could never be found.
A major portion of gameplay revolves around armies. Player has an army, foes have armies, castles have garrisons. Armies mostly come in three flavors - small (3 troops each), medium (4 troops each) and large (5 troops each). An army is a simple list of troop types and their counts.
Player is not allowed to have multiple stacks of the same troop type; neither empty slots - dismissing a troop, garrisoning, or losing a troop reorders the army. Foes, villains and monsters can have reoccurring troops however, and often abuse that to their favor.
Player always has some kind of army. Losing last troop sends player back to the home castle (to the tile just below the gate), where some default troops (20 peasants) are added for free. This event is known as "defeat".
Each troop type has the following values:
Skill Level (SL)
Movement Rate (MV)
Hit points (HP)
Melee Damage (minMelee, maxMelee)
Ranged Damage (minRanged, maxRanged)
Ammo (MaxAmmo)
Recruitment cost (RCost)
Weekly cost (WCost)
Maximum Population (MaxPop) -- in dwellings
Growth -- ammount to add to foes and unowned castles at the lucky week
Spoils Factor (Spoils) -- used to calculate spoils of war
Morale Group
Special Ability
Some values are not displayed in the game or the manual.
TROOP SPOILS GROWTH MAXPOP Peasants 1 6 250 Sprites 1 6 200 Militia 5 5 0 Wolfs 4 5 150 Skeletons 4 5 150 Zombies 5 5 100 Gnomes 6 5 250 Orcs 7 5 200 Archers 25 5 0 Elfs 20 4 100 Pikemen 30 4 0 Nomads 30 4 150 Dwarves 30 4 100 Ghosts 40 3 25 Knights 100 3 0 Ogres 75 3 200 Barbarians 75 3 100 Trolls 100 3 25 Cavalery 80 2 0 Druids 70 2 25 Archmages 120 2 25 Vampires 150 2 50 Giants 200 2 50 Demons 300 1 25 Dragons 500 1 25
Each step on a grassy tile takes one turn. A step on a desert tile ends the day.
Every 40 turns, a day passes, and every 5 days, a week comes to an end. See 'End Of Week' for details.
When on a boat, travel between continents is possible. This also ends the week.
Player's score can be calculated at any given moment by
score = ((villains caught * 500) + (artifacts found * 250) + (castles garrisoned * 100) - (followers killed * 1)) * difficulty_modifier
Where difficulty factors for Easy, Normal, Hard and Impossible are 0.5, 1, 2 and 4.
Each continent has a number of 'random treasure' tiles, which are filled with random treasures during world "salting".
Artifacts have hard-coded bonuses, described sketchily in the [Manual]. There are 2 artifacts per continent. Artifacts have their own tiles, and do not look like chests.
Ring of Heroism: absolutely no idea
Articles of Nobility: when picked up, player instantly gains +2000 commission
Shield of Protection: -25% base damage taken from enemy
Anchor of Admiralty: changes weekly cost of boat from 500 to 100 (and initial rental of boat as well)
Book of Necros: when picked up, spell capacity is multiplied x 2; when gaining max spells, points are multiplied x 2
Crown of Command: when picked up, base leadership is multiplied x 2, and leadership is reset; when gaining leadership, points are multiplied x 2
Amulet of Augmentation: when picked up, player instantly gains +5 spell power
Sword of Prowess: +50% base damage inflicted on enemy
Mystery of the Heroism Ring
Some manuals say "it gives more leadership". Well, it doesn't.
Some manuals say "it increases the odds" in fighting. As far as damage goes, nope.
Some manuals say "it increases luck". What luck?
A navigational map allows the player to travel to the next continent. Each continent (except the last one) has 1 map hidden within, placed there during world "salting". Map to the first continent is received for free upon game start, so players are always able to sail back home. Navigational Maps use the chest tile.
An orb allows you to view an entire mini-map. There is 1 orb per continent, placed on "salting". Orbs use the chest tile.
Due to a bug in "salting", player can never find orb on the first continent.
A treasure chest containing a random bonus. The event is rolled when it is being picked up, so it is possible to cheat around it using save-scumming. The possible events are:
Randomization algorithm works as follows:
1. Get random value (0x01 - 0x64) //roll 1d100 2. If randomvalue < gold_chance[continent] A. Points = rand(1, extra_gold_points[continent]) + base_gold_points[continent] B. Gold = Points * 100 C. Leadership = Gold / 50 D. If (player.has_crown) Leadership = Leadership * 2 E. Player chooses Gold or Leadership Player.gold += Gold or Player.leadership += Leadership 3. Else If randomvalue < income_chance[continent] A. Points = rand(1, extra_weekly_points[continent]) + base_weekly_points[continent] B. Player.Comission += Points 4. Else If randomvalue < spell_power_chance[continent] A. Points = 1 B. Player.Spellpower += Points 5. Else If randomvalue < number_of_spells_chance[continent] A. Points = base_number_of_spells[continent] B. If (player.has_necros_book) Points *= 2 C. Player.MaxNumberOfSpells += Points 6. Else If randomvalue < new_spell_chance[continent] A. Points = rand(1, (continent+1)) // continents are 0-based B. Spell Type = rand(0, 13) // there are 14 spells C. Player.spells[Spell Type] += Points 7. Else A. Play music B. Act as if a bonus was taken C. Show empty message box D. This should never happen!
And is bounded to those hard-coded tables:
Event GOLD COMMISSION SPELL_POWER MAX_SPELLS EXTRA_SPELLS Continent 0 0x3d 0x51 0x00 0x56 0x65 1 0x42 0x56 0x57 0x5c 0x65 2 0x4c 0x56 0x58 0x5d 0x65 3 0x47 0x51 0x56 0x5b 0x65
As you can see, step 7 never takes place, because EXTRA_SPELLS are always greater
than 0x64. However, the algorithm itself supports such behavior and can enter step 7,
if the tables are different.
RND Values BASE_GOLD EXTRA_GOLD BASE_INCOME EXTRA_INCOME MAX_SPELLS Continent 0 0x00 0x05 0x09 0x0029 0x01 1 0x04 0x10 0x31 0x0033 0x01 2 0x09 0x15 0x63 0x0065 0x02 3 0x13 0x1F 0xC7 0x012d 0x02
Note, that BASE_ and EXTRA_ should not be treated as MIN_ and MAX_, it's actually
" rand(1, EXTRA_) + BASE_ ", as per algorithm above.
Each continent has a number of 'friendly foes' that wish to join you instead of fighting.
When player encounters one, a troop type and number are generated, according to "Populating foe" algorithm described in "World Salting" above, and a yes/no prompt is presented. If player's army has no free slots (and non-free slots of same troop type do not count here), than friendly foe vanishes, without giving player a chance to accept it.
In any event the foe is erased from the map.
There are 26 towns, each mapped to a castle, so different towns provide different information regarding castle garrisons.
You can buy a boat in the town, at which point it spawns nearby on the water. Coordinates for such spawns are hard-coded.
TOWN BOAT_X BOAT_Y GATE_X GATE_Y 0x00 0x1e 0x0b 0x1d 0x0b 0x01 0x3b 0x05 0x39 0x04 0x02 0x27 0x32 0x26 0x31 0x03 0x22 0x16 0x23 0x17 0x04 0x04 0x31 0x05 0x31 0x05 0x12 0x2c 0x10 0x2c 0x06 0x0e 0x3c 0x0c 0x3c 0x07 0x0a 0x26 0x09 0x26 0x08 0x0e 0x1a 0x0d 0x1b 0x09 0x3a 0x20 0x39 0x21 0x0A 0x33 0x1b 0x33 0x1d 0x0B 0x3a 0x38 0x39 0x38 0x0C 0x02 0x24 0x03 0x24 0x0D 0x12 0x15 0x10 0x15 0x0E 0x29 0x39 0x28 0x3a 0x0F 0x31 0x0c 0x32 0x0e 0x10 0x3b 0x3c 0x3a 0x3b 0x11 0x38 0x04 0x38 0x05 0x12 0x0a 0x3c 0x09 0x3b 0x13 0x0c 0x07 0x0d 0x08 0x14 0x08 0x03 0x06 0x03 0x15 0x0b 0x03 0x0c 0x04 0x16 0x2f 0x24 0x2f 0x23 0x17 0x32 0x09 0x32 0x08 0x18 0x02 0x09 0x03 0x09 0x19 0x3b 0x30 0x3a 0x2f
There are 26 castles (not counting the Home Castle).
Each castle has a hard-coded difficulty level, that determines what monsters spawn there (see "Castle Population" in "World Salting" above), during salting and at the end of week (if you leave a castle un-garrisoned).
CASTLE | DIFFICULTY | TOWN |
---|---|---|
Azram | 00 | 0x03 |
Basefit | 01 | 0x0E |
Cancomar | 00 | 0x07 |
Duvock | 01 | 0x10 |
Endryx | 02 | 0x0C |
Faxis | 00 | 0x16 |
Goobare | 02 | 0x12 |
Hyppus | 02 | 0x15 |
Irok | 00 | 0x11 |
Jhan | 01 | 0x13 |
Kookamunga | 00 | 0x0D |
Lorsche | 02 | 0x05 |
Mooseweigh | 01 | 0x09 |
Nilslag | 00 | 0x0F |
Ophiraund | 00 | 0x0B |
Portalis | 00 | 0x02 |
Quinderwitch | 01 | 0x08 |
Rythacon | 00 | 0x00 |
Spockana | 03 | 0x06 |
Tylitch | 02 | 0x04 |
Uzare | 03 | 0x01 |
Vutar | 00 | 0x14 |
Wankelforte | 00 | 0x18 |
Xelox | 02 | 0x0A |
Yeneverre | 01 | 0x17 |
Zyzzarzaz | 03 | 0x19 |
When you leave a garrison in the castle, you pay them off in gold one last time (= weekly pay).
Villain and monster castles grow numbers of their troops at the end of week.
At the end of each week a creature is picked at random. Every 4th week is always a week of peasant.
At the week of peasant, all your ghosts permanently turn into peasants.
Player's leadership is reset to base_leadership value.
All non-garrisoned player castles, are re-occupied by monsters, as per "Castle repopulation" in world salting (see above).
All dwellings for the weekly creature are re-populated, meaning their creature count is at maximum (MaxPop) again.
All castles not owned by player and all the foes grow their troop counts for the weekly creature according to the growth value (Growth). This happens after castle repopulation.
There are two types of combat: "field combat" and "castle siege".
During siege, the level layout is predetermined with castle tiles. Player army starts at the bottom of the screen, and garrison stands on the top.
#3124# #.5..# #....# #534.# ##12##
For field combat, player army starts on the left and foe army stands to the right.
Some obstacles are randomly generated in between.
1....1 2....2 3....3 4....4 5....5
The algorithm for obstacle generation is unknown, but ANY approximation will look good.
A unit is an in-combat representation of a troop, spotting some additional properties:
* Initial Count (can never resurrect more than initial units)
* Damage counter (injury)
* Moves counter (move points spent/left)
* Ammo counter (ranged attacks left)
* Action counter (acted this turn)
* Retaliation flag (retaliated this turn)
* Retaliation Count (retaliate with full numbers even after kills have been made)
* X position on battlefield
* Y position on battlefield
Hit points.
Skill level.
Waiting.
Out-of-control: troop moves on it's own. Can attack both sides.
Frozen: under the effect of the freeze spell. Can't move.
Physical: Comes from Melee and Ranged attacks. Can not be blocked.
Arcane: Comes from magical creatures' Ranged attacks and spells. Immune creatures receive no damage.
Holy: Comes from Turn Undead spell. Non-demonic creatures receive no damage.
assuming each unit has those values: turnC - number in stack, before damage was dealt (used in retaliation,etc) curC - current number in stack maxC - maximum number in stack (==army at the begining of battle) damage could be dealt using: function deal_damage(a_UID, t_UID, is_ranged, is_external, external_damage, retaliation) //a_UID is attacker UID (0-9) //t_UID is target UID (0-9) if (!retaliation) units[a_UID].turnC = units[a_UID].curC units[t_UID].turnC = units[t_UID].curC dont_retaliate = retaliation demon_kills = 0 if (is_external) //magic-vs-unit final_damage = external_damage else //unit-vs-unit if (attacking troop IS demon) if (rand(1,100) > 89) //10% chance demon_kills = ceil(units[t_UID].curC / 2) if (is_ranged) dont_retaliate = 1 units[a_UID].ammo-- if (attacking troop IS druid) if (defending troop IS dragon) cancel attack dmg = 10 if (attacking troop IS archmage) if (defending troop IS dragon) cancel attack dmg = 25 else dmg = rand(minRanged, maxRanged) else dmg = rand(minMelee, maxMelee) total = dmg * units[a_UID].turnC skill_diff = units[a_UID].skill + 5 - units[t_UID].skill final_damage = (total * skill_diff) / 10 if (a_UID < 5) if ( under_control(a_UID) ) final_damage *= morale_modifier(a_UID) //1-norm,0.5-low,1.5-high if (a_UID < 5 && player.has_sword) final_damage *= 1.5f if (t_UID < 5 && player.has_shield) final_damage /= 4 final_damage *= 3 //almost same as multiplying 0.75, but more brutal, as div by 4 can yield 0 final_damage += units[t_UID].injury final_damage += units[t_UID].hp_per_unit * demon_kills kills = units_killed(final_damage, units[t_UID].hp_per_unit) injury = damage_remainder(final_damage, units[t_UID].hp_per_unit) units[t_UID].injury = injury if (kills < units[t_UID].curC) //stack survives units[t_UID].curC -= kills if (t_UID < 5) player_army_count[t_UID] = units[t_UID].curC else //stack dies units[t_UID].dead = 1 units[t_UID].curC = 0 final_damage = units[t_UID].turnC * units[t_UID].hp_per_unit if (t_UID < 5) player_army_troop[t_UID] = FF player_army_count[t_UID] = 0 if (t_UID < 5) player.followers_killed += kills if (!is_external) //undead powers: if (attacking troop IS ghost) units[a_UID].curC += kills if (attacking troop IS vampire) units[a_UID].curC += units_killed(final_damage, units[a_UID].hp_per_unit) if (units[a_UID].curC > units[a_UID].maxC) units[a_UID].curC = units[a_UID].maxC units[a_UID].injury = 0 if (!dont_retaliate) if (!units[t_UID].retaliated) dont_retaliate = 1 units[t_UID].retaliated = 1 deal_damage(t_UID, a_UID, 0, 0, 0, 1) //recursive else if (units[t_UID].dead) units[t_UID].coords = 0xFF
Value is calculated before the battle. Resulting gold is the sum of all troops' (spoils factor, multiplied by 5, multiplied by troop count).
When player wins a battle against a villain, but lacks proper contract, villain escapes to the next random castle not owned by another villain. Castles owned by players and random monsters are fair game. Then, he gains control of whatever army is stationed in that castle.
Thus, it seems villains can get control of EMPTY armies, in case player's empty castle is chosen. TODO: verify this.
After Walk and Fly actions take place, the algorithm is repeated.
After Attacking, Shooting or Waiting, the turn passes on as usual.
For distant targets, shooting units are picked. If there are no shooting units, units with minimum troop hp are picked.
For close targets, units with minimum troop hp are picked.
Neither check involves troop stack count, i.e. Peasants are always picked first, because
they have 1 HP. Even if there are 200 in the stack.
Note: this is rather disappointing. I was hoping the AI would have more tricks up it's sleeve.
Units steadily move to their targets. AI never does stupid moves, and if there are no
unoccupied tiles (that would make the Pythagorean distance between it and it's target smaller) around it, it waits.
Similar rules apply to Flying units: closest (to origin), unoccupied, adjacent to target unit tile is picked, and if none are available, AI waits.
10 hit points * spell power + injury
, accurately assigns new injury (clone remainder)25 * spell power
magic damage10 * spell power
magic damage50 * spell power
holy damageQuestions:
10 * spell power
steps, resets to 0 if you move over desert tile(spell_power + 1) * rank_multiplier
of units without paying any gold100 * spell power
till end of weekInstant Army table:
Rank | Knight | Paladin | Sorceress | Barbarian | MULTIPLIER |
---|---|---|---|---|---|
0 | Peasants | Peasants | Sprites | Peasants | 3 |
1 | Militia | Militia | Gnomes | Wolves | 2 |
2 | Archers | Archers | Elves | Orcs | 1 |
3 | Knights | Cavalry | Druids | Ogres | 1 |
In some versions of the game (MD, QFDBS), the overworld adventure happens in real-time. You and your foes move by pixels, and not by tiles; days pass by on their own.
In some version of the game (which?) spells are cast by troops and not heroes. TODO: Explore this.