bool loadGame(const Common::String &fname) { Common::InSaveFile *fp = g_system->getSavefileManager()->openForLoading(fname); FILETIME savedGameTime; while (allRunningFunctions) finishFunction(allRunningFunctions); if (fp == NULL) return false; bool headerBad = false; if (fp->readByte() != 'S') headerBad = true; if (fp->readByte() != 'L') headerBad = true; if (fp->readByte() != 'U') headerBad = true; if (fp->readByte() != 'D') headerBad = true; if (fp->readByte() != 'S') headerBad = true; if (fp->readByte() != 'A') headerBad = true; if (headerBad) { fatal(ERROR_GAME_LOAD_NO, fname); return NULL; } char c; c = fp->readByte(); while ((c = fp->readByte())) ; int majVersion = fp->readByte(); int minVersion = fp->readByte(); ssgVersion = VERSION(majVersion, minVersion); if (ssgVersion >= VERSION(1, 4)) { if (!g_sludge->_gfxMan->skipThumbnail(fp)) return fatal(ERROR_GAME_LOAD_CORRUPT, fname); } uint32 bytes_read = fp->read(&savedGameTime, sizeof(FILETIME)); if (bytes_read != sizeof(FILETIME) && fp->err()) { warning("Reading error in loadGame."); } 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 = fp->readByte(); } captureAllKeys = fp->readByte(); fp->readByte(); // updateDisplay (part of movie playing) g_sludge->_txtMan->loadFont(ssgVersion, fp); killAllPeople(); killAllRegions(); int camerX = fp->readUint16BE(); int camerY = fp->readUint16BE(); float camerZ; if (ssgVersion >= VERSION(2, 0)) { camerZ = fp->readFloatLE(); } else { camerZ = 1.0; } brightnessLevel = fp->readByte(); g_sludge->_gfxMan->loadHSI(fp, 0, 0, true); g_sludge->_evtMan->loadHandlers(fp); loadRegions(fp); if (!g_sludge->_cursorMan->loadCursor(fp)) { return false; } LoadedFunction *rFunc; LoadedFunction **buildList = &allRunningFunctions; int countFunctions = fp->readUint16BE(); while (countFunctions--) { rFunc = loadFunction(fp); rFunc->next = NULL; (*buildList) = rFunc; buildList = &(rFunc->next); } for (int a = 0; a < numGlobals; a++) { unlinkVar(globalVars[a]); loadVariable(&globalVars[a], fp); } loadPeople(fp); if (fp->readByte()) { if (!setFloor(fp->readUint16BE())) return false; } else setFloorNull(); if (!g_sludge->_gfxMan->loadZBuffer(fp)) return false; if (!g_sludge->_gfxMan->loadLightMap(ssgVersion, fp)) { return false; } fadeMode = fp->readByte(); g_sludge->_speechMan->load(fp); loadStatusBars(fp); g_sludge->_soundMan->loadSounds(fp); saveEncoding = fp->readUint16BE(); if (ssgVersion >= VERSION(1, 6)) { if (ssgVersion < VERSION(2, 0)) { // aaLoad fp->readByte(); fp->readFloatLE(); fp->readFloatLE(); } blur_loadSettings(fp); } if (ssgVersion >= VERSION(1, 3)) { g_sludge->_gfxMan->loadColors(fp); // Read parallax layers while (fp->readByte()) { int im = fp->readUint16BE(); int fx = fp->readUint16BE(); int fy = fp->readUint16BE(); if (!g_sludge->_gfxMan->loadParallax(im, fx, fy)) return false; } g_sludge->_languageMan->loadLanguageSetting(fp); } g_sludge->_gfxMan->nosnapshot(); if (ssgVersion >= VERSION(1, 4)) { if (fp->readByte()) { if (!g_sludge->_gfxMan->restoreSnapshot(fp)) return false; } } delete fp; g_sludge->_gfxMan->setCamera(camerX, camerY, camerZ); clearStackLib(); return true; }
bool continueFunction (loadedFunction * fun) { bool keepLooping = true; bool advanceNow; unsigned int param; sludgeCommand com; if (fun -> cancelMe) { abortFunction (fun); return true; } // if (numBIFNames) newDebug ("*** Function:", allUserFunc[fun -> originalNumber]); //debugOut ("SLUDGER: continueFunction\n"); while (keepLooping) { advanceNow = true; param = fun -> compiledLines[fun -> runThisLine].param; com = fun -> compiledLines[fun -> runThisLine].theCommand; // fprintf (stderr, "com: %d param: %d (%s)\n", com, param, // (com < numSludgeCommands) ? sludgeText[com] : ERROR_UNKNOWN_MCODE); fflush(stderr); if (numBIFNames) { setFatalInfo ( (fun -> originalNumber < numUserFunc) ? allUserFunc[fun -> originalNumber] : "Unknown user function", (com < numSludgeCommands) ? sludgeText[com] : ERROR_UNKNOWN_MCODE); // newDebug ( // (com < numSludgeCommands) ? sludgeText[com] : "Unknown SLUDGE machine code", // param); } //debugOut ("SLUDGER: continueFunction - in da loop: %s\n", sludgeText[com]); switch (com) { case SLU_RETURN: if (fun -> calledBy) { loadedFunction * returnTo = fun -> calledBy; if (fun -> returnSomething) copyVariable (fun -> reg, returnTo -> reg); finishFunction (fun); fun = returnTo; restartFunction (fun); } else { finishFunction (fun); advanceNow = false; // So we don't do anything else with "fun" keepLooping = false; // So we drop out of the loop } break; case SLU_CALLIT: switch (fun -> reg.varType) { case SVT_FUNC: pauseFunction (fun); if (numBIFNames) setFatalInfo ( (fun -> originalNumber < numUserFunc) ? allUserFunc[fun -> originalNumber] : "Unknown user function", (fun -> reg.varData.intValue < numUserFunc) ? allUserFunc[fun -> reg.varData.intValue] : "Unknown user function"); if (! startNewFunctionNum (fun -> reg.varData.intValue, param, fun, fun -> stack)) return false; fun = allRunningFunctions; advanceNow = false; // So we don't do anything else with "fun" break; case SVT_BUILT: { builtReturn br = callBuiltIn (fun -> reg.varData.intValue, param, fun); switch (br) { case BR_ERROR: return fatal("Unknown error. This shouldn't happen. Please notify the SLUDGE developers."); case BR_PAUSE: pauseFunction (fun); // No break! case BR_KEEP_AND_PAUSE: keepLooping = false; break; case BR_ALREADY_GONE: keepLooping = false; advanceNow = false; break; case BR_CALLAFUNC: { int i = fun -> reg.varData.intValue; setVariable (fun -> reg, SVT_INT, 1); pauseFunction (fun); if (numBIFNames) setFatalInfo ( (fun -> originalNumber < numUserFunc) ? allUserFunc[fun -> originalNumber] : "Unknown user function", (i < numUserFunc) ? allUserFunc[i] : "Unknown user function"); if (! startNewFunctionNum (i, 0, fun, noStack, false)) return false; fun = allRunningFunctions; advanceNow = false; // So we don't do anything else with "fun" } break; default: break; } } break; default: return fatal (ERROR_CALL_NONFUNCTION); } break; // These all grab things and shove 'em into the register case SLU_LOAD_NULL: setVariable (fun -> reg, SVT_NULL, 0); break; case SLU_LOAD_FILE: setVariable (fun -> reg, SVT_FILE, param); break; case SLU_LOAD_VALUE: setVariable (fun -> reg, SVT_INT, param); break; case SLU_LOAD_LOCAL: if (! copyVariable (fun -> localVars[param], fun -> reg)) return false; break; case SLU_AND: setVariable (fun -> reg, SVT_INT, getBoolean (fun -> reg) && getBoolean (fun -> stack -> thisVar)); trimStack (fun -> stack); break; case SLU_OR: setVariable (fun -> reg, SVT_INT, getBoolean (fun -> reg) || getBoolean (fun -> stack -> thisVar)); trimStack (fun -> stack); break; case SLU_LOAD_FUNC: setVariable (fun -> reg, SVT_FUNC, param); break; case SLU_LOAD_BUILT: setVariable (fun -> reg, SVT_BUILT, param); break; case SLU_LOAD_OBJTYPE: setVariable (fun -> reg, SVT_OBJTYPE, param); break; case SLU_UNREG: if (dialogValue != 1) fatal (ERROR_HACKER); break; case SLU_LOAD_STRING: if (! loadStringToVar (fun -> reg, param)) { return false; } break; case SLU_INDEXGET: case SLU_INCREMENT_INDEX: case SLU_DECREMENT_INDEX: switch (fun -> stack -> thisVar.varType) { case SVT_NULL: if (com == SLU_INDEXGET) { setVariable (fun -> reg, SVT_NULL, 0); trimStack (fun -> stack); } else { return fatal (ERROR_INCDEC_UNKNOWN); } break; case SVT_FASTARRAY: case SVT_STACK: if (fun -> stack -> thisVar.varData.theStack -> first == NULL) { return fatal (ERROR_INDEX_EMPTY); } else { int ii; if (! getValueType (ii, SVT_INT, fun -> reg)) return false; variable * grab = (fun -> stack -> thisVar.varType == SVT_FASTARRAY) ? fastArrayGetByIndex (fun -> stack -> thisVar.varData.fastArray, ii) : stackGetByIndex (fun -> stack -> thisVar.varData.theStack -> first, ii); trimStack (fun -> stack); if (! grab) { setVariable (fun -> reg, SVT_NULL, 0); } else { int ii; switch (com) { case SLU_INCREMENT_INDEX: if (! getValueType (ii, SVT_INT, * grab)) return false; setVariable (fun -> reg, SVT_INT, ii); grab -> varData.intValue = ii + 1; break; case SLU_DECREMENT_INDEX: if (! getValueType (ii, SVT_INT, * grab)) return false; setVariable (fun -> reg, SVT_INT, ii); grab -> varData.intValue = ii - 1; break; default: if (! copyVariable (* grab, fun -> reg)) return false; } } } break; default: return fatal (ERROR_INDEX_NONSTACK); } break; case SLU_INDEXSET: switch (fun -> stack -> thisVar.varType) { case SVT_STACK: if (fun -> stack -> thisVar.varData.theStack -> first == NULL) { return fatal (ERROR_INDEX_EMPTY); } else { int ii; if (! getValueType (ii, SVT_INT, fun -> reg)) return false; if (! stackSetByIndex (fun -> stack -> thisVar.varData.theStack -> first, ii, fun -> stack -> next -> thisVar)) { return false; } trimStack (fun -> stack); trimStack (fun -> stack); } break; case SVT_FASTARRAY: { int ii; if (! getValueType (ii, SVT_INT, fun -> reg)) return false; variable * v = fastArrayGetByIndex (fun -> stack -> thisVar.varData.fastArray, ii); if (v == NULL) return fatal ("Not within bounds of fast array."); if (! copyVariable (fun -> stack -> next -> thisVar, * v)) return false; trimStack (fun -> stack); trimStack (fun -> stack); } break; default: return fatal (ERROR_INDEX_NONSTACK); } break; // What can we do with the register? Well, we can copy it into a local // variable, a global or onto the stack... case SLU_INCREMENT_LOCAL: { int ii; if (! getValueType (ii, SVT_INT, fun -> localVars[param])) return false; setVariable (fun -> reg, SVT_INT, ii); setVariable (fun -> localVars[param], SVT_INT, ii + 1); } break; case SLU_INCREMENT_GLOBAL: { int ii; if (! getValueType (ii, SVT_INT, globalVars[param])) return false; setVariable (fun -> reg, SVT_INT, ii); setVariable (globalVars[param], SVT_INT, ii + 1); } break; case SLU_DECREMENT_LOCAL: { int ii; if (! getValueType (ii, SVT_INT, fun -> localVars[param])) return false; setVariable (fun -> reg, SVT_INT, ii); setVariable (fun -> localVars[param], SVT_INT, ii - 1); } break; case SLU_DECREMENT_GLOBAL: { int ii; if (! getValueType (ii, SVT_INT, globalVars[param])) return false; setVariable (fun -> reg, SVT_INT, ii); setVariable (globalVars[param], SVT_INT, ii - 1); } break; case SLU_SET_LOCAL: if (! copyVariable (fun -> reg, fun -> localVars[param])) return false; break; case SLU_SET_GLOBAL: // newDebug (" Copying TO global variable", param); // newDebug (" Global type at the moment", globalVars[param].varType); if (! copyVariable (fun -> reg, globalVars[param])) return false; // newDebug (" New type", globalVars[param].varType); break; case SLU_LOAD_GLOBAL: // newDebug (" Copying FROM global variable", param); // newDebug (" Global type at the moment", globalVars[param].varType); if (! copyVariable (globalVars[param], fun -> reg)) return false; break; case SLU_STACK_PUSH: if (! addVarToStack (fun -> reg, fun -> stack)) return false; break; case SLU_QUICK_PUSH: if (! addVarToStackQuick (fun -> reg, fun -> stack)) return false; break; case SLU_NOT: setVariable (fun -> reg, SVT_INT, ! getBoolean (fun -> reg)); break; case SLU_BR_ZERO: if (! getBoolean (fun -> reg)) { advanceNow = false; fun -> runThisLine = param; } break; case SLU_BRANCH: advanceNow = false; fun -> runThisLine = param; break; case SLU_NEGATIVE: { int i; if (! getValueType (i, SVT_INT, fun -> reg)) return false; setVariable (fun -> reg, SVT_INT, -i); } break; // All these things rely on there being somet' on the stack case SLU_MULT: case SLU_PLUS: case SLU_MINUS: case SLU_MODULUS: case SLU_DIVIDE: case SLU_EQUALS: case SLU_NOT_EQ: case SLU_LESSTHAN: case SLU_MORETHAN: case SLU_LESS_EQUAL: case SLU_MORE_EQUAL: if (fun -> stack) { int firstValue, secondValue; switch (com) { case SLU_PLUS: addVariablesInSecond (fun -> stack -> thisVar, fun -> reg); trimStack (fun -> stack); break; case SLU_EQUALS: compareVariablesInSecond (fun -> stack -> thisVar, fun -> reg); trimStack (fun -> stack); break; case SLU_NOT_EQ: compareVariablesInSecond (fun -> stack -> thisVar, fun -> reg); trimStack (fun -> stack); fun -> reg.varData.intValue = ! fun -> reg.varData.intValue; break; default: if (! getValueType (firstValue, SVT_INT, fun -> stack -> thisVar)) return false; if (! getValueType (secondValue, SVT_INT, fun -> reg)) return false; trimStack (fun -> stack); switch (com) { case SLU_MULT: setVariable (fun -> reg, SVT_INT, firstValue * secondValue); break; case SLU_MINUS: setVariable (fun -> reg, SVT_INT, firstValue - secondValue); break; case SLU_MODULUS: setVariable (fun -> reg, SVT_INT, firstValue % secondValue); break; case SLU_DIVIDE: setVariable (fun -> reg, SVT_INT, firstValue / secondValue); break; case SLU_LESSTHAN: setVariable (fun -> reg, SVT_INT, firstValue < secondValue); break; case SLU_MORETHAN: setVariable (fun -> reg, SVT_INT, firstValue > secondValue); break; case SLU_LESS_EQUAL: setVariable (fun -> reg, SVT_INT, firstValue <= secondValue); break; case SLU_MORE_EQUAL: setVariable (fun -> reg, SVT_INT, firstValue >= secondValue); break; default: break; } } } else { return fatal (ERROR_NOSTACK); } break; default: return fatal (ERROR_UNKNOWN_CODE); } if (advanceNow) fun -> runThisLine ++; } return true; }