aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEinar Johan Trøan Sømåen2012-06-19 02:02:20 +0200
committerEinar Johan Trøan Sømåen2012-06-19 02:02:20 +0200
commit721fd394def5d9930e12f2e7223831e6c2d3bb82 (patch)
tree0474004c42c4cc3b873cfb165ecc99f793bc7cc1
parent06e8306aab6458e01b4356b6afa95544c64eae9d (diff)
downloadscummvm-rg350-721fd394def5d9930e12f2e7223831e6c2d3bb82.tar.gz
scummvm-rg350-721fd394def5d9930e12f2e7223831e6c2d3bb82.tar.bz2
scummvm-rg350-721fd394def5d9930e12f2e7223831e6c2d3bb82.zip
WINTERMUTE: Add a first attempt at load-from-launcher support
-rw-r--r--engines/wintermute/Base/BPersistMgr.cpp213
-rw-r--r--engines/wintermute/Base/BPersistMgr.h15
-rw-r--r--engines/wintermute/detection.cpp51
-rw-r--r--engines/wintermute/wintermute.cpp8
4 files changed, 231 insertions, 56 deletions
diff --git a/engines/wintermute/Base/BPersistMgr.cpp b/engines/wintermute/Base/BPersistMgr.cpp
index 346a8bfa59..a70b915fc2 100644
--- a/engines/wintermute/Base/BPersistMgr.cpp
+++ b/engines/wintermute/Base/BPersistMgr.cpp
@@ -36,8 +36,11 @@
#include "engines/wintermute/utils/StringUtil.h"
#include "engines/wintermute/Base/BImage.h"
#include "engines/wintermute/Base/BSound.h"
-#include "commoN/memstream.h"
+#include "graphics/decoders/bmp.h"
+#include "common/memstream.h"
#include "common/str.h"
+#include "common/system.h"
+#include "common/savefile.h"
namespace WinterMute {
@@ -60,7 +63,7 @@ CBPersistMgr::CBPersistMgr(CBGame *inGame): CBBase(inGame) {
_richBufferSize = 0;
_savedDescription = NULL;
- _savedTimestamp = 0;
+// _savedTimestamp = 0;
_savedVerMajor = _savedVerMinor = _savedVerBuild = 0;
_savedExtMajor = _savedExtMinor = 0;
@@ -91,7 +94,7 @@ void CBPersistMgr::Cleanup() {
_richBufferSize = 0;
_savedDescription = NULL; // ref to buffer
- _savedTimestamp = 0;
+// _savedTimestamp = 0;
_savedVerMajor = _savedVerMinor = _savedVerBuild = 0;
_savedExtMajor = _savedExtMinor = 0;
@@ -114,6 +117,64 @@ uint32 makeUint32(byte first, byte second, byte third, byte fourth) {
return retVal;
}
+Common::String CBPersistMgr::getFilenameForSlot(int slot) {
+ // TODO: Temporary solution until I have the namespacing sorted out
+ return Common::String::format("save%03d.DirtySplitSav", slot);
+}
+
+void CBPersistMgr::getSaveStateDesc(int slot, SaveStateDescriptor& desc) {
+ Common::String filename = getFilenameForSlot(slot);
+ warning("Trying to list savegame %s in slot %d", filename.c_str(), slot);
+ if (FAILED(readHeader(filename))) {
+ warning("getSavedDesc(%d) - Failed for %s", slot, filename.c_str());
+ return;
+ }
+ desc.setSaveSlot(slot);
+ desc.setDescription(_savedDescription);
+ desc.setDeletableFlag(true);
+ desc.setWriteProtectedFlag(false);
+
+ if (_thumbnailDataSize > 0) {
+ Common::MemoryReadStream thumbStream(_thumbnailData, _thumbnailDataSize);
+ Graphics::BitmapDecoder bmpDecoder;
+ if (bmpDecoder.loadStream(thumbStream)) {
+ Graphics::Surface *surf = new Graphics::Surface;
+ surf = bmpDecoder.getSurface()->convertTo(g_system->getOverlayFormat());
+ desc.setThumbnail(surf);
+ }
+ }
+
+ desc.setSaveDate(_savedTimestamp.tm_year, _savedTimestamp.tm_mon, _savedTimestamp.tm_mday);
+ desc.setSaveTime(_savedTimestamp.tm_hour, _savedTimestamp.tm_min);
+ desc.setPlayTime(0);
+}
+
+void CBPersistMgr::deleteSaveSlot(int slot) {
+ Common::String filename = getFilenameForSlot(slot);
+ g_system->getSavefileManager()->removeSavefile(filename);
+}
+
+uint32 CBPersistMgr::getMaxUsedSlot() {
+ Common::StringArray saves = g_system->getSavefileManager()->listSavefiles("save???.DirtySplitSav");
+ Common::StringArray::iterator it = saves.begin();
+ int ret = -1;
+ for (; it != saves.end(); it++) {
+ int num = -1;
+ sscanf(it->c_str(), "save%d", &num);
+ ret = MAX(ret, num);
+ }
+ return ret;
+}
+
+bool CBPersistMgr::getSaveExists(int slot) {
+ Common::String filename = getFilenameForSlot(slot);
+ warning("Trying to list savegame %s in slot %d", filename.c_str(), slot);
+ if (FAILED(readHeader(filename))) {
+ return false;
+ }
+ return true;
+}
+
//////////////////////////////////////////////////////////////////////////
HRESULT CBPersistMgr::InitSave(const char *Desc) {
if (!Desc) return E_FAIL;
@@ -192,11 +253,11 @@ HRESULT CBPersistMgr::InitSave(const char *Desc) {
PutDWORD(DataOffset);
PutString(Desc);
-// TODO: Add usefull timestamps, we can't use ctime...
-/* time_t Timestamp;
- time(&Timestamp);
- PutDWORD((uint32)Timestamp);*/
- PutDWORD(0);
+
+ g_system->getTimeAndDate(_savedTimestamp);
+ putTimeDate(_savedTimestamp);
+ _savedPlayTime = g_system->getMillis();
+ _saveStream->writeUint32LE(_savedPlayTime);
}
return S_OK;
}
@@ -224,18 +285,21 @@ uint16 getHighWord(uint32 dword) {
return dword >> 16;
}
-//////////////////////////////////////////////////////////////////////////
-HRESULT CBPersistMgr::InitLoad(const char *Filename) {
+HRESULT CBPersistMgr::readHeader(const Common::String &filename) {
Cleanup();
-
+
_saving = false;
-
- _loadStream = Game->_fileManager->loadSaveGame(Filename);
+
+ _loadStream = g_system->getSavefileManager()->openForLoading(filename);
//_buffer = Game->_fileManager->ReadWholeFile(Filename, &_bufferSize);
if (_loadStream) {
uint32 Magic;
Magic = GetDWORD();
- if (Magic != DCGF_MAGIC) goto init_fail;
+
+ if (Magic != DCGF_MAGIC) {
+ Cleanup();
+ return E_FAIL;
+ }
Magic = GetDWORD();
@@ -244,14 +308,10 @@ HRESULT CBPersistMgr::InitLoad(const char *Filename) {
_savedVerMinor = _loadStream->readByte();
_savedExtMajor = _loadStream->readByte();
_savedExtMinor = _loadStream->readByte();
-
+
if (Magic == SAVE_MAGIC_2) {
_savedVerBuild = (byte)GetDWORD();
- char *SavedName = GetString();
- if (SavedName == NULL || scumm_stricmp(SavedName, Game->_name) != 0) {
- Game->LOG(0, "ERROR: Saved game name doesn't match current game");
- goto init_fail;
- }
+ _savedName = GetString();
// load thumbnail
_thumbnailDataSize = GetDWORD();
@@ -263,48 +323,68 @@ HRESULT CBPersistMgr::InitLoad(const char *Filename) {
}
} else _savedVerBuild = 35; // last build with ver1 savegames
+ uint32 DataOffset = GetDWORD();
- // if save is newer version than we are, fail
- if (_savedVerMajor > DCGF_VER_MAJOR ||
- (_savedVerMajor == DCGF_VER_MAJOR && _savedVerMinor > DCGF_VER_MINOR) ||
- (_savedVerMajor == DCGF_VER_MAJOR && _savedVerMinor == DCGF_VER_MINOR && _savedVerBuild > DCGF_VER_BUILD)
- ) {
- Game->LOG(0, "ERROR: Saved game version is newer than current game");
- goto init_fail;
- }
+ _savedDescription = GetString();
+ _savedTimestamp = getTimeDate();
+ _savedPlayTime = _loadStream->readUint32LE();
- // if save is older than the minimal version we support
- if (_savedVerMajor < SAVEGAME_VER_MAJOR ||
- (_savedVerMajor == SAVEGAME_VER_MAJOR && _savedVerMinor < SAVEGAME_VER_MINOR) ||
- (_savedVerMajor == SAVEGAME_VER_MAJOR && _savedVerMinor == SAVEGAME_VER_MINOR && _savedVerBuild < SAVEGAME_VER_BUILD)
- ) {
- Game->LOG(0, "ERROR: Saved game is too old and cannot be used by this version of game engine");
- goto init_fail;
- }
+ _offset = DataOffset;
+
+ return S_OK;
+ }
+ }
- /*
- if ( _savedVerMajor != DCGF_VER_MAJOR || _savedVerMinor != DCGF_VER_MINOR)
- {
- Game->LOG(0, "ERROR: Saved game is created by other WME version");
- goto init_fail;
- }
- */
- } else goto init_fail;
+ Cleanup();
+ return E_FAIL;
+}
+//////////////////////////////////////////////////////////////////////////
+HRESULT CBPersistMgr::InitLoad(const char *Filename) {
- uint32 DataOffset = GetDWORD();
- _savedDescription = GetString();
- _savedTimestamp = (time_t)GetDWORD();
+ if (FAILED(readHeader(Filename))) {
+ Cleanup();
+ return E_FAIL;
+ }
+ _saving = false;
- _offset = DataOffset;
+ if (_savedName == "" || scumm_stricmp(_savedName.c_str(), Game->_name) != 0) {
+ Game->LOG(0, "ERROR: Saved game name doesn't match current game");
+ Cleanup();
+ return E_FAIL;
+ }
- return S_OK;
+ // if save is newer version than we are, fail
+ if (_savedVerMajor > DCGF_VER_MAJOR ||
+ (_savedVerMajor == DCGF_VER_MAJOR && _savedVerMinor > DCGF_VER_MINOR) ||
+ (_savedVerMajor == DCGF_VER_MAJOR && _savedVerMinor == DCGF_VER_MINOR && _savedVerBuild > DCGF_VER_BUILD)
+ ) {
+ Game->LOG(0, "ERROR: Saved game version is newer than current game");
+ Cleanup();
+ return E_FAIL;
}
-init_fail:
- Cleanup();
- return E_FAIL;
+ // if save is older than the minimal version we support
+ if (_savedVerMajor < SAVEGAME_VER_MAJOR ||
+ (_savedVerMajor == SAVEGAME_VER_MAJOR && _savedVerMinor < SAVEGAME_VER_MINOR) ||
+ (_savedVerMajor == SAVEGAME_VER_MAJOR && _savedVerMinor == SAVEGAME_VER_MINOR && _savedVerBuild < SAVEGAME_VER_BUILD)
+ ) {
+ Game->LOG(0, "ERROR: Saved game is too old and cannot be used by this version of game engine");
+ Cleanup();
+ return E_FAIL;
+
+ }
+
+ /*
+ if ( _savedVerMajor != DCGF_VER_MAJOR || _savedVerMinor != DCGF_VER_MINOR)
+ {
+ Game->LOG(0, "ERROR: Saved game is created by other WME version");
+ goto init_fail;
+ }
+ */
+
+ return S_OK;
}
@@ -387,13 +467,40 @@ char *CBPersistMgr::GetString() {
ret[len] = '\0';
/* char *ret = (char *)(_buffer + _offset);
_offset += len;*/
-
+ warning("Read string %s with len %d", ret, len);
if (!strcmp(ret, "(null)")) {
delete[] ret;
return NULL;
} else return ret;
}
+HRESULT CBPersistMgr::putTimeDate(const TimeDate &t) {
+ _saveStream->writeSint32LE(t.tm_sec);
+ _saveStream->writeSint32LE(t.tm_min);
+ _saveStream->writeSint32LE(t.tm_hour);
+ _saveStream->writeSint32LE(t.tm_mday);
+ _saveStream->writeSint32LE(t.tm_mon);
+ _saveStream->writeSint32LE(t.tm_year);
+ // _saveStream->writeSint32LE(t.tm_wday); //TODO: Add this in when merging next
+
+ if (_saveStream->err()) {
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+TimeDate CBPersistMgr::getTimeDate() {
+ TimeDate t;
+ t.tm_sec = _loadStream->readSint32LE();
+ t.tm_min = _loadStream->readSint32LE();
+ t.tm_hour = _loadStream->readSint32LE();
+ t.tm_mday = _loadStream->readSint32LE();
+ t.tm_mon = _loadStream->readSint32LE();
+ t.tm_year = _loadStream->readSint32LE();
+ // t.tm_wday = _loadStream->readSint32LE(); //TODO: Add this in when merging next
+ return t;
+}
+
void CBPersistMgr::putFloat(float val) {
Common::String str = Common::String::format("F%f", val);
_saveStream->writeUint32LE(str.size());
diff --git a/engines/wintermute/Base/BPersistMgr.h b/engines/wintermute/Base/BPersistMgr.h
index 0fe1d75550..12760bf6ca 100644
--- a/engines/wintermute/Base/BPersistMgr.h
+++ b/engines/wintermute/Base/BPersistMgr.h
@@ -31,7 +31,10 @@
#include "engines/wintermute/Base/BBase.h"
+#include "engines/savestate.h"
#include "common/stream.h"
+#include "common/str.h"
+#include "common/system.h"
namespace WinterMute {
@@ -40,12 +43,14 @@ class Vector2;
class CBPersistMgr : public CBBase {
public:
char *_savedDescription;
- time_t _savedTimestamp;
+ TimeDate _savedTimestamp;
+ uint32 _savedPlayTime;
byte _savedVerMajor;
byte _savedVerMinor;
byte _savedVerBuild;
byte _savedExtMajor;
byte _savedExtMinor;
+ Common::String _savedName;
HRESULT SaveFile(const char *Filename);
uint32 GetDWORD();
void PutDWORD(uint32 Val);
@@ -56,6 +61,10 @@ public:
double getDouble();
void putDouble(double val);
void Cleanup();
+ void getSaveStateDesc(int slot, SaveStateDescriptor& desc);
+ void deleteSaveSlot(int slot);
+ uint32 getMaxUsedSlot();
+ bool getSaveExists(int slot);
HRESULT InitLoad(const char *Filename);
HRESULT InitSave(const char *Desc);
HRESULT GetBytes(byte *Buffer, uint32 Size);
@@ -89,6 +98,10 @@ public:
uint32 _thumbnailDataSize;
byte *_thumbnailData;
private:
+ Common::String getFilenameForSlot(int slot);
+ HRESULT readHeader(const Common::String &filename);
+ TimeDate getTimeDate();
+ HRESULT putTimeDate(const TimeDate &t);
Common::WriteStream *_saveStream;
Common::SeekableReadStream *_loadStream;
};
diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp
index 4756c96542..610f34c643 100644
--- a/engines/wintermute/detection.cpp
+++ b/engines/wintermute/detection.cpp
@@ -22,6 +22,7 @@
#include "engines/advancedDetector.h"
#include "engines/wintermute/wintermute.h"
+#include "engines/wintermute/Base/BPersistMgr.h"
#include "common/config-manager.h"
#include "common/error.h"
@@ -179,6 +180,56 @@ public:
// Failed to find any game data
return false;
}
+
+ bool hasFeature(MetaEngineFeature f) const {
+ switch (f) {
+ case MetaEngine::kSupportsListSaves:
+ return true;
+ case MetaEngine::kSupportsLoadingDuringStartup:
+ return true;
+ case MetaEngine::kSupportsDeleteSave:
+ return true;
+ case MetaEngine::kSavesSupportCreationDate:
+ return true;
+ case MetaEngine::kSavesSupportMetaInfo:
+ return true;
+ case MetaEngine::kSavesSupportThumbnail:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ SaveStateList listSaves(const char *target) const {
+ SaveStateList saves;
+ WinterMute::CBPersistMgr pm;
+ for (int i = 0; i < getMaximumSaveSlot(); i++) {
+ if (pm.getSaveExists(i)) {
+ SaveStateDescriptor desc;
+ pm.getSaveStateDesc(i, desc);
+ saves.push_back(desc);
+ }
+ }
+ return saves;
+ }
+
+ int getMaximumSaveSlot() const {
+ WinterMute::CBPersistMgr pm;
+ return pm.getMaxUsedSlot() + 1; // TODO: Since we use slot 0, this misses a bit.
+ }
+
+ void removeSaveState(const char *target, int slot) const {
+ WinterMute::CBPersistMgr pm;
+ pm.deleteSaveSlot(slot);
+ }
+
+ virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const {
+ WinterMute::CBPersistMgr pm;
+ SaveStateDescriptor retVal;
+ retVal.setDescription("Invalid savegame");
+ pm.getSaveStateDesc(slot, retVal);
+ return retVal;
+ }
};
#if PLUGIN_ENABLED_DYNAMIC(WINTERMUTE)
diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp
index 8b12a422cf..4e24d740b9 100644
--- a/engines/wintermute/wintermute.cpp
+++ b/engines/wintermute/wintermute.cpp
@@ -130,6 +130,7 @@ int WinterMuteEngine::init() {
int argc = 0;
_game = new CAdGame;
if (!_game) return 1;
+ CBPlatform::Initialize(_game, 0, NULL);
bool windowedMode = true;
@@ -234,14 +235,17 @@ int WinterMuteEngine::init() {
_game->LOG(0, "Engine initialized in %d ms", CBPlatform::GetTime() - DataInitStart);
_game->LOG(0, "");
+ if (ConfMan.hasKey("save_slot")) {
+ int slot = ConfMan.getInt("save_slot");
+ Common::String str = Common::String::format("save00%d.DirtySplitSav", slot);
+ _game->LoadGame(str.c_str());
+ }
if (SaveGame) {
_game->LoadGame(SaveGame);
delete [] SaveGame;
}
- CBPlatform::Initialize(_game, 0, NULL);
-
// all set, ready to go
return 0;
}