Darklands saved game

Files with this format: "saves\dksave*.sav".

This is the main portion of a Darklands saved game file.

Every saved game consists of a pair of files: ".sav" and ".bsv". The ".sav" file contains world and character data. The ".bsv" file contains battle and dungeon data (only for the last dungeon entered and not finished).

Table of Contents

Offsets

from 0x00 to 0xee
from 0xef to 0x188
starting at 0x189

Structures

cache
cache_item
character
event
person_colors
rgb

Offsets

Offset: from 0x00 to 0xee

0x00: curr_location_name: string(12) (null-delimited)
Current party location.
0x0c: unknown (9 bytes)
0x15: save_game_label: string(23) (null-delimited)
Saved game label.
0x2c: unknown (18 bytes) [constant: all 0x00]
0x3e: unknown (55 bytes)
  • The words at 0x43, word at 0x47 are almost constant, but seem to change just before dream.
0x63: unknown (1 bytes) [constant: 0x19]
0x64: city_contents_seed: word
City contents seed.
  • This appears to be a seed for a pseudo-RND used to calculate what saints/formulas/items are available in each location.
0x66: unknown (2 bytes) [constant: 0x07, 0x00]
0x68: curr_date: struct date_reversed (size )
Current date.
0x70: party_money: struct money (size )
Cash on hand.
0x76: unknown (4 bytes) [constant: all 0x00]
0x7a: reputation: word
Global reputation.
0x7c: curr_location: word
Current location.
  • Index into the locations array.
  • Wilderness locations get 0xffff.
0x7e: curr_coords: struct coordinates (size )
Current map coordinates.
0x82: curr_menu: word (enum menu)
Current menu (or screen).
  • This can be thought of as "current in-city location" for most intents and purposes. It defines which menu of options you get.
  • See also prev_menu.
0x84: unknown (6 bytes)
  • First word is always 0, 1, or 2.
0x8a: prev_menu: word (enum menu)
Previous menu (or screen).
  • This is the last menu/screen before the current one; only important in "shared" locations. For example, the "listen to rumors" board is accessible from both the inn and the town square. When you leave it, you return to the correct place, but curr_menu is identical in both cases.
  • Sometimes this value is incorrect; perhaps it's only reliable in shared locations?.
  • See also curr_menu.
0x8c: bank_notes: word
Bank notes (in Florins).
0x8e: unknown (4 bytes)
0x92: philosopher_stone: word
Quality of philosopher's stone.
  • Although a word, this rarely gets higher than 30(?) in real game play.
0x94: unknown (7 bytes)
0x9b: party_order_indices: array[ 5 ] of string(4) (enum image_group)
Party member walking order indices.
  • This is the order party members walk in when walking single-file.
  • 0-based.
  • TODO: For some reason, changing this number while in the mines doesn't change walking order. Probably another copy of this is stored in the corresponding .bsv file, and is used for large battlefields? When do changes take effect?
0xa0: unknown (1 bytes)
0xa1: party_leader_index: byte
Party leader index.
  • 0-based.
0xa2: unknown (3 bytes)
0xa5: unknown (74 bytes) [constant: all 0x00]

Offset: from 0xef to 0x188

0xef: num_curr_characters: word
Number of characters currently in the party.
  • Because this includes NPCs, it can change over the course of the game.
0xf1: num_characters: word
Number of characters defined.
  • This is the number of characters which are available when "swapping characters" (in the inn), plus any NPC (like Hanse or the town leader) currently in the party.
  • Because this includes NPCs, it can change over the course of the game.
0xf3: party_char_indices: array[ 5 ] of word
Party member character indices.
  • Indexes into the arrays of character data for each of the five party slots.
  • 0-based; an empty slot gets 0xffff.
0xfd: party_images: array[ 5 ] of string(4) (enum image_group)
Party member image file.
  • If defined, it will be one of the four 'player' images.
  • The string also corresponds to one of the "pics\???small.pic" files. TODO: where is that image used?
  • The byte pattern {0x00,0x30,0x00,0x30} is used for an empty slot.
0x111: party_colors: array[ 5 ] of struct person_colors (each size 0x18)
Party member colors.
  • The colormap used for the player's image (in battles) for each of the five character slots.

Offset: starting at 0x189

0x189: characters: array[ num_characters ] of struct character (each size 0x22a (554))
Character data.
[next]: num_events: word
Number of events.
  • The file offset for this depends on number of characters defined: for 4 characters, it's 0xa31; 5=0xc5b; 8=0x12d9; 9=0x1503.
