Hexing the Savegame

Hexing the Savegame – by Jet
Before starting this, the usual warning: BACKUP THE FILES BEFORE YOU MODIFY and use a real hex editor.

If you’re looking for a good HEX editor, I found that AXE is very useful, a bit difficult to learn how to best use it for newbies but lots nifty features (especially the ability to create structures to match the data in the files).

Latest updates:

  • detailed Missions status and Missions Handlers tables.
  • clarified how the ship availability was computed (thanks to Reverend for this one).
  • corrected a minor mistake in the Current act script reference/Uncomplete mission objectives references sections.
  • added some details to the ship related data section.
To Do:

  • exact faction reference list to check.
  • detail the ship related data section a bit more (make it clearer too, it’s probably somewhat obscure right now).
  • detail specific references in map reference section.
Credits:

  • Thanks to Red_Hex for providing his savegame to fix, poking around it while trying to fix it made me find a lot of these updates…
  • Thanks to Majiir (from US forum, known as Astral around the UK board) for providing his savegame, that gave the content of the missions status/handlers tables.
  • Thanks to RazorJak_Us (also from the US forum) for the cargo list link.
  • Thanks to Reverend for the small bit on the Ship Availability in the Ship basics section.
General Structure:

  • Header.
  • Savegame ID (title string).
  • Lucrecia’s Base map reference for system the base is in.
  • Current act script reference.
  • Uncomplete mission objectives references.
  • Faction relations.
  • Base Inventory.
  • Commodities sub-categories definitions.
  • Commodities categories definitions.
  • Base available construction units.
  • Currently proposed trades.
  • Ship related data:
    – Ship basics (class, class name, template).
    – subsims in template references.
    – avatar placeholder name list for visible subsims
    systems.
    – ship avatar.
    – ship properties.
    – ship collision hull.
    – collision hull modifiers.
    – ship setup scene.
    – subsims contents (programs, ammo, subsims subsystems).
    – ships available.
    – loaded programs list (subsims ref).
    – magazines contents (relative ammo types ref).
    – visible weapons avatar list (avatar ref).
  • Emails lists (unread, archives).
  • Player Statistics.
  • Missions.
  • Csv text files references.
  • Map files references
A string is defined as follows:

  • header ( 80 00 00 SS, where SS is the string size including the end of string indicator byte)
  • string characters translated to their ascii number equivalent and coded in hexadecimal.
  • end of string indicator (00, correspond to the NULL character that ends strings in C langage)

When referring to a string later on, it will cover these 3 parts.

Header:
Always the same:
07 56 47 53 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00

Savegame ID:
Just the savegame title string

Lucrecia’s Base Map reference (for system the base is located in):

It can have 3 different values (don’t know what happens if you put something else, logically if you add the appropriate entry in the map file, you should be able to locate your base somewhere else than the 3 preset locations).

The string is a map reference so it always start by “map:/geog/” followed by cluster ( “badlands/” or “gagarin/” ) and system ( “hoffers_wake”, “santa_romera” or “formalhaut” ). It matches the folder path in the resource dirs where the .map file is located.

Side note: the .map files seems to be in a compiled format so I doubt that you could add anything in them without a way to recompile them (but who knows).

There are 4 extra bytes which usually have a value of 00 00 00 00.

Current Act script reference:

This section start with a string giving a reference to the current act script:

it can be one of “iPrelude”, “iActOne”, “iActTwo”, “iActThree”

Active mission objectives references:

It starts with a the length of the uncomplete mission objectives list coded on 4 bytes.

Note: if there are no uncompleted mission objectives this has a value of 00 00 00 00.

If you have uncomplete mission objectives they should be listed there.

Each one starts by a string identifying the mission objective (ie. a4_m32_objectives_goto for first objective of the infamous MCA Terraforming mission)

then the mission reference numbers are given (using 4 bytes for each value): 00 00 00 XX : where XX is an in-game (or in-savegame) reference for the mission objective description. If there are more than one they will be separated by 4 bytes with a value of 00 00 00 00.

Then, the next uncompleted mission objective is given.

When all uncompleted mission objectives have been referenced, there is a 4 bytes section following that gives a number (probably useful for something but I don’t know what for sure, I think it could be a reference for current Act Script position).

Faction relations:

This section determines the relations between each Faction in the game (including the player).

Basically it’s a list of the faction (the readable text defining the start of a faction’s relation definition) which contains a table of all the faction with several values assigned to each faction to determine behaviour.

