Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
trs:savegame:tr1 [2017/02/23 02:21] zdimensiontrs:savegame:tr1 [2021/07/15 05:00] (current) – update savegame format with new discoveries stohrendorf
Line 1: Line 1:
 ====== TR1 ====== ====== TR1 ======
 +
 +<note tip>When loading a save game, classic TR games read the name and number and then load everything after that directly into the game RAM, without checking anything. That's why savegames from original versions don't work in multipatched versions (and make the game crash). It also makes the "struct-ification" of the format very hard, as it would need decompiling the whole game (which is already being done for TR1 by some awesome people). The way the game works also makes the savegames extremely level-dependent, at least for the entity info part (which is yet to be documented here) as when creating a new game, the game simply loads the level data in RAM, and when saving it writes that down in a file. Understanding a savegame file completely therefore requires having the original level file the savegame is for.</note>
  
 <code cpp> <code cpp>
-struct tr1_savegame+struct TR1Savegame // 10675 bytes
 { {
-    uint8_t SaveName[75]; // ASCII C string; null-terminated (there is always random data after \0, it is ignored); for accents see String Array section of TOMBPC.DAT page +    uint8_t saveName[75]; // ASCII C string; null-terminated (there is always random data after \0, it is ignored); for accents see String Array section of TOMBPC.DAT page 
-    uint16_t SaveNumber+    uint32_t saveNumber// game clips it to 16 bits 
-    uint8_t Unknown2[47]; +    uint8_t unknown2[15]; 
-    // First level use block 0, second use block 1... so that at the end of the game, +    // First level use block 0, second use block 1... so that at the end of the game,
     // it sums up everything and/or checks if you found all secrets, etc     // it sums up everything and/or checks if you found all secrets, etc
     struct     struct
     {     {
-        uint16_t Header; // Always 0x3E8 +        uint16_t ammoPistols; // Always 1000 
-        uint16_t Ammo_Magnums; // 65,535 means unlimited +        uint16_t ammoMagnums; // 65,535 means unlimited 
-        uint16_t Ammo_Uzis+        uint16_t ammoUzis
-        uint16_t Ammo_Shotgun+        uint16_t ammoShotgun
-        uint8_t SmallMedipacks; // 255 means unlimited +        uint8_t smallMedipacks; // 255 means unlimited 
-        uint8_t LargeMedipacks+        uint8_t largeMedipacks
-        uint8_t NumScionPieces+        uint8_t numScionPieces; 
-        uint8_t HandStatus;+        /* 0 None 
 +         * 1 Climbing 
 +         * 2 Draw weapon 
 +         * 3 Holster weapon 
 +         * 4 Combat (i.e. holding a weapon) 
 +         */ 
 +        uint8_t handStatus;
         /* 0 None         /* 0 None
          * 1 Pistols          * 1 Pistols
Line 25: Line 33:
          * 4 Shotgun          * 4 Shotgun
          */          */
-        uint8_t Weapon; // current held weapon  +        uint8_t weapon; // current held weapon 
-        /* 00000001 Always set+        /* 00000001 Level unlocked
          * 00000010 Pistols          * 00000010 Pistols
          * 00000100 Magnums          * 00000100 Magnums
Line 33: Line 41:
          * 00100000 Midas Hand          * 00100000 Midas Hand
          */          */
-        uint8_t Weapons+        uint8_t flags
-        uint8_t Unknown2+        uint8_t _padding
-    } Blocks[19];  +    } levelInitData[21]; // for the 21 levels (315 bytes) 
-    uint32_t ElapsedTime; // in game ticks (1/30th of a second), so divide by 30 for time in seconds +    uint32_t elapsedTime; // in game ticks (1/30th of a second), so divide by 30 for time in seconds 
-    uint32_t Kills+    uint32_t kills
-    /* 00000001 Bronze +    uint16_t secretsFound; // bitmask of the discovered secrets of the current level 
-     * 00000010 Jade +    uint16_t levelNumber; // First level = 1 
-     * 00000100 Gold +    uint8_t numPickups
-     *+    uint8_t unlimitedAmmo; // Enabled = 1 
-    uint8_t Secrets+    uint8_t hasItem141// From decompiled game source
-    uint8_t HealthPacksUsed; // Divide by 2 for value. Large medipack = 1; Small = 0.5 +    uint8_t hasItem142; // Strangely, those (unknown) items aren't present in any official TR1 level 
-    uint8_t LevelNumber; // First level = 1 +    uint8_t puzzles[4]; 
-    uint8_t Unknown5a[5]; +    uint8_t keys[4]; 
-    uint8_t UnlimitedAmmo; // Enabled = 1 +    uint8_t leadBar; 
-    uint8_t ReadToEOF[];+    uint8_t levelInitDataCRC; // not implemented, always 0 
 +    // 10240 bytes starting from now 
 +    uint8_t roomsAreSwapped; 
 +    uint8_t flipFlags[10]; // = (FlipFlag & 0xFF00)>>
 +    uint16_t cameraFlagsZoneIndices[cameraCount]; 
 +    // items block here todo 
 +#pragma pack(push, 8) 
 +    struct 
 +    { 
 +        int16_t itemID; 
 +        int16_t handStatus; 
 +        WeaponID currentWeapon; 
 +        WeaponID requestedWeapon; 
 +        int16_t climbFallSpeedOverride; 
 +        int16_t underwaterState; 
 +        int16_t unknown1; 
 +        int16_t collisionFrame; 
 +        int16_t collisionAxis; 
 +        int16_t air; // game ticks of air left 
 +        int16_t swimToDiveKeypressDuration; // game ticks 
 +        int16_t deadTime; // game ticks 
 +        int16_t underwaterCurrentStrength; 
 +        int16_t spasmEffectCounter; // e.g. when Lara is hit by lightning 
 +        Vertex4 *spasmSource; // from which direction Lara is hit 
 +#pragma pack(push, 1) 
 +        struct MeshTree 
 +        { 
 +            int32_t replacedMeshesBits; 
 +            MESH_HEADER *meshes[15]; 
 +        } laraMeshTree; 
 +#pragma pack(pop) 
 +        ITEM *enemy; 
 +        Vertex2YX weaponTargetVector; 
 +        int16_t yRotationSpeed; 
 +        int16_t movementAngle; 
 +        Vertex2YXZ headRotation; 
 +        Vertex2YXZ torsoRotation; 
 +        AimInfo aimInfoLeft; 
 +        AimInfo aimInfoRight; 
 +        Ammo pistolAmmo; 
 +        Ammo magnumAmmo; 
 +        Ammo uziAmmo; 
 +        Ammo shotgunAmmo; 
 +        struct RoutePlanner 
 +        { 
 +            BoxNode *node; 
 +            uint16_t head; 
 +            uint16_t tail; 
 +            uint16_t searchNumber; 
 +            int16_t blockMask; 
 +            int16_t stepHeight; 
 +            int16_t dropHeight; 
 +            int16_t flyHeight; 
 +            int16_t zoneCount; 
 +            int16_t destinationBox; 
 +            uint16_t searchOverride; 
 +            Vertex4 searchTarget; 
 +        } aiInfo; 
 +    } lara; // 236 bytes 
 +#pragma pack(pop) 
 +    int32_t postFxFunc; // this is usually -1 (and the last occurence of that in the file) so you can align it to that (replace the items blocks above by a filler block) so that Lara is aligned to postFxFunc 
 +    int32_t animFxTime;
 }; };
 +
 +enum WeaponID : int16_t
 +{
 +    None = 0,
 +    Pistols = 1,
 +    Autopistols = 2,
 +    Uzis = 3,
 +    Shotgun = 4,
 +};
 +
 +struct Vertex2
 +{
 +    int16_t x;
 +    int16_t y;
 +    int16_t z;
 +};
 +
 +struct Vertex2YX
 +{
 +    int16_t y;
 +    int16_t x;
 +};
 +
 +struct Vertex2YXZ
 +{
 +    int16_t y;
 +    int16_t x;
 +    int16_t z;
 +};
 +
 +struct Vertex4
 +{
 +    int32_t x;
 +    int32_t y;
 +    int32_t z;
 +};
 +
 +struct Ammo
 +{
 +    int32_t ammo;
 +    int32_t hits;
 +    int32_t misses;
 +};
 +
 +#pragma pack(push, 8)
 +struct AimInfo
 +{
 +    ANIM_FRAME *weaponAnimData;
 +    int16_t frame;
 +    int16_t aiming;
 +    Vertex2YXZ aimRotation;
 +    int16_t shootTimeout;
 +};
 +#pragma pack(pop)
 +
 </code> </code>
  
 +<note tip>The ''<nowiki>xxxxCount</nowiki>'' values are available in the table below.</note>
 ===== Identifications ===== ===== Identifications =====
  
-TODO+==== Levels ==== 
 + 
 +^ID^Level^Filename^Camera count^Items^  Secrets^Puzzle^^^^Key^^^| 
 +| ::: | ::: | ::: | ::: | ::: | ::: ^1^2^3^4^1^2^3^4| 
 +|  0|  Lara's Home  |  ''<nowiki>GYM</nowiki>''    |  1|  1|  0|                 | 
 +|  1|  Caves  |  ''<nowiki>LEVEL1</nowiki>''    |  2|  60|  3|                 | 
 +|  2|  City of Vilcabamba  |  ''<nowiki>LEVEL2</nowiki>''    |  6|  95|  3|  Gold Idol  |        Silver Key  |       | 
 +|  3|  Lost Valley  |  ''<nowiki>LEVEL3A</nowiki>''    |  6|  64|  5|  Machine Cog  |               | 
 +|  4|  Tomb of Qualopec  |  ''<nowiki>LEVEL3B</nowiki>''    |  10|  77|  3|                 | 
 +|  5|  St. Francis' Folly  |  ''<nowiki>LEVEL4</nowiki>''    |  14|  107|  4|          Neptune Key  |  Atlas Key  |  Damocles Key  |  Thor Key  | 
 +|  6|  Colosseum  |  ''<nowiki>LEVEL5</nowiki>''    |  10|  86|  3|          Rusty Key  |       | 
 +|  7|  Palace Midas  |  ''<nowiki>LEVEL6</nowiki>''    |  7|  136|  3|  Gold Bar  |               | 
 +|  8|  The Cistern  |  ''<nowiki>LEVEL7A</nowiki>''    |  7|  112|  3|          Gold Key  |  Silver Key  |  Rusty Key  |   | 
 +|  9|  Tomb of Tihocan  |  ''<nowiki>LEVEL7B</nowiki>''    |  15|  88|  2|          Gold Key  |  Rusty Key  |  Rusty Key  |   | 
 +|  10|  City of Khamoon  |  ''<nowiki>LEVEL8A</nowiki>''    |  3|  93|  3|          Saphire Key  |       | 
 +|  11|  Obelisk of Khamoon  |  ''<nowiki>LEVEL8B</nowiki>''    |  8|  103|  3|  Eye of Horus  |  Scarab  |  Seal of Anubis  |  Ankh  |  Saphire Key  |       | 
 +|  12|  Sanctuary of the Scion  |  ''<nowiki>LEVEL8C</nowiki>''    |  12|  74|  1|  Ankh  |  Scarab  |      Gold Key  |       | 
 +|  13|  Natla's Mines  |  ''<nowiki>LEVEL10A</nowiki>''    |  15|  101|  3|  Fuse  |  Pyramid Key  |             | 
 +|  14|  Atlantis  |  ''<nowiki>LEVEL10B</nowiki>''    |  6|  192|  3|                 | 
 +|  15|  The Great Pyramid  |  ''<nowiki>LEVEL10C</nowiki>''    |  2|  129|  3|                 | 
 +|  16|  Cut Scene 1  |  ''<nowiki>CUT1</nowiki>''    |  1|  3|  N/A  ||||||||| 
 +|  17|  Cut Scene 2  |  ''<nowiki>CUT2</nowiki>''    |  0|  1| ::: ||||||||| 
 +|  18|  Cut Scene 3  |  ''<nowiki>CUT3</nowiki>''    |  0|  4| ::: ||||||||| 
 +|  19|  Cut Scene 4  |  ''<nowiki>CUT4</nowiki>''    |  0|  6| ::: ||||||||| 
 +|  20|  Title  |  ''<nowiki>TITLE</nowiki>''    |  0|  1| ::: ||||||||| 
 +|  21|  Current Position  |  ''<nowiki>CURRENT</nowiki>''    |     | ::: ||||||||| 
 + 
 +<note important>The level "Current Position" (ID 21) seems to have been used internally during the development of the game, and its purposes are unknown. Its file "''<nowiki>CURRENT.PHD</nowiki>''" isn't present in any of the official releases. TODO: Check in the betas.</note> 
 + 
trs/savegame/tr1.1487812906.txt.gz · Last modified: 2017/02/23 02:21 by zdimension
Back to top
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0