Dungeons of the Unforgiven Player Character

From ModdingWiki
Jump to navigation Jump to search
Dungeons of the Unforgiven Player Character
Format typeSaved game
Save locationsUnknown
Elements savedPlayer character data
Games

The saved game format for Dungeons of the Unforgiven appears to be a simple dump of the game's internal structures, with a couple of checksum bytes added on, presumably to slow cheaters down a bit. Some of the chunks of data are in a very peculiar order (such as some of the items being in radically different spots of the file), which makes it somewhat annoying to try to directly load into a C struct or similar data structure.

If you're parsing this format, be very mindful of the data types. Signed and unsigned data types, as well as differing field sizes, are used even with related fields. For example, Rings of Protection are stored in an unsigned byte while Potions of Healing are stored in a signed word.

File Layout

Offset (hex) Data type Name Description
0x0000 char[18] playerName The name of the player character (including a null terminator).
0x0012 BYTE[22] unknown ! Unknown.
0x0028 INT8 playerRace The race of the player character.
0x0029 INT8 playerGender The player character's gender (0x00 == male; 0x01 == female)
0x002A INT8 playerClass The player character's class.
0x002B BYTE[6] unknown ! Unknown.
0x0031 INT16LE playerCurrentHP The player character's current hit points.
0x0033 INT16LE playerMaxHP The player character's maximum hit points.
0x0035 Single playerCurrentSP The player character's current spell points.
0x0039 Single playerMaxSP The player character's maximum spell points.
0x003D INT16LE playerHeight The player character's height, divided by 4. (The game multiplies this value by 4 to give the stated number of inches.)
0x003F INT16LE nakedWeight The player's base weight.
0x0041 INT16LE loadedWeight The player's loaded weight (note: this always gets updated by the game).
0x0043 BYTE[62] unknown ! Unknown.
0x0081 BYTE weaponFists Player character has their fists (normally these cannot be dropped).
0x0082 BYTE weaponStick Player character has the stick.
0x0083 BYTE weaponClub Player character has the club.
0x0084 BYTE weaponMace Player character has the mace.
0x0085 BYTE weaponKnife Player character has the knife.
0x0086 BYTE weaponShortSword Player character has the short sword.
0x0087 BYTE weaponLongSword Player character has the long sword.
0x0088 BYTE weaponGreatSword Player character has the great sword.
0x0089 BYTE[5] unknown ! Unknown.
0x008E INT8 levelFists The permanent enchantment level of the fists.
0x008F INT8 levelStick The permanent enchantment level of the stick.
0x0090 INT8 levelClub The permanent enchantment level of the club.
0x0091 INT8 levelMace The permanent enchantment level of the mace.
0x0092 INT8 levelKnife The permanent enchantment level of the knife.
0x0093 INT8 levelShortSword The permanent enchantment level of the short sword.
0x0094 INT8 levelLongSword The permanent enchantment level of the long sword.
0x0095 INT8 levelGreatSword The permanent enchantment level of the great sword.
0x0096 BYTE[5] unknown ! Unknown.
0x009B INT8 equippedWeapon The weapon that the player character currently has equipped. See the Weapon IDs section for valid values.
0x009C BYTE[20] unknown ! Unknown.
0x00B0 BYTE armorSkin Player character has their skin (normally this cannot be dropped).
0x00B1 BYTE armorLeather Player character has leather armor.
0x00B2 BYTE armorChain Player character has chain armor.
0x00B3 BYTE armorScale Player character has scale armor.
0x00B4 BYTE armorBreastPlate Player character has the breast plate.
0x00B5 BYTE armorFieldPlate Player character has field plate.
0x00B6 BYTE armorTitanium Player character has the titanium armor.
0x00B7 BYTE armorSlot8 This "armor" is not implemented in the game and points to garbage data. See the notes below for a little bit more information. ! Figure out exactly what in the executable this is pointing to, as it is technically fully usable.
0x00B8 INT8 levelSkin The permanent enchantment level of the skin.
0x00B9 INT8 levelLeather The permanent enchantment level of the leather armor.
0x00BA INT8 levelChain The permanent enchantment level of the chain armor.
0x00BB INT8 levelScale The permanent enchantment level of the scale armor.
0x00BC INT8 levelBreastPlate The permanent enchantment level of the breast plate.
0x00BD INT8 levelFieldPlate The permanent enchantment level of the field plate.
0x00BE INT8 levelTitanium The permanent enchantment level of the titanium armor.
0x00BF INT8 levelSlot8 The permanent enchantment level of the glitchy armor.
0x00C0 INT8 equippedArmor The armor that the player character currently has equipped. See the Armor IDs section for valid values.
0x00C1 BYTE[156] unknown ! Unknown.
0x015D INT8 orangePotions The number of orange potions in the player's inventory (+6 Strength / -3 Luck)
0x015E INT8 greenPotions The number of green potions in the player's inventory (+6 Intelligence / -3 Agility)
0x015F INT8 bluePotions The number of blue potions in the player's inventory (+6 Wisdom / -3 Constitution)
0x0160 INT8 redPotions The number of red potions in the player's inventory (+6 Constitution / -3 Wisdom)
0x0161 INT8 whitePotions The number of white potions in the player's inventory (+6 Agility / -3 Intelligence)
0x0162 INT8 yellowPotions The number of yellow potions in the player's inventory (+6 Luck / -3 Strength)
0x0163 BYTE[20] unknown ! Unknown.
0x0177 SPELL_LIST spellbook The spells that the player has learned and can cast at any time at the cost of spell power.
0x022B SPELL_LIST scrolls The spells that the player can cast from a scroll.
0x02DF SPELL_LIST wands The spell wands that the player possesses.
0x0393 SPELL_LIST papers The spell papers that the player owns.
0x0447 BYTE[13] unknown ! Unknown.
0x0454 INT32LE rublesInPocket The number of rubles that the player has on hand.
0x0458 INT32LE rublesInBank The number of rubles that the player has in the bank.
0x045C BYTE[8] unknown ! Unknown.
0x0464 INT32LE cultureStock The amount of culture stock that the player owns.
0x0468 INT32LE childrenHelped The number of children that the player helped (at the temple).
0x046C INT32LE magicCrystals The number of magic crystals that the player owns.
0x0470 INT32LE americanDollars The number of American Dollars that the player has.
0x0474 BYTE[816] unknown ! Unknown.
0x07A4 Double experiencePoints The number of experience points that the player has.
0x07AC INT16LE playerLevel The player character's current level.
0x07AE INT16LE playerDirection The direction that the player character is facing (0x00 == north; 0x01 == south; 0x02 == west; 0x03 == east).
0x07B0 INT16LE playerPositionX The X coordinate of the player in the current dungeon floor.
0x07B2 INT16LE playerPositionY The Y coordinate of the player in the current dungeon floor.
0x07B4 INT16LE playerFloor The floor of the dungeon that the player is currently on (0 is the town).
0x07B6 INT16LE playerModule The module that the player is currently playing.
0x07B8 BYTE[18] unknown ! Unknown.
0x07CA UINT8 ringsOfRegeneration The number of rings of regeneration that the player has.
0x07CB BYTE unknown ! Unknown.
0x07CC UINT8 nuclearHandGrenade The number of nuclear hand grenades that the player has.
0x07CD UINT8 stonesOfSeeing The number of stones of seeing that the player has.
0x07CE INT16LE diseaseTimer The number of turns until disease damages constitution (0 or -1 disables the timer).
0x07D0 INT16LE poisonTimer The number of turns until poison damages strength (0 or -1 disables the timer).
0x07D2 UINT8 enchantWeaponLevel The level of the current "Enchant Weapon" preparation spell in effect.
0x07D3 UINT8 enchantArmorLevel The level of the current "Enchant Armor" preparation spell in effect.
0x07D4 UINT8 bodyArmor The number of body armor items that the player has (not related to the gear, listed above).
0x07D5 UINT8 ringOfProtection The number of rings of protection that the player has.
0x07D6 UINT8 antiMagicRing The number of anti-magic rings that the player has.
0x07D7 BYTE feather Spell "Feather" is in effect. 0x01 == the preparation version; 0x64 == "Permanent Feather."
0x07D8 BYTE fastMove Preparation spell "Fast Move" is in effect. Values greater than 0x01 make it permanent despite there being no such permanent spell!
0x07D9 BYTE invisibility Spell "Invisibility" is in effect. 0x01 == the preparation version; 0x64 == "Permanent Invisibility."
0x07DA INT32LE playerAge The current age of the player character.
0x07DE UINT8 preparationStrength Preparation spell "Strength" is in effect. Normally set to 0x05 (yet changing it or any of the following strength/agility spell values to another nonzero value will not change the number of strength/agility points deducted by an inn stay).
0x07DF UINT8 preparationAgility Preparation spell "Agility" is in effect. Normally set to 0x05.
0x07E0 UINT8 superStrength Preparation spell "Super Strength" is in effect. Normally set to 0x0A.
0x07E1 UINT8 superAgility Preparation spell "Super Agility" is in effect. Normally set to 0x0A.
0x07E2 INT16LE battleStrengthTimer The number of turns the battle spell "Strength" remains in effect.
0x07E4 INT16LE battleSpeedTimer The number of turns the battle spell "Speed" remains in effect.
0x07E6 INT16LE slowMonsterTimer The number of turns the battle spell "Slow Enemies" remains in effect.
0x07E8 UINT8 powerWeaponLevel The level of the current "Power Weapon" battle spell in effect.
0x07E9 INT16LE powerWeaponTimer The number of turns the current "Power Weapon" battle spell remains in effect. If this is set to zero or negative while powerWeaponLevel is nonzero, the spell will never wear off until an inn stay!
0x07EB UINT8 protectLevel The level of the current "Protection" battle spell in effect (0x01 == "Minor Protection;" 0x02 == "Protection;" 0x03 == "Major Protection;" 0x04 == "Ultra Protection").
0x07EC INT16LE protectTimer The number of turns the current "Protection" battle spell remains in effect. If this is set to zero or negative while protectLevel is nonzero, the spell will never wear off until an inn stay!
0x07EE INT16LE resistPoisonTimer The number of turns the battle spell "Resist Poison" remains in effect.
0x07F0 INT16LE resistDiseaseTimer The number of turns the battle spell "Resist Disease" remains in effect.
0x07F2 INT16LE antiColdTimer The number of turns the battle spell "Anti-Cold" remains in effect.
0x07F4 INT16LE antiFireTimer The number of turns the battle spell "Anti-Fire" remains in effect.
0x07F6 INT16LE resistDrainTimer The number of turns the battle spell "Resist Level Drain" remains in effect.
0x07F8 INT16LE stopMonsterTimer The number of turns the battle spell "Sleep" could remain in effect (though it often wears off much earlier due to the vagaries of the spell).
0x07FA INT16LE holdMonsterTimer The number of turns the battle spell "Hold Monster" remains in effect.
0x07FC BYTE[6] unknown ! Unknown.
0x0802 INT8 floorSloshers The number of floor sloshers that the player has.
0x0803 BYTE[15] unknown ! Unknown.
0x0812 INT16LE potionsOfHealing The number of potions of healing that the player has.
0x0814 INT16LE stonesOfTeleportation The number of stones of teleportation that the player has.
0x0816 INT16LE playerStrength The number of strength points that the player has.
0x0818 INT16LE playerIntelligence The number of intelligence points that the player has.
0x081A INT16LE playerWisdom The number of wisdom points that the player has.
0x081C INT16LE playerConstitution The number of constitution points that the player has.
0x081E INT16LE playerAgility The number of agility points that the player has.
0x0820 INT16LE playerLuck The number of luck points that the player has.
0x0822 BYTE[21] trapDoorKey The trapdoor keys owned by the player. For each nonzero value in trapDoorKey[n], the player is able to use any trapdoors leading to floor (n * 5).
0x0837 BYTE[28] unknown ! Unknown.
0x0853 INT8 gauntlets The number of gauntlets that the player has.
0x0854 BYTE[162] unknown ! Unknown.
0x08F6 BYTE difficulty The difficulty level that the player is playing on. (0x00 == normal; 0x01 == "I can handle anything!")
0x08F7 BYTE[122] unknown ! Unknown.
0x0971 UINT32LE gameTimer This appears to be some sort of hidden in-game timer. ! Figure out when this is incremented and whether or not it actually does anything.
0x0975 BYTE[274] unknown ! Unknown.
0x0A87 UINT8[2] checksum The checksum of the saved game file. See below for more information.