There are 54 factions, (the only one, and probably the first in the list, not appearing in the savegame text is the Neutral faction).

The faction behaviour is determined by 4 bytes the first one is for general stance (hostile, neutral, allies with some nuances here and there).

I think the other ones just makes the behaviour more precise (ie. whether the ships will attack anything, or just transports, etc.). This shows the behaviour of the current faction entries toward all other factions (ie. how they view them).

Example:
If you modify the entry in the Independent faction corresponding to player to and make them hostiles, ships in the Independent faction will attack you (because they see you as hostile) but until they hit you, you’ll seen them as neutral (since we didn’t change the entry corresponding the independent in the Player faction). [I hope I’m making sense here]

A faction entry starts with the faction name (a string as defined up there) followed by a byte with 00 value (it’s separated from previous content, faction or preceding section by 3 bytes with a value of 80 00 00).

Then you have a 4 bytes entry giving the number of factions (so it always looks like 00 00 00 37 since there are 54 named factions + the number 0 faction which correspond to Neutral). Next are 55 entries four bytes in length describing the faction’s stance toward other factions (as described in previous paragraph). to conclude this there is a 1 byte entry giving the faction number.

Example:

80 00 00 0C : string header

49 6E 64 65 70 65 6E 64 65 6E 74 : current faction name in hexa, Independent in this case 00 : end of string indicator

00 00 00 37 : number of faction stance entries (same as total factions number)

GG HH II JJ : current faction’s stance toward this faction (55 times)

FN : current faction number (for this table, the numbers for the trades are different).

GG: 00 is neutral, 3F is ally, BF is [ref]hostile. (there’s more to it that this)

HH: don’t know

II: don’t know

JJ: don’t know

The faction list used for reference here starts with the Neutral faction (see note below) and then the factions as they appear in this section.

that is to say:

  1. Neutral
  2. Independent
  3. Exile
  4. Military
  5. Underworld
  6. Government
  7. Transient
  8. Society
  9. ????
  10. Stepson
  11. Kong
  12. MAAS Corporation
  13. Carva Cartel
  14. Junkers
  15. Police
  16. NOMEX Corporation (ie. Solan)
  17. NSO Laplace
  18. Marauders
  19. Angels
  20. The Oman
  21. M.C.A.
  22. Player (yeah, that’s you)
  23. League
  24. Trimann Shipping
  25. Rhondus Gas Mining
  26. Ashanti Investment
  27. Crosspoint Minerals
  28. Helios Mining
  29. Jardin Terraforming
  30. Chon Bodifule
  31. Orion Products
  32. Von Schelling Industries
  33. Megalith Corp
  34. Hibatsh PMC
  35. Dester Corporation
  36. Whind Weapons Systems
  37. Advanced Security Corp
  38. Network 54
  39. Infonet
  40. Stellar Net
  41. Wordszorth Technology
  42. Netcom SA
  43. Coventry Engineering Research
  44. NIMEX Wetware
  45. Universal Consumer Products
  46. Highlife Products
  47. Low Orbit Recovery
  48. KIMO Shipping
  49. Datagon Technologies
  50. Micoria Communications
  51. LOMAX Engines
  52. LOMAX Technologies
  53. Numiko Products
  54. The Third Way and Aliens

Note: it’s possible that the Neutral faction isn’t placed first but at the place where I put the question marks in previous list.

Base inventory:

This section starts right after the Alien Faction relations, by 4 bytes which gives the number of cargo entries in the section (ie 00 00 02 63 since its fixed).

This one is simple, the only obstacle is the sheer mass of entries (611), it correspond to every kind of cargo pod types that exist in the single player game that you can get hold of.

The structure is like this:
00 00 XX XX PP NN NN NN

00 00 XX XX is used to give the cargo type number (this part already exists in the savegame), PP with a value of 80 makes the “+” sign appear in the inventory screen, NN NN NN is the quantity of that cargo type you have in store.

I won’t give the exact cargo list (you have to work a little bit, don’t you?) but it’s organized following the contents of the subcategories (cqrgo alphabetically sorted ascending by english name inside the subcategories, I think ).

EDIT: there is a link to the Cargo List on the right, kindly provided by RazorJak_Us

For ammunitions, there are two inventory entries, the first one is the number of complete pod you have, the second one give the precise number of units left in an uncomplete pod (for ammo consumption). This uncomplete pod is showed as a complete one in the base inventory, that’s what gives the impression that you never use ammunitions, some of these pods do hold quite a bit.

