scummvm/engines/cruise/saveload.cpp

953 lines
23 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*
*/
#include "cruise/cruise_main.h"
#include "cruise/cruise.h"
#include "common/serializer.h"
#include "common/savefile.h"
#include "common/system.h"
#include "graphics/scaler.h"
#include "graphics/thumbnail.h"
namespace Cruise {
struct overlayRestoreTemporary {
int _sBssSize;
uint8* _pBss;
int _sNumObj;
objectParams* _pObj;
};
overlayRestoreTemporary ovlRestoreData[90];
bool readSavegameHeader(Common::InSaveFile *in, CruiseSavegameHeader &header) {
char saveIdentBuffer[6];
header.thumbnail = NULL;
// Validate the header Id
in->read(saveIdentBuffer, 6);
if (strcmp(saveIdentBuffer, "SVMCR"))
return false;
header.version = in->readByte();
if (header.version != CRUISE_SAVEGAME_VERSION)
return false;
// Read in the string
header.saveName.clear();
char ch;
while ((ch = (char)in->readByte()) != '\0') header.saveName += ch;
// Get the thumbnail
header.thumbnail = new Graphics::Surface();
if (!Graphics::loadThumbnail(*in, *header.thumbnail)) {
delete header.thumbnail;
header.thumbnail = NULL;
return false;
}
return true;
}
void writeSavegameHeader(Common::OutSaveFile *out, CruiseSavegameHeader &header) {
// Write out a savegame header
char saveIdentBuffer[6];
strcpy(saveIdentBuffer, "SVMCR");
out->write(saveIdentBuffer, 6);
out->writeByte(CRUISE_SAVEGAME_VERSION);
// Write savegame name
out->write(header.saveName.c_str(), header.saveName.size() + 1);
// Create a thumbnail and save it
Graphics::Surface *thumb = new Graphics::Surface();
::createThumbnail(thumb, globalScreen, 320, 200, workpal);
Graphics::saveThumbnail(*out, *thumb);
delete thumb;
}
static void syncPalette(Common::Serializer &s, uint8 *p) {
// This is different from the original, where palette entries are 2 bytes each
s.syncBytes(p, NBCOLORS * 3);
}
static void syncBasicInfo(Common::Serializer &s) {
s.syncAsSint16LE(activeMouse);
s.syncAsSint16LE(userEnabled);
s.syncAsSint16LE(dialogueEnabled);
s.syncAsSint16LE(dialogueOvl);
s.syncAsSint16LE(dialogueObj);
s.syncAsSint16LE(userDelay);
s.syncAsSint16LE(sysKey);
s.syncAsSint16LE(sysX);
s.syncAsSint16LE(sysY);
s.syncAsSint16LE(automoveInc);
s.syncAsSint16LE(automoveMax);
s.syncAsSint16LE(displayOn);
s.syncAsSint16LE(isMessage);
s.syncAsSint16LE(fadeFlag);
s.syncAsSint16LE(automaticMode);
s.syncAsSint16LE(titleColor);
s.syncAsSint16LE(itemColor);
s.syncAsSint16LE(selectColor);
s.syncAsSint16LE(subColor);
s.syncAsSint16LE(narratorOvl);
s.syncAsSint16LE(narratorIdx);
s.syncAsSint16LE(aniX);
s.syncAsSint16LE(aniY);
s.syncAsUint16LE(animationStart);
s.syncAsSint16LE(masterScreen);
s.syncAsSint16LE(switchPal);
s.syncAsSint16LE(scroll);
s.syncAsSint16LE(fadeFlag);
s.syncAsSint16LE(doFade);
s.syncAsSint16LE(numOfLoadedOverlay);
s.syncAsSint16LE(stateID);
s.syncAsSint16LE(fontFileIndex);
s.syncAsSint16LE(currentActiveMenu);
s.syncAsSint16LE(userWait);
s.syncAsSint16LE(autoOvl);
s.syncAsSint16LE(autoMsg);
s.syncAsSint16LE(autoTrack);
s.syncAsSint16LE(var39);
s.syncAsSint16LE(var42);
s.syncAsSint16LE(var45);
s.syncAsSint16LE(var46);
s.syncAsSint16LE(var47);
s.syncAsSint16LE(var48);
s.syncAsSint16LE(flagCt);
s.syncAsSint16LE(var41);
s.syncAsSint16LE(playerMenuEnabled);
}
static void syncBackgroundTable(Common::Serializer &s) {
// restore backgroundTable
for (int i = 0; i < 8; i++) {
s.syncString(backgroundTable[i].name, 9);
s.syncString(backgroundTable[i].extention, 6);
}
}
static void syncPalScreen(Common::Serializer &s) {
for (int i = 0; i < NBSCREENS; ++i) {
for (int j = 0; j < NBCOLORS; ++j)
s.syncAsUint16LE(palScreen[i][j]);
}
}
static void syncSoundList(Common::Serializer &s) {
for (int i = 0; i < 4; ++i) {
SoundEntry &se = soundList[i];
s.syncAsSint16LE(se.frameNum);
s.syncAsUint16LE(se.frequency);
s.syncAsSint16LE(se.volume);
}
}
static void syncFilesDatabase(Common::Serializer &s) {
uint8 dummyVal = 0;
uint32 tmp;
for (int i = 0; i < NUM_FILE_ENTRIES; i++) {
dataFileEntry &fe = filesDatabase[i];
s.syncAsUint16LE(fe.widthInColumn);
s.syncAsUint16LE(fe.width);
s.syncAsUint16LE(fe.resType);
s.syncAsUint16LE(fe.height);
// TODO: Have a look at the saving/loading of this pointer
tmp = (fe.subData.ptr) ? 1 : 0;
s.syncAsUint32LE(tmp);
if (s.isLoading()) {
fe.subData.ptr = (uint8 *)tmp;
}
s.syncAsSint16LE(fe.subData.index);
s.syncString(fe.subData.name, 13);
s.syncAsByte(dummyVal);
s.syncAsSint16LE(fe.subData.transparency);
// TODO: Have a look at the saving/loading of this pointer
tmp = (fe.subData.ptrMask) ? 1 : 0;
s.syncAsUint32LE(tmp);
if (s.isLoading()) {
fe.subData.ptrMask = (uint8 *)tmp;
}
s.syncAsUint16LE(fe.subData.resourceType);
s.syncAsSint16LE(fe.subData.compression);
}
}
static void syncPreloadData(Common::Serializer &s) {
uint8 dummyByte = 0;
uint32 dummyLong = 0;
for (int i = 0; i < 64; i++) {
preloadStruct &pe = preloadData[i];
s.syncString(pe.name, 15);
s.syncAsByte(dummyByte);
s.syncAsUint32LE(pe.size);
s.syncAsUint32LE(pe.sourceSize);
s.syncAsUint32LE(dummyLong);
s.syncAsUint16LE(pe.nofree);
s.syncAsUint16LE(pe.protect);
s.syncAsUint16LE(pe.ovl);
}
}
static void syncOverlays1(Common::Serializer &s) {
uint8 dummyByte = 0;
uint32 dummyLong = 0;
for (int i = 0; i < numOfLoadedOverlay; i++) {
overlayStruct &oe = overlayTable[i];
s.syncString(oe.overlayName, 13);
s.syncAsByte(dummyByte);
s.syncAsUint32LE(dummyLong);
s.syncAsUint16LE(oe.alreadyLoaded);
s.syncAsUint16LE(oe.state);
s.syncAsUint32LE(dummyLong);
s.syncAsUint32LE(dummyLong);
s.syncAsUint32LE(dummyLong);
s.syncAsUint32LE(dummyLong);
s.syncAsUint16LE(oe.executeScripts);
}
}
static void syncOverlays2(Common::Serializer &s) {
for (int i = 1; i < numOfLoadedOverlay; i++) {
if (s.isSaving()) {
// Saving code
if (!overlayTable[i].alreadyLoaded)
continue;
ovlDataStruct *ovlData = overlayTable[i].ovlData;
// save BSS
s.syncAsSint16LE(ovlData->sizeOfData4);
if (ovlData->sizeOfData4)
// FIXME: Endian and structure packing problems for this data pointer
s.syncBytes(ovlData->data4Ptr, ovlData->sizeOfData4);
// save variables
s.syncAsSint16LE(ovlData->size9);
for (int j = 0; j < ovlData->size9; j++) {
s.syncAsSint16LE(ovlData->arrayObjVar[j].X);
s.syncAsSint16LE(ovlData->arrayObjVar[j].Y);
s.syncAsSint16LE(ovlData->arrayObjVar[j].Z);
s.syncAsSint16LE(ovlData->arrayObjVar[j].frame);
s.syncAsSint16LE(ovlData->arrayObjVar[j].scale);
s.syncAsSint16LE(ovlData->arrayObjVar[j].state);
}
} else {
// Loading code
ovlRestoreData[i]._sBssSize = ovlRestoreData[i]._sNumObj = 0;
ovlRestoreData[i]._pBss = NULL;
ovlRestoreData[i]._pObj = NULL;
if (overlayTable[i].alreadyLoaded) {
s.syncAsSint16LE(ovlRestoreData[i]._sBssSize);
if (ovlRestoreData[i]._sBssSize) {
ovlRestoreData[i]._pBss = (uint8 *) mallocAndZero(ovlRestoreData[i]._sBssSize);
ASSERT(ovlRestoreData[i]._pBss);
s.syncBytes(ovlRestoreData[i]._pBss, ovlRestoreData[i]._sBssSize);
}
s.syncAsSint16LE(ovlRestoreData[i]._sNumObj);
if (ovlRestoreData[i]._sNumObj) {
ovlRestoreData[i]._pObj = (objectParams *) mallocAndZero(ovlRestoreData[i]._sNumObj * sizeof(objectParams));
ASSERT(ovlRestoreData[i]._pObj);
for (int j = 0; j < ovlRestoreData[i]._sNumObj; j++) {
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].X);
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].Y);
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].Z);
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].frame);
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].scale);
s.syncAsSint16LE(ovlRestoreData[i]._pObj[j].state);
}
}
}
}
}
}
void syncScript(Common::Serializer &s, scriptInstanceStruct *entry) {
int numScripts = 0;
uint32 dummyLong = 0;
uint16 dummyWord = 0;
if (s.isSaving()) {
// Figure out the number of scripts to save
scriptInstanceStruct* pCurrent = entry->nextScriptPtr;
while (pCurrent) {
++numScripts;
pCurrent = pCurrent->nextScriptPtr;
}
}
s.syncAsSint16LE(numScripts);
scriptInstanceStruct *ptr = entry->nextScriptPtr;
for (int i = 0; i < numScripts; ++i) {
if (s.isLoading())
ptr = (scriptInstanceStruct *)mallocAndZero(sizeof(scriptInstanceStruct));
s.syncAsUint16LE(dummyWord);
s.syncAsSint16LE(ptr->ccr);
s.syncAsSint16LE(ptr->var4);
s.syncAsUint32LE(dummyLong);
s.syncAsSint16LE(ptr->varA);
s.syncAsSint16LE(ptr->scriptNumber);
s.syncAsSint16LE(ptr->overlayNumber);
s.syncAsSint16LE(ptr->sysKey);
s.syncAsSint16LE(ptr->freeze);
s.syncAsSint16LE(ptr->type);
s.syncAsSint16LE(ptr->var16);
s.syncAsSint16LE(ptr->var18);
s.syncAsSint16LE(ptr->var1A);
s.syncAsSint16LE(ptr->varA);
if (ptr->varA) {
// FIXME: This code is not endian safe, and breaks if struct
// packing changes. Read/write the members one by one instead.
if (s.isLoading())
ptr->var6 = (byte *)mallocAndZero(ptr->varA);
s.syncBytes(ptr->var6, ptr->varA);
}
if (s.isLoading()) {
ptr->nextScriptPtr = NULL;
entry->nextScriptPtr = ptr;
entry = ptr;
} else {
ptr = ptr->nextScriptPtr;
}
}
}
static void syncCell(Common::Serializer &s) {
int chunkCount = 0;
cellStruct *t, *p;
uint16 dummyWord = 0;
if (s.isSaving()) {
// Figure out the number of chunks to save
t = cellHead.next;
while (t) {
++chunkCount;
t = t->next;
}
} else {
cellHead.next = NULL; // Not in ASM code, but I guess the variable is defaulted in the EXE
}
s.syncAsSint16LE(chunkCount);
t = s.isSaving() ? cellHead.next : &cellHead;
for (int i = 0; i < chunkCount; ++i) {
p = s.isSaving() ? t : (cellStruct *)mallocAndZero(sizeof(cellStruct));
s.syncAsUint16LE(dummyWord);
s.syncAsUint16LE(dummyWord);
s.syncAsSint16LE(p->idx);
s.syncAsSint16LE(p->type);
s.syncAsSint16LE(p->overlay);
s.syncAsSint16LE(p->x);
s.syncAsSint16LE(p->field_C);
s.syncAsSint16LE(p->spriteIdx);
s.syncAsSint16LE(p->color);
s.syncAsSint16LE(p->backgroundPlane);
s.syncAsSint16LE(p->freeze);
s.syncAsSint16LE(p->parent);
s.syncAsSint16LE(p->parentOverlay);
s.syncAsSint16LE(p->parentType);
s.syncAsSint16LE(p->followObjectOverlayIdx);
s.syncAsSint16LE(p->followObjectIdx);
s.syncAsSint16LE(p->animStart);
s.syncAsSint16LE(p->animEnd);
s.syncAsSint16LE(p->animWait);
s.syncAsSint16LE(p->animStep);
s.syncAsSint16LE(p->animChange);
s.syncAsSint16LE(p->animType);
s.syncAsSint16LE(p->animSignal);
s.syncAsSint16LE(p->animCounter);
s.syncAsSint16LE(p->animLoop);
s.syncAsUint16LE(dummyWord);
if (s.isSaving())
t = t->next;
else {
p->next = NULL;
t->next = p;
p->prev = cellHead.prev;
cellHead.prev = p;
t = p;
}
}
}
static void syncIncrust(Common::Serializer &s) {
int numEntries = 0;
backgroundIncrustStruct *pl, *pl1;
uint8 dummyByte = 0;
uint16 dummyWord = 0;
uint32 dummyLong = 0;
if (s.isSaving()) {
// Figure out the number of entries to save
pl = backgroundIncrustHead.next;
while (pl) {
++numEntries;
pl = pl->next;
}
}
s.syncAsSint16LE(numEntries);
pl = s.isSaving() ? backgroundIncrustHead.next : &backgroundIncrustHead;
pl1 = &backgroundIncrustHead;
for (int i = 0; i < numEntries; ++i) {
backgroundIncrustStruct *t = s.isSaving() ? pl :
(backgroundIncrustStruct *)mallocAndZero(sizeof(backgroundIncrustStruct));
s.syncAsUint32LE(dummyLong);
s.syncAsSint16LE(t->objectIdx);
s.syncAsSint16LE(t->type);
s.syncAsSint16LE(t->overlayIdx);
s.syncAsSint16LE(t->X);
s.syncAsSint16LE(t->Y);
s.syncAsSint16LE(t->field_E);
s.syncAsSint16LE(t->scale);
s.syncAsSint16LE(t->backgroundIdx);
s.syncAsSint16LE(t->scriptNumber);
s.syncAsSint16LE(t->scriptOverlayIdx);
s.syncAsUint32LE(dummyLong);
int tmp = t->saveWidth / 2;
s.syncAsSint16LE(tmp);
t->saveWidth = tmp * 2;
s.syncAsSint16LE(t->saveHeight);
s.syncAsSint16LE(t->saveSize);
s.syncAsSint16LE(t->savedX);
s.syncAsSint16LE(t->savedY);
s.syncString(t->name, 13);
s.syncAsByte(dummyByte);
s.syncAsSint16LE(t->spriteId);
s.syncAsUint16LE(dummyWord);
if (t->saveSize) {
byte *buffer = (byte *)malloc(t->saveSize);
memset(buffer, 0, t->saveSize);
s.syncBytes(buffer, t->saveSize);
free(buffer);
// TODO: convert graphic format here
if (s.isLoading()) {
int width = t->saveWidth;
int height = t->saveHeight;
t->ptr = (uint8*)malloc(width * height);
memset(t->ptr, 0, width * height);
}
}
if (s.isSaving())
pl = pl->next;
else {
t->next = NULL;
pl->next = t;
t->prev = pl1->prev;
pl1->prev = t;
pl = t;
}
}
}
static void syncActors(Common::Serializer &s) {
int numEntries = 0;
actorStruct *ptr;
uint16 dummyLong = 0;
if (s.isSaving()) {
ptr = actorHead.next;
while (ptr) {
++numEntries;
ptr = ptr->next;
}
}
s.syncAsSint16LE(numEntries);
ptr = s.isSaving() ? actorHead.next : &actorHead;
for (int i = 0; i < numEntries; ++i) {
actorStruct *p = s.isSaving() ? ptr : (actorStruct *)mallocAndZero(sizeof(actorStruct));
s.syncAsUint32LE(dummyLong);
s.syncAsSint16LE(p->idx);
s.syncAsSint16LE(p->type);
s.syncAsSint16LE(p->overlayNumber);
s.syncAsSint16LE(p->x_dest);
s.syncAsSint16LE(p->y_dest);
s.syncAsSint16LE(p->x);
s.syncAsSint16LE(p->y);
s.syncAsSint16LE(p->startDirection);
s.syncAsSint16LE(p->nextDirection);
s.syncAsSint16LE(p->endDirection);
s.syncAsSint16LE(p->stepX);
s.syncAsSint16LE(p->stepY);
s.syncAsSint16LE(p->pathId);
s.syncAsSint16LE(p->phase);
s.syncAsSint16LE(p->counter);
s.syncAsSint16LE(p->poly);
s.syncAsSint16LE(p->flag);
s.syncAsSint16LE(p->start);
s.syncAsSint16LE(p->freeze);
if (s.isSaving())
ptr = ptr->next;
else {
p->next = NULL;
ptr->next = p;
p->prev = actorHead.prev;
actorHead.prev = p;
ptr = p->next;
}
}
}
static void syncSongs(Common::Serializer &s) {
int size = 0;
if (songLoaded) {
// TODO: implement
s.syncAsByte(size);
if (s.isLoading()) {
saveVar1 = size;
if (saveVar1)
s.syncBytes(saveVar2, saveVar1);
}
} else {
s.syncAsByte(size);
}
}
static void syncCT(Common::Serializer &s) {
int v = (polyStruct) ? 1 : 0;
s.syncAsSint32LE(v);
if (v == 0)
// There is no further data to load or save
return;
s.syncAsSint16LE(numberOfWalkboxes);
if (numberOfWalkboxes) {
for (int i = 0; i < numberOfWalkboxes; ++i)
s.syncAsSint16LE(walkboxColor[i]);
for (int i = 0; i < numberOfWalkboxes; ++i)
s.syncAsSint16LE(walkboxState[i]);
}
for (int i = 0; i < 10; i++) {
v = 0;
if (s.isSaving()) v = (persoTable[i]) ? 1 : 0;
s.syncAsSint32LE(v);
if (s.isLoading())
// Set up the pointer for the next structure
persoTable[i] = (v == 0) ? NULL : (persoStruct *)mallocAndZero(sizeof(persoStruct));
if (v != 0) {
// FIXME: This code is not endian safe, and breaks if struct
// packing changes. Read/write the members one by one instead.
assert(sizeof(persoStruct) == 0x6AA);
s.syncBytes((byte *)persoTable[i], 0x6AA);
}
}
}
static void DoSync(Common::Serializer &s) {
syncBasicInfo(s);
_vm->music().doSync(s);
syncPalette(s, newPal);
syncPalette(s, workpal);
s.syncString(currentCtpName, 40);
syncBackgroundTable(s);
syncPalScreen(s);
syncSoundList(s);
for (int i = 0; i < stateID; ++i)
s.syncAsSint16LE(globalVars[i]);
syncFilesDatabase(s);
syncOverlays1(s);
syncPreloadData(s);
syncOverlays2(s);
syncScript(s, &procHead);
syncScript(s, &relHead);
syncCell(s);
syncIncrust(s);
syncActors(s);
syncSongs(s);
syncCT(s);
}
void resetPreload() {
for (unsigned long int i = 0; i < 64; i++) {
if (strlen(preloadData[i].name)) {
if (preloadData[i].ptr) {
free(preloadData[i].ptr);
preloadData[i].ptr = NULL;
}
strcpy(preloadData[i].name, "");
preloadData[i].nofree = 0;
}
}
}
void unloadOverlay(const char*name, int overlayNumber) {
releaseOverlay(name);
strcpy(overlayTable[overlayNumber].overlayName, "");
overlayTable[overlayNumber].ovlData = NULL;
overlayTable[overlayNumber].alreadyLoaded = 0;
}
void initVars(void) {
closeAllMenu();
resetFileEntryRange(0, NUM_FILE_ENTRIES);
resetPreload();
freeCTP();
freezeCell(&cellHead, -1, -1, -1, -1, -1, 0);
// TODO: unfreeze anims
freeObjectList(&cellHead);
removeAnimation(&actorHead, -1, -1, -1);
changeScriptParamInList(-1, -1, &procHead, -1, 0);
removeFinishedScripts(&procHead);
changeScriptParamInList(-1, -1, &relHead, -1, 0);
removeFinishedScripts(&relHead);
for (unsigned long int i = 0; i < 90; i++) {
if (strlen(overlayTable[i].overlayName) && overlayTable[i].alreadyLoaded) {
unloadOverlay(overlayTable[i].overlayName, i);
}
}
// TODO:
// stopSound();
// removeSound();
closeBase();
closeCnf();
initOverlayTable();
stateID = 0;
masterScreen = 0;
freeDisk();
soundList[0].frameNum = -1;
soundList[1].frameNum = -1;
soundList[2].frameNum = -1;
soundList[3].frameNum = -1;
for (unsigned long int i = 0; i < 8; i++) {
menuTable[i] = NULL;
}
for (unsigned long int i = 0; i < 2000; i++) {
globalVars[i] = 0;
}
for (unsigned long int i = 0; i < 8; i++) {
backgroundTable[i].name[0] = 0;
}
for (unsigned long int i = 0; i < NUM_FILE_ENTRIES; i++) {
filesDatabase[i].subData.ptr = NULL;
filesDatabase[i].subData.ptrMask = NULL;
}
initBigVar3();
resetPtr2(&procHead);
resetPtr2(&relHead);
resetPtr(&cellHead);
resetActorPtr(&actorHead);
resetBackgroundIncrustList(&backgroundIncrustHead);
vblLimit = 0;
remdo = 0;
songLoaded = 0;
songPlayed = 0;
songLoop = 1;
activeMouse = 0;
userEnabled = 1;
dialogueEnabled = 0;
dialogueOvl = 0;
dialogueObj = 0;
userDelay = 0;
sysKey = -1;
sysX = 0;
sysY = 0;
automoveInc = 0;
automoveMax = 0;
displayOn = true;
// here used to init clip
isMessage = 0;
fadeFlag = 0;
automaticMode = 0;
// video param (vga and mcga mode)
titleColor = 2;
itemColor = 1;
selectColor = 3;
subColor = 5;
//
narratorOvl = 0;
narratorIdx = 0;
aniX = 0;
aniY = 0;
animationStart = false;
selectDown = 0;
menuDown = 0;
buttonDown = 0;
var41 = 0;
playerMenuEnabled = 0;
PCFadeFlag = 0;
}
Common::Error saveSavegameData(int saveGameIdx, const Common::String &saveName) {
const char *filename = _vm->getSavegameFile(saveGameIdx);
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
Common::OutSaveFile *f = saveMan->openForSaving(filename);
if (f == NULL)
return Common::kNoGameDataFoundError;
// Save the savegame header
CruiseSavegameHeader header;
header.saveName = saveName;
writeSavegameHeader(f, header);
if (f->ioFailed()) {
delete f;
saveMan->removeSavefile(filename);
return Common::kWritingFailed;
} else {
// Create the remainder of the savegame
Common::Serializer s(NULL, f);
DoSync(s);
f->finalize();
delete f;
return Common::kNoError;
}
}
Common::Error loadSavegameData(int saveGameIdx) {
int lowMemorySave;
Common::String saveName;
cellStruct *currentcellHead;
Common::SaveFileManager *saveMan = g_system->getSavefileManager();
Common::InSaveFile *f = saveMan->openForLoading(_vm->getSavegameFile(saveGameIdx));
if (f == NULL) {
printInfoBlackBox("Savegame not found...");
waitForPlayerInput();
return Common::kNoGameDataFoundError;
}
printInfoBlackBox("Loading in progress...");
initVars();
// Skip over the savegame header
CruiseSavegameHeader header;
readSavegameHeader(f, header);
if (header.thumbnail) delete header.thumbnail;
// Synchronise the remaining data of the savegame
Common::Serializer s(f, NULL);
DoSync(s);
delete f;
// Post processing
for (int j = 0; j < 64; j++)
preloadData[j].ptr = NULL;
for (int j = 1; j < numOfLoadedOverlay; j++) {
if (overlayTable[j].alreadyLoaded) {
overlayTable[j].alreadyLoaded = 0;
loadOverlay(overlayTable[j].overlayName);
if (overlayTable[j].alreadyLoaded) {
ovlDataStruct *ovlData = overlayTable[j].ovlData;
// overlay BSS
if (ovlRestoreData[j]._sBssSize) {
if (ovlData->data4Ptr) {
free(ovlData->data4Ptr);
}
ovlData->data4Ptr = ovlRestoreData[j]._pBss;
ovlData->sizeOfData4 = ovlRestoreData[j]._sBssSize;
}
// overlay object data
if (ovlRestoreData[j]._sNumObj) {
if (ovlData->arrayObjVar) {
free(ovlData->arrayObjVar);
}
ovlData->arrayObjVar = ovlRestoreData[j]._pObj;
ovlData->size9 = ovlRestoreData[j]._sNumObj;
}
}
}
}
updateAllScriptsImports();
lastAni[0] = 0;
lowMemorySave = lowMemory;
for (int i = 0; i < NUM_FILE_ENTRIES; i++) {
if (filesDatabase[i].subData.ptr) {
int j;
int k;
for (j = i + 1; j < NUM_FILE_ENTRIES && filesDatabase[j].subData.ptr && !strcmp(filesDatabase[i].subData.name, filesDatabase[j].subData.name) && (filesDatabase[j].subData.index == (j - i)); j++)
;
for (k = i; k < j; k++) {
if (filesDatabase[k].subData.ptrMask)
lowMemory = 0;
filesDatabase[k].subData.ptr = NULL;
filesDatabase[k].subData.ptrMask = NULL;
}
/*if (j < 2) {
printf("Unsupported mono file load!\n");
ASSERT(0);
//loadFileMode1(filesDatabase[j].subData.name,filesDatabase[j].subData.var4);
} else */{
loadFileRange(filesDatabase[i].subData.name, filesDatabase[i].subData.index, i, j - i);
i = j - 1;
}
lowMemory = lowMemorySave;
}
}
lastAni[0] = 0;
currentcellHead = cellHead.next;
while (currentcellHead) {
if (currentcellHead->type == 5) {
uint8 *ptr = mainProc14(currentcellHead->overlay, currentcellHead->idx);
ASSERT(0);
if (ptr) {
ASSERT(0);
//*(int16*)(currentcellHead->datas+0x2E) = getSprite(ptr,*(int16*)(currentcellHead->datas+0xE));
} else {
ASSERT(0);
//*(int16*)(currentcellHead->datas+0x2E) = 0;
}
}
currentcellHead = currentcellHead->next;
}
//TODO: here, restart music
if (strlen(currentCtpName)) {
loadCtFromSave = 1;
initCt(currentCtpName);
loadCtFromSave = 0;
}
//prepareFadeOut();
//gfxModuleData.gfxFunction8();
for (int j = 0; j < 8; j++) {
if (strlen((char *)backgroundTable[j].name)) {
loadBackground(backgroundTable[j].name, j);
}
}
regenerateBackgroundIncrust(&backgroundIncrustHead);
// to finish
changeCursor(CURSOR_NORMAL);
mainDraw(1);
flipScreen();
return Common::kNoError;
}
} // End of namespace Cruise