From 0984405a0dbe718522117507d7c75dc619c586a8 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Tue, 21 Apr 2015 22:51:03 -0500 Subject: SHERLOCK: Implement savegame synchronization --- engines/sherlock/inventory.cpp | 20 +++++++++++ engines/sherlock/inventory.h | 3 ++ engines/sherlock/journal.cpp | 31 ++++++++++++++++ engines/sherlock/journal.h | 5 +++ engines/sherlock/people.cpp | 13 ++++++- engines/sherlock/people.h | 5 ++- engines/sherlock/saveload.cpp | 71 +++++++++++++++++++++++++++++++++++-- engines/sherlock/saveload.h | 6 ++++ engines/sherlock/scene.cpp | 61 +++++++++++++++++++------------ engines/sherlock/scene.h | 5 ++- engines/sherlock/screen.cpp | 10 ++++++ engines/sherlock/screen.h | 3 ++ engines/sherlock/sherlock.cpp | 10 +++++- engines/sherlock/sherlock.h | 3 +- engines/sherlock/talk.cpp | 12 +++++++ engines/sherlock/talk.h | 6 +++- engines/sherlock/user_interface.cpp | 2 +- 17 files changed, 234 insertions(+), 32 deletions(-) diff --git a/engines/sherlock/inventory.cpp b/engines/sherlock/inventory.cpp index 9eedac7c6a..3ba6f9d2bd 100644 --- a/engines/sherlock/inventory.cpp +++ b/engines/sherlock/inventory.cpp @@ -486,4 +486,24 @@ int Inventory::deleteItemFromInventory(const Common::String &name) { return 1; } +/** + * Synchronize the data for a savegame + */ +void Inventory::synchronize(Common::Serializer &s) { + s.syncAsSint16LE(_holdings); + + uint count = size(); + s.syncAsUint16LE(count); + if (s.isLoading()) { + resize(count); + + // Reset inventory back to start + _invIndex = 0; + } + + for (uint idx = 0; idx < size(); ++idx) { + // TODO + } +} + } // End of namespace Sherlock diff --git a/engines/sherlock/inventory.h b/engines/sherlock/inventory.h index 4e426beaf4..bccdc9336e 100644 --- a/engines/sherlock/inventory.h +++ b/engines/sherlock/inventory.h @@ -25,6 +25,7 @@ #include "common/scummsys.h" #include "common/array.h" +#include "common/serializer.h" #include "common/str-array.h" #include "sherlock/objects.h" #include "sherlock/resources.h" @@ -99,6 +100,8 @@ public: int putItemInInventory(Object &obj); int deleteItemFromInventory(const Common::String &name); + + void synchronize(Common::Serializer &s); }; } // End of namespace Sherlock diff --git a/engines/sherlock/journal.cpp b/engines/sherlock/journal.cpp index f9c2c54289..15d3a07c75 100644 --- a/engines/sherlock/journal.cpp +++ b/engines/sherlock/journal.cpp @@ -1175,4 +1175,35 @@ int Journal::getFindName(bool printError) { return done; } +/** + * Reset viewing position to the start of the journal + */ +void Journal::resetPosition() { + _index = _sub = _up = _down = 0; + _page = 1; +} + +/** + * Synchronize the data for a savegame + */ +void Journal::synchronize(Common::Serializer &s) { + s.syncAsSint16LE(_count); + s.syncAsSint16LE(_index); + s.syncAsSint16LE(_sub); + s.syncAsSint16LE(_page); + s.syncAsSint16LE(_maxPage); + + int journalCount = _journal.size(); + if (s.isLoading()) + _journal.resize(journalCount); + + for (uint idx = 0; idx < _journal.size(); ++idx) { + JournalEntry &je = _journal[idx]; + + s.syncAsSint16LE(je._converseNum); + s.syncAsByte(je._replyOnly); + s.syncAsSint16LE(je._statementNum); + } +} + } // End of namespace Sherlock diff --git a/engines/sherlock/journal.h b/engines/sherlock/journal.h index 894065759b..9db4b28665 100644 --- a/engines/sherlock/journal.h +++ b/engines/sherlock/journal.h @@ -25,6 +25,7 @@ #include "common/scummsys.h" #include "common/array.h" +#include "common/serializer.h" #include "common/str-array.h" #include "common/stream.h" @@ -77,6 +78,10 @@ public: void drawInterface(); bool handleEvents(int key); + + void resetPosition(); + + void synchronize(Common::Serializer &s); }; } // End of namespace Sherlock diff --git a/engines/sherlock/people.cpp b/engines/sherlock/people.cpp index d22c08f625..86c560a1d9 100644 --- a/engines/sherlock/people.cpp +++ b/engines/sherlock/people.cpp @@ -203,7 +203,7 @@ People::People(SherlockEngine *vm) : _vm(vm), _player(_data[0]) { _portraitSide = 0; _speakerFlip = false; _holmesFlip = false; - _homesQuotient = 0; + _holmesQuotient = 0; _portrait._sequences = new byte[32]; } @@ -700,4 +700,15 @@ void People::setTalking(int speaker) { } } +/** + * Synchronize the data for a savegame + */ +void People::synchronize(Common::Serializer &s) { + s.syncAsByte(_holmesOn); + s.syncAsSint16LE(_data[AL]._position.x); + s.syncAsSint16LE(_data[AL]._position.y); + s.syncAsSint16LE(_data[AL]._sequenceNumber); + s.syncAsSint16LE(_holmesQuotient); +} + } // End of namespace Sherlock diff --git a/engines/sherlock/people.h b/engines/sherlock/people.h index 593b516ee6..94f1d05c0d 100644 --- a/engines/sherlock/people.h +++ b/engines/sherlock/people.h @@ -24,6 +24,7 @@ #define SHERLOCK_PEOPLE_H #include "common/scummsys.h" +#include "common/serializer.h" #include "common/stack.h" #include "sherlock/objects.h" @@ -84,7 +85,7 @@ public: int _portraitSide; bool _speakerFlip; bool _holmesFlip; - int _homesQuotient; + int _holmesQuotient; public: People(SherlockEngine *vm); ~People(); @@ -118,6 +119,8 @@ public: void clearTalking(); void setTalking(int speaker); + + void synchronize(Common::Serializer &s); }; } // End of namespace Sherlock diff --git a/engines/sherlock/saveload.cpp b/engines/sherlock/saveload.cpp index 78c86c836e..0cdf1d228f 100644 --- a/engines/sherlock/saveload.cpp +++ b/engines/sherlock/saveload.cpp @@ -44,6 +44,7 @@ SaveManager::SaveManager(SherlockEngine *vm, const Common::String &target) : _vm(vm), _target(target) { _saveThumb = nullptr; _envMode = SAVEMODE_NONE; + _justLoaded = false; } SaveManager::~SaveManager() { @@ -308,14 +309,80 @@ void SaveManager::highlightButtons(int btnIndex) { * Load the game in the specified slot */ void SaveManager::loadGame(int slot) { - // TODO + Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading( + generateSaveName(slot)); + Common::Serializer s(saveFile, nullptr); + + // Load the savaegame header + SherlockSavegameHeader header; + if (!readSavegameHeader(saveFile, header)) + error("Invalid savegame"); + + if (header._thumbnail) { + header._thumbnail->free(); + delete header._thumbnail; + } + + // Synchronize the savegame data + synchronize(s); + + delete saveFile; } /** * Save the game in the specified slot with the given name */ void SaveManager::saveGame(int slot, const Common::String &name) { - // TODO + Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving( + generateSaveName(slot)); + + SherlockSavegameHeader header; + header._saveName = name; + writeSavegameHeader(out, header); + + Common::Serializer s(nullptr, out); + synchronize(s); + + out->finalize(); + delete out; +} + +/** + * Support method that generates a savegame name + * @param slot Slot number + */ +Common::String SaveManager::generateSaveName(int slot) { + return Common::String::format("%s.%03d", _target.c_str(), slot); +} + +/** + * Synchronize the data for a savegame + */ +void SaveManager::synchronize(Common::Serializer &s) { + Journal &journal = *_vm->_journal; + People &people = *_vm->_people; + Scene &scene = *_vm->_scene; + Screen &screen = *_vm->_screen; + Talk &talk = *_vm->_talk; + + int oldFont = screen.fontNumber(); + + journal.synchronize(s); + people.synchronize(s); + scene.synchronize(s); + screen.synchronize(s); + talk.synchronize(s); + _vm->synchronize(s); + + if (screen.fontNumber() != oldFont) + journal.resetPosition(); + /* + char room_flags[MAX_ROOMS * 9]; + + */ + + _vm->_loadingSavedGame = true; + _justLoaded = true; } /** diff --git a/engines/sherlock/saveload.h b/engines/sherlock/saveload.h index 20ce4e6067..0dad6256ca 100644 --- a/engines/sherlock/saveload.h +++ b/engines/sherlock/saveload.h @@ -25,6 +25,7 @@ #include "common/scummsys.h" #include "common/savefile.h" +#include "common/serializer.h" #include "common/str-array.h" #include "engines/savestate.h" #include "graphics/surface.h" @@ -56,10 +57,15 @@ private: Graphics::Surface *_saveThumb; void createSavegameList(); + + Common::String generateSaveName(int slot); + + void synchronize(Common::Serializer &s); public: Common::StringArray _savegames; int _savegameIndex; SaveMode _envMode; + bool _justLoaded; public: SaveManager(SherlockEngine *vm, const Common::String &target); ~SaveManager(); diff --git a/engines/sherlock/scene.cpp b/engines/sherlock/scene.cpp index 575523bc45..4671dbdade 100644 --- a/engines/sherlock/scene.cpp +++ b/engines/sherlock/scene.cpp @@ -85,7 +85,7 @@ void SceneSound::synchronize(Common::SeekableReadStream &s) { Scene::Scene(SherlockEngine *vm): _vm(vm) { for (int idx = 0; idx < SCENES_COUNT; ++idx) - Common::fill(&_stats[idx][0], &_stats[idx][9], false); + Common::fill(&_sceneStats[idx][0], &_sceneStats[idx][65], false); _currentScene = -1; _goToScene = -1; _changes = false; @@ -195,6 +195,7 @@ bool Scene::loadScene(const Common::String &filename) { Events &events = *_vm->_events; Map &map = *_vm->_map; People &people = *_vm->_people; + SaveManager &saves = *_vm->_saves; Screen &screen = *_vm->_screen; Sound &sound = *_vm->_sound; UserInterface &ui = *_vm->_ui; @@ -398,7 +399,7 @@ bool Scene::loadScene(const Common::String &filename) { _changes = false; checkSceneStatus(); - if (!_vm->_justLoaded) { + if (!saves._justLoaded) { for (uint idx = 0; idx < _bgShapes.size(); ++idx) { if (_bgShapes[idx]._type == HIDDEN && _bgShapes[idx]._aType == TALK_EVERY) _bgShapes[idx].toggleHidden(); @@ -450,30 +451,25 @@ bool Scene::loadScene(const Common::String &filename) { * opening or moving them */ void Scene::checkSceneStatus() { - if (_stats[_currentScene][8]) { - for (int idx = 0; idx < 8; ++idx) { - int val = _stats[_currentScene][idx]; + if (_sceneStats[_currentScene][65]) { + for (uint idx = 0; idx < 64; ++idx) { + int val = _sceneStats[_currentScene][idx]; - for (int bit = 0; bit < 8; ++bit) { - uint objNumber = idx * 8 + bit; - if (objNumber < _bgShapes.size()) { - Object &obj = _bgShapes[objNumber]; + if (idx < _bgShapes.size()) { + Object &obj = _bgShapes[idx]; - if (val & 1) { - // No shape to erase, so flag as hidden - obj._type = HIDDEN; - } else if (obj._images == nullptr || obj._images->size() == 0) { - // No shape - obj._type = NO_SHAPE; - } else { - obj._type = ACTIVE_BG_SHAPE; - } + if (val & 1) { + // No shape to erase, so flag as hidden + obj._type = HIDDEN; + } else if (obj._images == nullptr || obj._images->size() == 0) { + // No shape + obj._type = NO_SHAPE; } else { - // Finished checks - return; + obj._type = ACTIVE_BG_SHAPE; } - - val >>= 1; + } else { + // Finished checks + return; } } } @@ -560,6 +556,7 @@ void Scene::checkInventory() { */ void Scene::transitionToScene() { People &people = *_vm->_people; + SaveManager &saves = *_vm->_saves; Screen &screen = *_vm->_screen; Talk &talk = *_vm->_talk; @@ -583,7 +580,7 @@ void Scene::transitionToScene() { // Exit information exists, translate it to real sequence info // Note: If a savegame was just loaded, then the data is already correct. // Otherwise, this is a linked scene or entrance info, and must be translated - if (_hsavedFs < 8 && !_vm->_justLoaded) { + if (_hsavedFs < 8 && !saves._justLoaded) { _hsavedFs = FS_TRANS[_hsavedFs]; _hsavedPos.x *= 100; _hsavedPos.y *= 100; @@ -1457,4 +1454,22 @@ int Scene::closestZone(const Common::Point &pt) { return zone; } +/** + * Synchronize the data for a savegame + */ +void Scene::synchronize(Common::Serializer &s) { + s.syncAsSint16LE(_bigPos.x); + s.syncAsSint16LE(_bigPos.y); + s.syncAsSint16LE(_overPos.x); + s.syncAsSint16LE(_overPos.y); + s.syncAsSint16LE(_oldCharPoint); + s.syncAsSint16LE(_goToScene); + + for (int sceneNum = 0; sceneNum < SCENES_COUNT; ++sceneNum) { + for (int flag = 0; flag < 65; ++flag) { + s.syncAsByte(_sceneStats[sceneNum][flag]); + } + } +} + } // End of namespace Sherlock diff --git a/engines/sherlock/scene.h b/engines/sherlock/scene.h index 3549325e8e..cc01fa92ab 100644 --- a/engines/sherlock/scene.h +++ b/engines/sherlock/scene.h @@ -26,6 +26,7 @@ #include "common/scummsys.h" #include "common/array.h" #include "common/rect.h" +#include "common/serializer.h" #include "sherlock/objects.h" #include "sherlock/resources.h" @@ -104,7 +105,7 @@ public: int _currentScene; int _goToScene; bool _changes; - bool _stats[SCENES_COUNT][9]; + bool _sceneStats[SCENES_COUNT][65]; bool _savedStats[SCENES_COUNT][9]; Common::Point _bigPos; Common::Point _overPos; @@ -167,6 +168,8 @@ public: int closestZone(const Common::Point &pt); void updateBackground(); + + void synchronize(Common::Serializer &s); }; } // End of namespace Sherlock diff --git a/engines/sherlock/screen.cpp b/engines/sherlock/screen.cpp index a30108118c..3c9a10e4a1 100644 --- a/engines/sherlock/screen.cpp +++ b/engines/sherlock/screen.cpp @@ -480,4 +480,14 @@ Common::Rect Screen::getDisplayBounds() { return Common::Rect(0, 0, SHERLOCK_SCREEN_WIDTH, SHERLOCK_SCREEN_HEIGHT); } +/** + * Synchronize the data for a savegame + */ +void Screen::synchronize(Common::Serializer &s) { + int fontNumber = _fontNumber; + s.syncAsByte(fontNumber); + if (s.isLoading()) + setFont(fontNumber); +} + } // End of namespace Sherlock diff --git a/engines/sherlock/screen.h b/engines/sherlock/screen.h index 2cfd7c8a88..a8bdc53b5a 100644 --- a/engines/sherlock/screen.h +++ b/engines/sherlock/screen.h @@ -25,6 +25,7 @@ #include "common/list.h" #include "common/rect.h" +#include "common/serializer.h" #include "graphics/surface.h" #include "sherlock/graphics.h" #include "sherlock/resources.h" @@ -128,6 +129,8 @@ public: Common::Rect getDisplayBounds(); int fontNumber() const { return _fontNumber; } + + void synchronize(Common::Serializer &s); }; } // End of namespace Sherlock diff --git a/engines/sherlock/sherlock.cpp b/engines/sherlock/sherlock.cpp index d0744c4775..bc7b545719 100644 --- a/engines/sherlock/sherlock.cpp +++ b/engines/sherlock/sherlock.cpp @@ -45,7 +45,6 @@ SherlockEngine::SherlockEngine(OSystem *syst, const SherlockGameDescription *gam _talk = nullptr; _ui = nullptr; _useEpilogue2 = false; - _justLoaded = false; _loadingSavedGame = false; _onChessboard = false; _slowChess = false; @@ -185,4 +184,13 @@ void SherlockEngine::saveConfig() { // TODO } + +/** + * Synchronize the data for a savegame + */ +void SherlockEngine::synchronize(Common::Serializer &s) { + for (uint idx = 0; idx < _flags.size(); ++idx) + s.syncAsByte(_flags[idx]); +} + } // End of namespace Comet diff --git a/engines/sherlock/sherlock.h b/engines/sherlock/sherlock.h index 20afb6f0e3..48850fff06 100644 --- a/engines/sherlock/sherlock.h +++ b/engines/sherlock/sherlock.h @@ -101,7 +101,6 @@ public: Common::String _soundOverride; Common::String _titleOverride; bool _useEpilogue2; - bool _justLoaded; bool _loadingSavedGame; int _oldCharPoint; // Old scene Common::Point _over; // Old map position @@ -131,6 +130,8 @@ public: void freeSaveGameList(); void saveConfig(); + + void synchronize(Common::Serializer &s); }; } // End of namespace Sherlock diff --git a/engines/sherlock/talk.cpp b/engines/sherlock/talk.cpp index 158cae38a9..6740e89efc 100644 --- a/engines/sherlock/talk.cpp +++ b/engines/sherlock/talk.cpp @@ -1745,4 +1745,16 @@ void Talk::popStack() { } } +/** + * Synchronize the data for a savegame + */ +void Talk::synchronize(Common::Serializer &s) { + for (int idx = 0; idx < MAX_TALK_FILES; ++idx) { + TalkHistoryEntry &he = _talkHistory[idx]; + + for (int flag = 0; flag < 16; ++flag) + s.syncAsByte(he._data[flag]); + } +} + } // End of namespace Sherlock diff --git a/engines/sherlock/talk.h b/engines/sherlock/talk.h index 4a33f2f557..620a986454 100644 --- a/engines/sherlock/talk.h +++ b/engines/sherlock/talk.h @@ -26,12 +26,14 @@ #include "common/scummsys.h" #include "common/array.h" #include "common/rect.h" +#include "common/serializer.h" #include "common/stream.h" #include "common/stack.h" namespace Sherlock { #define MAX_TALK_SEQUENCES 11 +#define MAX_TALK_FILES 500 struct SequenceEntry { int _objNum; @@ -93,7 +95,7 @@ private: Common::Stack _sequenceStack; Common::Stack _scriptStack; Common::Array _statements; - TalkHistoryEntry _talkHistory[500]; + TalkHistoryEntry _talkHistory[MAX_TALK_FILES]; int _speaker; int _talkIndex; int _scriptSelect; @@ -145,6 +147,8 @@ public: bool isSequencesEmpty() const { return _scriptStack.empty(); } void popStack(); + + void synchronize(Common::Serializer &s); }; } // End of namespace Sherlock diff --git a/engines/sherlock/user_interface.cpp b/engines/sherlock/user_interface.cpp index c8cd300b5e..f7f387e9ad 100644 --- a/engines/sherlock/user_interface.cpp +++ b/engines/sherlock/user_interface.cpp @@ -1820,7 +1820,7 @@ void UserInterface::doTalkControl() { // Add any Holmes point to Holmes' total, if any if (talk._statements[_selector]._quotient) - people._homesQuotient += talk._statements[_selector]._quotient; + people._holmesQuotient += talk._statements[_selector]._quotient; } // Flag the response as having been used -- cgit v1.2.3