Commodities sub-categories definitions:

This section is not separated from the previous one, it starts right after the last entry in the inventory by 4 bytes giving the number of entries in the subcategory list (ie 00 00 00 3D since there are 61 subcategories).

Subcategory definition is composed of 3 parts:

  • the subcategory name string
    Ex: 80 00 00 0B : 42 6C 75 65 70 72 69 6E 74 73 (Blueprints) : 00 (end of string byte)
     
  • the subcategory html reference string
    always starts with “html:/html/encyclopedia/commodities/ ” then the Category name (ie. “raw_materials/” )
    Ex: to continue the previous example,
    80 00 00 2A: 68 74 6D 6C 3A 2F 68 74 6D 6C 2F 65 6E 63 79 63 6C 6F 70 65 64 69 61 2F 63 6F 6D 6D 6F 64 69 74 49 65 73 2F 64 61 74 61 2F (html:/html/encyclopedia/commodities/data/) : 00
     
  • lowest cargo ID number, highest cargo ID number in the subcategory (coded in 4 bytes each)
    Ex: 00 00 00 A4 (lowest cargo ID for Blueprints subcategory): 00 00 00 BF (highest cargo ID in this subcategory).
     

Commodities categories definitions:

Following the last subcategory, starts the Category section with the number of entries in this table given in 4 bytes (ie. always 00 00 00 09 since there are only 9 Categories).

Again these are composed of 3 parts:

  • the category name string
  • the category html reference string
  • the range of subcategories included in this Category (using the index from previous section, ie Blueprints is index 00) given with lowest subcategory index followed by highest subcategory index, these are in 4 bytes each, as usual.

Base available construction units

Next, simply coded on 4 bytes, is the number of construction units available at the base.

Currently proposed trades:

Plain and simple, these are the deal you see in your trade screen. This as most other structure it is dynamic structure, except that the dynamic nature of this table is really used, so it starts with the number corresponding to the current total of available trades at the beginning of the structure (in 4 bytes, as usual).

Note: if there is no trade available at all the 4 bytes indicating the table size (00 00 00 00) are all that is necessary to represent this section.

After that the deal structure looks like this:
FF FF FF FF NO NO NO NO GO GO GO GO GC GC GC GC NA NA NA NA GA GA GA GA MD MD MD MD 00 00 00 00 00

FF FF FF FF is the faction number the Stepson would correspond to faction 9 so that make 00 00 00 09.

NO NO NO NO is the number of offered goods in the exchange.

GO GO GO GO is the cargo type number corresponding to the offered good, ie. 00 00 00 52 for Algae.

GC GC GC GC is the an indicator flag set to 00 00 00 01 if the asked good is a subcategory.

NA NA NA NA is the number of asked goods in the exchange.

GA GA GA GA is the cargo type number corresponding to the asked good (or the subcategory number if GC flag is set).

MD MD MD MD is the number of times the exchange can be made before it disappear (FF FF FF FF means infinite).

MR indicate whether the trade is mission related (01) or not (00).

If the trade is not mission related then the next four bytes have a value of 00. Else, for a mission related trade, you append the mission string attaching the trade to the mission (ie. mission name) to the trade.

You then start the next trade, until you have a number of trade matching the number at the beginning of this section.

Note 1: cargo ID, are the same as the one used in the base inventory section.
Note 2: subcategories start from 00 up to 3C (60 in decimal) they’re indexed according to the increase cargo ID range.
Note 3: Faction ID numbers comes from the faction_names.csv file located in the text\ folder of the resource path.

Thus if you increase the deal number by one and add the following entry:
00 00 00 01 00 00 00 02 00 00 02 2a 00 00 00 00 00 00 00 02 00 00 02 33 00 00 00 02 00 00 00 00 00, you’ll find an entry for a Deal proposed by Independent which gives 2 Neutron PBCs in exchange for 2 Light PBCs which can be done 2 times before disappearing.

If you put the following line instead:
00 00 00 01 00 00 00 02 00 00 02 2a 00 00 00 01 00 00 00 02 00 00 00 3b 00 00 00 02 00 00 00 00 00, you’ll find an entry for a Deal proposed by Independent which gives 2 Neutron PBCs in exchange for 2 cargo of the Spacecraft Weapons (or Ship Weapons, not sure about the exact translation) subcategory which can be done 2 times before disappearing.

Ship related data:

Ship availability and selection (00 00 00 XX 00 00 00 SS)

