/* 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.syncBytes((byte *)backgroundTable[i].name, 9); s.syncBytes((byte *)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.syncBytes((byte *)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.syncBytes((byte *)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.syncBytes((byte *)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->scriptOffset); 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->frame); s.syncAsSint16LE(t->scale); s.syncAsSint16LE(t->backgroundIdx); s.syncAsSint16LE(t->scriptNumber); s.syncAsSint16LE(t->scriptOverlayIdx); s.syncAsUint32LE(dummyLong); s.syncAsSint16LE(t->saveWidth); s.syncAsSint16LE(t->saveHeight); s.syncAsSint16LE(t->saveSize); s.syncAsSint16LE(t->savedX); s.syncAsSint16LE(t->savedY); s.syncBytes((byte *)t->name, 13); s.syncAsByte(dummyByte); s.syncAsSint16LE(t->spriteId); s.syncAsUint16LE(dummyWord); if (t->saveSize) { if (s.isLoading()) t->ptr = (byte *)malloc(t->saveSize); s.syncBytes(t->ptr, t->saveSize); } 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.syncBytes((byte *)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->err()) { 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