Oni (folder)/persist.dat
The savegame file persist.dat corresponds to a dump of Oni's memory. It is written at specific moments during the game, e.g. after a new level is loaded, or after a new savepoint is reached. It also registers settings from the option menu and remembers whether the cheats are enabled (i.e. whether you have beaten the game) and whether you have killed Griffin.
The savegame file is a memory dump and has nothing to do with instance files despite the ".dat" extension (same for saved_film####.dat, ####_corpse.dat, etc). The binary format of a savegame file is detailed below. It applies to PC and PC demo; the Mac build writes all numbers as Big Endian, e.g., the 0x08 field in the header will appear as 00 0C 7F 5C for a Mac savegame. Therefore, savegames are not interchangeable between PC and Mac versions of Oni.
The header of the savegame file is 0x60=612 bytes long. It is followed by an array of 400 savepoints, 0x204=516 bytes each, grouped implicitly into 40 levels, 10 savepoints per level. The first 10 savepoints belong to level 0 and are never written to. The savepoints of the original 14 levels follow. This leaves 25 unused levels at the end of the savegame file.
The level names are taken from the ONLD files of level 0, except for Chapters 0 and 1: "TCTF Training" (level 1, savepoint 0) and "Syndicate Warehouse" (level 1 savepoint 1) are hardcoded in the engine.
Offset | Type | Raw Hex | Value | Description |
---|---|---|---|---|
0x00 | int32 | 0F 00 00 00 | 15 | unknown, maybe 15 levels; if not 15, file is invalid |
0x04 | int32 | 0E 0B D0 D0 | ??? | unknown |
0x08 | int32 | 5C 7F 0C 00 | 219+218+214+213+212+211 +210+29+28+26+24+23+22 |
visibility lock for levels 2 through 31; 0 and 1 unaffected |
0x0C | int32 | 00 00 00 00 | none | visibility lock for levels 32 through 63 |
0x10 | int32 | 00 00 00 00 | none | visibility lock for levels 64 through 95 |
0x14 | int32 | 00 00 00 00 | none | visibility lock for levels 96 through 127 |
0x18 | int32 | 00 00 00 00 | none | visibility lock for levels 128 through 159 |
0x1C | int32 | 00 00 00 00 | none | visibility lock for levels 160 through 191 |
0x20 | int32 | 00 00 00 00 | none | visibility lock for levels 192 through 223 |
0x24 | int32 | 00 00 00 00 | none | visibility lock for levels 224 through 255 |
0x28 | int32 | 01 00 00 00 | true | whether Griffin was killed: used in Chapters 13 and 14; set with func killed_griffen(bool), read with func did_kill_griffen() |
0x2C | int32 | FE 1B 00 00 | 212+211+29+28+27 +26+25+24+23+22+21 |
unknown |
0x30 | int32 | 1F 00 00 00 | 31 | unknown |
0x34 | int32 | 13 00 00 00 | 19 | unknown |
0x38 | int32 | 01 00 00 00 | 01 | unknown |
0x3C | int32 | 04 00 00 00 | 4 | quality: from superlow (0) to superhigh (4) |
0x40 | float | 00 00 80 3F | 1.000000 | sound volume: from 0.0 to 1.0 |
0x44 | bool32 | 06 00 00 00 | 22+21 | bitset: 1 - show subtitles; 2 - invert aiming; 4 - enable cheats |
0x48 | int32 | 02 00 00 00 | 2 | quality: from Easy (0) to Hard (2) |
0x4C | int16 | 20 03 | 800 | horizontal screen resolution |
0x4E | int16 | 02 58 | 600 | vertical screen resolution |
0x50 | int32 | 20 00 00 00 | 32 | color depth |
0x54 | float | 00 00 00 3F | 0.500000 | gamma correction; from 0.0 to 1.0, 0.5 means no correction |
0x58 | int32 | 03 00 00 00 | 3 | last loaded level; written at level load |
0x5C | int32 | 02 00 00 00 | 2 | last saved savepoint |
Example of a savepoint (chapter 1, savepoint 2)
Offset | Type | Raw Hex | Value | Description |
---|---|---|---|---|
0x00 | char[64] | "Save Point 2" | name of the savepoint in the Load Game dialog | |
0x40 | int32 | 01 00 00 00 | true | whether the savepoint is visible in the Load Game dialog |
0x44 | int32 | BE 00 00 00 | 190 | current health in hitpoints |
0x48 | int32 | C8 00 00 00 | 200 | max. health in hitpoints |
0x4C | float | AE 20 FB 43 | 502.255310 | x-position |
0x50 | float | 03 32 4B 42 | 50.798839 | y-position (height) |
0x54 | float | 55 12 25 C4 | -660.286437 | z-position |
0x58 | float | 80 06 C1 3F | 1.508010 | y-rotation (facing) |
0x5C | int32 | 00 00 00 00 | 0 | amount of ballistic ammo (red clips) |
0x60 | int32 | 01 00 00 00 | 1 | amount of energy cells (green clips) |
0x64 | int32 | 00 00 00 00 | 0 | shield in percent |
0x68 | int32 | 00 00 00 00 | 0 | phase cloak in frames (1/60 s) |
0x6C | int32 | 01 00 00 00 | 1 | amount of hypos |
0x70 | int32 | 00 00 00 00 | 0 | unknown; always 0 |
0x74 | int32 | 01 00 00 00 | true | whether the player has an LSI |
0x78 | int32 | 00 00 00 00 | 0 | unknown; always 0 |
0x7C | int32 | 00 00 00 00 | 0 | unknown; always 0 |
0x80 | char[256] | unknown, always 0 | ||
0x180 | char[128] | w2_sap | name of player's ONWC (weapon class) if any | |
0x200 | int32 | 1E 00 00 00 | 30 | ammo filling of the weapon (shots or percent?) |