XX: Ship Unlock Code, indicate which ships are available by adding ship codes (01 ComSec, 02 Tug, 04 Patcom, 08 Corvette and 0F for Storm Petrel).

For example, to have the Patcom and Corvette available, you add 04 and 08 which makes 0C.
SS: Currently Selected ship type (00 ComSec, 01 Tug, 02 Patcom, 03 Corvette, 04 Storm Petrel)
The loadout is described as a class (the Class string) that contains sets of subclasses.

The general description starts with 00 00 00 11 00 00 00 11 and is followed by the number of entries (or subclasses in this particular class) coded on 4 bytes.

The major tags (i.e. what appears between brackets in the .ini file) are processed/saved in a specific order.

  1. [Class]
  2. [Subsims]
    template entries (in this case, for each missile magazine there is an additional entry added at the end of the list).
  3. null entries.
  4. [Properties]
    properties entries.
  5. [Avatar]
    (that’s the ship in-flight graphic model description with corresponding mountpoints described in the null list of the Subsims section).
    avatar file entry.
  6. [CollisionHull]
    collision hull file entry.
  7. [Modifiers]
    template reference (i.e. .ini files) for ship properties modifiers (like hull plates).
  8. [SetupScene]
    setup scene entry.

If you have several ships (i.e. Turret fighters mounted) you have to repeat the structure for each additional ship (i.e. once for 1 mounted turret-fighter, twice for 2 turret-fighters).

The entries give the basic description of the systems installed on your ship.

Subsims contents (main ship programs, ammo, subsims systems, missile magazines) table.

This starts, as usual with the number of entries in the table (one for each entry in the template list of the Subsims section of you main ship). Then for each entry there is either nothing (4 bytes with a 00 00 00 00 value) or a string followed by some data to reference the subcontent (not detailed here) of the systems located at this position in the template.

Note that turret fighters don’t have entries for their missile loadout in here since they directly use a magazine of the selected missiles (written directly in the Subsims entries), but if you put an ammo dependent weapon on them (Gatling Cannon) there will probably be a similar table for each of turret-fighter you have.

Subsystems table (main ship only since you can’t put any on the T-fighters):

For each entry in the template that can host one or several subsystems (i.e. each entry specified in the .ini file “template=” lines) there is an entry here, systems with no subsystems have a value of 00 00 00 00, non-mounted systems (i.e. empty hardpoint) have a value of FF FF FF FF.

Flyable player ship types list:

TT TT TT TT : table size first (that’s 00 00 00 05 since there’s only 5 ship types)
XX XX XX XX : loadout type indicator (I think, 01 being for standard and 05 for custom) string : ship type name string

Repeat the last 2 for each ship type entry.

3 set of 4 bytes that have an unknon purpose.
XX XX XX XX : ?
YY YY YY YY : ?
ZZ ZZ ZZ ZZ : ?

Loaded programs table (programs .ini files ref)

The number of entries in this table on 4 bytes followed by strings referencing the .ini files with path relative to the resources search_path.

Magazines contents (relative ammo types ref) table determine the exact content of each missile magazine available on the main ship.

Visible weapons avatar list (avatar files ref), list of the avatars corresponding to weapons that can be seen.

Emails lists (unread, archives):

There are 2 lists, first the unread emails list then the read emails list (archives).

Each list start with the number of entries inside the list (on 4 bytes) followed by the emails as described below:

Empty lists only consist of the list length (00 00 00 00).

  • Subject string
  • Sender string
  • email html text reference string
  • email number (on 4 bytes)
  • read indicator byte (00 unread, 01 read)
  • unread indicator byte (00 read, 01 unread) should be inverse of previous byte
  • then next mail until all entries in the list have been filled

Statistics:

This is the statistics section where your various stats are recorded, unless specified otherwise all values are coded on 4 bytes, here is the list:

Kill list:

  • Containers
  • Gunstars
  • Stations
  • Biobombers
  • Drones
  • Waldos
  • CMD sections
  • Utilities
  • Fighters
  • Tugs
  • Patcoms
  • Interceptors
  • Corvettes
  • Transports
  • Destroyers
  • Cruisers
  • Carriers
  • Aliens

Kills summary:

  • Total victories
  • Score

Numbers for precision:
(calculated as a percentage by the game from these values)

  • Number of shots fired (8 bytes)
  • Number of to hit shots (8 bytes)
  • Number of missiles fired (8 bytes)
  • Number of missiles hits (8 bytes)

Pirating statistics:

  • Number of stolen containers
  • Stolen containers value divided by 1000