Races

The following races can be chosen:

ID Race
0x00 Humanoid
0x01 Ape
0x02 Childman
0x03 Rodent
0x04 Hobo
0x05 Giant
0x06 Midget
0x07 Shrimp

Classes

The following classes can be chosen:

ID Class
0x00 Fighter
0x01 Worshipper
0x02 Monk
0x03 Wizard
0x04 Priest
0x05 Sage
0x06 Mage

Spells

Spells are stored in the save file per the following table. In all cases, the spells are stored in order from left-to-right, top-to-bottom, with respect to the in-game spell browser. Each spell category has 15 unused bytes at the end; Monks have all these bytes filled with 0x01 in their spellbook section nonetheless.

Data type Name Description
INT8[45] spellsPermanent The permanent spells that the player has access to.
INT8[45] spellsPreparation The preparation spells that the player has access to.
INT8[45] spellsWizard The wizard battle spells that the player has access to.
INT8[45] spellsPriest The priest battle spells that the player has access to.

Weapon IDs

The following weapon IDs can be used in the equippedWeapon field.

ID Weapon Type
0x00 Fists
0x01 Stick
0x02 Club
0x03 Mace
0x04 Knife
0x05 Short Sword
0x06 Long Sword
0x07 Great Sword
  • Note: the player does not have to own the specified weapon type in order to have it equipped. The equipment check is only performed when the player switches their weapon in-game.

Armor IDs

The following weapon IDs can be used in the equippedArmor field.

ID Armor Type
0x00 Skin
0x01 Leather
0x02 Chain
0x03 Scale
0x04 Breast Plate
0x05 Field Plate
0x06 Titanium
0x07 Glitchy Armor*
  • Note: the player does not have to own the specified armor type in order to have it equipped. The equipment check is only performed when the player switches their armor in-game.
  • *The eighth armor slot always appears in the armor list of the game as a blank slot, but only seven armor types appear within the game world. If the set of armor is hacked into the game with a hex editor or memory editor, it appears as jumbled text and provides a currently-unknown amount of protection.

Checksum

The checksum is calculated as follows (example in C# and assuming saveBytes is the saved game data, sans checksum—that is, the first 2695 (0xA87) bytes in the file):

checksum[0] = checksum[1] = 0;
foreach(var b in saveBytes) {
    checksum[0] += b;
    checksum[1] += checksum[0] - checksum[0] * checksum[0];
}

If the checksum is incorrect for the saved game file, the player will be immediately booted back to the DOS prompt with a "corrupted character" error.

Credits

This file format was reverse engineered and documented by Spectere and Bag of Magic Food. 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!)