[Scummvm-git-logs] scummvm master -> 1880b37100511988b292d673ee32630e031f6dcb
bluegr
noreply at scummvm.org
Thu Dec 30 11:28:13 UTC 2021
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
1880b37100 BURIED: Add metadata to saved games - FR #12889
Commit: 1880b37100511988b292d673ee32630e031f6dcb
https://github.com/scummvm/scummvm/commit/1880b37100511988b292d673ee32630e031f6dcb
Author: Filippos Karapetis (bluegr at gmail.com)
Date: 2021-12-30T13:27:49+02:00
Commit Message:
BURIED: Add metadata to saved games - FR #12889
- Saved games now contain all metadata, including thumbnails, creation
date and play time
- Savesd games are now named buried.###, and they are compatible among
all versions
- Saved games are now sorted by slot, like in other engines, and are no
longer sorted alphabetically as before
- The engine checks on startup for saves using the original format and
converts them to the new format, thus it's possible to import saved
games from the original game
- The currently selected item is now stored in the saved game, thus
crashes that were related to loading a game with fewer items than the
currently selected item no longer occur
Changed paths:
engines/buried/buried.cpp
engines/buried/buried.h
engines/buried/frame_window.h
engines/buried/global_flags.h
engines/buried/inventory_window.cpp
engines/buried/inventory_window.h
engines/buried/metaengine.cpp
engines/buried/saveload.cpp
diff --git a/engines/buried/buried.cpp b/engines/buried/buried.cpp
index f4411088d8d..c7bfd749dc7 100644
--- a/engines/buried/buried.cpp
+++ b/engines/buried/buried.cpp
@@ -132,6 +132,8 @@ Common::Error BuriedEngine::run() {
_mainWindow = new FrameWindow(this);
_mainWindow->showWindow(Window::kWindowShow);
+ checkForOriginalSavedGames();
+
if (isDemo()) {
((FrameWindow *)_mainWindow)->showTitleSequence();
((FrameWindow *)_mainWindow)->showMainMenu();
diff --git a/engines/buried/buried.h b/engines/buried/buried.h
index 7216c79fb26..b02a98e631b 100644
--- a/engines/buried/buried.h
+++ b/engines/buried/buried.h
@@ -143,11 +143,11 @@ public:
// Save/Load
bool canLoadGameStateCurrently();
bool canSaveGameStateCurrently();
- Common::Error loadGameState(int slot);
- Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave);
- static Common::StringArray listSaveFiles();
- bool loadState(Common::SeekableReadStream *saveFile, Location &location, GlobalFlags &flags, Common::Array<int> &inventoryItems);
- bool saveState(Common::WriteStream *saveFile, Location &location, GlobalFlags &flags, Common::Array<int> &inventoryItems);
+ Common::String getSaveStateName(int slot) const override {
+ return Common::String::format("buried.%03d", slot);
+ }
+ Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
+ Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
void handleSaveDialog();
void handleRestoreDialog();
@@ -184,6 +184,10 @@ private:
// Saves
bool syncLocation(Common::Serializer &s, Location &location);
bool syncGlobalFlags(Common::Serializer &s, GlobalFlags &flags);
+ Common::Error syncSaveData(Common::Serializer &ser);
+ Common::Error syncSaveData(Common::Serializer &ser, Location &location, GlobalFlags &flags, Common::Array<int> &inventoryItems);
+ void checkForOriginalSavedGames();
+ void convertSavedGame(Common::String oldFile, Common::String newFile);
};
// Macro for creating a version field
diff --git a/engines/buried/frame_window.h b/engines/buried/frame_window.h
index 91190f09df5..a2ad6110b7f 100644
--- a/engines/buried/frame_window.h
+++ b/engines/buried/frame_window.h
@@ -48,7 +48,6 @@ public:
bool showCompletionScene(GlobalFlags &globalFlags);
bool showCredits();
bool showOverview();
- bool notifyUserOfFrameCycling();
bool setTimerPause(bool pause);
bool onEraseBackground();
diff --git a/engines/buried/global_flags.h b/engines/buried/global_flags.h
index 2632551987c..5126e7b4a84 100644
--- a/engines/buried/global_flags.h
+++ b/engines/buried/global_flags.h
@@ -93,7 +93,8 @@ struct GlobalFlags {
byte myMCStingerChannelID; // 54
byte faStingerID; // 55
byte faStingerChannelID; // 56
- byte unused0[3]; // 57-59
+ uint16 curItem; // ScummVM enhancement, originally unused bytes 57-58
+ byte unused0; // 59
uint32 cgMWCatapultData; // 60-63
uint32 cgMWCatapultOffset; // 64-67
byte cgTSTriedDoor; // 68
diff --git a/engines/buried/inventory_window.cpp b/engines/buried/inventory_window.cpp
index ef23a3df8d1..0fcf6c5d30f 100644
--- a/engines/buried/inventory_window.cpp
+++ b/engines/buried/inventory_window.cpp
@@ -68,7 +68,7 @@ InventoryWindow::InventoryWindow(BuriedEngine *vm, Window *parent) : Window(vm,
_itemArray.push_back(kItemBioChipJump);
}
- _curItem = 0;
+ setCurItem(0);
_infoWindow = nullptr;
_letterViewWindow = nullptr;
@@ -142,7 +142,8 @@ bool InventoryWindow::rebuildPreBuffer() {
if (!_itemArray.empty()) {
// Draw the icon for the current item
- Graphics::Surface *icon = _vm->_gfx->getBitmap(IDB_PICON_BITMAP_BASE + _itemArray[_curItem]);
+ const uint16 curItem = getCurItem();
+ Graphics::Surface *icon = _vm->_gfx->getBitmap(IDB_PICON_BITMAP_BASE + _itemArray[curItem]);
_vm->_gfx->crossBlit(_background, 17, 8, icon->w, icon->h, icon, 0, 0);
icon->free();
delete icon;
@@ -160,7 +161,7 @@ bool InventoryWindow::addItem(int itemID) {
// Find the new position, and set the current selection to that
for (int i = 0; i < (int)_itemArray.size(); i++) {
if (_itemArray[i] == itemID) {
- _curItem = i;
+ setCurItem(i);
break;
}
}
@@ -220,8 +221,10 @@ bool InventoryWindow::removeItem(int itemID) {
if (!found)
return false;
- if (_curItem >= (int)_itemArray.size())
- _curItem--;
+ const uint16 curItem = getCurItem();
+ if (curItem >= (int)_itemArray.size()) {
+ setCurItem(curItem - 1);
+ }
rebuildPreBuffer();
invalidateWindow(false);
@@ -300,8 +303,9 @@ void InventoryWindow::onPaint() {
// Draw inventory item names
uint32 textColor = _vm->_gfx->getColor(212, 109, 0);
+ const uint16 curItem = getCurItem();
for (int i = -2; i < 3; i++) {
- if ((i + _curItem) >= 0 && (i + _curItem) < (int)_itemArray.size()) {
+ if ((i + curItem) >= 0 && (i + curItem) < (int)_itemArray.size()) {
Common::Rect textRect = Common::Rect(120, (i + 2) * 13 + 8, 254, (i + 3) * 13 + 8);
if (_vm->getLanguage() == Common::JA_JPN) {
@@ -311,7 +315,7 @@ void InventoryWindow::onPaint() {
}
textRect.translate(absoluteRect.left, absoluteRect.top);
- Common::String text = _vm->getString(IDES_ITEM_TITLE_BASE + _itemArray[_curItem + i]);
+ Common::String text = _vm->getString(IDES_ITEM_TITLE_BASE + _itemArray[curItem + i]);
_vm->_gfx->renderText(_vm->_gfx->getScreen(), _textFont, text, textRect.left, textRect.top, textRect.width(), textRect.height(), textColor, _fontHeight);
}
}
@@ -332,7 +336,7 @@ void InventoryWindow::onLButtonDown(const Common::Point &point, uint flags) {
bool redraw = false;
if (up.contains(point)) {
- if (_curItem > 0) {
+ if (getCurItem() > 0) {
_upSelected = true;
redraw = true;
_scrollTimer = setTimer(250);
@@ -340,7 +344,7 @@ void InventoryWindow::onLButtonDown(const Common::Point &point, uint flags) {
}
if (down.contains(point)) {
- if (_curItem < ((int)_itemArray.size() - 1)) {
+ if (getCurItem() < ((int)_itemArray.size() - 1)) {
_downSelected = true;
redraw = true;
_scrollTimer = setTimer(250);
@@ -360,7 +364,8 @@ void InventoryWindow::onLButtonDown(const Common::Point &point, uint flags) {
}
if (picon.contains(point) && !_itemArray.empty() && !_infoWindow) {
- int itemID = _itemArray[_curItem];
+ const uint16 curItem = getCurItem();
+ int itemID = _itemArray[curItem];
switch (itemID) {
case kItemBioChipAI:
@@ -407,7 +412,7 @@ void InventoryWindow::onLButtonDown(const Common::Point &point, uint flags) {
return;
}
- InventoryElement staticItemData = getItemStaticData(_itemArray[_curItem]);
+ InventoryElement staticItemData = getItemStaticData(_itemArray[curItem]);
if (staticItemData.firstDragID < 0)
return;
@@ -466,13 +471,16 @@ void InventoryWindow::onLButtonUp(const Common::Point &point, uint flags) {
inventoryText[i] = Common::Rect(120, i * 13 + 8, 254, (i + 1) * 13 + 8);
bool redraw = _upSelected || _downSelected || _magSelected;
+ uint16 curItem = getCurItem();
if (up.contains(point) && _upSelected) {
- if (_curItem > 0)
- _curItem--;
+ if (curItem > 0) {
+ curItem--;
+ setCurItem(curItem);
+ }
if (_infoWindow)
- _infoWindow->changeCurrentItem(_itemArray[_curItem]);
+ _infoWindow->changeCurrentItem(_itemArray[curItem]);
if (_scrollTimer != 0) {
killTimer(_scrollTimer);
@@ -481,11 +489,13 @@ void InventoryWindow::onLButtonUp(const Common::Point &point, uint flags) {
}
if (down.contains(point) && _downSelected) {
- if (_curItem < ((int)_itemArray.size() - 1))
- _curItem++;
+ if (curItem < ((int)_itemArray.size() - 1)) {
+ curItem++;
+ setCurItem(curItem);
+ }
if (_infoWindow)
- _infoWindow->changeCurrentItem(_itemArray[_curItem]);
+ _infoWindow->changeCurrentItem(_itemArray[curItem]);
if (_scrollTimer != 0) {
killTimer(_scrollTimer);
@@ -499,7 +509,7 @@ void InventoryWindow::onLButtonUp(const Common::Point &point, uint flags) {
if (_infoWindow) {
destroyInfoWindow();
} else {
- _infoWindow = new InventoryInfoWindow(_vm, ((GameUIWindow *)_parent)->_sceneViewWindow, _itemArray[_curItem]);
+ _infoWindow = new InventoryInfoWindow(_vm, ((GameUIWindow *)_parent)->_sceneViewWindow, _itemArray[curItem]);
((GameUIWindow *)_parent)->_sceneViewWindow->infoWindowDisplayed(true);
_infoWindow->setWindowPos(kWindowPosTop, 0, 0, 0, 0, kWindowPosShowWindow | kWindowPosNoMove | kWindowPosNoSize);
_magSelected = true;
@@ -508,13 +518,15 @@ void InventoryWindow::onLButtonUp(const Common::Point &point, uint flags) {
}
if (_textSelected >= 0) {
+ const uint16 curItem = getCurItem();
+
for (int i = 0; i < 5; i++) {
- if (inventoryText[i].contains(point) && (_curItem + i - 2) >= 0 && (_curItem + i - 2) < (int)_itemArray.size() && i == _textSelected) {
- _curItem += i - 2;
+ if (inventoryText[i].contains(point) && (curItem + i - 2) >= 0 && (curItem + i - 2) < (int)_itemArray.size() && i == _textSelected) {
+ setCurItem(curItem + i - 2);
redraw = true;
if (_infoWindow)
- _infoWindow->changeCurrentItem(_itemArray[_curItem]);
+ _infoWindow->changeCurrentItem(_itemArray[curItem]);
}
}
}
@@ -717,15 +729,16 @@ bool InventoryWindow::onSetCursor(uint message) {
}
void InventoryWindow::onTimer(uint timer) {
+ const uint16 curItem = getCurItem();
if (_upSelected) {
- if (_curItem > 0) {
- _curItem--;
+ if (curItem > 0) {
+ setCurItem(curItem - 1);
rebuildPreBuffer();
invalidateWindow(false);
}
} else if (_downSelected) {
- if (_curItem < (int)_itemArray.size() - 1) {
- _curItem++;
+ if (curItem < (int)_itemArray.size() - 1) {
+ setCurItem(curItem + 1);
rebuildPreBuffer();
invalidateWindow(false);
}
@@ -773,6 +786,22 @@ bool InventoryWindow::destroyInfoWindow() {
void InventoryWindow::setItemArray(const Common::Array<int> &array) {
_itemArray = array;
Common::sort(_itemArray.begin(), _itemArray.end());
+
+ // Sanity check
+ uint16 curItem = getCurItem();
+ if (curItem >= _itemArray.size()) {
+ warning("Invalid current item, resetting it to the first one");
+ setCurItem(0);
+ }
}
+void InventoryWindow::setCurItem(uint16 itemId) {
+ GlobalFlags &globalFlags = ((GameUIWindow *)_parent)->_sceneViewWindow->getGlobalFlags();
+ globalFlags.curItem = itemId;
+}
+
+uint16 InventoryWindow::getCurItem() const {
+ GlobalFlags &globalFlags = ((GameUIWindow *)_parent)->_sceneViewWindow->getGlobalFlags();
+ return globalFlags.curItem;
+}
} // End of namespace Buried
diff --git a/engines/buried/inventory_window.h b/engines/buried/inventory_window.h
index 74ee13eb61f..be7d551aefb 100644
--- a/engines/buried/inventory_window.h
+++ b/engines/buried/inventory_window.h
@@ -52,7 +52,6 @@ public:
bool removeItem(int itemID);
bool startDraggingNewItem(int itemID, const Common::Point &pointStart);
- int getCurrentItemID() { return _itemArray[_curItem]; }
bool isItemInInventory(int itemID);
InventoryElement getItemStaticData(int itemID);
int getItemCount() { return _itemArray.size(); }
@@ -75,11 +74,13 @@ public:
void onTimer(uint timer);
private:
+ void setCurItem(uint16 itemId);
+ uint16 getCurItem() const;
+
Graphics::Font *_textFont;
int _fontHeight;
Graphics::Surface *_background;
Common::Array<int> _itemArray;
- int _curItem;
bool _magSelected;
bool _upSelected;
diff --git a/engines/buried/metaengine.cpp b/engines/buried/metaengine.cpp
index b94320c55ac..a7bb1676a61 100644
--- a/engines/buried/metaengine.cpp
+++ b/engines/buried/metaengine.cpp
@@ -80,49 +80,24 @@ public:
bool hasFeature(MetaEngineFeature f) const override;
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
- SaveStateList listSaves(const char *target) const override;
int getMaximumSaveSlot() const override { return 999; }
- void removeSaveState(const char *target, int slot) const override;
Common::String getSavegameFile(int saveGameIdx, const char *target) const override {
- if (!target)
- target = getEngineId();
- if (saveGameIdx == kSavegameFilePattern)
- return Common::String::format("buried-*.sav");
- else
- return Common::String::format("buried-%s.sav", target);
+ // We set a standard target because saves are compatible among all versions
+ return AdvancedMetaEngine::getSavegameFile(saveGameIdx, "buried");
}
};
bool BuriedMetaEngine::hasFeature(MetaEngineFeature f) const {
return
- (f == kSupportsListSaves)
- || (f == kSupportsLoadingDuringStartup)
- || (f == kSupportsDeleteSave);
-}
-
-SaveStateList BuriedMetaEngine::listSaves(const char *target) const {
- // The original had no pattern, so the user must rename theirs
- // Note that we ignore the target because saves are compatible between
- // all versions
- Common::StringArray fileNames = Buried::BuriedEngine::listSaveFiles();
-
- SaveStateList saveList;
- for (uint32 i = 0; i < fileNames.size(); i++) {
- // Isolate the description from the file name
- Common::String desc = fileNames[i].c_str() + 7;
- for (int j = 0; j < 4; j++)
- desc.deleteLastChar();
-
- saveList.push_back(SaveStateDescriptor(this, i, desc));
- }
-
- return saveList;
-}
-
-void BuriedMetaEngine::removeSaveState(const char *target, int slot) const {
- // See listSaves() for info on the pattern
- const Common::StringArray &fileNames = Buried::BuriedEngine::listSaveFiles();
- g_system->getSavefileManager()->removeSavefile(fileNames[slot].c_str());
+ f == kSupportsListSaves ||
+ f == kSupportsLoadingDuringStartup ||
+ f == kSupportsDeleteSave ||
+ f == kSavesSupportMetaInfo ||
+ f == kSavesSupportThumbnail ||
+ f == kSavesSupportCreationDate ||
+ f == kSavesSupportPlayTime ||
+ f == kSimpleSavesNames ||
+ f == kSavesUseExtendedFormat;
}
Common::Error BuriedMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
diff --git a/engines/buried/saveload.cpp b/engines/buried/saveload.cpp
index 41fd3249544..9f732a5c26d 100644
--- a/engines/buried/saveload.cpp
+++ b/engines/buried/saveload.cpp
@@ -25,6 +25,7 @@
#include "common/scummsys.h"
#include "common/config-manager.h"
#include "common/error.h"
+#include "common/file.h"
#include "common/savefile.h"
#include "common/serializer.h"
#include "common/system.h"
@@ -32,21 +33,19 @@
#include "gui/message.h"
#include "gui/saveload.h"
+#include "buried/biochip_right.h"
#include "buried/buried.h"
#include "buried/frame_window.h"
#include "buried/gameui.h"
#include "buried/global_flags.h"
+#include "buried/graphics.h"
#include "buried/inventory_window.h"
#include "buried/navdata.h"
#include "buried/scene_view.h"
namespace Buried {
-Common::StringArray BuriedEngine::listSaveFiles() {
- Common::StringArray fileNames = g_system->getSavefileManager()->listSavefiles("buried-*.sav");
- Common::sort(fileNames.begin(), fileNames.end());
- return fileNames;
-}
+#define SAVEGAME_CURRENT_VERSION 1
bool BuriedEngine::canLoadGameStateCurrently() {
return !isDemo() && _mainWindow && !_yielding;
@@ -56,141 +55,218 @@ bool BuriedEngine::canSaveGameStateCurrently() {
return !isDemo() && _mainWindow && !_yielding && ((FrameWindow *)_mainWindow)->isGameInProgress();
}
-Common::Error BuriedEngine::loadGameState(int slot) {
- Common::StringArray fileNames = listSaveFiles();
- Common::InSaveFile *loadFile = _saveFileMan->openForLoading(fileNames[slot]);
- if (!loadFile)
- return Common::kUnknownError;
+void BuriedEngine::checkForOriginalSavedGames() {
+ Common::StringArray fileNames = _saveFileMan->listSavefiles("buried-*.sav");
+ Common::StringArray newFileNames = _saveFileMan->listSavefiles("buried.###");
+ Common::sort(newFileNames.begin(), newFileNames.end());
+ if (fileNames.size() == 0)
+ return;
+
+ GUI::MessageDialog dialog(
+ _("ScummVM found that you have saved games that should be converted from the original saved game format.\n"
+ "The original saved game format is no longer supported directly, so you will not be able to load your games if you don't convert them.\n\n"
+ "Press OK to convert them now, otherwise you will be asked again the next time you start the game.\n"),
+ _("OK"), _("Cancel"));
+
+ int choice = dialog.runModal();
+ if (choice != GUI::kMessageOK)
+ return;
+
+ // Convert every save slot we find with the original naming scheme
+ for (Common::StringArray::const_iterator file = fileNames.begin(); file != fileNames.end(); ++file) {
+ int slotNum = 1;
+ if (newFileNames.size() > 0) {
+ Common::String lastFile = newFileNames.back();
+ const char *slotStr = lastFile.c_str() + lastFile.size() - 3;
+ slotNum = atoi(slotStr) + 1;
+ }
+
+ Common::String newFile = getMetaEngine()->getSavegameFile(slotNum);
+ convertSavedGame(*file, newFile);
+ newFileNames.push_back(newFile);
+ }
+}
+enum {
+ kSavedGameHeaderSize = 9,
+ kSavedGameHeaderSizeAlt = 7
+};
+
+void BuriedEngine::convertSavedGame(Common::String oldFile, Common::String newFile) {
+ static const byte s_savedGameHeader[kSavedGameHeaderSize] = {'B', 'I', 'T', 'M', 'P', 'C', 0, 5, 0};
Location location;
GlobalFlags flags;
Common::Array<int> inventoryItems;
- if (!loadState(loadFile, location, flags, inventoryItems)) {
- delete loadFile;
- return Common::kUnknownError;
- }
+ byte header[9];
- // Done with the file
- delete loadFile;
+ debug("Converting %s to %s", oldFile.c_str(), newFile.c_str());
- if (isTrial() && location.timeZone != 4) {
- // Display a message preventing the user from loading a non-apartment
- // saved game in the trial version
- GUI::MessageDialog dialog("ERROR: The location in this saved game is not included in this version of Buried in Time");
- dialog.runModal();
+ // Read original/old saved game
+ // Isolate the description from the file name
+ Common::String desc = oldFile.c_str() + 7;
+ for (int j = 0; j < 4; j++)
+ desc.deleteLastChar();
- // Don't return an error. It's an "error" that we can't load,
- // but we're still in a valid state. The message above will
- // be displayed instead of the usual GUI load error.
- return Common::kNoError;
- }
+ Common::InSaveFile *inFile = _saveFileMan->openForLoading(oldFile);
+ inFile->read(header, kSavedGameHeaderSize);
- ((FrameWindow *)_mainWindow)->loadFromState(location, flags, inventoryItems);
- return Common::kNoError;
-}
+ // Only compare the first 6 bytes
+ // Win95 version of the game output garbage as the last two bytes
+ if (inFile->eos() || memcmp(header, s_savedGameHeader, kSavedGameHeaderSizeAlt) != 0) {
+ delete inFile;
+ warning("Saved game %s is using an unsupported format, skipping", oldFile.c_str());
+ return;
+ }
+
+ // Set necessary properties from the old save
+ Common::Serializer inS(inFile, nullptr);
+ Common::Error res = syncSaveData(inS, location, flags, inventoryItems);
+ delete inFile;
+ if (res.getCode() != Common::kNoError) {
+ warning("Error reading data from saved game %s, skipping", oldFile.c_str());
+ return;
+ }
-static bool isValidSaveFileChar(char c) {
- // Limit it to letters, digits, and a few other characters that should be safe
- return Common::isAlnum(c) || c == ' ' || c == '_' || c == '+' || c == '-' || c == '.';
-}
+ flags.curItem = 0; // did not persist in the original format, so set it here
-static bool isValidSaveFileName(const Common::String &desc) {
- for (uint32 i = 0; i < desc.size(); i++)
- if (!isValidSaveFileChar(desc[i]))
- return false;
+ // Write the new saved format
+ Common::OutSaveFile *outFile = _saveFileMan->openForSaving(newFile);
+ if (!outFile) {
+ warning("Error creating new save file %s", newFile.c_str());
+ return;
+ }
- return true;
-}
+ const byte version = SAVEGAME_CURRENT_VERSION;
+ Common::Serializer outS(nullptr, outFile);
+ outS.setVersion(version);
+ outFile->writeByte(version);
-Common::Error BuriedEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
- if (!isValidSaveFileName(desc))
- return Common::Error(Common::kCreatingFileFailed, _("Invalid save file name"));
+ if (syncSaveData(outS, location, flags, inventoryItems).getCode() == Common::kNoError) {
+ getMetaEngine()->appendExtendedSave(outFile, getTotalPlayTime() / 1000, desc, false);
- Common::String output = Common::String::format("buried-%s.sav", desc.c_str());
- Common::OutSaveFile *saveFile = _saveFileMan->openForSaving(output, false);
- if (!saveFile)
- return Common::kUnknownError;
+ outFile->finalize();
+ delete outFile;
- GameUIWindow *gameUI = (GameUIWindow *)((FrameWindow *)_mainWindow)->getMainChildWindow();
+ // Delete the old saved game
+ _saveFileMan->removeSavefile(oldFile);
+ } else {
+ delete outFile;
- Location location;
- gameUI->_sceneViewWindow->getCurrentSceneLocation(location);
- GlobalFlags &flags = gameUI->_sceneViewWindow->getGlobalFlags();
- Common::Array<int> &inventoryItems = gameUI->_inventoryWindow->getItemArray();
+ warning("Error writing data to saved game %s, skipping", newFile.c_str());
- if (!saveState(saveFile, location, flags, inventoryItems)) {
- delete saveFile;
- return Common::kUnknownError;
+ // The newly created saved game is corrupted, delete it
+ _saveFileMan->removeSavefile(newFile);
}
-
- delete saveFile;
- return Common::kNoError;
}
-enum {
- kSavedGameHeaderSize = 9,
- kSavedGameHeaderSizeAlt = 7
-};
-
-static const byte s_savedGameHeader[kSavedGameHeaderSize] = { 'B', 'I', 'T', 'M', 'P', 'C', 0, 5, 0 };
-
-bool BuriedEngine::loadState(Common::SeekableReadStream *saveFile, Location &location, GlobalFlags &flags, Common::Array<int> &inventoryItems) {
- byte header[9];
- saveFile->read(header, kSavedGameHeaderSize);
-
- // Only compare the first 6 bytes
- // Win95 version of the game output garbage as the last two bytes
- if (saveFile->eos() || memcmp(header, s_savedGameHeader, kSavedGameHeaderSizeAlt) != 0)
- return false;
+Common::Error BuriedEngine::loadGameStream(Common::SeekableReadStream *stream) {
+ const byte version = stream->readByte();
+ if (version > SAVEGAME_CURRENT_VERSION) {
+ GUI::MessageDialog dialog(_s("Saved game was created with a newer version of ScummVM. Unable to load."));
+ dialog.runModal();
+ return Common::kUnknownError;
+ }
- Common::Serializer s(saveFile, nullptr);
+ Common::Serializer ser(stream, nullptr);
+ ser.setVersion(version);
- if (!syncLocation(s, location))
- return false;
+ return syncSaveData(ser);
+}
- if (saveFile->eos())
- return false;
+Common::Error BuriedEngine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
+ const byte version = SAVEGAME_CURRENT_VERSION;
+ Common::Serializer ser(nullptr, stream);
+ ser.setVersion(version);
+ stream->writeByte(version);
- if (!syncGlobalFlags(s, flags))
- return false;
+ GameUIWindow *gameUI = (GameUIWindow *)((FrameWindow *)_mainWindow)->getMainChildWindow();
+ gameUI->_bioChipRightWindow->destroyBioChipViewWindow(); // to capture a game screenshot
+ _gfx->updateScreen();
- if (saveFile->eos())
- return false;
+ return syncSaveData(ser);
+}
- uint16 itemCount = saveFile->readUint16LE();
+Common::Error BuriedEngine::syncSaveData(Common::Serializer &ser) {
+ Common::Error result;
+
+ if (ser.isLoading()) {
+ Location location;
+ GlobalFlags flags;
+ Common::Array<int> inventoryItems;
+
+ result = syncSaveData(ser, location, flags, inventoryItems);
+
+ if (isTrial() && location.timeZone != 4) {
+ // Display a message preventing the user from loading a non-apartment
+ // saved game in the trial version
+ GUI::MessageDialog dialog("ERROR: The location in this saved game is not included in this version of Buried in Time");
+ dialog.runModal();
+ } else {
+ ((FrameWindow *)_mainWindow)->loadFromState(location, flags, inventoryItems);
+ }
+ } else {
+ Location location;
+ GameUIWindow *gameUI = (GameUIWindow *)((FrameWindow *)_mainWindow)->getMainChildWindow();
+ gameUI->_sceneViewWindow->getCurrentSceneLocation(location);
+ GlobalFlags &flags = gameUI->_sceneViewWindow->getGlobalFlags();
+ Common::Array<int> &inventoryItems = gameUI->_inventoryWindow->getItemArray();
+
+ result = syncSaveData(ser, location, flags, inventoryItems);
+ }
- if (saveFile->eos())
- return false;
+ return result;
+}
- inventoryItems.clear();
- for (uint16 i = 0; i < itemCount; i++)
- inventoryItems.push_back(saveFile->readUint16LE());
+Common::Error BuriedEngine::syncSaveData(Common::Serializer &ser, Location &location, GlobalFlags &flags, Common::Array<int> &inventoryItems) {
+ if (!syncLocation(ser, location)) {
+ warning("Error while synchronizing location data");
+ return Common::kUnknownError;
+ }
- return !saveFile->eos();
-}
+ if (!syncGlobalFlags(ser, flags)) {
+ warning("Error while synchronizing global flag data");
+ return Common::kUnknownError;
+ }
-bool BuriedEngine::saveState(Common::WriteStream *saveFile, Location &location, GlobalFlags &flags, Common::Array<int> &inventoryItems) {
- saveFile->write(s_savedGameHeader, kSavedGameHeaderSize);
+ if (ser.err()) {
+ warning("Error while synchronizing data");
+ return Common::kUnknownError;
+ }
- Common::Serializer s(nullptr, saveFile);
+ uint16 itemCount = inventoryItems.size();
+ ser.syncAsUint16LE(itemCount);
- if (!syncLocation(s, location))
- return false;
+ if (ser.isLoading()) {
+ inventoryItems.clear();
+ inventoryItems.reserve(itemCount);
+ }
- if (!syncGlobalFlags(s, flags))
- return false;
+ for (uint16 i = 0; i < itemCount; i++) {
+ uint16 itemId = 0;
- saveFile->writeUint16LE(inventoryItems.size());
+ if (ser.isLoading()) {
+ ser.syncAsUint16LE(itemId);
+ inventoryItems.push_back(itemId);
+ } else {
+ itemId = inventoryItems[i];
+ ser.syncAsUint16LE(itemId);
+ }
+ }
- for (uint16 i = 0; i < inventoryItems.size(); i++)
- saveFile->writeUint16LE(inventoryItems[i]);
+ if (ser.isSaving()) {
+ // Fill in remaining items with all zeroes
+ uint16 fillItems = 50 - itemCount;
+ uint16 filler = 0;
+ while (fillItems--)
+ ser.syncAsUint16LE(filler);
+ }
- // Fill in remaining items with all zeroes
- uint16 fillItems = 50 - inventoryItems.size();
- while (fillItems--)
- saveFile->writeUint16LE(0);
+ if (ser.err()) {
+ warning("Error while synchronizing inventory data");
+ return Common::kUnknownError;
+ }
- return true;
+ return Common::kNoError;
}
// Since we can't take the address of a uint16 or uint32 from
@@ -288,7 +364,8 @@ bool BuriedEngine::syncGlobalFlags(Common::Serializer &s, GlobalFlags &flags) {
s.syncAsByte(flags.myMCStingerChannelID);
s.syncAsByte(flags.faStingerID);
s.syncAsByte(flags.faStingerChannelID);
- s.syncBytes(flags.unused0, sizeof(flags.unused0));
+ SYNC_FLAG_UINT16(curItem);
+ s.syncAsByte(flags.unused0);
SYNC_FLAG_UINT32(cgMWCatapultData);
SYNC_FLAG_UINT32(cgMWCatapultOffset);
s.syncAsByte(flags.cgTSTriedDoor);
More information about the Scummvm-git-logs
mailing list