summaryrefslogtreecommitdiffstats
path: root/src/save
diff options
context:
space:
mode:
Diffstat (limited to 'src/save')
-rw-r--r--src/save/GenericGameStorage.cpp497
-rw-r--r--src/save/GenericGameStorage.h11
-rw-r--r--src/save/PCSave.cpp18
-rw-r--r--src/save/PCSave.h2
-rw-r--r--src/save/SaveBuf.h74
5 files changed, 363 insertions, 239 deletions
diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp
index e4ee4542..b68b805a 100644
--- a/src/save/GenericGameStorage.cpp
+++ b/src/save/GenericGameStorage.cpp
@@ -30,6 +30,7 @@
#include "Radar.h"
#include "Restart.h"
#include "Script.h"
+#include "SetPieces.h"
#include "Stats.h"
#include "Streaming.h"
#include "Timer.h"
@@ -37,9 +38,11 @@
#include "Weather.h"
#include "World.h"
#include "Zones.h"
+#include "Timecycle.h"
+#include "Fluff.h"
-#define BLOCK_COUNT 20
-#define SIZE_OF_SIMPLEVARS 0xBC
+#define BLOCK_COUNT 22
+#define SIZE_OF_SIMPLEVARS 0xE4
const uint32 SIZE_OF_ONE_GAME_IN_BYTES = 201729;
@@ -56,8 +59,7 @@ wchar SlotSaveDate[SLOT_COUNT][70];
int CheckSum;
eLevelName m_LevelToLoad;
char SaveFileNameJustSaved[260];
-int Slots[SLOT_COUNT+1];
-CDate CompileDateAndTime;
+int Slots[SLOT_COUNT];
bool b_FoundRecentSavedGameWantToLoad;
bool JustLoadedDontFadeInYet;
@@ -65,6 +67,28 @@ bool StillToFadeOut;
uint32 TimeStartedCountingForFade;
uint32 TimeToStayFadedBeforeFadeOut = 1750;
+int32 RadioStationPosition[NUM_RADIOS];
+
+void
+InitRadioStationPositionList()
+{
+ for (int i = 0; i < NUM_RADIOS; i++)
+ RadioStationPosition[i] = -1;
+}
+
+int32
+GetSavedRadioStationPosition(int32 station)
+{
+ return RadioStationPosition[station];
+}
+
+void
+PopulateRadioStationPositionList()
+{
+ for (int i = 0; i < NUM_RADIOS; i++)
+ RadioStationPosition[i] = DMAudio.GetRadioPosition(i);
+}
+
#define ReadDataFromBufferPointer(buf, to) memcpy(&to, buf, sizeof(to)); buf += align4bytes(sizeof(to));
#define WriteDataToBufferPointer(buf, from) memcpy(buf, &from, sizeof(from)); buf += align4bytes(sizeof(from));
@@ -87,12 +111,14 @@ do {\
buf += size;\
} while (0)
-#define WriteSaveDataBlock(save_func)\
+#define WriteSaveDataBlock(save_func, msg)\
do {\
+ size = 0;\
buf = work_buff;\
reserved = 0;\
MakeSpaceForSizeInBufferPointer(presize, buf, postsize);\
save_func(buf, &size);\
+ debug(msg"== %i \n", size);\
CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);\
if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff))\
return false;\
@@ -119,24 +145,23 @@ GenericSave(int file)
reserved = 0;
// Save simple vars
- lastMissionPassed = TheText.Get(CStats::LastMissionPassedName);
- if (lastMissionPassed[0] != '\0') {
- AsciiToUnicode("...'", suffix);
+ lastMissionPassed = TheText.Get(CStats::LastMissionPassedName[0] ? CStats::LastMissionPassedName : "ITBEG");
+ AsciiToUnicode("...'", suffix);
+ suffix[3] = L'\0';
#ifdef FIX_BUGS
- // fix buffer overflow
- int len = UnicodeStrlen(lastMissionPassed);
- if (len > ARRAY_SIZE(saveName)-1)
- len = ARRAY_SIZE(saveName)-1;
- memcpy(saveName, lastMissionPassed, sizeof(wchar) * len);
+ // fix buffer overflow
+ int len = UnicodeStrlen(lastMissionPassed);
+ if (len > ARRAY_SIZE(saveName)-1)
+ len = ARRAY_SIZE(saveName)-1;
+ memcpy(saveName, lastMissionPassed, sizeof(wchar) * len);
#else
- TextCopy(saveName, lastMissionPassed);
- int len = UnicodeStrlen(saveName);
+ TextCopy(saveName, lastMissionPassed);
+ int len = UnicodeStrlen(saveName);
#endif
- saveName[len] = '\0';
- if (len > ARRAY_SIZE(saveName)-2)
- TextCopy(&saveName[ARRAY_SIZE(saveName)-ARRAY_SIZE(suffix)], suffix);
- saveName[ARRAY_SIZE(saveName)-1] = '\0';
- }
+ saveName[len] = '\0';
+ if (len > ARRAY_SIZE(saveName)-2)
+ TextCopy(&saveName[ARRAY_SIZE(saveName)-ARRAY_SIZE(suffix)], suffix);
+ saveName[ARRAY_SIZE(saveName)-1] = '\0';
WriteDataToBufferPointer(buf, saveName);
GetLocalTime(&saveTime);
WriteDataToBufferPointer(buf, saveTime);
@@ -168,12 +193,6 @@ GenericSave(int file)
WriteDataToBufferPointer(buf, CWeather::NewWeatherType);
WriteDataToBufferPointer(buf, CWeather::ForcedWeatherType);
WriteDataToBufferPointer(buf, CWeather::InterpolationValue);
- WriteDataToBufferPointer(buf, CompileDateAndTime.m_nSecond);
- WriteDataToBufferPointer(buf, CompileDateAndTime.m_nMinute);
- WriteDataToBufferPointer(buf, CompileDateAndTime.m_nHour);
- WriteDataToBufferPointer(buf, CompileDateAndTime.m_nDay);
- WriteDataToBufferPointer(buf, CompileDateAndTime.m_nMonth);
- WriteDataToBufferPointer(buf, CompileDateAndTime.m_nYear);
WriteDataToBufferPointer(buf, CWeather::WeatherTypeInList);
#ifdef COMPATIBLE_SAVES
// converted to float for compatibility with original format
@@ -186,6 +205,14 @@ GenericSave(int file)
WriteDataToBufferPointer(buf, TheCamera.CarZoomIndicator);
WriteDataToBufferPointer(buf, TheCamera.PedZoomIndicator);
#endif
+ WriteDataToBufferPointer(buf, CGame::currArea);
+ WriteDataToBufferPointer(buf, CVehicle::bAllTaxisHaveNitro);
+ WriteDataToBufferPointer(buf, CPad::bInvertLook4Pad);
+ WriteDataToBufferPointer(buf, CTimeCycle::m_ExtraColour);
+ WriteDataToBufferPointer(buf, CTimeCycle::m_bExtraColourOn);
+ WriteDataToBufferPointer(buf, CTimeCycle::m_ExtraColourInter);
+ PopulateRadioStationPositionList();
+ WriteDataToBufferPointer(buf, RadioStationPosition);
assert(buf - work_buff == SIZE_OF_SIMPLEVARS);
// Save scripts, block is nested within the same block as simple vars for some reason
@@ -193,6 +220,7 @@ GenericSave(int file)
buf += 4;
postsize = buf;
CTheScripts::SaveAllScripts(buf, &size);
+ debug("ScriptSize== %i \n", size);
CopySizeAndPreparePointer(presize, buf, postsize, reserved, size);
if (!PcSaveHelper.PcClassSaveRoutine(file, work_buff, buf - work_buff))
return false;
@@ -200,25 +228,28 @@ GenericSave(int file)
totalSize = buf - work_buff;
// Save the rest
- WriteSaveDataBlock(CPools::SavePedPool);
- WriteSaveDataBlock(CGarages::Save);
- WriteSaveDataBlock(CPools::SaveVehiclePool);
- WriteSaveDataBlock(CPools::SaveObjectPool);
- WriteSaveDataBlock(ThePaths.Save);
- WriteSaveDataBlock(CCranes::Save);
- WriteSaveDataBlock(CPickups::Save);
- WriteSaveDataBlock(gPhoneInfo.Save);
- WriteSaveDataBlock(CRestart::SaveAllRestartPoints);
- WriteSaveDataBlock(CRadar::SaveAllRadarBlips);
- WriteSaveDataBlock(CTheZones::SaveAllZones);
- WriteSaveDataBlock(CGangs::SaveAllGangData);
- WriteSaveDataBlock(CTheCarGenerators::SaveAllCarGenerators);
- WriteSaveDataBlock(CParticleObject::SaveParticle);
- WriteSaveDataBlock(cAudioScriptObject::SaveAllAudioScriptObjects);
- WriteSaveDataBlock(CWorld::Players[CWorld::PlayerInFocus].SavePlayerInfo);
- WriteSaveDataBlock(CStats::SaveStats);
- WriteSaveDataBlock(CStreaming::MemoryCardSave);
- WriteSaveDataBlock(CPedType::Save);
+ WriteSaveDataBlock(CPools::SavePedPool, "PedPoolSize");
+ WriteSaveDataBlock(CGarages::Save, "GaragesSize");
+ WriteSaveDataBlock(CGameLogic::Save, "GameLogicSize");
+ WriteSaveDataBlock(CPools::SaveVehiclePool, "VehPoolSize");
+ WriteSaveDataBlock(CPools::SaveObjectPool, "ObjectPoolSize");
+ WriteSaveDataBlock(ThePaths.Save, "ThePathsSize");
+ WriteSaveDataBlock(CCranes::Save, "CranesSize");
+ WriteSaveDataBlock(CPickups::Save, "PickUpsSize");
+ WriteSaveDataBlock(gPhoneInfo.Save, "PhoneInfoSize");
+ WriteSaveDataBlock(CRestart::SaveAllRestartPoints, "RestartPointsBufferSize");
+ WriteSaveDataBlock(CRadar::SaveAllRadarBlips, "RadarBlipsBufferSize");
+ WriteSaveDataBlock(CTheZones::SaveAllZones, "AllZonesBufferSize");
+ WriteSaveDataBlock(CGangs::SaveAllGangData, "AllGangDataSize");
+ WriteSaveDataBlock(CTheCarGenerators::SaveAllCarGenerators, "AllCarGeneratorsSize");
+ WriteSaveDataBlock(CParticleObject::SaveParticle, "ParticlesSize");
+ WriteSaveDataBlock(cAudioScriptObject::SaveAllAudioScriptObjects, "AllAudioScriptObjectsSize");
+ WriteSaveDataBlock(CScriptPaths::Save, "ScriptPathsSize");
+ WriteSaveDataBlock(CWorld::Players[CWorld::PlayerInFocus].SavePlayerInfo, "PlayerInfoSize");
+ WriteSaveDataBlock(CStats::SaveStats, "StatsSize");
+ WriteSaveDataBlock(CSetPieces::Save, "SetPiecesSize");
+ WriteSaveDataBlock(CStreaming::MemoryCardSave, "StreamingSize");
+ WriteSaveDataBlock(CPedType::Save, "PedTypeSize");
// sure just write garbage data repeatedly ...
#ifndef THIS_IS_STUPID
@@ -246,7 +277,8 @@ GenericSave(int file)
return false;
}
-
+
+ CPad::FixPadsAfterSave();
return true;
}
@@ -297,13 +329,12 @@ GenericLoad()
ReadDataFromBufferPointer(buf, CWeather::OldWeatherType);
ReadDataFromBufferPointer(buf, CWeather::NewWeatherType);
ReadDataFromBufferPointer(buf, CWeather::ForcedWeatherType);
+#ifdef SECUROM
+ if (CTimer::m_FrameCounter > 72000){
+ buf += align4bytes(4);
+ }
+#endif
ReadDataFromBufferPointer(buf, CWeather::InterpolationValue);
- ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nSecond);
- ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nMinute);
- ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nHour);
- ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nDay);
- ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nMonth);
- ReadDataFromBufferPointer(buf, CompileDateAndTime.m_nYear);
ReadDataFromBufferPointer(buf, CWeather::WeatherTypeInList);
#ifdef COMPATIBLE_SAVES
// converted to float for compatibility with original format
@@ -317,6 +348,17 @@ GenericLoad()
ReadDataFromBufferPointer(buf, TheCamera.CarZoomIndicator);
ReadDataFromBufferPointer(buf, TheCamera.PedZoomIndicator);
#endif
+ ReadDataFromBufferPointer(buf, CGame::currArea);
+ ReadDataFromBufferPointer(buf, CVehicle::bAllTaxisHaveNitro);
+#ifdef LOAD_INI_SETTINGS
+ buf += align4bytes(sizeof(CPad::bInvertLook4Pad));
+#else
+ ReadDataFromBufferPointer(buf, CPad::bInvertLook4Pad);
+#endif
+ ReadDataFromBufferPointer(buf, CTimeCycle::m_ExtraColour);
+ ReadDataFromBufferPointer(buf, CTimeCycle::m_bExtraColourOn);
+ ReadDataFromBufferPointer(buf, CTimeCycle::m_ExtraColourInter);
+ ReadDataFromBufferPointer(buf, RadioStationPosition);
assert(buf - work_buff == SIZE_OF_SIMPLEVARS);
#ifdef MISSION_REPLAY
WaitForSave = 0;
@@ -331,6 +373,8 @@ GenericLoad()
LoadSaveDataBlock();
ReadDataFromBlock("Loading Garages \n", CGarages::Load);
LoadSaveDataBlock();
+ ReadDataFromBlock("Loading GameLogic \n", CGameLogic::Load);
+ LoadSaveDataBlock();
ReadDataFromBlock("Loading Vehicles \n", CPools::LoadVehiclePool);
LoadSaveDataBlock();
CProjectileInfo::RemoveAllProjectiles();
@@ -360,16 +404,20 @@ GenericLoad()
LoadSaveDataBlock();
ReadDataFromBlock("Loading AudioScript Objects \n", cAudioScriptObject::LoadAllAudioScriptObjects);
LoadSaveDataBlock();
+ ReadDataFromBlock("Loading ScriptPaths \n", CScriptPaths::Load);
+ LoadSaveDataBlock();
ReadDataFromBlock("Loading Player Info \n", CWorld::Players[CWorld::PlayerInFocus].LoadPlayerInfo);
LoadSaveDataBlock();
ReadDataFromBlock("Loading Stats \n", CStats::LoadStats);
LoadSaveDataBlock();
+ ReadDataFromBlock("Loading Set Pieces \n", CSetPieces::Load);
+ LoadSaveDataBlock();
ReadDataFromBlock("Loading Streaming Stuff \n", CStreaming::MemoryCardLoad);
LoadSaveDataBlock();
ReadDataFromBlock("Loading PedType Stuff \n", CPedType::Load);
- DMAudio.SetMusicMasterVolume(CMenuManager::m_PrefsMusicVolume);
- DMAudio.SetEffectsMasterVolume(CMenuManager::m_PrefsSfxVolume);
+ DMAudio.SetMusicMasterVolume(FrontEndMenuManager.m_PrefsMusicVolume);
+ DMAudio.SetEffectsMasterVolume(FrontEndMenuManager.m_PrefsSfxVolume);
if (!CloseFile(file)) {
PcSaveHelper.nErrorCode = SAVESTATUS_ERR_LOAD_CLOSE;
return false;
@@ -424,8 +472,13 @@ CloseFile(int32 file)
void
DoGameSpecificStuffAfterSucessLoad()
{
+ CCollision::SortOutCollisionAfterLoad();
+ CStreaming::LoadSceneCollision(TheCamera.GetPosition());
+ CStreaming::LoadScene(TheCamera.GetPosition());
+ CGame::TidyUpMemory(true, false);
StillToFadeOut = true;
JustLoadedDontFadeInYet = true;
+ TheCamera.Fade(0.0f, FADE_OUT);
CTheScripts::Process();
}
@@ -572,19 +625,9 @@ RestoreForStartLoad()
ReadDataFromBufferPointer(_buf, TheCamera.GetMatrix().GetPosition().x);
ReadDataFromBufferPointer(_buf, TheCamera.GetMatrix().GetPosition().y);
ReadDataFromBufferPointer(_buf, TheCamera.GetMatrix().GetPosition().z);
- ISLAND_LOADING_IS(LOW)
- {
- CStreaming::RemoveUnusedBigBuildings(CGame::currLevel);
- CStreaming::RemoveUnusedBuildings(CGame::currLevel);
- }
- CCollision::SortOutCollisionAfterLoad();
- ISLAND_LOADING_IS(LOW)
- {
- CStreaming::RequestBigBuildings(CGame::currLevel);
- CStreaming::LoadAllRequestedModels(false);
- CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel);
- CGame::TidyUpMemory(true, false);
- }
+ CStreaming::RemoveUnusedBigBuildings(CGame::currLevel);
+ CStreaming::RemoveUnusedBuildings(CGame::currLevel);
+
if (CloseFile(file)) {
return true;
} else {
@@ -650,6 +693,7 @@ enum
SAVE_TYPE_64_BIT = 2,
SAVE_TYPE_MSVC = 4,
SAVE_TYPE_GCC = 8,
+ SAVE_TYPE_STEAM = 16,
};
uint8
@@ -664,6 +708,14 @@ GetSaveType(char *savename)
uint8 *buf = work_buff;
CFileMgr::Read(file, (const char *)work_buff, size); // simple vars + scripts
+ buf += 0x40 + sizeof(int32) + sizeof(int32) + sizeof(float) * 3;
+
+ int8 steam_byte;
+ ReadDataFromBufferPointer(buf, steam_byte);
+
+ if (steam_byte == -3)
+ save_type |= SAVE_TYPE_STEAM;
+
LoadSaveDataBlockNoCheck(buf, file, size); // ped pool
LoadSaveDataBlockNoCheck(buf, file, size); // garages
@@ -672,6 +724,7 @@ GetSaveType(char *savename)
// store for later after we know how much data we need to skip
ReadDataFromBufferPointerWithSize(buf, work_buff2, size);
+ LoadSaveDataBlockNoCheck(buf, file, size); // game logic
LoadSaveDataBlockNoCheck(buf, file, size); // vehicle pool
LoadSaveDataBlockNoCheck(buf, file, size); // object pool
LoadSaveDataBlockNoCheck(buf, file, size); // paths
@@ -682,7 +735,7 @@ GetSaveType(char *savename)
ReadDataFromBufferPointer(buf, size);
- if (size == 1032)
+ if (size == 1000)
save_type |= SAVE_TYPE_32_BIT;
else if (size == 1160)
save_type |= SAVE_TYPE_64_BIT;
@@ -691,22 +744,21 @@ GetSaveType(char *savename)
buf = work_buff2;
- buf += 760; // skip everything before the first garage
- buf += save_type & SAVE_TYPE_32_BIT ? 28 : 40; // skip first garage up to m_fX1
+ buf += 1964; // skip everything before the first garage
+ buf += save_type & SAVE_TYPE_32_BIT ? 28 : 40; // skip first garage up to m_vecCorner1
- // now the values we want to verify
- float fX1, fX2, fY1, fY2, fZ1, fZ2;
+ CVector2D vecCorner1;
+ float fInfZ, fSupZ;
- ReadBuf(buf, fX1);
- ReadBuf(buf, fX2);
- ReadBuf(buf, fY1);
- ReadBuf(buf, fY2);
- ReadBuf(buf, fZ1);
- ReadBuf(buf, fZ2);
+ ReadBuf(buf, vecCorner1);
+ ReadBuf(buf, fInfZ);
+ SkipBuf(buf, sizeof(CVector2D));
+ SkipBuf(buf, sizeof(CVector2D));
+ ReadBuf(buf, fSupZ);
- if (fX1 == CRUSHER_GARAGE_X1 && fX2 == CRUSHER_GARAGE_X2 &&
- fY1 == CRUSHER_GARAGE_Y1 && fY2 == CRUSHER_GARAGE_Y2 &&
- fZ1 == CRUSHER_GARAGE_Z1 && fZ2 == CRUSHER_GARAGE_Z2)
+ // SET_GARAGE -914.129028 -1263.540039 10.706000 -907.137024 -1246.625977 -906.299988 -1266.900024 14.421000
+ if (vecCorner1.x == -914.129028f && vecCorner1.y == -1263.540039f &&
+ fInfZ == 10.706000f && fSupZ == 14.421000f)
save_type |= SAVE_TYPE_MSVC;
else
save_type |= SAVE_TYPE_GCC;
@@ -715,25 +767,48 @@ GetSaveType(char *savename)
}
static void
+FixSimpleVarsAndScripts(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
+{
+ uint8 *buf_start = buf;
+ uint8 *buf2_start = buf2;
+ uint32 read = *size;
+ uint32 written = *size - (sizeof(int8) + 3);
+
+ uint32 pre_steam = 0x40 + sizeof(int32) + sizeof(int32) + sizeof(float) * 3;
+ uint32 post_steam = *size - (sizeof(int8) + 3) - pre_steam;
+
+ CopyBuf(buf, buf2, pre_steam);
+ SkipBuf(buf, sizeof(int8) + 3);
+ CopyBuf(buf, buf2, post_steam);
+
+ *size = 0;
+
+ assert(buf - buf_start == read);
+ assert(buf2 - buf2_start == written);
+
+ *size = written;
+}
+
+static void
FixGarages(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
{
- // hardcoded: 5484
- // x86 msvc: 5240
- // x86 gcc: 5040
- // amd64 msvc: 5880
- // amd64 gcc: 5808
+ // hardcoded: 7876
+ // x86 msvc: 7340
+ // x86 gcc: 7020
+ // amd64 msvc: 7852
+ // amd64 gcc: 7660
uint8 *buf_start = buf;
uint8 *buf2_start = buf2;
uint32 read;
- uint32 written = 5240;
+ uint32 written = 7340;
if (save_type & SAVE_TYPE_32_BIT && save_type & SAVE_TYPE_GCC)
- read = 5040;
+ read = 7020;
else if (save_type & SAVE_TYPE_64_BIT && save_type & SAVE_TYPE_GCC)
- read = 5808;
+ read = 7660;
else
- read = 5880;
+ read = 7852;
uint32 ptrsize = save_type & SAVE_TYPE_32_BIT ? 4 : 8;
@@ -745,62 +820,45 @@ FixGarages(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
{
for (int32 i = 0; i < NUM_GARAGE_STORED_CARS; i++)
{
-#define FixStoredCar(buf, buf2) \
-do { \
- CopyBuf(buf, buf2, 4 + sizeof(CVector) + sizeof(CVector)); \
- uint8 nFlags8; \
- ReadBuf(buf, nFlags8); \
- int32 nFlags32 = nFlags8; \
- WriteBuf(buf2, nFlags32); \
- CopyBuf(buf, buf2, 1 * 6); \
- SkipBuf(buf, 1); \
- SkipBuf(buf2, 2); \
-} while(0)
-
- FixStoredCar(buf, buf2);
- FixStoredCar(buf, buf2);
- FixStoredCar(buf, buf2);
-
-#undef FixStoredCar
+ for (int32 j = 0; j < TOTAL_HIDEOUT_GARAGES; j++)
+ {
+ CopyBuf(buf, buf2, 4 + sizeof(CVector) + sizeof(CVector));
+ uint8 nFlags8;
+ ReadBuf(buf, nFlags8);
+ int32 nFlags32 = nFlags8;
+ WriteBuf(buf2, nFlags32);
+ CopyBuf(buf, buf2, 1 * 6);
+ SkipBuf(buf, 1);
+ SkipBuf(buf2, 2);
+ }
}
}
else
{
- CopyBuf(buf, buf2, sizeof(CStoredCar) * NUM_GARAGE_STORED_CARS);
- CopyBuf(buf, buf2, sizeof(CStoredCar) * NUM_GARAGE_STORED_CARS);
- CopyBuf(buf, buf2, sizeof(CStoredCar) * NUM_GARAGE_STORED_CARS);
+ CopyBuf(buf, buf2, sizeof(CStoredCar) * NUM_GARAGE_STORED_CARS * TOTAL_HIDEOUT_GARAGES);
}
for (int32 i = 0; i < NUM_GARAGES; i++)
{
- // skip the last 5 garages in 64bit builds without FIX_GARAGE_SIZE since they weren't actually saved and are unused
- if (save_type & SAVE_TYPE_64_BIT && *size == 5484 && i >= NUM_GARAGES - 5)
- {
- SkipBuf(buf, 160); // sizeof(CGarage) on x64
- SkipBuf(buf2, 140); // sizeof(CGarage) on x86
- }
+ CopyBuf(buf, buf2, 1 * 7);
+ SkipBoth(buf, buf2, 1);
+ CopyBuf(buf, buf2, 4);
+ SkipBuf(buf, ptrsize - 4); // write 4 bytes padding if 8 byte pointer, if not, write 0
+ SkipBuf(buf, ptrsize * 2);
+ SkipBuf(buf2, 4 * 2);
+ CopyBuf(buf, buf2, 1 * 7);
+ SkipBoth(buf, buf2, 1);
+ CopyBuf(buf, buf2, sizeof(CVector2D) * 3 + 4 * 17 + 1);
+ SkipBoth(buf, buf2, 3);
+ SkipBuf(buf, ptrsize);
+ SkipBuf(buf2, 4);
+
+ if (save_type & SAVE_TYPE_GCC)
+ SkipBuf(buf, save_type & SAVE_TYPE_64_BIT ? 36 + 4 : 36); // sizeof(CStoredCar) on gcc 64/32 before fix
else
- {
- CopyBuf(buf, buf2, 1 * 6);
- SkipBoth(buf, buf2, 2);
- CopyBuf(buf, buf2, 4);
- SkipBuf(buf, ptrsize - 4); // write 4 bytes padding if 8 byte pointer, if not, write 0
- SkipBuf(buf, ptrsize * 2);
- SkipBuf(buf2, 4 * 2);
- CopyBuf(buf, buf2, 1 * 7);
- SkipBoth(buf, buf2, 1);
- CopyBuf(buf, buf2, 4 * 15 + 1);
- SkipBoth(buf, buf2, 3);
- SkipBuf(buf, ptrsize * 2);
- SkipBuf(buf2, 4 * 2);
-
- if (save_type & SAVE_TYPE_GCC)
- SkipBuf(buf, save_type & SAVE_TYPE_64_BIT ? 36 + 4 : 36); // sizeof(CStoredCar) on gcc 64/32 before fix
- else
- SkipBuf(buf, sizeof(CStoredCar));
-
- SkipBuf(buf2, sizeof(CStoredCar));
- }
+ SkipBuf(buf, sizeof(CStoredCar));
+
+ SkipBuf(buf2, sizeof(CStoredCar));
}
*size = 0;
@@ -808,11 +866,7 @@ do { \
assert(buf - buf_start == read);
assert(buf2 - buf2_start == written);
-#ifdef FIX_GARAGE_SIZE
- *size = (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CGarages::CarTypesCollected) + sizeof(uint32) + 3 * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage));
-#else
- *size = 5484;
-#endif
+ *size = 7876;
}
static void
@@ -821,7 +875,7 @@ FixCranes(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
uint8 *buf_start = buf;
uint8 *buf2_start = buf2;
uint32 read = 2 * sizeof(uint32) + 0x480; // sizeof(aCranes)
- uint32 written = 2 * sizeof(uint32) + 0x400; // see CRANES_SAVE_SIZE
+ uint32 written = 2 * sizeof(uint32) + 0x3E0; // see CRANES_SAVE_SIZE
CopyBuf(buf, buf2, 4 + 4);
@@ -829,7 +883,8 @@ FixCranes(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
{
CopyPtr(buf, buf2);
CopyPtr(buf, buf2);
- CopyBuf(buf, buf2, 15 * 4 + sizeof(CVector) * 3 + sizeof(CVector2D));
+ CopyBuf(buf, buf2, 14 * 4 + sizeof(CVector) * 3 + sizeof(CVector2D));
+ SkipBuf(buf, 4);
CopyPtr(buf, buf2);
CopyBuf(buf, buf2, 4 + 7 * 1);
SkipBuf(buf, 5);
@@ -849,16 +904,17 @@ FixPickups(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
{
uint8 *buf_start = buf;
uint8 *buf2_start = buf2;
- uint32 read = 0x3480 + sizeof(uint16) + sizeof(uint16) + sizeof(int32) * NUMCOLLECTEDPICKUPS; // sizeof(aPickUps)
- uint32 written = 0x24C0 + sizeof(uint16) + sizeof(uint16) + sizeof(int32) * NUMCOLLECTEDPICKUPS; // see PICKUPS_SAVE_SIZE
+ uint32 read = 0x5400 + sizeof(uint16) + sizeof(uint16) + sizeof(int32) * NUMCOLLECTEDPICKUPS; // sizeof(aPickUps)
+ uint32 written = 0x4440 + sizeof(uint16) + sizeof(uint16) + sizeof(int32) * NUMCOLLECTEDPICKUPS; // see PICKUPS_SAVE_SIZE
for (int32 i = 0; i < NUMPICKUPS; i++)
{
- CopyBuf(buf, buf2, 1 + 1 + 2);
- SkipBuf(buf, 4);
+ CopyBuf(buf, buf2, sizeof(CVector) + 4);
CopyPtr(buf, buf2);
- CopyBuf(buf, buf2, 4 + 2 + 2 + sizeof(CVector));
- SkipBuf(buf, 4);
+ CopyPtr(buf, buf2);
+ CopyBuf(buf, buf2, 4 * 2 + 2 * 3 + 8 + 1 * 3);
+ SkipBuf(buf, 7);
+ SkipBuf(buf2, 3);
}
CopyBuf(buf, buf2, 2);
@@ -910,54 +966,6 @@ FixPhoneInfo(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
}
static void
-FixZones(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
-{
- uint8 *buf_start = buf;
- uint8 *buf2_start = buf2;
- uint32 read = 11300; // see SaveAllZones
- uint32 written = 10100; // see SaveAllZones
-
- CopyBuf(buf, buf2, 1 * 4);
-
- SkipBuf(buf, 4);
- uint32 hdr_size = 10100 - (1 * 4 + 4); // see SaveAllZones
- WriteBuf(buf2, hdr_size);
-
- CopyBuf(buf, buf2, 4 * 2 + 2);
- SkipBoth(buf, buf2, 2);
-
-#define FixOneZone(buf, buf2) \
-do { \
- CopyBuf(buf, buf2, 8 + 8 * 4 + 2 * 2); \
- SkipBuf(buf, 4); \
- CopyPtr(buf, buf2); \
- CopyPtr(buf, buf2); \
- CopyPtr(buf, buf2); \
-} while(0)
-
- for (int32 i = 0; i < NUMZONES; i++)
- FixOneZone(buf, buf2);
-
- CopyBuf(buf, buf2, sizeof(CZoneInfo) * NUMZONES * 2);
- CopyBuf(buf, buf2, 2 + 2);
-
- for (int32 i = 0; i < NUMMAPZONES; i++)
- FixOneZone(buf, buf2);
-
- CopyBuf(buf, buf2, 2 * NUMAUDIOZONES);
- CopyBuf(buf, buf2, 2 + 2);
-
-#undef FixOneZone
-
- *size = 0;
-
- assert(buf - buf_start == read);
- assert(buf2 - buf2_start == written);
-
- *size = written;
-}
-
-static void
FixParticles(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
{
uint8 *buf_start = buf;
@@ -967,13 +975,12 @@ FixParticles(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
ReadBuf(buf, numObjects);
WriteBuf(buf2, numObjects);
- uint32 read = 0xA0 * (numObjects + 1) + 4; // sizeof(CParticleObject)
- uint32 written = 0x88 * (numObjects + 1) + 4; // see PARTICLE_OBJECT_SIZEOF
+ uint32 read = 0x98 * (numObjects + 1) + 4; // sizeof(CParticleObject)
+ uint32 written = 0x84 * (numObjects + 1) + 4; // see PARTICLE_OBJECT_SIZEOF
for (int32 i = 0; i < numObjects; i++)
{
// CPlaceable
- SkipPtr(buf, buf2);
CopyBuf(buf, buf2, 4 * 4 * 4);
SkipPtr(buf, buf2);
CopyBuf(buf, buf2, 1);
@@ -990,8 +997,47 @@ FixParticles(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
SkipBoth(buf, buf2, 2);
}
- SkipBuf(buf, 0xA0); // sizeof(CParticleObject)
- SkipBuf(buf2, 0x88); // see PARTICLE_OBJECT_SIZEOF
+ SkipBuf(buf, 0x98); // sizeof(CParticleObject)
+ SkipBuf(buf2, 0x84); // see PARTICLE_OBJECT_SIZEOF
+
+ *size = 0;
+
+ assert(buf - buf_start == read);
+ assert(buf2 - buf2_start == written);
+
+ *size = written;
+}
+
+static void
+FixScriptPaths(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
+{
+ uint8 *buf_start = buf;
+ uint8 *buf2_start = buf2;
+ uint32 read = 0x108; // sizeof(CScriptPath) * 3
+ uint32 written = 0x9C; // see SCRIPTPATHS_SAVE_SIZE
+
+ for (int32 i = 0; i < 3; i++)
+ {
+ int32 numNodes;
+ ReadBuf(buf, numNodes);
+ WriteBuf(buf2, numNodes);
+ SkipBuf(buf, 4);
+ SkipPtr(buf, buf2);
+ CopyBuf(buf, buf2, 4 * 5);
+ SkipBuf(buf, 4);
+
+ for (int32 i = 0; i < 6; i++)
+ {
+ CopyPtr(buf, buf2);
+ }
+
+ for (int32 i = 0; i < numNodes; i++)
+ {
+ CopyBuf(buf, buf2, sizeof(CPlaneNode));
+ read += sizeof(CPlaneNode);
+ written += sizeof(CPlaneNode);
+ }
+ }
*size = 0;
@@ -1004,7 +1050,7 @@ FixParticles(uint8 save_type, uint8 *buf, uint8 *buf2, uint32 *size)
bool
FixSave(int32 slot, uint8 save_type)
{
- if (save_type & SAVE_TYPE_32_BIT && save_type & SAVE_TYPE_MSVC)
+ if (save_type & SAVE_TYPE_32_BIT && save_type & SAVE_TYPE_MSVC && !(save_type & SAVE_TYPE_STEAM))
return true;
bool success = false;
@@ -1035,13 +1081,27 @@ FixSave(int32 slot, uint8 save_type)
buf = work_buff;
CFileMgr::Read(file_in, (const char *)work_buff, size); // simple vars + scripts
- WriteSavaDataBlockNoFunc(buf, file_out, size);
+ if (save_type & SAVE_TYPE_STEAM && save_type & SAVE_TYPE_MSVC && save_type & SAVE_TYPE_32_BIT) {
+ memset(work_buff2, 0, sizeof(work_buff2));
+ buf2 = work_buff2;
+ FixSimpleVarsAndScripts(save_type, buf, buf2, &size);
+ if (!PcSaveHelper.PcClassSaveRoutine(file_out, work_buff2, size))
+ goto fail;
+ totalSize += size;
+ } else
+ WriteSavaDataBlockNoFunc(buf, file_out, size);
LoadSaveDataBlockNoCheck(buf, file_in, size); // ped pool
WriteSavaDataBlockNoFunc(buf, file_out, size);
LoadSaveDataBlockNoCheck(buf, file_in, size); // garages
- FixSaveDataBlock(FixGarages, file_out, size); // garages need to be fixed in either case
+ if (!(save_type & SAVE_TYPE_STEAM && save_type & SAVE_TYPE_MSVC && save_type & SAVE_TYPE_32_BIT))
+ FixSaveDataBlock(FixGarages, file_out, size);
+ else
+ WriteSavaDataBlockNoFunc(buf, file_out, size);
+
+ LoadSaveDataBlockNoCheck(buf, file_in, size); // game logic
+ WriteSavaDataBlockNoFunc(buf, file_out, size);
LoadSaveDataBlockNoCheck(buf, file_in, size); // vehicle pool
WriteSavaDataBlockNoFunc(buf, file_out, size);
@@ -1077,10 +1137,7 @@ FixSave(int32 slot, uint8 save_type)
WriteSavaDataBlockNoFunc(buf, file_out, size);
LoadSaveDataBlockNoCheck(buf, file_in, size); // zones
- if (save_type & SAVE_TYPE_64_BIT)
- FixSaveDataBlock(FixZones, file_out, size);
- else
- WriteSavaDataBlockNoFunc(buf, file_out, size);
+ WriteSavaDataBlockNoFunc(buf, file_out, size);
LoadSaveDataBlockNoCheck(buf, file_in, size); // gang data
WriteSavaDataBlockNoFunc(buf, file_out, size);
@@ -1097,12 +1154,21 @@ FixSave(int32 slot, uint8 save_type)
LoadSaveDataBlockNoCheck(buf, file_in, size); // audio script objects
WriteSavaDataBlockNoFunc(buf, file_out, size);
+ LoadSaveDataBlockNoCheck(buf, file_in, size); // script paths
+ if (save_type & SAVE_TYPE_64_BIT)
+ FixSaveDataBlock(FixScriptPaths, file_out, size);
+ else
+ WriteSavaDataBlockNoFunc(buf, file_out, size);
+
LoadSaveDataBlockNoCheck(buf, file_in, size); // player info
WriteSavaDataBlockNoFunc(buf, file_out, size);
LoadSaveDataBlockNoCheck(buf, file_in, size); // stats
WriteSavaDataBlockNoFunc(buf, file_out, size);
+ LoadSaveDataBlockNoCheck(buf, file_in, size); // set pieces
+ WriteSavaDataBlockNoFunc(buf, file_out, size);
+
LoadSaveDataBlockNoCheck(buf, file_in, size); // streaming
WriteSavaDataBlockNoFunc(buf, file_out, size);
@@ -1154,15 +1220,20 @@ void DisplaySaveResult(int unk, char* name)
bool SaveGameForPause(int type)
{
- if (AllowMissionReplay != MISSION_RETRY_STAGE_NORMAL)
+ if (AllowMissionReplay != MISSION_RETRY_STAGE_NORMAL && AllowMissionReplay != MISSION_RETRY_STAGE_WAIT_FOR_TIMER_AFTER_RESTART) {
+ debug("SaveGameForPause failed during AllowMissionReplay %d", AllowMissionReplay);
return false;
- if (type != SAVE_TYPE_QUICKSAVE_FOR_MISSION_REPLAY && WaitForSave > CTimer::GetTimeInMilliseconds())
+ }
+ if (type != SAVE_TYPE_QUICKSAVE_FOR_MISSION_REPLAY && WaitForSave > CTimer::GetTimeInMilliseconds()) {
+ debug("SaveGameForPause failed WaitForSave");
return false;
+ }
WaitForSave = 0;
- if (gGameState != GS_PLAYING_GAME || CTheScripts::IsPlayerOnAMission() || CStats::LastMissionPassedName[0] == '\0') {
+ if (gGameState != GS_PLAYING_GAME || (CTheScripts::bAlreadyRunningAMissionScript && type != SAVE_TYPE_QUICKSAVE_FOR_SCRIPT_ON_A_MISSION)) {
DisplaySaveResult(3, CStats::LastMissionPassedName);
return false;
}
+ debug("SaveGameForPause ******************************** %s doSave %d", CStats::LastMissionPassedName, !CTheScripts::bAlreadyRunningAMissionScript);
IsQuickSave = type;
MissionStartTime = 0;
int res = PcSaveHelper.SaveSlot(PAUSE_SAVE_SLOT);
diff --git a/src/save/GenericGameStorage.h b/src/save/GenericGameStorage.h
index 6a5b04fa..bebf426a 100644
--- a/src/save/GenericGameStorage.h
+++ b/src/save/GenericGameStorage.h
@@ -5,6 +5,9 @@
#define SLOT_COUNT (8)
+void InitRadioStationPositionList();
+int32 GetSavedRadioStationPosition(int32 station);
+void PopulateRadioStationPositionList();
bool GenericSave(int file);
bool GenericLoad();
bool ReadInSizeofSaveFileBuffer(int32 &file, uint32 &size);
@@ -27,8 +30,6 @@ uint8 GetSaveType(char *savename);
bool FixSave(int32 slot, uint8 save_type);
#endif
-extern class CDate CompileDateAndTime;
-
extern char DefaultPCSaveFileName[260];
extern char ValidSaveName[260];
extern char LoadFileName[256];
@@ -36,7 +37,7 @@ extern wchar SlotFileName[SLOT_COUNT][260];
extern wchar SlotSaveDate[SLOT_COUNT][70];
extern int CheckSum;
extern enum eLevelName m_LevelToLoad;
-extern int Slots[SLOT_COUNT+1];
+extern int Slots[SLOT_COUNT];
extern bool b_FoundRecentSavedGameWantToLoad;
extern bool JustLoadedDontFadeInYet;
@@ -57,7 +58,9 @@ enum {
SAVE_TYPE_NORMAL,
SAVE_TYPE_QUICKSAVE,
SAVE_TYPE_2,
- SAVE_TYPE_QUICKSAVE_FOR_MISSION_REPLAY
+ SAVE_TYPE_QUICKSAVE_FOR_MISSION_REPLAY,
+ SAVE_TYPE_QUICKSAVE_FOR_SCRIPT,
+ SAVE_TYPE_QUICKSAVE_FOR_SCRIPT_ON_A_MISSION
};
#endif
diff --git a/src/save/PCSave.cpp b/src/save/PCSave.cpp
index 0c228a6d..a33e9d90 100644
--- a/src/save/PCSave.cpp
+++ b/src/save/PCSave.cpp
@@ -19,7 +19,7 @@ C_PcSave PcSaveHelper;
void
C_PcSave::SetSaveDirectory(const char *path)
{
- sprintf(DefaultPCSaveFileName, "%s\\%s", path, "GTA3sf");
+ sprintf(DefaultPCSaveFileName, "%s\\%s", path, "GTAVCsf");
}
bool
@@ -38,7 +38,7 @@ C_PcSave::DeleteSlot(int32 slot)
return true;
}
-bool
+int8
C_PcSave::SaveSlot(int32 slot)
{
MakeValidSaveName(slot);
@@ -53,10 +53,10 @@ C_PcSave::SaveSlot(int32 slot)
if (GenericSave(file)) {
if (!!CFileMgr::CloseFile(file))
nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE;
- return true;
+ return 0;
}
- return false;
+ return 2;
}
PcSaveHelper.nErrorCode = SAVESTATUS_ERR_SAVE_CREATE;
return false;
@@ -93,7 +93,7 @@ void
C_PcSave::PopulateSlotInfo()
{
for (int i = 0; i < SLOT_COUNT; i++) {
- Slots[i + 1] = SLOT_EMPTY;
+ Slots[i] = SLOT_EMPTY;
SlotFileName[i][0] = '\0';
SlotSaveDate[i][0] = '\0';
}
@@ -113,19 +113,19 @@ C_PcSave::PopulateSlotInfo()
if (file != 0) {
CFileMgr::Read(file, (char*)&header, sizeof(header));
if (strncmp((char*)&header, TopLineEmptyFile, sizeof(TopLineEmptyFile)-1) != 0) {
- Slots[i + 1] = SLOT_OK;
+ Slots[i] = SLOT_OK;
memcpy(SlotFileName[i], &header.FileName, sizeof(header.FileName));
SlotFileName[i][24] = '\0';
}
CFileMgr::CloseFile(file);
}
- if (Slots[i + 1] == SLOT_OK) {
+ if (Slots[i] == SLOT_OK) {
if (CheckDataNotCorrupt(i, savename)) {
#ifdef FIX_INCOMPATIBLE_SAVES
if (!FixSave(i, GetSaveType(savename))) {
CMessages::InsertNumberInString(TheText.Get("FEC_SLC"), i + 1, -1, -1, -1, -1, -1, SlotFileName[i]);
- Slots[i + 1] = SLOT_CORRUPTED;
+ Slots[i] = SLOT_CORRUPTED;
continue;
}
#endif
@@ -159,7 +159,7 @@ C_PcSave::PopulateSlotInfo()
} else {
CMessages::InsertNumberInString(TheText.Get("FEC_SLC"), i + 1, -1, -1, -1, -1, -1, SlotFileName[i]);
- Slots[i + 1] = SLOT_CORRUPTED;
+ Slots[i] = SLOT_CORRUPTED;
}
}
}
diff --git a/src/save/PCSave.h b/src/save/PCSave.h
index 83471b5d..2a29fa95 100644
--- a/src/save/PCSave.h
+++ b/src/save/PCSave.h
@@ -32,7 +32,7 @@ public:
C_PcSave() : nErrorCode(SAVESTATUS_SUCCESSFUL) {}
void PopulateSlotInfo();
bool DeleteSlot(int32 slot);
- bool SaveSlot(int32 slot);
+ int8 SaveSlot(int32 slot);
bool PcClassSaveRoutine(int32 file, uint8 *data, uint32 size);
static void SetSaveDirectory(const char *path);
};
diff --git a/src/save/SaveBuf.h b/src/save/SaveBuf.h
index aad2e1a8..d0817e9a 100644
--- a/src/save/SaveBuf.h
+++ b/src/save/SaveBuf.h
@@ -18,24 +18,52 @@ SkipSaveBuf(uint8 *&buf, int32 skip)
#endif
}
-template <typename T>
inline void
-ReadSaveBuf(T* out, uint8 *&buf)
+SkipSaveBuf(uint8*& buf, uint32 &length, int32 skip)
+{
+ buf += skip;
+ length += skip;
+#ifdef VALIDATE_SAVE_SIZE
+ _saveBufCount += skip;
+#endif
+}
+
+template<typename T>
+inline void
+ReadSaveBuf(T *out, uint8 *&buf)
{
*out = *(T *)buf;
SkipSaveBuf(buf, sizeof(T));
}
-template <typename T>
+template<typename T>
+inline void
+ReadSaveBuf(T *out, uint8 *&buf, uint32 &length)
+{
+ *out = *(T *)buf;
+ SkipSaveBuf(buf, length, sizeof(T));
+}
+
+template<typename T>
inline T *
WriteSaveBuf(uint8 *&buf, const T &value)
{
- T *p = (T *)buf;
+ T *p = (T*)buf;
*p = value;
SkipSaveBuf(buf, sizeof(T));
return p;
}
+template<typename T>
+inline T *
+WriteSaveBuf(uint8 *&buf, uint32 &length, const T &value)
+{
+ T *p = (T*)buf;
+ *p = value;
+ SkipSaveBuf(buf, length, sizeof(T));
+ return p;
+}
+
#ifdef COMPATIBLE_SAVES
inline void
ZeroSaveBuf(uint8 *&buf, uint32 length)
@@ -45,14 +73,21 @@ ZeroSaveBuf(uint8 *&buf, uint32 length)
}
#endif
-#define SAVE_HEADER_SIZE (4 * sizeof(char) + sizeof(uint32))
+#define SAVE_HEADER_SIZE (4*sizeof(char)+sizeof(uint32))
-#define WriteSaveHeader(buf, a, b, c, d, size) \
- WriteSaveBuf(buf, a); \
- WriteSaveBuf(buf, b); \
- WriteSaveBuf(buf, c); \
- WriteSaveBuf(buf, d); \
- WriteSaveBuf(buf, (uint32)(size));
+#define WriteSaveHeader(buf,a,b,c,d,size) \
+ WriteSaveBuf(buf, a);\
+ WriteSaveBuf(buf, b);\
+ WriteSaveBuf(buf, c);\
+ WriteSaveBuf(buf, d);\
+ WriteSaveBuf<uint32>(buf, size);
+
+#define WriteSaveHeaderWithLength(buf,len,a,b,c,d,size) \
+ WriteSaveBuf(buf, len, a);\
+ WriteSaveBuf(buf, len, b);\
+ WriteSaveBuf(buf, len, c);\
+ WriteSaveBuf(buf, len, d);\
+ WriteSaveBuf(buf, len, (uint32)(size));
#ifdef VALIDATE_SAVE_SIZE
#define CheckSaveHeader(buf, a, b, c, d, size) do { \
@@ -68,6 +103,21 @@ ZeroSaveBuf(uint8 *&buf, uint32 length)
ReadSaveBuf(&_size, buf);\
assert(_size == size);\
} while(0)
+
+#define CheckSaveHeaderWithLength(buf,len,a,b,c,d,size) do { \
+ char _c; uint32 _size;\
+ ReadSaveBuf(&_c, buf, len);\
+ assert(_c == a);\
+ ReadSaveBuf(&_c, buf, len);\
+ assert(_c == b);\
+ ReadSaveBuf(&_c, buf, len);\
+ assert(_c == c);\
+ ReadSaveBuf(&_c, buf, len);\
+ assert(_c == d);\
+ ReadSaveBuf(&_size, buf, len);\
+ assert(_size == size);\
+ } while(0)
#else
#define CheckSaveHeader(buf, a, b, c, d, size) SkipSaveBuf(buf, 8);
-#endif \ No newline at end of file
+#define CheckSaveHeaderWithLength(buf, len, a, b, c, d, size) SkipSaveBuf(buf, 8);
+#endif