diff options
Diffstat (limited to 'engines/sludge/loadsave.cpp')
-rw-r--r-- | engines/sludge/loadsave.cpp | 678 |
1 files changed, 678 insertions, 0 deletions
diff --git a/engines/sludge/loadsave.cpp b/engines/sludge/loadsave.cpp new file mode 100644 index 0000000000..8641a67a7d --- /dev/null +++ b/engines/sludge/loadsave.cpp @@ -0,0 +1,678 @@ +/* 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. + * + */ +#include "allfiles.h" +#include "sprites.h" +#include "fonttext.h" +#include "newfatal.h" +#include "variable.h" +#include "CommonCode/version.h" +#include "language.h" +#include "moreio.h" +#include "sludger.h" +#include "people.h" +#include "talk.h" +#include "objtypes.h" +#include "backdrop.h" +#include "region.h" +#include "floor.h" +#include "zbuffer.h" +#include "cursors.h" +#include "statusba.h" +#include "sound.h" +#include "fileset.h" +#include "debug.h" + +//---------------------------------------------------------------------- +// From elsewhere +//---------------------------------------------------------------------- + +extern loadedFunction *allRunningFunctions; // In sludger.cpp +extern char *typeName[]; // In variable.cpp +extern int numGlobals; // In sludger.cpp +extern variable *globalVars; // In sludger.cpp +extern flor *currentFloor; // In floor.cpp +extern zBufferData zBuffer; // In zbuffer.cpp +extern speechStruct *speech; // In talk.cpp +extern personaAnimation *mouseCursorAnim; // In cursor.cpp +extern int mouseCursorFrameNum; // " " " +extern int loadedFontNum, fontHeight, fontTableSize; // In fonttext.cpp +extern int numFontColours; // " " " +extern char *fontOrderString; // " " " +extern FILETIME fileTime; // In sludger.cpp +extern int speechMode; // " " " +extern int lightMapNumber; // In backdrop.cpp +extern unsigned int sceneWidth, sceneHeight; // " " " +extern int cameraX, cameraY; // " " " +extern float cameraZoom; +extern unsigned char brightnessLevel; // " " " +extern short fontSpace; // in textfont.cpp +extern unsigned char fadeMode; // In transition.cpp +extern bool captureAllKeys; +extern bool allowAnyFilename; +extern unsigned short saveEncoding; // in savedata.cpp +extern unsigned char currentBurnR, currentBurnG, currentBurnB; +extern unsigned int currentBlankColour; // in backdrop.cpp +extern parallaxLayer *parallaxStuff; // " +extern int lightMapMode; // " +extern int languageNum; + + +//---------------------------------------------------------------------- +// Globals (so we know what's saved already and what's a reference +//---------------------------------------------------------------------- + +struct stackLibrary { + stackHandler *stack; + stackLibrary *next; +}; + +int stackLibTotal = 0; +stackLibrary *stackLib = NULL; + +//---------------------------------------------------------------------- +// For saving and loading stacks... +//---------------------------------------------------------------------- +#if ALLOW_FILE +bool saveVariable(variable *from, FILE *fp); +bool loadVariable(variable *to, FILE *fp); + +void saveStack(variableStack *vs, FILE *fp) { + int elements = 0; + int a; + + variableStack *search = vs; + while (search) { + elements ++; + search = search -> next; + } + + stackDebug((stackfp, " stack contains %d elements\n", elements)); + + put2bytes(elements, fp); + search = vs; + for (a = 0; a < elements; a ++) { + saveVariable(& search -> thisVar, fp); + search = search -> next; + } +} + +variableStack *loadStack(FILE *fp, variableStack **last) { + int elements = get2bytes(fp); + int a; + variableStack *first = NULL; + variableStack * * changeMe = & first; + + for (a = 0; a < elements; a ++) { + variableStack *nS = new variableStack; + if (!checkNew(nS)) return NULL; + loadVariable(& (nS -> thisVar), fp); + if (last && a == elements - 1) { + stackDebug((stackfp, "Setting last to %p\n", nS)); + *last = nS; + } + nS -> next = NULL; + (* changeMe) = nS; + changeMe = & (nS -> next); + } + + return first; +} + +bool saveStackRef(stackHandler *vs, FILE *fp) { + stackLibrary *s = stackLib; + int a = 0; + while (s) { + if (s -> stack == vs) { + fputc(1, fp); + put2bytes(stackLibTotal - a, fp); + return true; + } + s = s -> next; + a ++; + } + fputc(0, fp); + saveStack(vs -> first, fp); + s = new stackLibrary; + stackLibTotal ++; + if (! checkNew(s)) return false; + s -> next = stackLib; + s -> stack = vs; + stackLib = s; + return true; +} +#endif + +void clearStackLib() { + stackLibrary *k; + while (stackLib) { + k = stackLib; + stackLib = stackLib -> next; + delete k; + } + stackLibTotal = 0; +} + +stackHandler *getStackFromLibrary(int n) { + n = stackLibTotal - n; + while (n) { + stackLib = stackLib -> next; + n --; + } + return stackLib -> stack; +} +#if ALLOW_FILE +stackHandler *loadStackRef(FILE *fp) { + stackHandler *nsh; + + if (fgetc(fp)) { // It's one we've loaded already... + stackDebug((stackfp, "loadStackRef (duplicate, get from library)\n")); + + nsh = getStackFromLibrary(get2bytes(fp)); + nsh -> timesUsed ++; + } else { + stackDebug((stackfp, "loadStackRef (new one)\n")); + + // Load the new stack + + nsh = new stackHandler; + if (! checkNew(nsh)) return NULL; + nsh -> last = NULL; + nsh -> first = loadStack(fp, & nsh->last); + nsh -> timesUsed = 1; + stackDebug((stackfp, " first = %p\n", nsh->first)); + if (nsh->first) + stackDebug((stackfp, " first->next = %p\n", nsh->first->next)); + stackDebug((stackfp, " last = %p\n", nsh->last)); + if (nsh->last) + stackDebug((stackfp, " last->next = %p\n", nsh->last->next)); + + // Add it to the library of loaded stacks + + stackLibrary *s = new stackLibrary; + if (! checkNew(s)) return NULL; + s -> stack = nsh; + s -> next = stackLib; + stackLib = s; + stackLibTotal ++; + } + return nsh; +} + +//---------------------------------------------------------------------- +// For saving and loading variables... +//---------------------------------------------------------------------- + +bool saveVariable(variable *from, FILE *fp) { +#if DEBUG_STACKINESS + { + char *str = getTextFromAnyVar(*from); + stackDebug((stackfp, "in saveVariable, type %d, %s\n", from->varType, str)); + delete str; + } +#endif + + fputc(from -> varType, fp); + switch (from -> varType) { + case SVT_INT: + case SVT_FUNC: + case SVT_BUILT: + case SVT_FILE: + case SVT_OBJTYPE: + put4bytes(from -> varData.intValue, fp); + return true; + + case SVT_STRING: + writeString(from -> varData.theString, fp); + return true; + + case SVT_STACK: + return saveStackRef(from -> varData.theStack, fp); + + case SVT_COSTUME: + saveCostume(from -> varData.costumeHandler, fp); + return false; + + case SVT_ANIM: + saveAnim(from -> varData.animHandler, fp); + return false; + + case SVT_NULL: + return false; + + default: + fatal("Can't save variables of this type:", + (from->varType < SVT_NUM_TYPES) ? + typeName[from->varType] : + "bad ID"); + } + return true; +} + +bool loadVariable(variable *to, FILE *fp) { + to -> varType = (variableType) fgetc(fp); + switch (to -> varType) { + case SVT_INT: + case SVT_FUNC: + case SVT_BUILT: + case SVT_FILE: + case SVT_OBJTYPE: + to -> varData.intValue = get4bytes(fp); + return true; + + case SVT_STRING: + to -> varData.theString = readString(fp); + return true; + + case SVT_STACK: + to -> varData.theStack = loadStackRef(fp); +#if DEBUG_STACKINESS + { + char *str = getTextFromAnyVar(*to); + stackDebug((stackfp, "just loaded %s\n", str)); + delete str; + } +#endif + return true; + + case SVT_COSTUME: + to -> varData.costumeHandler = new persona; + if (! checkNew(to -> varData.costumeHandler)) return false; + loadCostume(to -> varData.costumeHandler, fp); + return true; + + case SVT_ANIM: + to -> varData.animHandler = new personaAnimation; + if (! checkNew(to -> varData.animHandler)) return false; + loadAnim(to -> varData.animHandler, fp); + return true; + + default: + break; + } + return true; +} + +//---------------------------------------------------------------------- +// For saving and loading functions +//---------------------------------------------------------------------- + +void saveFunction(loadedFunction *fun, FILE *fp) { + int a; + put2bytes(fun -> originalNumber, fp); + if (fun -> calledBy) { + fputc(1, fp); + saveFunction(fun -> calledBy, fp); + } else { + fputc(0, fp); + } + put4bytes(fun -> timeLeft, fp); + put2bytes(fun -> runThisLine, fp); + fputc(fun -> cancelMe, fp); + fputc(fun -> returnSomething, fp); + fputc(fun -> isSpeech, fp); + saveVariable(& (fun -> reg), fp); + + if (fun -> freezerLevel) { + fatal(ERROR_GAME_SAVE_FROZEN); + } + saveStack(fun -> stack, fp); + for (a = 0; a < fun -> numLocals; a ++) { + saveVariable(& (fun -> localVars[a]), fp); + } +} + + +loadedFunction *loadFunction(FILE *fp) { + int a; + + // Reserve memory... + + loadedFunction *buildFunc = new loadedFunction; + if (! checkNew(buildFunc)) return NULL; + + // See what it was called by and load if we need to... + + buildFunc -> originalNumber = get2bytes(fp); + buildFunc -> calledBy = NULL; + if (fgetc(fp)) { + buildFunc -> calledBy = loadFunction(fp); + if (! buildFunc -> calledBy) return NULL; + } + + buildFunc -> timeLeft = get4bytes(fp); + buildFunc -> runThisLine = get2bytes(fp); + buildFunc -> freezerLevel = 0; + buildFunc -> cancelMe = fgetc(fp); + buildFunc -> returnSomething = fgetc(fp); + buildFunc -> isSpeech = fgetc(fp); + loadVariable(& (buildFunc -> reg), fp); + loadFunctionCode(buildFunc); + + buildFunc -> stack = loadStack(fp, NULL); + + for (a = 0; a < buildFunc -> numLocals; a ++) { + loadVariable(& (buildFunc -> localVars[a]), fp); + } + + return buildFunc; +} +#endif +//---------------------------------------------------------------------- +// Save everything +//---------------------------------------------------------------------- + +bool saveGame(char *fname) { +#if ALLOW_FILE + int a; + + FILE *fp = fopen(fname, "wb"); + if (fp == NULL) return false; + + fprintf(fp, "SLUDSA"); + fputc(0, fp); + fputc(0, fp); + fputc(MAJOR_VERSION, fp); + fputc(MINOR_VERSION, fp); + + if (! saveThumbnail(fp)) return false; + + fwrite(& fileTime, sizeof(FILETIME), 1, fp); + + // DON'T ADD ANYTHING NEW BEFORE THIS POINT! + + fputc(allowAnyFilename, fp); + fputc(captureAllKeys, fp); + fputc(true, fp); // updateDisplay + fputc(fontTableSize > 0, fp); + + if (fontTableSize > 0) { + put2bytes(loadedFontNum, fp); + put2bytes(fontHeight, fp); + writeString(fontOrderString, fp); + } + putSigned(fontSpace, fp); + + // Save backdrop + put2bytes(cameraX, fp); + put2bytes(cameraY, fp); + putFloat(cameraZoom, fp); + + fputc(brightnessLevel, fp); + saveHSI(fp); + + // Save event handlers + saveHandlers(fp); + + // Save regions + saveRegions(fp); + + saveAnim(mouseCursorAnim, fp); + put2bytes(mouseCursorFrameNum, fp); + + // Save functions + loadedFunction *thisFunction = allRunningFunctions; + int countFunctions = 0; + while (thisFunction) { + countFunctions ++; + thisFunction = thisFunction -> next; + } + put2bytes(countFunctions, fp); + + thisFunction = allRunningFunctions; + while (thisFunction) { + saveFunction(thisFunction, fp); + thisFunction = thisFunction -> next; + } + + for (a = 0; a < numGlobals; a ++) { + saveVariable(& globalVars[a], fp); + } + + savePeople(fp); + + if (currentFloor -> numPolygons) { + fputc(1, fp); + put2bytes(currentFloor -> originalNum, fp); + } else fputc(0, fp); + + if (zBuffer.tex) { + fputc(1, fp); + put2bytes(zBuffer.originalNum, fp); + } else fputc(0, fp); + + if (lightMap.data) { + fputc(1, fp); + put2bytes(lightMapNumber, fp); + } else fputc(0, fp); + + fputc(lightMapMode, fp); + fputc(speechMode, fp); + fputc(fadeMode, fp); + saveSpeech(speech, fp); + saveStatusBars(fp); + saveSounds(fp); + + put2bytes(saveEncoding, fp); + + blur_saveSettings(fp); + + put2bytes(currentBlankColour, fp); + fputc(currentBurnR, fp); + fputc(currentBurnG, fp); + fputc(currentBurnB, fp); + + saveParallaxRecursive(parallaxStuff, fp); + fputc(0, fp); + + fputc(languageNum, fp); // Selected language + + saveSnapshot(fp); + + fclose(fp); +#endif + clearStackLib(); + return true; +} + +//---------------------------------------------------------------------- +// Load everything +//---------------------------------------------------------------------- + +int ssgVersion; + +bool loadGame(char *fname) { +#if ALLOW_FILE + FILE *fp; + FILETIME savedGameTime; + int a; + + while (allRunningFunctions) finishFunction(allRunningFunctions); + + fp = openAndVerify(fname, 'S', 'A', ERROR_GAME_LOAD_NO, ssgVersion); + if (fp == NULL) return false; + + if (ssgVersion >= VERSION(1, 4)) { + if (! skipThumbnail(fp)) return fatal(ERROR_GAME_LOAD_CORRUPT, fname); + } + + size_t bytes_read = fread(& savedGameTime, sizeof(FILETIME), 1, fp); + if (bytes_read != sizeof(FILETIME) && ferror(fp)) { + debugOut("Reading error in loadGame.\n"); + } + + if (savedGameTime.dwLowDateTime != fileTime.dwLowDateTime || + savedGameTime.dwHighDateTime != fileTime.dwHighDateTime) { + return fatal(ERROR_GAME_LOAD_WRONG, fname); + } + + // DON'T ADD ANYTHING NEW BEFORE THIS POINT! + + if (ssgVersion >= VERSION(1, 4)) { + allowAnyFilename = fgetc(fp); + } + captureAllKeys = fgetc(fp); + fgetc(fp); // updateDisplay (part of movie playing) + + bool fontLoaded = fgetc(fp); + int fontNum; + char *charOrder; + if (fontLoaded) { + fontNum = get2bytes(fp); + fontHeight = get2bytes(fp); + + if (ssgVersion < VERSION(2, 2)) { + int x; + charOrder = new char[257]; + if (! checkNew(charOrder)) return false; + + for (int a = 0; a < 256; a ++) { + x = fgetc(fp); + charOrder[x] = a; + } + charOrder[256] = 0; + } else { + charOrder = readString(fp); + } + } + loadFont(fontNum, charOrder, fontHeight); + delete [] charOrder; + + fontSpace = getSigned(fp); + + killAllPeople(); + killAllRegions(); + + int camerX = get2bytes(fp); + int camerY = get2bytes(fp); + float camerZ; + if (ssgVersion >= VERSION(2, 0)) { + camerZ = getFloat(fp); + } else { + camerZ = 1.0; + } + + brightnessLevel = fgetc(fp); + + loadHSI(fp, 0, 0, true); + loadHandlers(fp); + loadRegions(fp); + + mouseCursorAnim = new personaAnimation; + if (! checkNew(mouseCursorAnim)) return false; + if (! loadAnim(mouseCursorAnim, fp)) return false; + mouseCursorFrameNum = get2bytes(fp); + + loadedFunction *rFunc; + loadedFunction * * buildList = & allRunningFunctions; + + + int countFunctions = get2bytes(fp); + while (countFunctions --) { + rFunc = loadFunction(fp); + rFunc -> next = NULL; + (* buildList) = rFunc; + buildList = & (rFunc -> next); + } + + for (a = 0; a < numGlobals; a ++) { + unlinkVar(globalVars[a]); + loadVariable(& globalVars[a], fp); + } + + loadPeople(fp); + + + if (fgetc(fp)) { + if (! setFloor(get2bytes(fp))) return false; + } else setFloorNull(); + + if (fgetc(fp)) { + if (! setZBuffer(get2bytes(fp))) return false; + } + + if (fgetc(fp)) { + if (! loadLightMap(get2bytes(fp))) return false; + } + + if (ssgVersion >= VERSION(1, 4)) { + lightMapMode = fgetc(fp) % 3; + } + + speechMode = fgetc(fp); + fadeMode = fgetc(fp); + loadSpeech(speech, fp); + loadStatusBars(fp); + loadSounds(fp); + + saveEncoding = get2bytes(fp); + + if (ssgVersion >= VERSION(1, 6)) { + if (ssgVersion < VERSION(2, 0)) { + // aaLoad + fgetc(fp); + getFloat(fp); + getFloat(fp); + } + + blur_loadSettings(fp); + } + + if (ssgVersion >= VERSION(1, 3)) { + currentBlankColour = get2bytes(fp); + currentBurnR = fgetc(fp); + currentBurnG = fgetc(fp); + currentBurnB = fgetc(fp); + + // Read parallax layers + while (fgetc(fp)) { + int im = get2bytes(fp); + int fx = get2bytes(fp); + int fy = get2bytes(fp); + + if (! loadParallax(im, fx, fy)) return false; + } + + int selectedLanguage = fgetc(fp); + if (selectedLanguage != languageNum) { + // Load the saved language! + languageNum = selectedLanguage; + setFileIndices(NULL, gameSettings.numLanguages, languageNum); + } + } + + nosnapshot(); + if (ssgVersion >= VERSION(1, 4)) { + if (fgetc(fp)) { + if (! restoreSnapshot(fp)) return false; + } + } + + fclose(fp); + + cameraX = camerX; + cameraY = camerY; + cameraZoom = camerZ; +#endif + + clearStackLib(); + return true; +} |