bool StarTrekEngine::saveGame(int slot, Common::String desc) { Common::String filename = getSavegameFilename(slot); Common::OutSaveFile *out; if (!(out = _saveFileMan->openForSaving(filename))) { warning("Can't create file '%s', game not saved", filename.c_str()); return false; } else { debug(3, "Successfully opened %s for writing", filename.c_str()); } SavegameMetadata meta; meta.version = CURRENT_SAVEGAME_VERSION; memset(meta.description, 0, sizeof(meta.description)); strncpy(meta.description, desc.c_str(), SAVEGAME_DESCRIPTION_LEN); TimeDate curTime; _system->getTimeAndDate(curTime); meta.setSaveTimeAndDate(curTime); meta.playTime = g_engine->getTotalPlayTime(); if (!saveOrLoadMetadata(nullptr, out, &meta)) { delete out; return false; } if (!saveOrLoadGameData(nullptr, out, &meta)) { delete out; return false; } out->finalize(); delete out; return true; }
Common::Error AgiEngine::saveGameState(int slot, const Common::String &desc) { Common::String saveLoadSlot = getSavegameFilename(slot); if (saveGame(saveLoadSlot, desc) == errOK) return Common::kNoError; else return Common::kUnknownError; }
void AgiEngine::getSavegameDescription(int num, char *buf, bool showEmpty) { Common::InSaveFile *in; Common::String fileName = getSavegameFilename(num); debugC(4, kDebugLevelMain | kDebugLevelSavegame, "Current game id is %s", _targetName.c_str()); if (!(in = _saveFileMan->openForLoading(fileName))) { debugC(4, kDebugLevelMain | kDebugLevelSavegame, "File %s does not exist", fileName.c_str()); if (showEmpty) strcpy(buf, " (empty slot)"); else *buf = 0; } else { debugC(4, kDebugLevelMain | kDebugLevelSavegame, "Successfully opened %s for reading", fileName.c_str()); uint32 type = in->readUint32BE(); if (type == AGIflag) { debugC(6, kDebugLevelMain | kDebugLevelSavegame, "Has AGI flag, good start"); in->read(buf, 31); } else { warning("This doesn't appear to be an AGI savegame"); strcpy(buf, "(corrupt file)"); } delete in; } }
int AgiEngine::saveGameSimple() { Common::String fileName = getSavegameFilename(0); int result = saveGame(fileName, "Default savegame"); if (result != errOK) messageBox("Error saving game."); return result; }
void KyraEngine_v1::loadGameStateCheck(int slot) { if (loadGameState(slot) != Common::kNoError) { const char *filename = getSavegameFilename(slot); Common::String errorMessage = "Could not load savegame: '"; errorMessage += filename; errorMessage += "'"; GUIErrorMessage(errorMessage); error("%s", errorMessage.c_str()); } }
bool StarTrekEngine::loadGame(int slot) { Common::String filename = getSavegameFilename(slot); Common::InSaveFile *in; if (!(in = _saveFileMan->openForLoading(filename))) { warning("Can't open file '%s', game not loaded", filename.c_str()); return false; } else { debug(3, "Successfully opened %s for loading", filename.c_str()); } SavegameMetadata meta; if (!saveOrLoadMetadata(in, nullptr, &meta)) { delete in; return false; } if (meta.version > CURRENT_SAVEGAME_VERSION) { delete in; error("Savegame version (%u) is newer than current version (%u). A newer version of ScummVM is needed", meta.version, CURRENT_SAVEGAME_VERSION); } if (!saveOrLoadGameData(in, nullptr, &meta)) { delete in; return false; } delete in; _lastGameMode = _gameMode; if (_gameMode == GAMEMODE_AWAYMISSION) { for (int i = 0; i < NUM_ACTORS; i++) { Actor *a = &_actorList[i]; if (a->spriteDrawn) { if (a->animType != 1) a->animFile = loadFile(Common::String(a->animFilename) + ".anm"); _gfx->addSprite(&a->sprite); a->sprite.setBitmap(loadAnimationFrame(a->bitmapFilename, a->scale)); } } } else if (_gameMode == -1) { initBridge(true); _lastGameMode = GAMEMODE_BRIDGE; // TODO: mode change } else { _txtFilename = _missionToLoad; initBridge(false); // TODO: mode change } return true; }
void AgiEngine::checkQuickLoad() { if (ConfMan.hasKey("save_slot")) { Common::String saveNameBuffer = getSavegameFilename(ConfMan.getInt("save_slot")); _sprites->eraseBoth(); _sound->stopSound(); if (loadGame(saveNameBuffer, false) == errOK) { // Do not check game id _game.exitAllLogics = 1; _menu->enableAll(); } } }
void KyraEngine_v1::loadGameStateCheck(int slot) { // FIXME: Instead of throwing away the error returned by // loadGameState, we should use it / augment it. if (loadGameState(slot).getCode() != Common::kNoError) { const char *filename = getSavegameFilename(slot); Common::String errorMessage = "Could not load savegame: '"; errorMessage += filename; errorMessage += "'"; GUIErrorMessage(errorMessage); error("%s", errorMessage.c_str()); } }
Common::Error AgiEngine::loadGameState(int slot) { Common::String saveLoadSlot = getSavegameFilename(slot); _sprites->eraseBoth(); _sound->stopSound(); if (loadGame(saveLoadSlot) == errOK) { _game.exitAllLogics = 1; _menu->enableAll(); return Common::kNoError; } else { return Common::kUnknownError; } }
bool KyraEngine_v1::saveFileLoadable(int slot) { if (slot < 0 || slot > 999) return false; SaveHeader header; Common::SeekableReadStream *in = openSaveForReading(getSavegameFilename(slot), header); if (in) { delete in; return true; } return false; }
int AgiEngine::loadGameSimple() { int rc = 0; Common::String fileName = getSavegameFilename(0); _sprites->eraseBoth(); _sound->stopSound(); closeWindow(); if ((rc = loadGame(fileName)) == errOK) { messageBox("Game restored."); _game.exitAllLogics = 1; _menu->enableAll(); } else { messageBox("Error restoring game."); } return rc; }
int AgiEngine::loadGameDialog() { int rc, slot = 0; int hm, vm, hp, vp; // box margins int w; hm = 1; vm = 3; hp = hm * CHAR_COLS; vp = vm * CHAR_LINES; w = (40 - 2 * hm) - 1; _sprites->eraseBoth(); _sound->stopSound(); drawWindow(hp, vp, GFX_WIDTH - hp, GFX_HEIGHT - vp); printText("Select a game which you wish to\nrestore:", 0, hm + 1, vm + 1, w, MSG_BOX_TEXT, MSG_BOX_COLOR); slot = selectSlot(); if (slot < 0) { if (slot == -1) // slot = -2 when GMM was launched messageBox("Game NOT restored."); return errOK; } Common::String fileName = getSavegameFilename(_firstSlot + slot); if ((rc = loadGame(fileName)) == errOK) { messageBox("Game restored."); _game.exitAllLogics = 1; _menu->enableAll(); } else { messageBox("Error restoring game."); } return rc; }
int AgiEngine::playGame() { int ec = errOK; debugC(2, kDebugLevelMain, "initializing..."); debugC(2, kDebugLevelMain, "game version = 0x%x", getVersion()); _sound->stopSound(); _gfx->clearScreen(0); _game.horizon = HORIZON; _game.playerControl = false; setflag(fLogicZeroFirsttime, true); // not in 2.917 setflag(fNewRoomExec, true); // needed for MUMG and SQ2! setflag(fSoundOn, true); // enable sound setvar(vTimeDelay, 2); // "normal" speed _game.gfxMode = true; _game.clockEnabled = true; _game.lineUserInput = 22; // We run AGIMOUSE always as a side effect if (getFeatures() & GF_AGIMOUSE || true) debug(1, "Using AGI Mouse 1.0 protocol"); if (getFeatures() & GF_AGIPAL) debug(1, "Running AGIPAL game"); debug(0, "Running AGI script.\n"); setflag(fEnteredCli, false); setflag(fSaidAcceptedInput, false); _game.vars[vWordNotFound] = 0; _game.vars[vKey] = 0; debugC(2, kDebugLevelMain, "Entering main loop"); bool firstLoop = !getflag(fRestartGame); // Do not restore on game restart do { if (!mainCycle()) continue; if (getvar(vTimeDelay) == 0 || (1 + _clockCount) % getvar(vTimeDelay) == 0) { if (!_game.hasPrompt && _game.inputMode == INPUT_NORMAL) { writePrompt(); _game.hasPrompt = 1; } else if (_game.hasPrompt && _game.inputMode == INPUT_NONE) { writePrompt(); _game.hasPrompt = 0; } interpretCycle(); // Check if the user has asked to load a game from the command line // or the launcher if (firstLoop) { checkQuickLoad(); firstLoop = false; } setflag(fEnteredCli, false); setflag(fSaidAcceptedInput, false); _game.vars[vWordNotFound] = 0; _game.vars[vKey] = 0; } if (shouldPerformAutoSave(_lastSaveTime)) { saveGame(getSavegameFilename(0), "Autosave"); } } while (!(shouldQuit() || _restartGame)); _sound->stopSound(); return ec; }
const char *KyraEngine_v1::getSavegameFilename(int num) { _savegameFilename = getSavegameFilename(_targetName, num); return _savegameFilename.c_str(); }
Common::Error ToltecsEngine::saveGameState(int slot, const Common::String &description) { const char *fileName = getSavegameFilename(slot); savegame(fileName, description.c_str()); return Common::kNoError; }
Common::Error ToltecsEngine::loadGameState(int slot) { const char *fileName = getSavegameFilename(slot); loadgame(fileName); return Common::kNoError; }
bool BbvsEngine::existsSavegame(int num) { return _system->getSavefileManager()->listSavefiles(getSavegameFilename(_targetName, num)).size() != 0; }
Common::Error NeverhoodEngine::saveGameState(int slot, const Common::String &description) { const char *fileName = getSavegameFilename(slot); if (!savegame(fileName, description.c_str())) return Common::kWritingFailed; return Common::kNoError; }
Common::Error KyraEngine_MR::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumb) { const char *fileName = getSavegameFilename(slot); Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb); if (!out) return _saveFileMan->getError(); _timer->saveDataToFile(*out); out->writeUint32BE(sizeof(_flagsTable)); out->write(_flagsTable, sizeof(_flagsTable)); out->writeSint16BE(_lastMusicCommand); out->writeByte(_currentChapter); out->writeByte(_characterShapeFile); out->writeByte(_album.curPage); out->writeSint16BE(_score); out->writeSint16BE(_scoreMax); out->writeByte(_malcolmsMood); for (int i = 0; i < 30; ++i) out->write(_conversationState[i], 30); out->write(_newSceneDlgState, 40); for (int i = 0; i < 100; ++i) out->writeSint16BE(_hiddenItems[i]); out->write(_scoreFlagTable, 26); out->writeUint16BE(_mainCharacter.sceneId); out->writeSint16BE(_mainCharacter.dlgIndex); out->writeByte(_mainCharacter.height); out->writeByte(_mainCharacter.facing); out->writeUint16BE(_mainCharacter.animFrame); out->writeByte(_mainCharacter.walkspeed); for (int i = 0; i < 10; ++i) out->writeUint16BE(_mainCharacter.inventory[i]); out->writeSint16BE(_mainCharacter.x1); out->writeSint16BE(_mainCharacter.y1); out->writeSint16BE(_mainCharacter.x2); out->writeSint16BE(_mainCharacter.y2); out->writeSint16BE(_mainCharacter.x3); out->writeSint16BE(_mainCharacter.y3); for (int i = 0; i < 50; ++i) { out->writeSint16BE(_itemList[i].id); out->writeUint16BE(_itemList[i].sceneId); out->writeSint16BE(_itemList[i].x); out->writeSint16BE(_itemList[i].y); } for (int i = 0; i < 88; ++i) { out->write(_talkObjectList[i].filename, 13); out->writeByte(_talkObjectList[i].sceneAnim); out->writeByte(_talkObjectList[i].sceneScript); out->writeSint16BE(_talkObjectList[i].x); out->writeSint16BE(_talkObjectList[i].y); out->writeByte(_talkObjectList[i].color); out->writeByte(_talkObjectList[i].sceneId); } for (int i = 0; i < 98; ++i) { out->write(_sceneList[i].filename1, 10); out->write(_sceneList[i].filename2, 10); out->writeUint16BE(_sceneList[i].exit1); out->writeUint16BE(_sceneList[i].exit2); out->writeUint16BE(_sceneList[i].exit3); out->writeUint16BE(_sceneList[i].exit4); out->writeByte(_sceneList[i].flags); out->writeByte(_sceneList[i].sound); } out->writeSint16BE(_itemInHand); out->writeUint16BE(_sceneExit1); out->writeUint16BE(_sceneExit2); out->writeUint16BE(_sceneExit3); out->writeUint16BE(_sceneExit4); out->finalize(); // check for errors if (out->err()) { warning("Can't write file '%s'. (Disk full?)", fileName); return Common::kUnknownError; } else { debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName); } delete out; return Common::kNoError; }
int AgiEngine::playGame() { int ec = errOK; const AgiAppleIIgsDelayOverwriteGameEntry *appleIIgsDelayOverwrite = nullptr; const AgiAppleIIgsDelayOverwriteRoomEntry *appleIIgsDelayRoomOverwrite = nullptr; debugC(2, kDebugLevelMain, "initializing..."); debugC(2, kDebugLevelMain, "game version = 0x%x", getVersion()); _sound->stopSound(); // We need to do this accurately and reset the AGI priorityscreen to 4 // otherwise at least the fan game Nick's Quest will go into an endless // loop, because the game draws views before it draws the first background picture. // For further study see bug #3451122 _gfx->clear(0, 4); _game.horizon = 36; _game.playerControl = false; setFlag(VM_FLAG_LOGIC_ZERO_FIRST_TIME, true); // not in 2.917 setFlag(VM_FLAG_NEW_ROOM_EXEC, true); // needed for MUMG and SQ2! setFlag(VM_FLAG_SOUND_ON, true); // enable sound // do not set VM_VAR_TIME_DELAY, original AGI did not do it (in the data segment it was simply set to 0) _game.gfxMode = true; _text->promptRow_Set(22); // We run AGIMOUSE always as a side effect //if (getFeatures() & GF_AGIMOUSE) debug(1, "Using AGI Mouse 1.0 protocol"); if (getFeatures() & GF_AGIPAL) debug(1, "Running AGIPAL game"); debug(0, "Running AGI script.\n"); setFlag(VM_FLAG_ENTERED_CLI, false); setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, false); setVar(VM_VAR_WORD_NOT_FOUND, 0); setVar(VM_VAR_KEY, 0); debugC(2, kDebugLevelMain, "Entering main loop"); bool firstLoop = !getFlag(VM_FLAG_RESTART_GAME); // Do not restore on game restart if (firstLoop) { if (ConfMan.hasKey("save_slot")) { // quick restore enabled _game.automaticRestoreGame = true; } } artificialDelay_Reset(); if (getPlatform() == Common::kPlatformApple2GS) { // Look up, if there is a time delay overwrite table for the current game appleIIgsDelayOverwrite = appleIIgsDelayOverwriteGameTable; while (appleIIgsDelayOverwrite->gameId != GID_AGIDEMO) { if (appleIIgsDelayOverwrite->gameId == getGameID()) break; // game found appleIIgsDelayOverwrite++; } } do { processAGIEvents(); inGameTimerUpdate(); uint16 timeDelay = getVar(VM_VAR_TIME_DELAY); if (getPlatform() == Common::kPlatformApple2GS) { timeDelay++; // It seems that either Apple IIgs ran very slowly or that the delay in its interpreter was not working as everywhere else // Most games on that platform set the delay to 0, which means no delay in DOS // Gold Rush! even "optimizes" itself when larger sprites are on the screen it sets TIME_DELAY to 0. // Normally that game runs at TIME_DELAY 1. // Maybe a script patch for this game would make sense. // TODO: needs further investigation int16 timeDelayOverwrite = -99; // Now check, if we got a time delay overwrite entry for current room if (appleIIgsDelayOverwrite->roomTable) { byte curRoom = getVar(VM_VAR_CURRENT_ROOM); appleIIgsDelayRoomOverwrite = appleIIgsDelayOverwrite->roomTable; while (appleIIgsDelayRoomOverwrite->fromRoom >= 0) { if ((appleIIgsDelayRoomOverwrite->fromRoom <= curRoom) && (appleIIgsDelayRoomOverwrite->toRoom >= curRoom)) { if (appleIIgsDelayRoomOverwrite->onlyWhenPlayerNotInControl) { if (_game.playerControl) { // Player is actually currently in control? -> then skip this entry appleIIgsDelayRoomOverwrite++; continue; } } timeDelayOverwrite = appleIIgsDelayRoomOverwrite->timeDelayOverwrite; break; } appleIIgsDelayRoomOverwrite++; } if (timeDelayOverwrite == -99) { // use default time delay in case no room specific one was found timeDelayOverwrite = appleIIgsDelayOverwrite->defaultTimeDelayOverwrite; } } else { timeDelayOverwrite = appleIIgsDelayOverwrite->defaultTimeDelayOverwrite; } if (timeDelayOverwrite >= 0) { if (timeDelayOverwrite != timeDelay) { // delayOverwrite is not the same as the delay taken from the scripts? overwrite it warning("AppleIIgs: time delay overwrite from %d to %d", timeDelay, timeDelayOverwrite); setVar(VM_VAR_TIME_DELAY, timeDelayOverwrite - 1); // adjust for Apple IIgs timeDelay = timeDelayOverwrite; } } } if (_passedPlayTimeCycles >= timeDelay) { inGameTimerResetPassedCycles(); interpretCycle(); // Check if the user has asked to load a game from the command line // or the launcher if (_game.automaticRestoreGame) { _game.automaticRestoreGame = false; checkQuickLoad(); } setFlag(VM_FLAG_ENTERED_CLI, false); setFlag(VM_FLAG_SAID_ACCEPTED_INPUT, false); setVar(VM_VAR_WORD_NOT_FOUND, 0); setVar(VM_VAR_KEY, 0); } if (shouldPerformAutoSave(_lastSaveTime)) { saveGame(getSavegameFilename(0), "Autosave"); } } while (!(shouldQuit() || _restartGame)); _sound->stopSound(); return ec; }
Common::Error LoLEngine::loadGameState(int slot) { const uint16 *cdf[] = { _charDefsMan, _charDefsWoman, _charDefsKieran, _charDefsMan, _charDefsAkshel }; const char *fileName = getSavegameFilename(slot); SaveHeader header; Common::InSaveFile *saveFile = openSaveForReading(fileName, header); if (!saveFile) { _txt->printMessage(2, "%s", getLangString(0x425d)); return Common::kNoError; } _screen->fadeClearSceneWindow(10); completeDoorOperations(); _screen->fillRect(112, 0, 287, 119, 0, 0); _screen->updateScreen(); Common::SeekableSubReadStreamEndian in(saveFile, saveFile->pos(), saveFile->size(), !header.originalSave, DisposeAfterUse::YES); for (int i = 0; i < 4; i++) { LoLCharacter *c = &_characters[i]; c->flags = in.readUint16BE(); in.read(c->name, 11); c->raceClassSex = in.readByte(); c->id = in.readSint16BE(); c->curFaceFrame = in.readByte(); c->tempFaceFrame = in.readByte(); c->screamSfx = in.readByte(); for (int ii = 0; ii < 8; ii++) c->itemsMight[ii] = in.readUint16BE(); for (int ii = 0; ii < 8; ii++) c->protectionAgainstItems[ii] = in.readUint16BE(); c->itemProtection = in.readUint16BE(); c->hitPointsCur = in.readSint16BE(); c->hitPointsMax = in.readUint16BE(); c->magicPointsCur = in.readSint16BE(); c->magicPointsMax = in.readUint16BE(); c->field_41 = in.readByte(); c->damageSuffered = in.readUint16BE(); c->weaponHit = in.readUint16BE(); c->totalMightModifier = in.readUint16BE(); c->totalProtectionModifier = in.readUint16BE(); c->might = in.readUint16BE(); c->protection = in.readUint16BE(); c->nextAnimUpdateCountdown = in.readSint16BE(); for (int ii = 0; ii < 11; ii++) c->items[ii] = in.readUint16BE(); for (int ii = 0; ii < 3; ii++) c->skillLevels[ii] = in.readByte(); for (int ii = 0; ii < 3; ii++) c->skillModifiers[ii] = in.readSByte(); for (int ii = 0; ii < 3; ii++) c->experiencePts[ii] = in.readUint32BE(); for (int ii = 0; ii < 5; ii++) c->characterUpdateEvents[ii] = in.readByte(); for (int ii = 0; ii < 5; ii++) c->characterUpdateDelay[ii] = in.readByte(); if (c->flags & 1) { loadCharFaceShapes(i, c->id); c->defaultModifiers = cdf[c->raceClassSex]; } } in.read(_wllBuffer4, 80); _currentBlock = in.readUint16BE(); _partyPosX = in.readUint16BE(); _partyPosY = in.readUint16BE(); _updateFlags = in.readUint16BE(); _scriptDirection = in.readByte(); _selectedSpell = in.readByte(); _sceneDefaultUpdate = in.readByte(); _compassBroken = in.readByte(); _drainMagic = in.readByte(); _currentDirection = in.readUint16BE(); _compassDirection = in.readUint16BE(); _selectedCharacter = in.readSByte(); _currentLevel = in.readByte(); for (int i = 0; i < 48; i++) _inventory[i] = in.readSint16BE(); _inventoryCurItem = in.readSint16BE(); _itemInHand = in.readSint16BE(); _lastMouseRegion = in.readSint16BE(); if (header.version <= 15) { uint16 flags[40]; memset(flags, 0, sizeof(flags)); if (header.version == 14) { for (int i = 0; i < 16; i++) flags[i] = in.readUint16BE(); flags[26] = in.readUint16BE(); flags[36] = in.readUint16BE(); } else if (header.version == 15) { for (int i = 0; i < 40; i++) flags[i] = in.readUint16BE(); } memset(_flagsTable, 0, sizeof(_flagsTable)); for (uint i = 0; i < ARRAYSIZE(flags); ++i) { for (uint k = 0; k < 16; ++k) { if (flags[i] & (1 << k)) setGameFlag(((i << 4) & 0xFFF0) | (k & 0x000F)); } } } else { uint32 flagsSize = in.readUint32BE(); assert(flagsSize <= sizeof(_flagsTable)); in.read(_flagsTable, flagsSize); } for (int i = 0; i < 24; i++) _globalScriptVars[i] = in.readUint16BE(); _brightness = in.readByte(); _lampOilStatus = in.readByte(); _lampEffect = in.readSByte(); _credits = in.readUint16BE(); for (int i = 0; i < 8; i++) _globalScriptVars2[i] = in.readUint16BE(); in.read(_availableSpells, 7); _hasTempDataFlags = in.readUint32BE(); for (int i = 0; i < 400; i++) { ItemInPlay *t = &_itemsInPlay[i]; t->nextAssignedObject = in.readUint16BE(); t->nextDrawObject = in.readUint16BE(); t->flyingHeight = in.readByte(); t->block = in.readUint16BE(); t->x = in.readUint16BE(); t->y = in.readUint16BE(); t->level = in.readSByte(); t->itemPropertyIndex = in.readUint16BE(); t->shpCurFrame_flg = in.readUint16BE(); t->destDirection = in.readByte(); t->hitOffsX = in.readSByte(); t->hitOffsY = in.readSByte(); t->currentSubFrame = in.readByte(); } for (int i = 0; i < 1024; i++) { LevelBlockProperty *l = &_levelBlockProperties[i]; l->assignedObjects = l->drawObjects = 0; l->direction = 5; } for (int i = 0; i < 29; i++) { if (!(_hasTempDataFlags & (1 << i))) continue; if (_lvlTempData[i]) { delete[] _lvlTempData[i]->wallsXorData; delete[] _lvlTempData[i]->flags; delete[] _lvlTempData[i]->monsters; delete[] _lvlTempData[i]->flyingObjects; delete _lvlTempData[i]; } _lvlTempData[i] = new LevelTempData; _lvlTempData[i]->wallsXorData = new uint8[4096]; _lvlTempData[i]->flags = new uint8[1024]; _lvlTempData[i]->monsters = new MonsterInPlay[30]; _lvlTempData[i]->flyingObjects = new FlyingObject[8]; LevelTempData *l = _lvlTempData[i]; in.read(l->wallsXorData, 4096); in.read(l->flags, 1024); for (int ii = 0; ii < 30; ii++) { MonsterInPlay *m = &l->monsters[ii]; m->nextAssignedObject = in.readUint16BE(); m->nextDrawObject = in.readUint16BE(); m->flyingHeight = in.readByte(); m->block = in.readUint16BE(); m->x = in.readUint16BE(); m->y = in.readUint16BE(); m->shiftStep = in.readSByte(); m->destX = in.readUint16BE(); m->destY = in.readUint16BE(); m->destDirection = in.readByte(); m->hitOffsX = in.readSByte(); m->hitOffsY = in.readSByte(); m->currentSubFrame = in.readByte(); m->mode = in.readByte(); m->fightCurTick = in.readSByte(); m->id = in.readByte(); m->direction = in.readByte(); m->facing = in.readByte(); m->flags = in.readUint16BE(); m->damageReceived = in.readUint16BE(); m->hitPoints = in.readSint16BE(); m->speedTick = in.readByte(); m->type = in.readByte(); m->numDistAttacks = in.readByte(); m->curDistWeapon = in.readByte(); m->distAttackTick = in.readSByte(); m->assignedItems = in.readUint16BE(); m->properties = &_monsterProperties[m->type]; in.read(m->equipmentShapes, 4); } for (int ii = 0; ii < 8; ii++) { FlyingObject *m = &l->flyingObjects[ii]; m->enable = in.readByte(); m->objectType = in.readByte(); m->attackerId = in.readUint16BE(); m->item = in.readSint16BE(); m->x = in.readUint16BE(); m->y = in.readUint16BE(); m->flyingHeight = in.readByte(); m->direction = in.readByte(); m->distance = in.readByte(); m->field_D = in.readSByte(); m->c = in.readByte(); m->flags = in.readByte(); m->wallFlags = in.readByte(); } l->monsterDifficulty = in.readByte(); } calcCharPortraitXpos(); memset(_moneyColumnHeight, 0, sizeof(_moneyColumnHeight)); int t = _credits; _credits = 0; giveCredits(t, 0); setDelayedCursorUpdate(); loadLevel(_currentLevel); gui_drawPlayField(); timerSpecialCharacterUpdate(0); _flagsTable[73] |= 0x08; while (!_screen->isMouseVisible()) _screen->showMouse(); return Common::kNoError; }
Common::Error LoLEngine::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail) { const char *fileName = getSavegameFilename(slot); Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumbnail); if (!out) return _saveFileMan->getError(); completeDoorOperations(); generateTempData(); for (int i = 0; i < 4; i++) { LoLCharacter *c = &_characters[i]; out->writeUint16BE(c->flags); out->write(c->name, 11); out->writeByte(c->raceClassSex); out->writeSint16BE(c->id); out->writeByte(c->curFaceFrame); out->writeByte(c->tempFaceFrame); out->writeByte(c->screamSfx); for (int ii = 0; ii < 8; ii++) out->writeUint16BE(c->itemsMight[ii]); for (int ii = 0; ii < 8; ii++) out->writeUint16BE(c->protectionAgainstItems[ii]); out->writeUint16BE(c->itemProtection); out->writeSint16BE(c->hitPointsCur); out->writeUint16BE(c->hitPointsMax); out->writeSint16BE(c->magicPointsCur); out->writeUint16BE(c->magicPointsMax); out->writeByte(c->field_41); out->writeUint16BE(c->damageSuffered); out->writeUint16BE(c->weaponHit); out->writeUint16BE(c->totalMightModifier); out->writeUint16BE(c->totalProtectionModifier); out->writeUint16BE(c->might); out->writeUint16BE(c->protection); out->writeSint16BE(c->nextAnimUpdateCountdown); for (int ii = 0; ii < 11; ii++) out->writeUint16BE(c->items[ii]); for (int ii = 0; ii < 3; ii++) out->writeByte(c->skillLevels[ii]); for (int ii = 0; ii < 3; ii++) out->writeSByte(c->skillModifiers[ii]); for (int ii = 0; ii < 3; ii++) out->writeUint32BE(c->experiencePts[ii]); for (int ii = 0; ii < 5; ii++) out->writeByte(c->characterUpdateEvents[ii]); for (int ii = 0; ii < 5; ii++) out->writeByte(c->characterUpdateDelay[ii]); } out->write(_wllBuffer4, 80); out->writeUint16BE(_currentBlock); out->writeUint16BE(_partyPosX); out->writeUint16BE(_partyPosY); out->writeUint16BE(_updateFlags); out->writeByte(_scriptDirection); out->writeByte(_selectedSpell); out->writeByte(_sceneDefaultUpdate); out->writeByte(_compassBroken); out->writeByte(_drainMagic); out->writeUint16BE(_currentDirection); out->writeUint16BE(_compassDirection); out->writeSByte(_selectedCharacter); out->writeByte(_currentLevel); for (int i = 0; i < 48; i++) out->writeSint16BE(_inventory[i]); out->writeSint16BE(_inventoryCurItem); out->writeSint16BE(_itemInHand); out->writeSint16BE(_lastMouseRegion); out->writeUint32BE(ARRAYSIZE(_flagsTable)); out->write(_flagsTable, ARRAYSIZE(_flagsTable)); for (int i = 0; i < 24; i++) out->writeUint16BE(_globalScriptVars[i]); out->writeByte(_brightness); out->writeByte(_lampOilStatus); out->writeSByte(_lampEffect); out->writeUint16BE(_credits); for (int i = 0; i < 8; i++) out->writeUint16BE(_globalScriptVars2[i]); out->write(_availableSpells, 7); out->writeUint32BE(_hasTempDataFlags); resetItems(0); for (int i = 0; i < 400; i++) { ItemInPlay *t = &_itemsInPlay[i]; out->writeUint16BE(t->nextAssignedObject); out->writeUint16BE(t->nextDrawObject); out->writeByte(t->flyingHeight); out->writeUint16BE(t->block); out->writeUint16BE(t->x); out->writeUint16BE(t->y); out->writeSByte(t->level); out->writeUint16BE(t->itemPropertyIndex); out->writeUint16BE(t->shpCurFrame_flg); out->writeByte(t->destDirection); out->writeSByte(t->hitOffsX); out->writeSByte(t->hitOffsY); out->writeByte(t->currentSubFrame); } addLevelItems(); for (int i = 0; i < 29; i++) { LevelTempData *l = _lvlTempData[i]; if (!l || !(_hasTempDataFlags & (1 << i))) continue; out->write(l->wallsXorData, 4096); out->write(l->flags, 1024); for (int ii = 0; ii < 30; ii++) { MonsterInPlay *m = &l->monsters[ii]; out->writeUint16BE(m->nextAssignedObject); out->writeUint16BE(m->nextDrawObject); out->writeByte(m->flyingHeight); out->writeUint16BE(m->block); out->writeUint16BE(m->x); out->writeUint16BE(m->y); out->writeSByte(m->shiftStep); out->writeUint16BE(m->destX); out->writeUint16BE(m->destY); out->writeByte(m->destDirection); out->writeSByte(m->hitOffsX); out->writeSByte(m->hitOffsY); out->writeByte(m->currentSubFrame); out->writeByte(m->mode); out->writeSByte(m->fightCurTick); out->writeByte(m->id); out->writeByte(m->direction); out->writeByte(m->facing); out->writeUint16BE(m->flags); out->writeUint16BE(m->damageReceived); out->writeSint16BE(m->hitPoints); out->writeByte(m->speedTick); out->writeByte(m->type); out->writeByte(m->numDistAttacks); out->writeByte(m->curDistWeapon); out->writeSByte(m->distAttackTick); out->writeUint16BE(m->assignedItems); out->write(m->equipmentShapes, 4); } for (int ii = 0; ii < 8; ii++) { FlyingObject *m = &l->flyingObjects[ii]; out->writeByte(m->enable); out->writeByte(m->objectType); out->writeUint16BE(m->attackerId); out->writeSint16BE(m->item); out->writeUint16BE(m->x); out->writeUint16BE(m->y); out->writeByte(m->flyingHeight); out->writeByte(m->direction); out->writeByte(m->distance); out->writeSByte(m->field_D); out->writeByte(m->c); out->writeByte(m->flags); out->writeByte(m->wallFlags); } out->writeByte(l->monsterDifficulty); } out->finalize(); // check for errors if (out->err()) { warning("Can't write file '%s'. (Disk full?)", fileName); return Common::kUnknownError; } else { debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName); } delete out; return Common::kNoError; }
Common::Error KyraEngine_MR::loadGameState(int slot) { const char *fileName = getSavegameFilename(slot); SaveHeader header; Common::InSaveFile *saveFile = openSaveForReading(fileName, header); if (!saveFile) { showMessageFromCCode(17, 0xB3, 0); snd_playSoundEffect(0x0D, 0xC8); return Common::kUnknownError; } if (header.originalSave) warning("Trying to load savegame from original interpreter, while this is possible, it is not officially supported"); if (_inventoryState) { updateCharacterAnim(0); restorePage3(); drawAnimObjects(); _inventoryState = true; refreshAnimObjects(0); hideInventory(); } _deathHandler = -1; if (!_unkSceneScreenFlag1) _lastMusicCommand = -1; int curShapes = _characterShapeFile; Common::SeekableSubReadStreamEndian in(saveFile, saveFile->pos(), saveFile->size(), !header.originalSave, DisposeAfterUse::YES); _screen->hideMouse(); if (!header.originalSave) { _timer->loadDataFromFile(in, header.version); uint32 flagsSize = in.readUint32BE(); assert(flagsSize <= sizeof(_flagsTable)); in.read(_flagsTable, flagsSize); } _lastMusicCommand = in.readSint16(); _currentChapter = in.readByte(); _characterShapeFile = in.readByte(); if (header.version >= 12 || header.originalSave) _album.curPage = in.readByte(); if (header.originalSave) in.readByte(); _score = in.readSint16(); _scoreMax = in.readSint16(); _malcolmsMood = in.readByte(); if (header.originalSave) in.seek(8, SEEK_CUR); for (int i = 0; i < 30; ++i) in.read(_conversationState[i], 30); if (!header.originalSave) { in.read(_newSceneDlgState, 40); } else { for (int i = 0; i < 40; ++i) _newSceneDlgState[i] = in.readUint16(); } for (int i = 0; i < 100; ++i) _hiddenItems[i] = in.readSint16(); if (header.originalSave) in.read(_flagsTable, 69); in.read(_scoreFlagTable, 26); _mainCharacter.sceneId = in.readUint16(); _mainCharacter.dlgIndex = in.readSint16(); _mainCharacter.height = in.readByte(); _mainCharacter.facing = in.readByte(); _mainCharacter.animFrame = in.readUint16(); if (!header.originalSave) { _mainCharacter.walkspeed = in.readByte(); } else { in.seek(2, SEEK_CUR); _mainCharacter.walkspeed = in.readUint32(); } for (int i = 0; i < 10; ++i) _mainCharacter.inventory[i] = in.readUint16(); _mainCharacter.x1 = in.readSint16(); _mainCharacter.y1 = in.readSint16(); _mainCharacter.x2 = in.readSint16(); _mainCharacter.y2 = in.readSint16(); _mainCharacter.x3 = in.readSint16(); _mainCharacter.y3 = in.readSint16(); for (int i = 0; i < 50; ++i) { _itemList[i].id = in.readSint16(); _itemList[i].sceneId = in.readUint16(); _itemList[i].x = in.readSint16(); _itemList[i].y = in.readSint16(); if (header.version <= 9 || header.originalSave) in.readUint16(); } for (int i = 0; i < 88; ++i) { in.read(_talkObjectList[i].filename, 13); _talkObjectList[i].sceneAnim = in.readByte(); _talkObjectList[i].sceneScript = in.readByte(); _talkObjectList[i].x = in.readSint16(); _talkObjectList[i].y = in.readSint16(); _talkObjectList[i].color = in.readByte(); if (header.version >= 13 || header.originalSave) _talkObjectList[i].sceneId = in.readByte(); } for (int i = 0; i < 98; ++i) { if (!header.originalSave) { in.read(_sceneList[i].filename1, 10); } else { in.read(_sceneList[i].filename1, 9); _sceneList[i].filename1[9] = 0; } if (!header.originalSave) { in.read(_sceneList[i].filename2, 10); } else { in.read(_sceneList[i].filename2, 9); _sceneList[i].filename2[9] = 0; } _sceneList[i].exit1 = in.readUint16(); _sceneList[i].exit2 = in.readUint16(); _sceneList[i].exit3 = in.readUint16(); _sceneList[i].exit4 = in.readUint16(); _sceneList[i].flags = in.readByte(); _sceneList[i].sound = in.readByte(); } _itemInHand = in.readSint16(); if (header.originalSave) { uint32 currentTime = _system->getMillis(); for (int i = 0; i < 6; ++i) _timer->setDelay(i, in.readSint32LE()); for (int i = 0; i < 6; ++i) { if (in.readUint16LE()) _timer->enable(i); else _timer->disable(i); } for (int i = 0; i < 6; ++i) _timer->setNextRun(i, currentTime + (in.readUint32LE() * _tickLength)); _timer->resetNextRun(); } _sceneExit1 = in.readUint16(); _sceneExit2 = in.readUint16(); _sceneExit3 = in.readUint16(); _sceneExit4 = in.readUint16(); if (saveFile->err() || saveFile->eos()) { warning("Load failed ('%s', '%s').", fileName, header.description.c_str()); return Common::kUnknownError; } else { debugC(1, kDebugLevelMain, "Loaded savegame '%s.'", header.description.c_str()); } _loadingState = true; updateCharacterAnim(0); _loadingState = false; if (curShapes != _characterShapeFile) loadCharacterShapes(_characterShapeFile); _mainCharX = _mainCharacter.x2 = _mainCharacter.x1; _mainCharY = _mainCharacter.y2 = _mainCharacter.y1; _mainCharacter.facing = 4; _badConscienceShown = false; _badConsciencePosition = false; _goodConscienceShown = false; _goodConsciencePosition = false; enterNewScene(_mainCharacter.sceneId, _mainCharacter.facing, 0, 0, 1); setHandItem(_itemInHand); if (_lastMusicCommand >= 0 && !_unkSceneScreenFlag1) snd_playWanderScoreViaMap(_lastMusicCommand, 1); else if (_lastMusicCommand == -1) snd_playWanderScoreViaMap(28, 1); while (!_screen->isMouseVisible()) _screen->showMouse(); setCommandLineRestoreTimer(7); _shownMessage = " "; _restoreCommandLine = false; // We didn't explicitly set the walk speed, but it's saved as part of // the _timers array, so we need to re-sync it with _configWalkspeed. setWalkspeed(_configWalkspeed); return Common::kNoError; }
Common::Error KyraEngine_HoF::loadGameState(int slot) { const char *fileName = getSavegameFilename(slot); SaveHeader header; Common::InSaveFile *saveFile = openSaveForReading(fileName, header); if (!saveFile) { showMessageFromCCode(0x35, 0x84, 0); snd_playSoundEffect(0x0D); return Common::kUnknownError; } if (header.originalSave) warning("Trying to load savegame from original interpreter, while this is possible, it is not officially supported"); bool setFlag1EE = (queryGameFlag(0x1EE) != 0); _deathHandler = -1; if (!_unkSceneScreenFlag1) { _sound->beginFadeOut(); _system->delayMillis(5 * _tickLength); _lastMusicCommand = -1; } int loadedZTable = _characterShapeFile; Common::SeekableSubReadStreamEndian in(saveFile, saveFile->pos(), saveFile->size(), !header.originalSave, DisposeAfterUse::YES); _screen->hideMouse(); if (!header.originalSave) { _timer->loadDataFromFile(in, header.version); uint32 flagsSize = in.readUint32BE(); assert(flagsSize <= sizeof(_flagsTable)); in.read(_flagsTable, flagsSize); } // usually we have to save the flag set by opcode 10 here //word_2AB05 = in.readUint16(); if (header.originalSave) in.readUint16(); _lastMusicCommand = in.readSint16(); _newChapterFile = in.readByte(); _characterShapeFile = in.readByte(); _cauldronState = in.readByte(); _colorCodeFlag1 = in.readByte(); _colorCodeFlag2 = in.readByte(); _bookCurPage = in.readByte(); _bookMaxPage = in.readByte(); for (int i = 0; i < 7; ++i) _presetColorCode[i] = in.readByte(); for (int i = 0; i < 7; ++i) _inputColorCode[i] = in.readByte(); for (int i = 0; i < 25; ++i) _cauldronTable[i] = in.readSint16(); for (int i = 0; i < 20; ++i) _hiddenItems[i] = in.readSint16(); if (header.originalSave) { assert(sizeof(_flagsTable) >= 0x41); in.read(_flagsTable, 0x41); } for (int i = 0; i < 19; ++i) in.read(_conversationState[i], 14); if (!header.originalSave) { in.read(_newSceneDlgState, 32); } else { for (int i = 0; i < 31; ++i) _newSceneDlgState[i] = in.readUint16(); } _cauldronUseCount = in.readSint16(); if (header.originalSave) in.seek(6, SEEK_CUR); _mainCharacter.sceneId = in.readUint16(); _mainCharacter.dlgIndex = in.readSint16(); _mainCharacter.height = in.readByte(); _mainCharacter.facing = in.readByte(); _mainCharacter.animFrame = in.readUint16(); if (header.version <= 10 || header.originalSave) in.seek(3, SEEK_CUR); for (int i = 0; i < 20; ++i) _mainCharacter.inventory[i] = in.readUint16(); _mainCharacter.x1 = in.readSint16(); _mainCharacter.y1 = in.readSint16(); _mainCharacter.x2 = in.readSint16(); _mainCharacter.y2 = in.readSint16(); for (int i = 0; i < 30; ++i) { _itemList[i].id = in.readSint16(); _itemList[i].sceneId = in.readUint16(); _itemList[i].x = in.readSint16(); _itemList[i].y = in.readByte(); if (header.version <= 9 || header.originalSave) in.readUint16(); } for (int i = 0; i < 72; ++i) { in.read(_talkObjectList[i].filename, 13); _talkObjectList[i].scriptId = in.readByte(); _talkObjectList[i].x = in.readSint16(); _talkObjectList[i].y = in.readSint16(); _talkObjectList[i].color = in.readByte(); } for (int i = 0; i < 86; ++i) { if (!header.originalSave) { in.read(_sceneList[i].filename1, 10); } else { in.read(_sceneList[i].filename1, 9); _sceneList[i].filename1[9] = 0; } _sceneList[i].exit1 = in.readUint16(); _sceneList[i].exit2 = in.readUint16(); _sceneList[i].exit3 = in.readUint16(); _sceneList[i].exit4 = in.readUint16(); _sceneList[i].flags = in.readByte(); _sceneList[i].sound = in.readByte(); } _itemInHand = in.readSint16(); if (header.originalSave) { uint32 currentTime = _system->getMillis(); for (int i = 0; i < 6; ++i) _timer->setDelay(i, in.readSint32LE()); for (int i = 0; i < 6; ++i) { if (in.readUint16LE()) _timer->enable(i); else _timer->disable(i); } for (int i = 0; i < 6; ++i) _timer->setNextRun(i, currentTime + (in.readUint32LE() * _tickLength)); _timer->resetNextRun(); } _sceneExit1 = in.readUint16(); _sceneExit2 = in.readUint16(); _sceneExit3 = in.readUint16(); _sceneExit4 = in.readUint16(); if (saveFile->err() || saveFile->eos()) { warning("Load failed ('%s', '%s').", fileName, header.description.c_str()); return Common::kUnknownError; } else { debugC(1, kDebugLevelMain, "Loaded savegame '%s.'", header.description.c_str()); } if (loadedZTable != _characterShapeFile) loadCharacterShapes(_characterShapeFile); _screen->loadBitmap("_PLAYFLD.CPS", 3, 3, 0); if (!queryGameFlag(1)) _screen->copyRegion(0xCE, 0x90, 0xCE, 0x90, 0x2C, 0x2C, 2, 0, Screen::CR_NO_P_CHECK); if (!queryGameFlag(2)) _screen->copyRegion(0xFA, 0x90, 0xFA, 0x90, 0x46, 0x2C, 2, 0, Screen::CR_NO_P_CHECK); _screen->loadBitmap("_PLAYALL.CPS", 3, 3, 0); if (queryGameFlag(1)) _screen->copyRegion(0xCE, 0x90, 0xCE, 0x90, 0x2C, 0x2C, 2, 0, Screen::CR_NO_P_CHECK); if (queryGameFlag(2)) _screen->copyRegion(0xFA, 0x90, 0xFA, 0x90, 0x46, 0x2C, 2, 0, Screen::CR_NO_P_CHECK); redrawInventory(0); int cauldronUseCount = _cauldronUseCount; setCauldronState(_cauldronState, 0); _cauldronUseCount = cauldronUseCount; _mainCharX = _mainCharacter.x2 = _mainCharacter.x1; _mainCharY = _mainCharacter.y2 = _mainCharacter.y1; _mainCharacter.facing = 4; enterNewScene(_mainCharacter.sceneId, _mainCharacter.facing, 0, 0, 1); setDelayedCursorUpdate(); if (_lastMusicCommand >= 0 && !_unkSceneScreenFlag1) snd_playWanderScoreViaMap(_lastMusicCommand, 1); while (!_screen->isMouseVisible()) _screen->showMouse(); setTimer1DelaySecs(7); _shownMessage = " "; _fadeMessagePalette = false; if (setFlag1EE) setGameFlag(0x1EE); // We didn't explicitly set the walk speed, but it's saved as part of // the _timers array, so we need to re-sync it with _configWalkspeed. setWalkspeed(_configWalkspeed); return Common::kNoError; }
Common::Error NeverhoodEngine::loadGameState(int slot) { const char *fileName = getSavegameFilename(slot); if (!loadgame(fileName)) return Common::kReadingFailed; return Common::kNoError; }
Common::Error KyraEngine_HoF::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumb) { const char *fileName = getSavegameFilename(slot); Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumb); if (!out) return _saveFileMan->getError(); _timer->saveDataToFile(*out); out->writeUint32BE(sizeof(_flagsTable)); out->write(_flagsTable, sizeof(_flagsTable)); // usually we have to save the flag set by opcode 10 here //out->writeUint16BE(word_2AB05); out->writeSint16BE(_lastMusicCommand); out->writeByte(_newChapterFile); out->writeByte(_characterShapeFile); out->writeByte(_cauldronState); out->writeByte(_colorCodeFlag1); out->writeByte(_colorCodeFlag2); out->writeByte(_bookCurPage); out->writeByte(_bookMaxPage); for (int i = 0; i < 7; ++i) out->writeByte(_presetColorCode[i]); for (int i = 0; i < 7; ++i) out->writeByte(_inputColorCode[i]); for (int i = 0; i < 25; ++i) out->writeSint16BE(_cauldronTable[i]); for (int i = 0; i < 20; ++i) out->writeSint16BE(_hiddenItems[i]); for (int i = 0; i < 19; ++i) out->write(_conversationState[i], 14); out->write(_newSceneDlgState, 32); out->writeSint16BE(_cauldronUseCount); out->writeUint16BE(_mainCharacter.sceneId); out->writeSint16BE(_mainCharacter.dlgIndex); out->writeByte(_mainCharacter.height); out->writeByte(_mainCharacter.facing); out->writeUint16BE(_mainCharacter.animFrame); for (int i = 0; i < 20; ++i) out->writeUint16BE(_mainCharacter.inventory[i]); out->writeSint16BE(_mainCharacter.x1); out->writeSint16BE(_mainCharacter.y1); out->writeSint16BE(_mainCharacter.x2); out->writeSint16BE(_mainCharacter.y2); for (int i = 0; i < 30; ++i) { out->writeSint16BE(_itemList[i].id); out->writeUint16BE(_itemList[i].sceneId); out->writeSint16BE(_itemList[i].x); out->writeByte(_itemList[i].y); } for (int i = 0; i < 72; ++i) { out->write(_talkObjectList[i].filename, 13); out->writeByte(_talkObjectList[i].scriptId); out->writeSint16BE(_talkObjectList[i].x); out->writeSint16BE(_talkObjectList[i].y); out->writeByte(_talkObjectList[i].color); } for (int i = 0; i < 86; ++i) { out->write(_sceneList[i].filename1, 10); out->writeUint16BE(_sceneList[i].exit1); out->writeUint16BE(_sceneList[i].exit2); out->writeUint16BE(_sceneList[i].exit3); out->writeUint16BE(_sceneList[i].exit4); out->writeByte(_sceneList[i].flags); out->writeByte(_sceneList[i].sound); } out->writeSint16BE(_itemInHand); out->writeUint16BE(_sceneExit1); out->writeUint16BE(_sceneExit2); out->writeUint16BE(_sceneExit3); out->writeUint16BE(_sceneExit4); out->finalize(); // check for errors if (out->err()) { warning("Can't write file '%s'. (Disk full?)", fileName); return Common::kUnknownError; } else { debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName); } delete out; return Common::kNoError; }
const char *NeverhoodEngine::getSavegameFilename(int num) { static Common::String filename; filename = getSavegameFilename(_targetName, num); return filename.c_str(); }
Common::Error EoBCoreEngine::loadGameState(int slot) { // Special slot id -1 for EOB1 party transfer const char *fileName = (slot == -1) ? _savegameFilename.c_str() : getSavegameFilename(slot); SaveHeader header; Common::InSaveFile *saveFile = openSaveForReading(fileName, header, (slot != -1)); if (!saveFile) return Common::Error(Common::kReadingFailed); Common::SeekableSubReadStreamEndian in(saveFile, saveFile->pos(), saveFile->size(), !header.originalSave, DisposeAfterUse::YES); _loading = true; if (slot != -1) _screen->fadeToBlack(10); for (int i = 0; i < 6; i++) { EoBCharacter *c = &_characters[i]; c->id = in.readByte(); c->flags = in.readByte(); in.read(c->name, 11); c->strengthCur = in.readSByte(); c->strengthMax = in.readSByte(); c->strengthExtCur = in.readSByte(); c->strengthExtMax = in.readSByte(); c->intelligenceCur = in.readSByte(); c->intelligenceMax = in.readSByte(); c->wisdomCur = in.readSByte(); c->wisdomMax = in.readSByte(); c->dexterityCur = in.readSByte(); c->dexterityMax = in.readSByte(); c->constitutionCur = in.readSByte(); c->constitutionMax = in.readSByte(); c->charismaCur = in.readSByte(); c->charismaMax = in.readSByte(); c->hitPointsCur = in.readSint16BE(); c->hitPointsMax = in.readSint16BE(); c->armorClass = in.readSByte(); c->disabledSlots = in.readByte(); c->raceSex = in.readByte(); c->cClass = in.readByte(); c->alignment = in.readByte(); c->portrait = in.readSByte(); if (slot == -1 && c->portrait < 0) c->portrait = -c->portrait + 43; c->food = in.readByte(); in.read(c->level, 3); for (int ii = 0; ii < 3; ii++) c->experience[ii] = in.readUint32BE(); delete[] c->faceShape; c->faceShape = 0; in.read(c->mageSpells, 80); in.read(c->clericSpells, 80); c->mageSpellsAvailableFlags = in.readUint32BE(); for (int ii = 0; ii < 27; ii++) c->inventory[ii] = in.readSint16BE(); uint32 ct = _system->getMillis(); for (int ii = 0; ii < 10; ii++) { c->timers[ii] = in.readUint32BE(); if (c->timers[ii]) c->timers[ii] += ct; } in.read(c->events, 10); in.read(c->effectsRemainder, 4); c->effectFlags = in.readUint32BE(); c->damageTaken = in.readByte(); in.read(c->slotStatus, 5); } setupCharacterTimers(); _screen->loadShapeSetBitmap("CHARGENA", 3, 3); for (int i = 0; i < 6; i++) { EoBCharacter *c = &_characters[i]; if (!c->flags || c->portrait < 0) continue; c->faceShape = _screen->encodeShape((c->portrait % 10) << 2, (c->portrait / 10) << 5, 4, 32, true); } _screen->loadShapeSetBitmap(_flags.gameID == GI_EOB2 ? "OUTPORTS" : "OUTTAKE", 3, 3); for (int i = 0; i < 6; i++) { EoBCharacter *c = &_characters[i]; if (!c->flags || c->portrait >= 0) continue; c->faceShape = _screen->encodeShape((-(c->portrait + 1)) << 2, _flags.gameID == GI_EOB2 ? 0 : 160, 4, 32, true); } _screen->_curPage = 0; if (slot == -1) { // Skip all settings which aren't necessary for party transfer. // Jump directly to the items list. in.skip(108); } else { _currentLevel = in.readByte(); _currentSub = in.readSByte(); _currentBlock = in.readUint16BE(); _currentDirection = in.readUint16BE(); _itemInHand = in.readSint16BE(); _hasTempDataFlags = in.readUint32BE(); _partyEffectFlags = in.readUint32BE(); _updateFlags = in.readUint16BE(); _compassDirection = in.readUint16BE(); _currentControlMode = in.readUint16BE(); _updateCharNum = in.readUint16BE(); _openBookSpellLevel = in.readSByte(); _openBookSpellSelectedItem = in.readSByte(); _openBookSpellListOffset = in.readSByte(); _openBookChar = in.readByte(); _openBookType = in.readByte(); _openBookCharBackup = in.readByte(); _openBookTypeBackup = in.readByte(); _activeSpellCharId = in.readByte(); _activeSpellCharacterPos = in.readByte(); _activeSpell = in.readByte(); _returnAfterSpellCallback = in.readByte() ? true : false; _inf->loadState(in); } for (int i = 0; i < 600; i++) { EoBItem *t = &_items[i]; t->nameUnid = in.readByte(); t->nameId = in.readByte(); t->flags = in.readByte(); t->icon = in.readSByte(); t->type = in.readSByte(); t->pos = in.readSByte(); t->block = in.readSint16BE(); t->next = in.readSint16BE(); t->prev = in.readSint16BE(); t->level = in.readByte(); t->value = in.readSByte(); } // No more data needed for party transfer if (slot == -1) { _loading = false; return Common::kNoError; } for (int i = 51; i < 65; i++) { EoBItemType *t = &_itemTypes[i]; t->invFlags = in.readUint16BE(); t->handFlags = in.readUint16BE(); t->armorClass = in.readSByte(); t->allowedClasses = in.readSByte(); t->requiredHands = in.readSByte(); t->dmgNumDiceS = in.readSByte(); t->dmgNumPipsS = in.readSByte(); t->dmgIncS = in.readSByte(); t->dmgNumDiceL = in.readSByte(); t->dmgNumPipsL = in.readSByte(); t->dmgIncL = in.readSByte(); t->unk1 = in.readByte(); t->extraProperties = in.readUint16BE(); } for (int i = 0; i < 18; i++) { if (!(_hasTempDataFlags & (1 << i))) continue; if (_lvlTempData[i]) { delete[] _lvlTempData[i]->wallsXorData; delete[] _lvlTempData[i]->flags; releaseMonsterTempData(_lvlTempData[i]); releaseFlyingObjectTempData(_lvlTempData[i]); releaseWallOfForceTempData(_lvlTempData[i]); delete _lvlTempData[i]; } _lvlTempData[i] = new LevelTempData; LevelTempData *l = _lvlTempData[i]; l->wallsXorData = new uint8[4096]; l->flags = new uint16[1024]; EoBMonsterInPlay *lm = new EoBMonsterInPlay[30]; l->monsters = lm; EoBFlyingObject *lf = new EoBFlyingObject[_numFlyingObjects]; l->flyingObjects = lf; WallOfForce *lw = new WallOfForce[5]; l->wallsOfForce = lw; in.read(l->wallsXorData, 4096); for (int ii = 0; ii < 1024; ii++) l->flags[ii] = in.readByte(); for (int ii = 0; ii < 30; ii++) { EoBMonsterInPlay *m = &lm[ii]; m->type = in.readByte(); m->unit = in.readByte(); m->block = in.readUint16BE(); m->pos = in.readByte(); m->dir = in.readSByte(); m->animStep = in.readByte(); m->shpIndex = in.readByte(); m->mode = in.readSByte(); m->f_9 = in.readSByte(); m->curAttackFrame = in.readSByte(); m->spellStatusLeft = in.readSByte(); m->hitPointsMax = in.readSint16BE(); m->hitPointsCur = in.readSint16BE(); m->dest = in.readUint16BE(); m->randItem = in.readUint16BE(); m->fixedItem = in.readUint16BE(); m->flags = in.readByte(); m->idleAnimState = in.readByte(); m->curRemoteWeapon = in.readByte(); m->numRemoteAttacks = in.readByte(); m->palette = in.readSByte(); m->directionChanged = in.readByte(); m->stepsTillRemoteAttack = in.readByte(); m->sub = in.readByte(); } for (int ii = 0; ii < _numFlyingObjects; ii++) { EoBFlyingObject *m = &lf[ii]; m->enable = in.readByte(); m->objectType = in.readByte(); m->attackerId = in.readSint16BE(); m->item = in.readSint16BE(); m->curBlock = in.readUint16BE(); m->u2 = in.readUint16BE(); m->u1 = in.readByte(); m->direction = in.readByte(); m->distance = in.readByte(); m->callBackIndex = in.readSByte(); m->curPos = in.readByte(); m->flags = in.readByte(); m->unused = in.readByte(); } for (int ii = 0; ii < 5; ii++) { WallOfForce *w = &lw[ii]; w->block = in.readUint16BE(); w->duration = in.readUint32BE(); } } loadLevel(_currentLevel, _currentSub); _sceneUpdateRequired = true; _screen->setFont(Screen::FID_6_FNT); for (int i = 0; i < 6; i++) { for (int ii = 0; ii < 10; ii++) { if (_characters[i].events[ii] == -57) spellCallback_start_trueSeeing(); } } _screen->setCurPage(0); gui_drawPlayField(false); if (_currentControlMode) _screen->copyRegion(176, 0, 0, 0, 144, 168, 0, 5, Screen::CR_NO_P_CHECK); _screen->setCurPage(0); gui_drawAllCharPortraitsWithStats(); drawScene(1); if (_updateFlags) { _updateFlags = 0; useMagicBookOrSymbol(_openBookChar, _openBookType); } _screen->copyRegion(0, 120, 0, 0, 176, 24, 0, 12, Screen::CR_NO_P_CHECK); gui_toggleButtons(); setHandItem(_itemInHand); while (!_screen->isMouseVisible()) _screen->showMouse(); _loading = false; _screen->fadeFromBlack(20); removeInputTop(); return Common::kNoError; }
Common::Error EoBCoreEngine::saveGameStateIntern(int slot, const char *saveName, const Graphics::Surface *thumbnail) { Common::String saveNameTmp; const char *fileName = 0; // Special slot id -1 to create final save for party transfer if (slot == -1) { _savegameFilename = _targetName + Common::String(".fin"); fileName = _savegameFilename.c_str(); saveNameTmp = _targetName + Common::String(" final"); saveNameTmp.toUppercase(); saveName = saveNameTmp.c_str(); } else { fileName = getSavegameFilename(slot); } Common::OutSaveFile *out = openSaveForWriting(fileName, saveName, thumbnail); if (!out) return _saveFileMan->getError(); completeDoorOperations(); generateTempData(); advanceTimers(_restPartyElapsedTime); _restPartyElapsedTime = 0; for (int i = 0; i < 6; i++) timerSpecialCharacterUpdate(0x30 + i); for (int i = 0; i < 6; i++) { EoBCharacter *c = &_characters[i]; out->writeByte(c->id); out->writeByte(c->flags); out->write(c->name, 11); out->writeSByte(c->strengthCur); out->writeSByte(c->strengthMax); out->writeSByte(c->strengthExtCur); out->writeSByte(c->strengthExtMax); out->writeSByte(c->intelligenceCur); out->writeSByte(c->intelligenceMax); out->writeSByte(c->wisdomCur); out->writeSByte(c->wisdomMax); out->writeSByte(c->dexterityCur); out->writeSByte(c->dexterityMax); out->writeSByte(c->constitutionCur); out->writeSByte(c->constitutionMax); out->writeSByte(c->charismaCur); out->writeSByte(c->charismaMax); out->writeSint16BE(c->hitPointsCur); out->writeSint16BE(c->hitPointsMax); out->writeSByte(c->armorClass); out->writeByte(c->disabledSlots); out->writeByte(c->raceSex); out->writeByte(c->cClass); out->writeByte(c->alignment); out->writeByte(c->portrait); out->writeByte(c->food); out->write(c->level, 3); for (int ii = 0; ii < 3; ii++) out->writeUint32BE(c->experience[ii]); out->write(c->mageSpells, 80); out->write(c->clericSpells, 80); out->writeUint32BE(c->mageSpellsAvailableFlags); for (int ii = 0; ii < 27; ii++) out->writeSint16BE(c->inventory[ii]); uint32 ct = _system->getMillis(); for (int ii = 0; ii < 10; ii++) out->writeUint32BE((c->timers[ii] && c->timers[ii] > ct) ? c->timers[ii] - ct : 0); out->write(c->events, 10); out->write(c->effectsRemainder, 4); out->writeUint32BE(c->effectFlags); out->writeByte(c->damageTaken); out->write(c->slotStatus, 5); } out->writeByte(_currentLevel); out->writeSByte(_currentSub); out->writeUint16BE(_currentBlock); out->writeUint16BE(_currentDirection); out->writeSint16BE(_itemInHand); out->writeUint32BE(_hasTempDataFlags); out->writeUint32BE(_partyEffectFlags); out->writeUint16BE(_updateFlags); out->writeUint16BE(_compassDirection); out->writeUint16BE(_currentControlMode); out->writeUint16BE(_updateCharNum); out->writeSByte(_openBookSpellLevel); out->writeSByte(_openBookSpellSelectedItem); out->writeSByte(_openBookSpellListOffset); out->writeByte(_openBookChar); out->writeByte(_openBookType); out->writeByte(_openBookCharBackup); out->writeByte(_openBookTypeBackup); out->writeByte(_activeSpellCharId); out->writeByte(_activeSpellCharacterPos); out->writeByte(_activeSpell); out->writeByte(_returnAfterSpellCallback ? 1 : 0); _inf->saveState(out); for (int i = 0; i < 600; i++) { EoBItem *t = &_items[i]; out->writeByte(t->nameUnid); out->writeByte(t->nameId); out->writeByte(t->flags); out->writeSByte(t->icon); out->writeSByte(t->type); out->writeSByte(t->pos); out->writeSint16BE(t->block); out->writeSint16BE(t->next); out->writeSint16BE(t->prev); out->writeByte(t->level); out->writeSByte(t->value); } for (int i = 51; i < 65; i++) { EoBItemType *t = &_itemTypes[i]; out->writeUint16BE(t->invFlags); out->writeUint16BE(t->handFlags); out->writeSByte(t->armorClass); out->writeSByte(t->allowedClasses); out->writeSByte(t->requiredHands); out->writeSByte(t->dmgNumDiceS); out->writeSByte(t->dmgNumPipsS); out->writeSByte(t->dmgIncS); out->writeSByte(t->dmgNumDiceL); out->writeSByte(t->dmgNumPipsL); out->writeSByte(t->dmgIncL); out->writeByte(t->unk1); out->writeUint16BE(t->extraProperties); } for (int i = 0; i < 18; i++) { LevelTempData *l = _lvlTempData[i]; if (!l || !(_hasTempDataFlags & (1 << i))) continue; out->write(l->wallsXorData, 4096); for (int ii = 0; ii < 1024; ii++) out->writeByte(l->flags[ii] & 0xff); EoBMonsterInPlay *lm = (EoBMonsterInPlay *)_lvlTempData[i]->monsters; EoBFlyingObject *lf = (EoBFlyingObject *)_lvlTempData[i]->flyingObjects; WallOfForce *lw = (WallOfForce *)_lvlTempData[i]->wallsOfForce; for (int ii = 0; ii < 30; ii++) { EoBMonsterInPlay *m = &lm[ii]; out->writeByte(m->type); out->writeByte(m->unit); out->writeUint16BE(m->block); out->writeByte(m->pos); out->writeSByte(m->dir); out->writeByte(m->animStep); out->writeByte(m->shpIndex); out->writeSByte(m->mode); out->writeSByte(m->f_9); out->writeSByte(m->curAttackFrame); out->writeSByte(m->spellStatusLeft); out->writeSint16BE(m->hitPointsMax); out->writeSint16BE(m->hitPointsCur); out->writeUint16BE(m->dest); out->writeUint16BE(m->randItem); out->writeUint16BE(m->fixedItem); out->writeByte(m->flags); out->writeByte(m->idleAnimState); out->writeByte(m->curRemoteWeapon); out->writeByte(m->numRemoteAttacks); out->writeSByte(m->palette); out->writeByte(m->directionChanged); out->writeByte(m->stepsTillRemoteAttack); out->writeByte(m->sub); } for (int ii = 0; ii < _numFlyingObjects; ii++) { EoBFlyingObject *m = &lf[ii]; out->writeByte(m->enable); out->writeByte(m->objectType); out->writeSint16BE(m->attackerId); out->writeSint16BE(m->item); out->writeUint16BE(m->curBlock); out->writeUint16BE(m->u2); out->writeByte(m->u1); out->writeByte(m->direction); out->writeByte(m->distance); out->writeSByte(m->callBackIndex); out->writeByte(m->curPos); out->writeByte(m->flags); out->writeByte(m->unused); } for (int ii = 0; ii < 5; ii++) { WallOfForce *w = &lw[ii]; out->writeUint16BE(w->block); out->writeUint32BE(w->duration); } } out->finalize(); // check for errors if (out->err()) { warning("Can't write file '%s'. (Disk full?)", fileName); return Common::kUnknownError; } else { debugC(1, kDebugLevelMain, "Saved game '%s.'", saveName); } delete out; _gui->notifyUpdateSaveSlotsList(); return Common::kNoError; }
int AgiEngine::saveGameDialog() { char *desc; const char *buttons[] = { "Do as I say!", "I regret", NULL }; char dstr[200]; int rc, slot = 0; int hm, vm, hp, vp; int w; hm = 1; vm = 3; hp = hm * CHAR_COLS; vp = vm * CHAR_LINES; w = (40 - 2 * hm) - 1; do { drawWindow(hp, vp, GFX_WIDTH - hp, GFX_HEIGHT - vp); printText("Select a slot in which you wish to\nsave the game:", 0, hm + 1, vm + 1, w, MSG_BOX_TEXT, MSG_BOX_COLOR); slot = selectSlot(); if (slot + _firstSlot == 0) messageBox("That slot is for Autosave only."); else if (slot < 0) return errOK; } while (slot + _firstSlot == 0); drawWindow(hp, vp + 5 * CHAR_LINES, GFX_WIDTH - hp, GFX_HEIGHT - vp - 9 * CHAR_LINES); printText("Enter a description for this game:", 0, hm + 1, vm + 6, w, MSG_BOX_TEXT, MSG_BOX_COLOR); _gfx->drawRectangle(3 * CHAR_COLS, 11 * CHAR_LINES - 1, 37 * CHAR_COLS, 12 * CHAR_LINES, MSG_BOX_TEXT); _gfx->flushBlock(3 * CHAR_COLS, 11 * CHAR_LINES - 1, 37 * CHAR_COLS, 12 * CHAR_LINES); // The description field of the save/restore dialog holds 32 characters // but we use four of them for the slot number. The input field is a // bit wider than that, so we don't have to worry about leaving space // for the cursor. getString(2, 11, 28, MAX_STRINGS); // If we're saving over an old slot, show the old description. We can't // access that buffer directly, so we have to feed the characters to // the input handler one at a time. char name[40]; int numChars; getSavegameDescription(_firstSlot + slot, name, false); for (numChars = 0; numChars < 28 && name[numChars]; numChars++) handleGetstring(name[numChars]); _gfx->printCharacter(numChars + 3, 11, _game.cursorChar, MSG_BOX_COLOR, MSG_BOX_TEXT); do { mainCycle(); } while (_game.inputMode == INPUT_GETSTRING); closeWindow(); desc = _game.strings[MAX_STRINGS]; sprintf(dstr, "Are you sure you want to save the game " "described as:\n\n%s\n\nin slot %d?\n\n\n", desc, _firstSlot + slot); rc = selectionBox(dstr, buttons); if (rc != 0) { messageBox("Game NOT saved."); return errOK; } Common::String fileName = getSavegameFilename(_firstSlot + slot); debugC(8, kDebugLevelMain | kDebugLevelResources, "file is [%s]", fileName.c_str()); // Make sure all graphics was blitted to screen. This fixes bug // #2960567: "AGI: Ego partly erased in Load/Save thumbnails" _gfx->doUpdate(); int result = saveGame(fileName, desc); if (result == errOK) messageBox("Game saved."); else messageBox("Error saving game."); return result; }