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 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); setDelayedCursorUpdate(); 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 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; }