[next]: events: array[ num_events ] of struct event (each size 0x30 (48))
Event data.
  • Events include: all quests (Raubritter and "find the X") and the expiration of saint effects.
  • Events probably also include: endgame quests; the dream; maybe also wilderness encounters.
  • A new game starts with 4-9 events already defined.
[next]: num_locations: word = 0x19e
Number of map locations.
[next]: locations: array[ num_locations ] of struct location (each size )
Map location data.
  • Map location data includes cities, villages, castles, dungeons, etc; anything that can be found on the map.
  • Most -- but not all -- of this data is a straight copy from darkland.loc. Some data (local reputation, cache index, destroyed sites) changes over the course of the game.
  • The coordinates of Marienburg differ just slightly between here and darkland.loc; it seems like the city was located off the edge of the map, and some executable patch moves it back on when creating a new game.
[next]: max_cache_slot: byte [constant: 0x63]
  • This seems to be a "warning value"; there are actually 0x62 entries in cache_offsets.
[next]: num_caches: byte
Number of current item caches.
[next]: cache_offsets: array[ 0x62 ] of word
Local offset to cache data.
  • The offsets are relative to max_cache_slot.
  • 0x62 offsets should suffice, as there are only 0x5c cities with inns -- but these slots are never reused (see the notes below). Inserting a 0x63rd entry would clearly be extremely bad!
  • Only num_caches of these are actually used; remaining slots are all zero.
[next]: caches: array[ num_caches ] of struct cache (each size varies)
Item caches.
  • These are items that you "stored with the innkeeper" in cities.
  • This structure is often corrupted. If you cache items at an inn, then remove the items, the offset cache_offsets remains (and num_caches stays the same). Returning to recache items sometimes causes an overflow, causing this "array" to become 64k larger, full of random memory contents! Needless to say, you probably lose your items then.

Structures

Structure: rgb

Size 0x03.

A color value (RGB triplet).

0x00: red: byte
0x01: green: byte
0x02: blue: byte

Structure: person_colors

Size 0x18.

A set of colors for a person (battle mode).

0x00: first_hi: struct rgb (size 0x03)
Color 1: bright shade.
0x03: first_lo: struct rgb (size 0x03)
Color 1: dark shade.
0x06: second_hi: struct rgb (size 0x03)
Color 2: bright shade.
0x09: second_med: struct rgb (size 0x03)
Color 2: medium shade.
0x0c: second_lo: struct rgb (size 0x03)
Color 2: dark shade.
0x0f: third_hi: struct rgb (size 0x03)
Color 3: bright shade.
0x12: third_med: struct rgb (size 0x03)
Color 3: medium shade.
0x15: third_lo: struct rgb (size 0x03)
Color 3: dark shade.

Structure: character

Size 0x22a (554).

A character (and all their belongings).

0x00: unknown (17 bytes)
0x12: age: word
Age.
  • A character's birthday is dependent on their party order (not marching order). The first character is January 1st, the second February, etc.
  • Note that the birthday effects can be exploited (by swapping characters at inns) so that some characters never age -- although since age after initial training has no deleterious effects, there's no reason to do so. It would also cost 40-50% of your on-hand gold for each swap.
0x14: unknown (1 bytes)
0x15: shield: char
Heraldic shield.
  • Ranges from 'A' to 'O'.
  • This corresponds to one of the "pics\shield?.pic" files.
  • TODO: is this a null-delimited string or just a char?
0x16: unknown (12 bytes)
0x22: equip_missile_type: byte
Item type of the currently equipped missile device.
  • This is the first of ten bytes (scattered through this structure) which indicate what a character currently has equipped.
  • Instead of offsets into the items array, the item type and quality are stored. The game does not seem to enforce that you must own the item.
0x23: unknown (2 bytes)
0x25: full_name: string(25)
Full name.
0x3e: short_name: string(11) (null-delimited)
Nickname.
  • Possibly longer or shorter, but seems to be 10 characters and a null.
0x49: unknown (2 bytes)
0x4b: equip_vital_type: byte
Item type of the currently equipped vital armor.
0x4c: equip_leg_type: byte
Item type of the currently equipped leg armor.
0x4d: unknown (2 bytes)
0x4f: equip_vital_q: byte
Quality of the currently equipped vital armor.
0x50: equip_leg_q: byte
Quality of the currently equipped leg armor.
0x51: equip_weapon_type: byte
Item type of the currently equipped weapon.
0x52: unknown (6 bytes)
0x58: equip_weapon_q: byte
Quality of the currently equipped weapon.
0x59: unknown (1 bytes)
0x5a: equip_missile_q: byte
Quality of the currently equipped missile device.
0x5b: equip_shield_q: byte
Quality of the currently equipped shield.
0x5c: equip_shield_type: byte
Item type of the currently equipped shield.
0x5d: curr_attrs: struct attribute_set (size )
Current attributes.
  • If a saint is invoked or a potion is quaffed, any resulting changes to attributes are directly reflected here; events are added (for the near future) which then alter the attribute back to normal.
