Load/save system

At the superficial level, loading and saving of savegames is handled by the loadgame() and savegame() functions in loadsave.c. Savefiles are simple data files containing linear dumps of each aspect of the game state; each module which requires data to be saved must have the appropriate save and load functions added to savegame() and loadgame() respectively. One important point to note is that there are dependencies on the order in which data is loaded. The current save format is as follows:

  1. File header
    This consists of the (unterminated) string "DeathDawn", followed by the version number of the save file, followed by a null byte. The version number is used to ensure files from incompatible releases of the engine are not loaded; the isasavefile() function performs this check.
  2. Basic game state
    This area of the file contains the following:
  3. Faction state
  4. Mission variable list
    This block is saved by the mvar_save() function. It consists of a seqeunce of null-terminated strings (variable names), with each followed by the variable value. For arrays, the variable name is followed by the array size (stored as a word), then the values of all the elements. The list of variables is terminated with a null byte (i.e. null variable name). Ped/car/obj/ent reference variables merely have their name written out, and no value (except for arrays, which have the name and size written). The values of these variables are contained later on in the save file.
  5. Map data
    This section of the save file contains a dump of the entire map data, as saved by map_save(). The block starts with the width and height of the map (2 words), followed by the block definition list: One word giving the number of entries, then for each block, a 1-word unique block ID (actually a pointer to the block structure in memory), the names of the top/north/south/east/west textures (null strings for none), then 3 words comprising the block flags, h1, and h2 values.
    Following the block list is the stack list; This consists of one word giving the number of stacks, then for each stack, a 1-word stack ID (again a pointer to the stack), the stack size (1 word), and then the unique IDs of each block in the stack.
    Finally there is the map column list; Working through the map in linear memory order, for each column there is the base height (1 word) and the unique ID of the stack (1 word).
  6. Ped data
    This section of the save file contains a dump of the ped data, as saved by peds_save(). The block starts with the 1-word number of peds, and then the data for each ped. Data of note includes the list of reference variables (saved by ref_save()), event list (saved by events_save()), and sound list (saved by sounds_save()). A unique ID is also saved with each ped; this is merely the pointer to its location in memory.
  7. Car data
    This section of the save file contains a dump of the car data, as saved by cars_save(). This block starts with the number of cars (1 word), and is followed by the data for eac car. Data of note includes the list of reference variables (saved by ref_save()), event list (saved by events_save()), and sound list (saved by sounds_save()). A unique ID is also saved with each car; this is merely the pointer to its location in memory. The car data uses ped unique IDs (memory pointers) to list all the peds which are sat in the car, and car unique IDs to list the cab and trailer vehicles (if any). It's also worth noting that the car flags are saved with the CAR_OLDIMG bit set, to ensure that the cached sprite is rebuilt the next time it is needed, and that the number of seats in the car is saved, to ensure that the save file can still be read if the number of seats in the car definition changes (although any extra seats will be discarded when loading).
  8. Objects data
    This section of the save file contains a dump of the object data, as saved by objects_save(). Unlike the ped and car data, this does not contain a count of items at the start; instead, the list is termianted with a word containing the value OBJECT_NONE. Additionally, no unique object IDs are saved, as there are no other structures that need to reference objects in the save file. The reference, event, and sound list is saved as per usual.
  9. Mission script name
    This is a null-terminated string containing the name of the current mission script.
  10. Timed events
    This is the list of timed mission events, as saved by timeevents_save(). The list starts with the number of items (1 word), then for each item, the trigger time (1 word) and the null-terminated name of the script function to execute.
  11. Mission triggers
    This area of the save file contains no data. This no data is saved by the empty function save_mission_triggers().
  12. Messages list
    This is a list of all on-screen messages which are currently queued for display, as saved by messages_save(). The block starts with MESSAGE_MAX words, each containing the expiry time of the current message in each message list. The list is then followed by a list of messages; each message starts with a 1-word type, null-terminated sprite name (if MESSAGE_TEXT; else, just a null byte), and a null-terminated string containing the text of the message. This list is terminated with a word containing the value -1.
  13. Map zones
    This data is last, to allow it to more easily reference the zonedefs that will have been loaded by the mission script

Inbetween each section of the savefile is a sentinel string, which aids in the detection of corrupt files by the game. To ensure each section is loaded and saved in the correct order, an array of filebits is used to control the load/save process, detailing the sentinel, load function, and save function for each section of the savefile.

Reference variables

Ped/car/obj/ent reference variables are all saved by the ref_save() function, for each ped/car/object. The data saved by ref_save() is merely a list of null-terminated variable names and array indicies, indicating the names of the variables that reference the given object. Storing the reference variables in the ped/car/obj data blocks simplifies loading, as it allows the variables to be reassigned as they are loaded - as opposed to the variable list storing unique IDs for each entity referenced, and having to swap the IDs with pointers to entities after loading.

Event lists

These are saved by the events_save() function. For each event for each entity, the event type is saved (1 word), and the null-terminated script function name.

Sound state

To keep the code structured, all the entity sounds are managed by sounds.c. Therefore, the sound state for each entity is also loaded and saved by sounds.c. For each sound assigned to an entity, its slot number is saved, along with its flags, pitch, volume, current playing position (calculated afresh for the save op), and null-terminated sample name. The list of sounds is terminated with a -1 word.

Loading

Loading is a bit more complex than saving, and highlights the dependencies in the save file structure:

  1. First, the basic game state is reloaded
  2. Then the factions data is loaded
  3. Then the gameconfig script is loaded, with the newgameflag set to false
  4. Then the mission variables are loaded (this depends on the gameconfig script being loaded - otherwise any default values in the gameconfig script may overwrite the saved values from the savegame)
  5. The HUD data is loaded
  6. Then the map and zone data is loaded
  7. Then the ped list is loaded. This also involves the generation of a unique ID-ped ptr lookup table, which is then used by the car load code
  8. Then the car list is loaded. This depends on the ped unique ID-ptr lookup table, to allow peds to be placed back in the correct cars. The car code also builds its own lookup table, to allow truck cabs to be linked with trailers, and vice-versa. If the car load code finds a car which now has less seats than it used to, then any peds in the extra seats will be teleported out of the car and to the same location as the car itself (not an ideal solution, but it will stop the game from breaking)
  9. Then the object list is loaded. This actually doesn't rely on the ped or car ID-ptr lookups, or build any lookups of its own; but it does rely on the mission variables having been loaded (as does the ped and car load code), to ensure the reference variables aren't reset by default values, reference arrays are allocated to the correct size, etc.
  10. Once the objects are loaded, the ped and car ID-ptr lookup tables are deleted. The main mission script is then loaded (which can detect that this is a savegame load by the presence of the map data). This occurs after the mission variable load, to ensure that the mission script is able to replace or update any old variables with new values, to take into account extra missions added, etc.
  11. Finally the timed events, onscreen messages, and map zones are loaded.
TODO:
DOCS: UNKNOWN: Change to profile-based system? Would allow maps to be cached and saved to disc instead of rebuilt each time the player changes map
???
Profit!