Sphinx and the Cursed Mummy Wiki
Advertisement

A savegame is a file that allows the player to store their progress, enabling them to quit the game and resume later from the same place they left off. Sphinx and the Cursed Mummy has three save slots, letting the player have three different playthroughs at different stages simultaneously.

PC port[]

The format was largely unchanged in the PC port, with the first slot stored in a file called DATA0 and the second and third slots are stored as DATA1 and DATA2, respectively. This mirrors the contents of a memory card in a sixth-generation console.

Additionally, the PC version holds backups of all the previous versions of a slot, named with a timestamp. This is in order to simplify the task of rolling back to a previous state just by copying and renaming files.

Savegame slot location[]

On Windows the game uses the per-user Saved Games folder. Because macOS and Linux don't have a standardized way of doing the same thing, save slots are instead stored in their respective configuration folders:

Operating system File path
Windows %USERPROFILE%\Saved Games\Sphinx\
Linux $XDG_DATA_HOME/Sphinx/
macOS ~/Library/Application Support/Sphinx/

Mod savegames[]

Mods use their own independent set of save slots. Instead of just Sphinx, the folder is suffixed with the name of the mod folder, i.e. Sphinx_ModFolderName. So Steam Workshop mods will use their unique ID code. For example, the Shadow of Set mod by jmarti856 will use the folder Sphinx_1614156774.

If two normal mods share the same folder name, they will also share slots.

Internal format[]

The save file is composed of player entry-points, various objective and inventory sections and it is check-summed via a trailing CRC-32 sum of the whole file minus the field for the hash itself. If the game detects that the data is corrupt it will grey out the slot, making it unplayable until overwritten.

Jmarti856 has a C# tool to view and edit savegame files here: https://github.com/eurotools/sphinx-savegame-editor

A good chunk of the internal structure is described below from reverse-engineered efforts; by comparing saves, loading them and after some trial and error:

Header[]

The header is mostly fixed in place.

Offset Size Type Field name Value
0h 2h uint32_t version the constant 8020004h, which is made out of two parts:

0x0802 (2050) for the top 16-bits, and 0x0004 (base v4 file version) for the bottom ones note: autogenerated from the size limits (1700 + 200 + 50 + 100) << 16

i.e. maximum objectives + the (former) inventory items + (former) ability items + saved triggers

if the cumulative max size for those fields doesn't match, or the base Sphinx save format is too old, the save won't load

4h 2h uint32_t version_again
8h 4h uint32_t game_time_sec (in 1/60ths of a second, time shown under the slot name)
Ch 2h uint16_t scarabs Money count, probably vestigial
Eh 2h uint16_t health_ankhs (whole available Ankhs; life upgrades)
10h 2h uint16_t crowns (always zero, I think)
12h 10h char[16] save_name_tag SPHINX
22h 2h byte alignment_22h Uninitialized
24h 4h uint32_t cur_level_hashcode e.g. 1000262h
28h 4h uint32_t cur_level_restart_id index for the last used checkpoint in the current level, e.g. 2
2Ch 4h int32_t cur_level_entrance_id where to spawn the player from in the current level, e.g. -1
30h 4h int32_t cur_level_timer Time spent in the current map
34h 4h int32_t game_time_sec_b (mirrors game_time_sec)
38h 8h byte alignment_38h Uninitialized
3Ch 58h notes_t notes_sphinx
notes_t
Size Type Field name Value
4h uint32_t padding Uninitialized
50h note_entry_t notes[10] Preallocated with enough space for ten notes
note_entry_t
Type Field name
uint32_t title_hashcode
uint32_t desc_hashcode
4h uint32_t note_count from 0 to 10, how many active notes


94h 58h notes_t notes_mummy

Objective array[]

Each game can store up to a maximum of 1700 objectives, the space is preallocated.

objectives_t
Offset Size Type Field name Value
ECh 4h uint32_t objective_count 0<>1700
F0h 3520h objective_entry_t objective_array[1700] There is enough space for a maximum of 1700 elements and each element is made out of the following structure.
objective_entry_t
Size Type Field name
4h uint32_t hashcode
4h uint32_t value

Secondary header fields[]