0x64: max_attrs: struct attribute_set (size )
Maximum attributes (aside from temporary increases).
0x6b: skills: struct skill_set (size )
Skills.
  • As with attributes, if a saint is invoked or a potion is quaffed, any resulting changes to skills are directly reflected here; events are added (for the near future) which then alter the skill back to normal.
0x7e: num_items: word
Number of items carried.
0x80: saints_known: array[ 160 bits ] of bit
Knowledge of saints.
  • The array spans 20 bytes, 160 bits.
  • The bit offset into this array corresponds to the the offset of the saint in the array saint_full_names (found in darkland.lst).
  • Fewer than 160 saints are actually defined; it is unknown what happens if bits past the actual number of saints are turned on.
  • Bit is on if saint is known
0x94: formulae_known: array[ 22 ] of bitmask[1]
Knowledge of alchemical formulae.
  • Byte offset into the array corresponds to the offset of the type of formula (fleadust, essence'o'grace, etc) in the array formula_full_names (found in darkland.lst).
  • It is unknown what happens if any of the first five bits are turned on; probably nothing, though.
bit 1: [constant: 0]
bit 2: [constant: 0]
bit 3: [constant: 0]
bit 4: [constant: 0]
bit 5: [constant: 0]
bit 6: q45: Knowledge of q45 formula.
bit 7: q35: Knowledge of q35 formula.
bit 8: q25: Knowledge of q25 formula.
0xaa: items: array[ 64 ] of struct item (each size )
  • Only num_items of the 64 items are populated; the rest are all 0x00.

Structure: event

Size 0x30 (48).

An event, effect, or quest.

0x00: unknown word
  • For RB quests, when first given this value is sort of the name of the person who gave it to you. After killing the RB the value moves to offset 0x1e, and this gets a copy of the value from 0x1a.
0x02: create_date: struct date (size )
Date the event was created.
0x0a: unknown struct date (size )
0x12: expire_date: struct date (size )
Date the event will expire.
  • TODO: for effects, is this the date it happens instead??
0x1a: unknown word
  • For quests, this is the location where the quest was given, until the reward is taken; then it becomes -2.
  • For other things this is usually -2, although occasionally it is 0.
  • TODO: make this an enum.
0x1c: unknown word
  • For newly given RB quests, this is the location of the RB. Once the RB is slain it becomes the location of the city to return to.
0x1e: unknown word
  • For newly given RB quests, this is the location of the city that gave the quest.
  • Once the RB quest reward is taken, this becomes 0.
0x21: unknown word
  • Common values are 0x63, 0x5f, 0x32, and 0, although others appear sporadically.
0x23: unknown word
  • Maybe this is a sort of state variable?
  • For RB quests the sequence is: 0x8 (got quest), 0x24 (killed RB), 0x7 (got reward).
0x25: unknown word
  • This and the next five are usually, but not always, zero.
0x27: unknown word
0x29: unknown word
  • For RB quests this is often 0x03; it becomes 0 after the reward is taken, and no reward can be gotten if it is not 3.
  • Possibly (for quests, at least) this is the index of the option to 'enable' within the card? The 'ask X for your reward' option is the 3rd option on the screen...
  • TODO: this could maybe be tested by (carefully) altering the card and the index...? Unless the logic is in the executable.
0x2a: unknown word
0x2c: unknown word
0x2e: unknown word
  • This is usually the item code for an item required by a quest.
  • Codes are a reference to offsets into the item_definitions array (found in darkland.lst).
  • However, I've seen an event appear where this is non-zero and an item quest has not just been taken.

Structure: cache

Size varies.

0x00: num_items: byte
Number of items in the cache.
  • This is probably limited to the range 0-64 (just as characters can only carry 64 items).
0x01: items: array[ num_items ] of struct cache_item (each size 4)
Cached items.

Structure: cache_item

Size 4.

0x00: item_code: word
Code of the item(s).
0x02: quality: byte
Quality of the item(s).
0x03: quantity: byte
Number of items.