Missions status:

First, mission status Table size (number of entries on 4 bytes).

Then the entries are detailed, these have a type attached to them which describes what should be expected inside the whole entry.

All entries start with an indentifier string (i.e. entry name) followed by the entry type (on 4 bytes) and entry description/data. There is no separator between entries.

So far, I’ve seen 5 different values for the type, here is the list with what I think (yeah, that means its a guess, a sensible one but a guess anyway) they represent and the structure that is attached to them.

Type:
00: stores a numeric value, composed of 2 values each 4 bytes length.
XX XX XX XX : data word 1 (unknown purpose).
YY YY YY YY : the numeric value stored coded in hexadecimal on 4 bytes (actual number on the right).

Example: for the “g_sn_general_110” entry, we have type=0, data_word_1=1 and numeric value=2
00 00 00 00: type
00 00 00 01: data_word_1
00 00 00 02: numeric value

01: stores a timeout/clock ticker value (2 times 4 bytes).
XX XX XX XX : data word 1 (unknown purpose).
YY YY YY YY : the value stored coded in hexadecimal on 4 bytes (actual number on the right), read this one from right to left.

Example: for the “g_gangster_delay_check” entry, we have type=1 Data_Word_1=2 value=3138
00 00 00 01 : type
00 00 00 02 : Data_Word_1
42 0C 00 00 : I guess you have to reverse this one to get a relatively small value (i.e. manageable).

02: stores a boolean (i.e. 0 or 1) flag value.
XX XX XX XX : data word 1 (unknown purpose).
YY : the boolean value (0 or 1)

Example: for the “g_tfighters_menu_option_enabled” entry we have type=2, first data word= 2 and flag=1 (i.e. true after you get the T-fighters).

03: scripts references (this one can have several subentries).
XX XX XX XX : data word 1 (unknown purpose).
YY YY YY YY : data word 2 (unknown purpose).
string : script class and name.
SS SS SS SS : number of subentries.
subentries… (no separator between subentries).

The subentries are composed of an identifier string and 2 data words.
subentry string: ex 80 00 00 05 6E 61 6D 65 00 (for string “name”
VV VV VV VV: data word 1 (or sub-type).

If Data_word_1 is equal to 3, then we have a single byte value (boolean usually). Otherwise, the secondary data is 4 bytes long (WW WW WW WW: data word 2).

04: string value.
XX XX XX XX : data word 1 (unknown purpose).
YY … YY : a string (as defined before).

Example: for “g_mt_mstring” entry, we have type=4 data_word_1=2, string value=”active missions:” (when no mission is active).

Generally speaking it seems reasonable to assume that what I called Data_Word_1 is a kind of subtype for the entry’s real data (the leftover bytes).

missions scripts/handlers:

When all the entries in the Mission status table are entered, we start the Missions Handlers table with it’s size (on 4 bytes, as usual).

Then each Handler entry is similar in structure to type 3 mission status entries (starting at YY YY YY YY). Which gives use something like:
YY YY YY YY : data word 2 (unknown purpose).
string : script class and name.
SS SS SS SS : number of subentries.
subentries… (no separator between subentries).

The subentries are composed of an identifier string and 2 data words.
subentry string: ex 80 00 00 05 6E 61 6D 65 00 (for string “name”
VV VV VV VV: data word 1 (or sub-type).

If Data_word_1 is equal to 3, then we have a single byte value (boolean usually). Otherwise, the secondary data is 4 bytes long (WW WW WW WW: data word 2).

CSV text files references:

The list of all the .csv files used, starts with number of entries coded on 4 bytes (number can vary depending on the act you’re in an missions you’ve done/been proposed followed by the strings for each entry (in the form of “csv:/text/” followed by access access path/name of the .csv file).

Map files references:

This section is separated from the previous one by two 4 bytes blocks (each containing the value 00 00 00 11).

Some entries contain system specific references to hide/display special objects (usually mission related) in the system (at least I think that’s what it is).

The section starts with the number of map entries that contains specific references coded in a 4 bytes block.

  • map string is given (ie. map:/geog/badlands/dante),
  • specific references each coded on 4 bytes blocks (number of references vary for each system).

Last is the list of all the map for systems that the player visited, just given as strings following each other.

That’s it for now, feel free comment this if I’m being obscure somewhere or to contribute (I know some people have been poking around the Ship data section), any help on the points listed in the TO DO at the beginning of this posted is welcomed.

Leave a Comment