Offset Size Type Field name Value
3610h 4h uint32_t health_thirds remaining life (always <= than the total, each Ankh/piece has three parts)
3614h 4h uint32_t total_health_thirds total available life; health_ankhs * 3

Book of Sphinx/inventory items and other general fields[]

Most of these are raw dumps of internal game memory, for performance reasons there doesn't seem to have any serialization. Tread carefully.

Offset Size Type Field name Value
3618h 3D8Ch bos_inventory_t bos_items_sphinx These header fields seem to be used at runtime for the HUD selector, think of when selecting only available monsters or amulets that you present to the Portal God or some seller guy.
bos_inventory_t
Size Type Field name Value
4h uint32_t filter_include Bitwise flag
4h uint32_t filter_exclude Bitwise flag
4h uint32_t filter_optional Bitwise flag
4h uint32_t current_cycle Last cycle/section used in the HUD selector, probably
4h uint32_t used_cycle_count There is preallocated space for a maximum of seven inventory cycles/sections. This field says how many of them are in use. Generally five for Sphinx and one for the Mummy
3D78h item_cycle_t item_cycle[7] The first cycle for Sphinx seems to store dart items, then there are the quest, ability, ability possession and ability Ka dart.
item_cycle_t
Size Type Field name Value
4h uint32_t cur_sel_item Last item selected in the HUD picker, probably
4h uint32_t item_count There is enough space for 140 elements in any of these thematic sections.
8C0h item_entry_t items[140]
item_entry_t
Size Type Field name
4h uint32_t hashcode
4h int32_t count_cur
4h int32_t count_max
4h uint32_t flags
73A4h 3D8Ch bos_inventory_t bos_items_mummy Unlike Sphinx the Mummy seems to only use a single inventory cycle/array/section/group for both quest and ability items.
B12Ch 4h uint32_t unused_ability_items_count vestigial from the older inventory system; always zero in the final version
B130h 190h ability_item_t unused_ability_items[50] vestigial, holds uninitialized garbage memory in the final version

each ability_item_t was an early version of item_entry_t but with just the first two fields

B2C4h 4h uint32_t cur_level_saved_triggers_count How many of the 100 trigger entries are in use?
B2C8h 960h saved_trigger_t cur_level_saved_triggers[100]
saved_trigger_t
Size Type Field name
4h uint32_t trig_type
4h uint32_t trig_subtype
4h uint32_t saved_state_value
Ch vector_xyz_t saved_position
vector_xyz_t
Size Type Field name
4h float x
4h float y
4h float z
BC28h 4h uint32_t player_character_idx Stores which character was being used while saving in the map; Sphinx is index zero and it's numerically followed by the Mummy, Lion and Tut.
BC2Ch Ch uint32_t mummy_ability_which[3] The currently active Mummy ability for each of the three possible Mummies.

How long the ability bar is in seconds and how much time remains until it disappears.

BC38h Ch uint32_t mummy_ability_time_current[3]
BC44h Ch uint32_t mummy_ability_time_maximum[3]
BC50h 8h uint32_t triple_mummy_copies_are_active[2] If the second or third Mummies are active they get set to one here.
BC58h 20h vector_xyzw_t triple_mummy_copies_position[2]
vector_xyzw_t
Size Type Field name
4h float x
4h float y
4h float z
4h float w
The in-level position of each extra Mummy.
BC78h 20h vector_xyzw_t triple_mummy_copies_rotation[2] The way each copy is currently facing.
BC98h 4h float camera_angle I believe that the camera gets reset after reloading the save, so the previous values aren't actually going to get used.
BC9Ch 4h float camera_elevation
BCA0h 4h float camera_distance
BCA4h 10h vector_xyzw_t camera_position
BCB4h 10h uint32_t mummy_prog_buttons[4] Four hashcodes; four configurable HUD buttons that can be mapped to actions or items.


The Mummy doesn't seem to actually use these in the final game.

BCC4h 10h uint32_t sphinx_prog_buttons[4]
BCD4H 4h uint32_t unused_padding


Footer[]

The cyclic redundancy check uses a standard CRC-32 algorithm computed over all the previous bytes.

Offset Size Type Field name
BCD8h 4h uint32_t trailing_crc32
Advertisement