diff --git a/engines/kyra/saveload.cpp b/engines/kyra/saveload.cpp index a0aaa05ba62..7d6fcaa0c10 100644 --- a/engines/kyra/saveload.cpp +++ b/engines/kyra/saveload.cpp @@ -52,7 +52,7 @@ Common::InSaveFile *KyraEngine::openSaveForReading(const char *filename, uint32 // following line to graciously handle old savegames from LE machines. // if (type != MKID_BE('KYRA') && type != MKID_BE('ARYK')) { if (type != MKID_BE(saveGameID())) { - warning("No Kyrandia savefile header."); + warning("No ScummVM Kyra engine savefile header."); delete in; return 0; } diff --git a/engines/kyra/saveload_v2.cpp b/engines/kyra/saveload_v2.cpp index add9c0638fc..62cc11ca828 100644 --- a/engines/kyra/saveload_v2.cpp +++ b/engines/kyra/saveload_v2.cpp @@ -134,8 +134,45 @@ void KyraEngine_v2::loadGame(const char *fileName) { uint32 version = 0; char saveName[31]; Common::InSaveFile *in = openSaveForReading(fileName, version, saveName); - if (!in) - return; + if (!in) { + // check for original savefile + if (in = _saveFileMan->openForLoading(fileName)) { + in->seek(0x50, SEEK_CUR); + + uint8 type[4]; + uint8 acceptedType[4] = { 0x4D, 0x42, 0x4C, 0x33 }; // 'MBL3' + in->read(type, sizeof(type)); + uint16 origVersion = in->readUint16LE(); + + debug(1, "Savegame type: '%c%c%c%c' version: %d", type[0], type[1], type[2], type[3], version); + + if (!memcmp(type, acceptedType, 4) && origVersion == 100) { + warning("Trying to load savegame from original interpreter, while this is possible, it is not officially supported."); + + in->seek(0, SEEK_SET); + + // read first 31 bytes of original description + in->read(saveName, 30); + saveName[30] = 0; + // skip last part of original description + in->seek(0x50-30, SEEK_CUR); + version = 0xF000 + origVersion; + // skip type + in->seek(4, SEEK_CUR); + // skip version + in->seek(2, SEEK_CUR); + } else { + delete in; + in = 0; + } + } + + if (!in) { + showMessageFromCCode(0x35, 0x84, 0); + snd_playSoundEffect(0x0D); + return; + } + } bool setFlag1EE = (queryGameFlag(0x1EE) != 0); @@ -150,82 +187,181 @@ void KyraEngine_v2::loadGame(const char *fileName) { _screen->hideMouse(); - _timer->loadDataFromFile(in, version); + if (version < 0xF000) { + _timer->loadDataFromFile(in, version); - uint32 flagsSize = in->readUint32BE(); - assert(flagsSize <= sizeof(_flagsTable)); - in->read(_flagsTable, flagsSize); + 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->readUint16BE(); - _lastMusicCommand = in->readSint16BE(); - _newChapterFile = in->readByte(); - _loadedZTable = 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->readSint16BE(); - for (int i = 0; i < 20; ++i) - _hiddenItems[i] = in->readUint16BE(); - for (int i = 0; i < 19; ++i) - in->read(_conversationState[i], 14); - in->read(_newSceneDlgState, 32); - _cauldronUseCount = in->readSint16BE(); + // usually we have to save the flag set by opcode 10 here + //word_2AB05 = in->readUint16BE(); + _lastMusicCommand = in->readSint16BE(); + _newChapterFile = in->readByte(); + _loadedZTable = 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->readSint16BE(); + for (int i = 0; i < 20; ++i) + _hiddenItems[i] = in->readUint16BE(); + for (int i = 0; i < 19; ++i) + in->read(_conversationState[i], 14); + in->read(_newSceneDlgState, 32); + _cauldronUseCount = in->readSint16BE(); - _mainCharacter.sceneId = in->readUint16BE(); - _mainCharacter.dlgIndex = in->readUint16BE(); - _mainCharacter.height = in->readByte(); - _mainCharacter.facing = in->readByte(); - _mainCharacter.animFrame = in->readUint16BE(); - _mainCharacter.unk8 = in->readByte(); - _mainCharacter.unk9 = in->readByte(); - _mainCharacter.unkA = in->readByte(); - for (int i = 0; i < 20; ++i) - _mainCharacter.inventory[i] = in->readUint16BE(); - _mainCharacter.x1 = in->readSint16BE(); - _mainCharacter.y1 = in->readSint16BE(); - _mainCharacter.x2 = in->readSint16BE(); - _mainCharacter.y2 = in->readSint16BE(); + _mainCharacter.sceneId = in->readUint16BE(); + _mainCharacter.dlgIndex = in->readUint16BE(); + _mainCharacter.height = in->readByte(); + _mainCharacter.facing = in->readByte(); + _mainCharacter.animFrame = in->readUint16BE(); + _mainCharacter.unk8 = in->readByte(); + _mainCharacter.unk9 = in->readByte(); + _mainCharacter.unkA = in->readByte(); + for (int i = 0; i < 20; ++i) + _mainCharacter.inventory[i] = in->readUint16BE(); + _mainCharacter.x1 = in->readSint16BE(); + _mainCharacter.y1 = in->readSint16BE(); + _mainCharacter.x2 = in->readSint16BE(); + _mainCharacter.y2 = in->readSint16BE(); - for (int i = 0; i < 30; ++i) { - _itemList[i].id = in->readUint16BE(); - _itemList[i].sceneId = in->readUint16BE(); - _itemList[i].x = in->readSint16BE(); - _itemList[i].y = in->readByte(); - _itemList[i].unk7 = in->readUint16BE(); + for (int i = 0; i < 30; ++i) { + _itemList[i].id = in->readUint16BE(); + _itemList[i].sceneId = in->readUint16BE(); + _itemList[i].x = in->readSint16BE(); + _itemList[i].y = in->readByte(); + _itemList[i].unk7 = in->readUint16BE(); + } + + for (int i = 0; i < 72; ++i) { + in->read(_talkObjectList[i].filename, 13); + _talkObjectList[i].scriptId = in->readByte(); + _talkObjectList[i].x = in->readSint16BE(); + _talkObjectList[i].y = in->readSint16BE(); + _talkObjectList[i].color = in->readByte(); + } + + for (int i = 0; i < 86; ++i) { + in->read(_sceneList[i].filename, 10); + _sceneList[i].exit1 = in->readUint16BE(); + _sceneList[i].exit2 = in->readUint16BE(); + _sceneList[i].exit3 = in->readUint16BE(); + _sceneList[i].exit4 = in->readUint16BE(); + _sceneList[i].flags = in->readByte(); + _sceneList[i].sound = in->readByte(); + } + + _itemInHand = in->readSint16BE(); + _sceneExit1 = in->readUint16BE(); + _sceneExit2 = in->readUint16BE(); + _sceneExit3 = in->readUint16BE(); + _sceneExit4 = in->readUint16BE(); + } else { + version -= 0xF000; + + /*word_2AB05 = */in->readUint16LE(); + _lastMusicCommand = in->readSint16LE(); + _newChapterFile = in->readByte(); + _loadedZTable = 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->readSint16LE(); + for (int i = 0; i < 20; ++i) + _hiddenItems[i] = in->readUint16LE(); + + assert(sizeof(_flagsTable) >= 0x41); + in->read(_flagsTable, 0x41); + + for (int i = 0; i < 19; ++i) + in->read(_conversationState[i], 14); + for (int i = 0; i < 31; ++i) + _newSceneDlgState[i] = in->readUint16LE(); + _cauldronUseCount = in->readSint16LE(); + in->seek(6, SEEK_CUR); + + _mainCharacter.sceneId = in->readUint16LE(); + _mainCharacter.dlgIndex = in->readUint16LE(); + _mainCharacter.height = in->readByte(); + _mainCharacter.facing = in->readByte(); + _mainCharacter.animFrame = in->readUint16LE(); + _mainCharacter.unk8 = in->readByte(); + _mainCharacter.unk9 = in->readByte(); + _mainCharacter.unkA = in->readByte(); + for (int i = 0; i < 20; ++i) + _mainCharacter.inventory[i] = in->readUint16LE(); + _mainCharacter.x1 = in->readSint16LE(); + _mainCharacter.y1 = in->readSint16LE(); + _mainCharacter.x2 = in->readSint16LE(); + _mainCharacter.y2 = in->readSint16LE(); + + for (int i = 0; i < 30; ++i) { + _itemList[i].id = in->readUint16LE(); + _itemList[i].sceneId = in->readUint16LE(); + _itemList[i].x = in->readSint16LE(); + _itemList[i].y = in->readByte(); + _itemList[i].unk7 = in->readUint16LE(); + } + + for (int i = 0; i < 72; ++i) { + in->read(_talkObjectList[i].filename, 13); + _talkObjectList[i].scriptId = in->readByte(); + _talkObjectList[i].x = in->readSint16LE(); + _talkObjectList[i].y = in->readSint16LE(); + _talkObjectList[i].color = in->readByte(); + } + + for (int i = 0; i < 86; ++i) { + in->read(_sceneList[i].filename, 9); + _sceneList[i].filename[9] = 0; + _sceneList[i].exit1 = in->readUint16LE(); + _sceneList[i].exit2 = in->readUint16LE(); + _sceneList[i].exit3 = in->readUint16LE(); + _sceneList[i].exit4 = in->readUint16LE(); + _sceneList[i].flags = in->readByte(); + _sceneList[i].sound = in->readByte(); + } + + _itemInHand = in->readSint16LE(); + + 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->readUint16LE(); + _sceneExit2 = in->readUint16LE(); + _sceneExit3 = in->readUint16LE(); + _sceneExit4 = in->readUint16LE(); } - for (int i = 0; i < 72; ++i) { - in->read(_talkObjectList[i].filename, 13); - _talkObjectList[i].scriptId = in->readByte(); - _talkObjectList[i].x = in->readSint16BE(); - _talkObjectList[i].y = in->readSint16BE(); - _talkObjectList[i].color = in->readByte(); - } - - for (int i = 0; i < 86; ++i) { - in->read(_sceneList[i].filename, 10); - _sceneList[i].exit1 = in->readUint16BE(); - _sceneList[i].exit2 = in->readUint16BE(); - _sceneList[i].exit3 = in->readUint16BE(); - _sceneList[i].exit4 = in->readUint16BE(); - _sceneList[i].flags = in->readByte(); - _sceneList[i].sound = in->readByte(); - } - - _itemInHand = in->readSint16BE(); - _sceneExit1 = in->readUint16BE(); - _sceneExit2 = in->readUint16BE(); - _sceneExit3 = in->readUint16BE(); - _sceneExit4 = in->readUint16BE(); - if (in->ioFailed()) error("Load failed ('%s', '%s').", fileName, saveName); else diff --git a/engines/kyra/timer.cpp b/engines/kyra/timer.cpp index d14b22ef116..a2d5a0c7d94 100644 --- a/engines/kyra/timer.cpp +++ b/engines/kyra/timer.cpp @@ -164,6 +164,18 @@ int32 TimerManager::getDelay(uint8 id) const { return -1; } +void TimerManager::setNextRun(uint8 id, uint32 nextRun) { + debugC(9, kDebugLevelTimer, "TimerManager::setNextRun(%d, %u)", id, nextRun); + + Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + if (timer != _timers.end()) { + timer->nextRun = nextRun; + return; + } + + warning("TimerManager::getNextRun: No timer %d", id); +} + uint32 TimerManager::getNextRun(uint8 id) const { debugC(9, kDebugLevelTimer, "TimerManager::getNextRun(%d)", id); diff --git a/engines/kyra/timer.h b/engines/kyra/timer.h index d3d6f6834d1..d943ec5cb06 100644 --- a/engines/kyra/timer.h +++ b/engines/kyra/timer.h @@ -69,17 +69,18 @@ public: void setCountdown(uint8 id, int32 countdown); void setDelay(uint8 id, int32 countdown); int32 getDelay(uint8 id) const; + void setNextRun(uint8 id, uint32 nextRun); uint32 getNextRun(uint8 id) const; bool isEnabled(uint8 id) const; void enable(uint8 id); void disable(uint8 id); - void resync(); - void loadDataFromFile(Common::InSaveFile *file, int version); void saveDataToFile(Common::OutSaveFile *file) const; private: + void resync(); + KyraEngine *_vm; OSystem *_system; Common::List _timers;