[Scummvm-cvs-logs] scummvm master -> 504ffd2aba0fcb67216242475cff4bbf54650a96
bgK
bastien.bouclet at gmail.com
Sun Jul 10 22:03:08 CEST 2016
This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
c06e347d90 MOHAWK: Make the Riven saved games loadable by the original engine
792548f28f MOHAWK: The French DVD version of Riven is just a repackaged CD version
f78bb08b18 MOHAWK: Save ScummVM specific metadata in the Riven saves
504ffd2aba MOHAWK: Switch Riven saves to a slot based naming scheme
Commit: c06e347d90687c4549b18f158f087af878cc4636
https://github.com/scummvm/scummvm/commit/c06e347d90687c4549b18f158f087af878cc4636
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2016-07-10T22:01:02+02:00
Commit Message:
MOHAWK: Make the Riven saved games loadable by the original engine
Changed paths:
engines/mohawk/riven_saveload.cpp
diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp
index 6af66f7..7bb8582 100644
--- a/engines/mohawk/riven_saveload.cpp
+++ b/engines/mohawk/riven_saveload.cpp
@@ -72,8 +72,11 @@ Common::Error RivenSaveLoad::loadGame(Common::String filename) {
Common::Array<uint32> rawVariables;
while (!vars->eos()) {
- vars->readUint32BE(); // Unknown (Stack?)
- vars->readUint32BE(); // Unknown (0 or 1)
+ // The original engine stores the variables values in an array. All the slots in
+ // the array may not be in use, which is why it needs a reference counter and
+ // a flag to tell if the value has been set.
+ vars->readUint32BE(); // Reference counter
+ vars->readUint32BE(); // Variable initialized flag
rawVariables.push_back(vars->readUint32BE());
}
@@ -162,14 +165,18 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genVARSSection() {
Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
- stream->writeUint32BE(0); // Unknown
- stream->writeUint32BE(0); // Unknown
+ stream->writeUint32BE(1); // Reference counter
+ stream->writeUint32BE(1); // Variable initialized flag
stream->writeUint32BE(it->_value);
}
return stream;
}
+static int stringCompareToIgnoreCase(const Common::String &s1, const Common::String &s2) {
+ return s1.compareToIgnoreCase(s2) < 0;
+}
+
Common::MemoryWriteStreamDynamic *RivenSaveLoad::genNAMESection() {
Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
@@ -181,8 +188,28 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genNAMESection() {
curPos += it->_key.size() + 1;
}
- for (uint16 i = 0; i < _vm->_vars.size(); i++)
- stream->writeUint16BE(i);
+ // The original engine does not store the variables in a HashMap, but in a "NameList"
+ // for the keys and an array for the values. The NameList data structure maintains an array
+ // of indices in the string table sorted by case insensitive key alphabetical order.
+ // It is used to perform fast key -> index lookups.
+ // ScummVM does not need the sorted array, but has to write it anyway for the saved games
+ // to be compatible with original engine.
+ Common::Array<Common::String> sortedKeys;
+ for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
+ sortedKeys.push_back(it->_key);
+ }
+ Common::sort(sortedKeys.begin(), sortedKeys.end(), stringCompareToIgnoreCase);
+
+ for (uint i = 0; i < sortedKeys.size(); i++) {
+ uint16 varIndex = 0;
+ for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
+ if (it->_key == sortedKeys[i]) {
+ stream->writeUint16BE(varIndex);
+ break;
+ }
+ varIndex++;
+ }
+ }
for (RivenVariableMap::const_iterator it = _vm->_vars.begin(); it != _vm->_vars.end(); it++) {
stream->write(it->_key.c_str(), it->_key.size());
@@ -214,10 +241,6 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
// games need this, we should think about coming up with some
// more common way of outputting resources to an archive.
- // TODO: Make these saves work with the original interpreter.
- // Not sure why they don't work yet (they still can be loaded
- // by ScummVM).
-
// Make sure we have the right extension
if (!filename.matchString("*.rvn", true))
filename += ".rvn";
@@ -262,15 +285,17 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
saveFile->writeUint16BE(4); // 4 Type Table Entries
// Hardcode Entries (32 bytes - total: 64)
- saveFile->writeUint32BE(ID_VERS);
+ // The original engine relies on the entries being sorted by tag alphabetical order
+ // to optimize its lookup algorithm.
+ saveFile->writeUint32BE(ID_NAME);
saveFile->writeUint16BE(46); // Resource table offset
saveFile->writeUint16BE(38); // String table offset
- saveFile->writeUint32BE(ID_NAME);
+ saveFile->writeUint32BE(ID_VARS);
saveFile->writeUint16BE(52);
saveFile->writeUint16BE(40);
- saveFile->writeUint32BE(ID_VARS);
+ saveFile->writeUint32BE(ID_VERS);
saveFile->writeUint16BE(58);
saveFile->writeUint16BE(42);
@@ -281,23 +306,23 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
// Pseudo-String Table (2 bytes - total: 66)
saveFile->writeUint16BE(0); // We don't need a name list
- // Psuedo-Name Tables (8 bytes - total: 74)
+ // Pseudo-Name Tables (8 bytes - total: 74)
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
- // VERS Section (Resource Table) (6 bytes - total: 80)
+ // NAME Section (Resource Table) (6 bytes - total: 80)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
- // NAME Section (Resource Table) (6 bytes - total: 86)
+ // VARS Section (Resource Table) (6 bytes - total: 86)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(2);
- // VARS Section (Resource Table) (6 bytes - total: 92)
+ // VERS Section (Resource Table) (6 bytes - total: 92)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(3);
@@ -310,37 +335,37 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
// File Table (4 bytes - total: 102)
saveFile->writeUint32BE(4);
- // VERS Section (File Table) (10 bytes - total: 112)
+ // NAME Section (File Table) (10 bytes - total: 112)
saveFile->writeUint32BE(142);
- saveFile->writeUint16BE(versSection->size() & 0xFFFF);
- saveFile->writeByte((versSection->size() & 0xFF0000) >> 16);
- saveFile->writeByte(0);
- saveFile->writeUint16BE(0);
-
- // NAME Section (File Table) (10 bytes - total: 122)
- saveFile->writeUint32BE(142 + versSection->size());
saveFile->writeUint16BE(nameSection->size() & 0xFFFF);
saveFile->writeByte((nameSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- // VARS Section (File Table) (10 bytes - total: 132)
- saveFile->writeUint32BE(142 + versSection->size() + nameSection->size());
+ // VARS Section (File Table) (10 bytes - total: 122)
+ saveFile->writeUint32BE(142 + nameSection->size());
saveFile->writeUint16BE(varsSection->size() & 0xFFFF);
saveFile->writeByte((varsSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
+ // VERS Section (File Table) (10 bytes - total: 132)
+ saveFile->writeUint32BE(142 + nameSection->size() + varsSection->size());
+ saveFile->writeUint16BE(versSection->size() & 0xFFFF);
+ saveFile->writeByte((versSection->size() & 0xFF0000) >> 16);
+ saveFile->writeByte(0);
+ saveFile->writeUint16BE(0);
+
// ZIPS Section (File Table) (10 bytes - total: 142)
- saveFile->writeUint32BE(142 + versSection->size() + nameSection->size() + varsSection->size());
+ saveFile->writeUint32BE(142 + nameSection->size() + varsSection->size() + versSection->size());
saveFile->writeUint16BE(zipsSection->size() & 0xFFFF);
saveFile->writeByte((zipsSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- saveFile->write(versSection->getData(), versSection->size());
saveFile->write(nameSection->getData(), nameSection->size());
saveFile->write(varsSection->getData(), varsSection->size());
+ saveFile->write(versSection->getData(), versSection->size());
saveFile->write(zipsSection->getData(), zipsSection->size());
saveFile->finalize();
Commit: 792548f28fd0529077f01a56a026892dfcdcb7b0
https://github.com/scummvm/scummvm/commit/792548f28fd0529077f01a56a026892dfcdcb7b0
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2016-07-10T22:01:02+02:00
Commit Message:
MOHAWK: The French DVD version of Riven is just a repackaged CD version
Changed paths:
engines/mohawk/detection_tables.h
diff --git a/engines/mohawk/detection_tables.h b/engines/mohawk/detection_tables.h
index e3eab89..d9aba26 100644
--- a/engines/mohawk/detection_tables.h
+++ b/engines/mohawk/detection_tables.h
@@ -337,6 +337,24 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
+ // Version 1.0 (5CD), 1.02 (DVD, From "Myst: La Trilogie")
+ // From gamin
+ {
+ {
+ "riven",
+ "",
+ AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"),
+ Common::FR_FRA,
+ Common::kPlatformWindows,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NOASPECT)
+ },
+ GType_RIVEN,
+ 0,
+ 0,
+ },
+
+ // Riven: The Sequel to Myst
// Version 1.0 (5CD) - Italian
// From dodomorandi on bug #6629
{
@@ -425,24 +443,6 @@ static const MohawkGameDescription gameDescriptions[] = {
},
// Riven: The Sequel to Myst
- // Version ? (DVD, From "Myst: La Trilogie")
- // From gamin
- {
- {
- "riven",
- "",
- AD_ENTRY1("a_Data.MHK", "aff2a384aaa9a0e0ec51010f708c5c04"),
- Common::FR_FRA,
- Common::kPlatformWindows,
- ADGF_UNSTABLE,
- GUIO1(GUIO_NOASPECT)
- },
- GType_RIVEN,
- GF_DVD,
- 0,
- },
-
- // Riven: The Sequel to Myst
// Version 1.02 (DVD, From "Myst: Antologia")
// From pykman
{
Commit: f78bb08b1850b349f28b3cb5f1357fdebd5b8e00
https://github.com/scummvm/scummvm/commit/f78bb08b1850b349f28b3cb5f1357fdebd5b8e00
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2016-07-10T22:01:03+02:00
Commit Message:
MOHAWK: Save ScummVM specific metadata in the Riven saves
- Thumbnail
- Save date
- Save description
- Total play time
Changed paths:
engines/mohawk/detection.cpp
engines/mohawk/resource.h
engines/mohawk/riven_saveload.cpp
engines/mohawk/riven_saveload.h
diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp
index 7c20299..e1aac64 100644
--- a/engines/mohawk/detection.cpp
+++ b/engines/mohawk/detection.cpp
@@ -41,6 +41,7 @@
#ifdef ENABLE_RIVEN
#include "mohawk/riven.h"
+#include "mohawk/riven_saveload.h"
#endif
namespace Mohawk {
@@ -240,14 +241,18 @@ SaveStateList MohawkMetaEngine::listSaves(const char *target) const {
}
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
- } else
+ }
#endif
+#ifdef ENABLE_RIVEN
if (strstr(target, "riven")) {
filenames = g_system->getSavefileManager()->listSavefiles("*.rvn");
- for (uint32 i = 0; i < filenames.size(); i++)
- saveList.push_back(SaveStateDescriptor(i, filenames[i]));
+ for (uint32 i = 0; i < filenames.size(); i++) {
+ Common::String description = Mohawk::RivenSaveLoad::querySaveDescription(filenames[i]);
+ saveList.push_back(SaveStateDescriptor(i, description));
+ }
}
+#endif
return saveList;
}
@@ -270,6 +275,12 @@ SaveStateDescriptor MohawkMetaEngine::querySaveMetaInfos(const char *target, int
#ifdef ENABLE_MYST
if (strstr(target, "myst")) {
return Mohawk::MystGameState::querySaveMetaInfos(slot);
+ }
+#endif
+#ifdef ENABLE_RIVEN
+ if (strstr(target, "riven")) {
+ Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("*.rvn");
+ return Mohawk::RivenSaveLoad::querySaveMetaInfos(filenames[slot].c_str());
} else
#endif
{
diff --git a/engines/mohawk/resource.h b/engines/mohawk/resource.h
index d9074a5..12c5a13 100644
--- a/engines/mohawk/resource.h
+++ b/engines/mohawk/resource.h
@@ -68,6 +68,8 @@ namespace Mohawk {
#define ID_VARS MKTAG('V','A','R','S') // Variable Values
#define ID_VERS MKTAG('V','E','R','S') // Version Info
#define ID_ZIPS MKTAG('Z','I','P','S') // Zip Mode Status
+#define ID_META MKTAG('M','E','T','A') // ScummVM save metadata
+#define ID_THMB MKTAG('T','H','M','B') // ScummVM save thumbnail
// Zoombini Resource FourCC's
#define ID_SND MKTAG( 0 ,'S','N','D') // Standard Mohawk Sound
diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp
index 7bb8582..4d52179 100644
--- a/engines/mohawk/riven_saveload.cpp
+++ b/engines/mohawk/riven_saveload.cpp
@@ -24,10 +24,38 @@
#include "mohawk/riven.h"
#include "mohawk/riven_saveload.h"
-#include "common/util.h"
+#include "common/system.h"
+#include "graphics/thumbnail.h"
namespace Mohawk {
+RivenSaveMetadata::RivenSaveMetadata() {
+ saveDay = 0;
+ saveMonth = 0;
+ saveYear = 0;
+ saveHour = 0;
+ saveMinute = 0;
+ totalPlayTime = 0;
+}
+
+bool RivenSaveMetadata::sync(Common::Serializer &s) {
+ static const Common::Serializer::Version kCurrentVersion = 1;
+
+ if (!s.syncVersion(kCurrentVersion)) {
+ return false;
+ }
+
+ s.syncAsByte(saveDay);
+ s.syncAsByte(saveMonth);
+ s.syncAsUint16BE(saveYear);
+ s.syncAsByte(saveHour);
+ s.syncAsByte(saveMinute);
+ s.syncString(saveDescription);
+ s.syncAsUint32BE(totalPlayTime);
+
+ return true;
+}
+
RivenSaveLoad::RivenSaveLoad(MohawkEngine_Riven *vm, Common::SaveFileManager *saveFileMan) : _vm(vm), _saveFileMan(saveFileMan) {
}
@@ -38,11 +66,96 @@ Common::StringArray RivenSaveLoad::generateSaveGameList() {
return _saveFileMan->listSavefiles("*.rvn");
}
+Common::String RivenSaveLoad::querySaveDescription(const Common::String &filename) {
+ Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
+ if (!loadFile) {
+ return "";
+ }
+
+ MohawkArchive mhk;
+ if (!mhk.openStream(loadFile)) {
+ return "";
+ }
+
+ if (!mhk.hasResource(ID_META, 1)) {
+ return "";
+ }
+
+ Common::SeekableReadStream *metaStream = mhk.getResource(ID_META, 1);
+ if (!metaStream) {
+ return "";
+ }
+
+ Common::Serializer serializer = Common::Serializer(metaStream, nullptr);
+
+ RivenSaveMetadata metadata;
+ if (!metadata.sync(serializer)) {
+ delete metaStream;
+ return "";
+ }
+
+ delete metaStream;
+
+ return metadata.saveDescription;
+}
+
+SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const Common::String &filename) {
+ Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
+ if (!loadFile) {
+ return SaveStateDescriptor();
+ }
+
+ MohawkArchive mhk;
+ if (!mhk.openStream(loadFile)) {
+ return SaveStateDescriptor();
+ }
+
+ if (!mhk.hasResource(ID_META, 1)) {
+ return SaveStateDescriptor();
+ }
+
+ Common::SeekableReadStream *metaStream = mhk.getResource(ID_META, 1);
+ if (!metaStream) {
+ return SaveStateDescriptor();
+ }
+
+ Common::Serializer serializer = Common::Serializer(metaStream, nullptr);
+
+ RivenSaveMetadata metadata;
+ if (!metadata.sync(serializer)) {
+ delete metaStream;
+ return SaveStateDescriptor();
+ }
+
+ SaveStateDescriptor descriptor;
+ descriptor.setDescription(metadata.saveDescription);
+ descriptor.setPlayTime(metadata.totalPlayTime);
+ descriptor.setSaveDate(metadata.saveYear, metadata.saveMonth, metadata.saveDay);
+ descriptor.setSaveTime(metadata.saveHour, metadata.saveMinute);
+
+ delete metaStream;
+
+ if (!mhk.hasResource(ID_THMB, 1)) {
+ return descriptor;
+ }
+
+ Common::SeekableReadStream *thmbStream = mhk.getResource(ID_THMB, 1);
+ if (!thmbStream) {
+ return descriptor;
+ }
+
+ descriptor.setThumbnail(Graphics::loadThumbnail(*thmbStream));
+
+ delete thmbStream;
+
+ return descriptor;
+}
+
Common::Error RivenSaveLoad::loadGame(Common::String filename) {
if (_vm->getFeatures() & GF_DEMO) // Don't load games in the demo
return Common::kNoError;
- Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename);
+ Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename);
if (!loadFile)
return Common::kReadingFailed;
@@ -147,6 +260,20 @@ Common::Error RivenSaveLoad::loadGame(Common::String filename) {
}
delete zips;
+
+ // Load the ScummVM specific save metadata
+ if (mhk->hasResource(ID_META, 1)) {
+ Common::SeekableReadStream *metadataStream = mhk->getResource(ID_META, 1);
+ Common::Serializer serializer = Common::Serializer(metadataStream, nullptr);
+
+ RivenSaveMetadata metadata;
+ metadata.sync(serializer);
+
+ // Set the saved total play time
+ _vm->setTotalPlayTime(metadata.totalPlayTime);
+
+ delete metadataStream;
+ }
delete mhk;
return Common::kNoError;
@@ -233,6 +360,34 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genZIPSSection() {
return stream;
}
+Common::MemoryWriteStreamDynamic *RivenSaveLoad::genTHMBSection() const {
+ Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
+
+ Graphics::saveThumbnail(*stream);
+
+ return stream;
+}
+
+Common::MemoryWriteStreamDynamic *RivenSaveLoad::genMETASection(const Common::String &desc) const {
+ Common::MemoryWriteStreamDynamic *stream = new Common::MemoryWriteStreamDynamic();
+ Common::Serializer serializer = Common::Serializer(nullptr, stream);
+
+ TimeDate t;
+ _vm->_system->getTimeAndDate(t);
+
+ RivenSaveMetadata metadata;
+ metadata.saveDay = t.tm_mday;
+ metadata.saveMonth = t.tm_mon + 1;
+ metadata.saveYear = t.tm_year + 1900;
+ metadata.saveHour = t.tm_hour;
+ metadata.saveMinute = t.tm_min;
+ metadata.saveDescription = desc;
+ metadata.totalPlayTime = _vm->getTotalPlayTime();
+ metadata.sync(serializer);
+
+ return stream;
+}
+
Common::Error RivenSaveLoad::saveGame(Common::String filename) {
// NOTE: This code is designed to only output a Mohawk archive
// for a Riven saved game. It's hardcoded to do this because
@@ -255,16 +410,20 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
debug (0, "Saving game to \'%s\'", filename.c_str());
- Common::MemoryWriteStreamDynamic *versSection = genVERSSection();
+ Common::MemoryWriteStreamDynamic *metaSection = genMETASection(filename);
Common::MemoryWriteStreamDynamic *nameSection = genNAMESection();
+ Common::MemoryWriteStreamDynamic *thmbSection = genTHMBSection();
Common::MemoryWriteStreamDynamic *varsSection = genVARSSection();
+ Common::MemoryWriteStreamDynamic *versSection = genVERSSection();
Common::MemoryWriteStreamDynamic *zipsSection = genZIPSSection();
// Let's calculate the file size!
- uint32 fileSize = 142;
- fileSize += versSection->size();
+ uint32 fileSize = 194;
+ fileSize += metaSection->size();
fileSize += nameSection->size();
+ fileSize += thmbSection->size();
fileSize += varsSection->size();
+ fileSize += versSection->size();
fileSize += zipsSection->size();
// MHWK Header (8 bytes - total: 8)
@@ -277,93 +436,129 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
saveFile->writeUint16BE(1); // Compaction -- original saves have this too
saveFile->writeUint32BE(fileSize); // Subtract off the MHWK header size
saveFile->writeUint32BE(28); // Absolute offset: right after both headers
- saveFile->writeUint16BE(70); // File Table Offset
- saveFile->writeUint16BE(44); // File Table Size (4 bytes count + 4 entries * 10 bytes per entry)
+ saveFile->writeUint16BE(102); // File Table Offset
+ saveFile->writeUint16BE(64); // File Table Size (4 bytes count + 6 entries * 10 bytes per entry)
// Type Table (4 bytes - total: 32)
- saveFile->writeUint16BE(36); // String table offset After the Type Table Entries
- saveFile->writeUint16BE(4); // 4 Type Table Entries
+ saveFile->writeUint16BE(52); // String table offset After the Type Table Entries
+ saveFile->writeUint16BE(6); // 6 Type Table Entries
- // Hardcode Entries (32 bytes - total: 64)
+ // Hardcode Entries (48 bytes - total: 80)
// The original engine relies on the entries being sorted by tag alphabetical order
// to optimize its lookup algorithm.
+ saveFile->writeUint32BE(ID_META);
+ saveFile->writeUint16BE(66); // Resource table offset
+ saveFile->writeUint16BE(54); // String table offset
+
saveFile->writeUint32BE(ID_NAME);
- saveFile->writeUint16BE(46); // Resource table offset
- saveFile->writeUint16BE(38); // String table offset
+ saveFile->writeUint16BE(72);
+ saveFile->writeUint16BE(56);
+
+ saveFile->writeUint32BE(ID_THMB);
+ saveFile->writeUint16BE(78);
+ saveFile->writeUint16BE(58);
saveFile->writeUint32BE(ID_VARS);
- saveFile->writeUint16BE(52);
- saveFile->writeUint16BE(40);
+ saveFile->writeUint16BE(84);
+ saveFile->writeUint16BE(60);
saveFile->writeUint32BE(ID_VERS);
- saveFile->writeUint16BE(58);
- saveFile->writeUint16BE(42);
+ saveFile->writeUint16BE(90);
+ saveFile->writeUint16BE(62);
saveFile->writeUint32BE(ID_ZIPS);
+ saveFile->writeUint16BE(96);
saveFile->writeUint16BE(64);
- saveFile->writeUint16BE(44);
- // Pseudo-String Table (2 bytes - total: 66)
+ // Pseudo-String Table (2 bytes - total: 82)
saveFile->writeUint16BE(0); // We don't need a name list
- // Pseudo-Name Tables (8 bytes - total: 74)
+ // Pseudo-Name Tables (12 bytes - total: 94)
+ saveFile->writeUint16BE(0);
+ saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
saveFile->writeUint16BE(0);
- // NAME Section (Resource Table) (6 bytes - total: 80)
+ // META Section (Resource Table) (6 bytes - total: 100)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
- // VARS Section (Resource Table) (6 bytes - total: 86)
+ // NAME Section (Resource Table) (6 bytes - total: 106)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(2);
- // VERS Section (Resource Table) (6 bytes - total: 92)
+ // THMB Section (Resource Table) (6 bytes - total: 112)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(3);
- // ZIPS Section (Resource Table) (6 bytes - total: 98)
+ // VARS Section (Resource Table) (6 bytes - total: 118)
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(1);
saveFile->writeUint16BE(4);
- // File Table (4 bytes - total: 102)
- saveFile->writeUint32BE(4);
+ // VERS Section (Resource Table) (6 bytes - total: 124)
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(5);
- // NAME Section (File Table) (10 bytes - total: 112)
- saveFile->writeUint32BE(142);
+ // ZIPS Section (Resource Table) (6 bytes - total: 130)
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(1);
+ saveFile->writeUint16BE(6);
+
+ // File Table (4 bytes - total: 134)
+ saveFile->writeUint32BE(6);
+
+ // META Section (File Table) (10 bytes - total: 144)
+ saveFile->writeUint32BE(194);
+ saveFile->writeUint16BE(metaSection->size() & 0xFFFF);
+ saveFile->writeByte((metaSection->size() & 0xFF0000) >> 16);
+ saveFile->writeByte(0);
+ saveFile->writeUint16BE(0);
+
+ // NAME Section (File Table) (10 bytes - total: 154)
+ saveFile->writeUint32BE(194 + metaSection->size());
saveFile->writeUint16BE(nameSection->size() & 0xFFFF);
saveFile->writeByte((nameSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- // VARS Section (File Table) (10 bytes - total: 122)
- saveFile->writeUint32BE(142 + nameSection->size());
+ // THMB Section (File Table) (10 bytes - total: 164)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size());
+ saveFile->writeUint16BE(thmbSection->size() & 0xFFFF);
+ saveFile->writeByte((thmbSection->size() & 0xFF0000) >> 16);
+ saveFile->writeByte(0);
+ saveFile->writeUint16BE(0);
+
+ // VARS Section (File Table) (10 bytes - total: 174)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size());
saveFile->writeUint16BE(varsSection->size() & 0xFFFF);
saveFile->writeByte((varsSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- // VERS Section (File Table) (10 bytes - total: 132)
- saveFile->writeUint32BE(142 + nameSection->size() + varsSection->size());
+ // VERS Section (File Table) (10 bytes - total: 184)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size() + varsSection->size());
saveFile->writeUint16BE(versSection->size() & 0xFFFF);
saveFile->writeByte((versSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
- // ZIPS Section (File Table) (10 bytes - total: 142)
- saveFile->writeUint32BE(142 + nameSection->size() + varsSection->size() + versSection->size());
+ // ZIPS Section (File Table) (10 bytes - total: 194)
+ saveFile->writeUint32BE(194 + metaSection->size() + nameSection->size() + thmbSection->size() + varsSection->size() + versSection->size());
saveFile->writeUint16BE(zipsSection->size() & 0xFFFF);
saveFile->writeByte((zipsSection->size() & 0xFF0000) >> 16);
saveFile->writeByte(0);
saveFile->writeUint16BE(0);
+ saveFile->write(metaSection->getData(), metaSection->size());
saveFile->write(nameSection->getData(), nameSection->size());
+ saveFile->write(thmbSection->getData(), thmbSection->size());
saveFile->write(varsSection->getData(), varsSection->size());
saveFile->write(versSection->getData(), versSection->size());
saveFile->write(zipsSection->getData(), zipsSection->size());
@@ -371,9 +566,11 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
saveFile->finalize();
delete saveFile;
- delete versSection;
+ delete metaSection;
delete nameSection;
+ delete thmbSection;
delete varsSection;
+ delete versSection;
delete zipsSection;
return Common::kNoError;
diff --git a/engines/mohawk/riven_saveload.h b/engines/mohawk/riven_saveload.h
index a6ddce5..2ef4326 100644
--- a/engines/mohawk/riven_saveload.h
+++ b/engines/mohawk/riven_saveload.h
@@ -23,10 +23,13 @@
#ifndef MOHAWK_SAVELOAD_H
#define MOHAWK_SAVELOAD_H
+#include "common/serializer.h"
#include "common/savefile.h"
#include "common/str.h"
#include "common/memstream.h"
+#include "engines/savestate.h"
+
namespace Mohawk {
class MohawkEngine_Riven;
@@ -36,6 +39,22 @@ enum {
kDVDSaveGameVersion = 0x00010100
};
+struct RivenSaveMetadata {
+ uint8 saveDay;
+ uint8 saveMonth;
+ uint16 saveYear;
+
+ uint8 saveHour;
+ uint8 saveMinute;
+
+ uint32 totalPlayTime;
+
+ Common::String saveDescription;
+
+ RivenSaveMetadata();
+ bool sync(Common::Serializer &s);
+};
+
class RivenSaveLoad {
public:
RivenSaveLoad(MohawkEngine_Riven*, Common::SaveFileManager*);
@@ -46,13 +65,18 @@ public:
Common::Error saveGame(Common::String);
void deleteSave(Common::String);
+ static SaveStateDescriptor querySaveMetaInfos(const Common::String &filename);
+ static Common::String querySaveDescription(const Common::String &filename);
+
private:
MohawkEngine_Riven *_vm;
Common::SaveFileManager *_saveFileMan;
- Common::MemoryWriteStreamDynamic *genVERSSection();
Common::MemoryWriteStreamDynamic *genNAMESection();
+ Common::MemoryWriteStreamDynamic *genMETASection(const Common::String &desc) const;
+ Common::MemoryWriteStreamDynamic *genTHMBSection() const;
Common::MemoryWriteStreamDynamic *genVARSSection();
+ Common::MemoryWriteStreamDynamic *genVERSSection();
Common::MemoryWriteStreamDynamic *genZIPSSection();
};
Commit: 504ffd2aba0fcb67216242475cff4bbf54650a96
https://github.com/scummvm/scummvm/commit/504ffd2aba0fcb67216242475cff4bbf54650a96
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2016-07-10T22:01:03+02:00
Commit Message:
MOHAWK: Switch Riven saves to a slot based naming scheme
Existing saves are compatible but must be renamed to riven-###.rvn
Changed paths:
engines/mohawk/detection.cpp
engines/mohawk/riven.cpp
engines/mohawk/riven_saveload.cpp
engines/mohawk/riven_saveload.h
diff --git a/engines/mohawk/detection.cpp b/engines/mohawk/detection.cpp
index e1aac64..246d3ec 100644
--- a/engines/mohawk/detection.cpp
+++ b/engines/mohawk/detection.cpp
@@ -199,6 +199,7 @@ public:
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual SaveStateList listSaves(const char *target) const;
+ SaveStateList listSavesForPrefix(const char *prefix, const char *extension) const;
virtual int getMaximumSaveSlot() const { return 999; }
virtual void removeSaveState(const char *target, int slot) const;
virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
@@ -215,41 +216,55 @@ bool MohawkMetaEngine::hasFeature(MetaEngineFeature f) const {
|| (f == kSavesSupportPlayTime);
}
+SaveStateList MohawkMetaEngine::listSavesForPrefix(const char *prefix, const char *extension) const {
+ Common::String pattern = Common::String::format("%s-###.%s", prefix, extension);
+ Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles(pattern);
+ size_t prefixLen = strlen(prefix);
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
+ // Extract the slot number from the filename
+ char slot[4];
+ slot[0] = (*filename)[prefixLen + 1];
+ slot[1] = (*filename)[prefixLen + 2];
+ slot[2] = (*filename)[prefixLen + 3];
+ slot[3] = '\0';
+
+ int slotNum = atoi(slot);
+
+ saveList.push_back(SaveStateDescriptor(slotNum, ""));
+ }
+
+ Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
+
+ return saveList;
+}
+
SaveStateList MohawkMetaEngine::listSaves(const char *target) const {
- Common::StringArray filenames;
SaveStateList saveList;
// Loading games is only supported in Myst/Riven currently.
#ifdef ENABLE_MYST
if (strstr(target, "myst")) {
- filenames = g_system->getSavefileManager()->listSavefiles("myst-###.mys");
- size_t prefixLen = sizeof("myst") - 1;
-
- for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
- // Extract the slot number from the filename
- char slot[4];
- slot[0] = (*filename)[prefixLen + 1];
- slot[1] = (*filename)[prefixLen + 2];
- slot[2] = (*filename)[prefixLen + 3];
- slot[3] = '\0';
-
- int slotNum = atoi(slot);
+ saveList = listSavesForPrefix("myst", "mys");
+ for (SaveStateList::iterator save = saveList.begin(); save != saveList.end(); ++save) {
// Read the description from the save
- Common::String description = Mohawk::MystGameState::querySaveDescription(slotNum);
- saveList.push_back(SaveStateDescriptor(slotNum, description));
+ int slot = save->getSaveSlot();
+ Common::String description = Mohawk::MystGameState::querySaveDescription(slot);
+ save->setDescription(description);
}
-
- Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
}
#endif
#ifdef ENABLE_RIVEN
if (strstr(target, "riven")) {
- filenames = g_system->getSavefileManager()->listSavefiles("*.rvn");
+ saveList = listSavesForPrefix("riven", "rvn");
- for (uint32 i = 0; i < filenames.size(); i++) {
- Common::String description = Mohawk::RivenSaveLoad::querySaveDescription(filenames[i]);
- saveList.push_back(SaveStateDescriptor(i, description));
+ for (SaveStateList::iterator save = saveList.begin(); save != saveList.end(); ++save) {
+ // Read the description from the save
+ int slot = save->getSaveSlot();
+ Common::String description = Mohawk::RivenSaveLoad::querySaveDescription(slot);
+ save->setDescription(description);
}
}
#endif
@@ -263,12 +278,13 @@ void MohawkMetaEngine::removeSaveState(const char *target, int slot) const {
#ifdef ENABLE_MYST
if (strstr(target, "myst")) {
Mohawk::MystGameState::deleteSave(slot);
- } else
+ }
#endif
+#ifdef ENABLE_RIVEN
if (strstr(target, "riven")) {
- Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("*.rvn");
- g_system->getSavefileManager()->removeSavefile(filenames[slot].c_str());
+ Mohawk::RivenSaveLoad::deleteSave(slot);
}
+#endif
}
SaveStateDescriptor MohawkMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
@@ -279,8 +295,7 @@ SaveStateDescriptor MohawkMetaEngine::querySaveMetaInfos(const char *target, int
#endif
#ifdef ENABLE_RIVEN
if (strstr(target, "riven")) {
- Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("*.rvn");
- return Mohawk::RivenSaveLoad::querySaveMetaInfos(filenames[slot].c_str());
+ return Mohawk::RivenSaveLoad::querySaveMetaInfos(slot);
} else
#endif
{
diff --git a/engines/mohawk/riven.cpp b/engines/mohawk/riven.cpp
index 0f764ae..aa168a3 100644
--- a/engines/mohawk/riven.cpp
+++ b/engines/mohawk/riven.cpp
@@ -176,13 +176,10 @@ Common::Error MohawkEngine_Riven::run() {
changeToCard(6);
} else if (ConfMan.hasKey("save_slot")) {
// Load game from launcher/command line if requested
- uint32 gameToLoad = ConfMan.getInt("save_slot");
- Common::StringArray savedGamesList = _saveLoad->generateSaveGameList();
- if (gameToLoad > savedGamesList.size())
- error ("Could not find saved game");
+ int gameToLoad = ConfMan.getInt("save_slot");
// Attempt to load the game. On failure, just send us to the main menu.
- if (_saveLoad->loadGame(savedGamesList[gameToLoad]).getCode() != Common::kNoError) {
+ if (_saveLoad->loadGame(gameToLoad).getCode() != Common::kNoError) {
changeToStack(kStackAspit);
changeToCard(1);
}
@@ -734,16 +731,11 @@ void MohawkEngine_Riven::runLoadDialog() {
}
Common::Error MohawkEngine_Riven::loadGameState(int slot) {
- return _saveLoad->loadGame(_saveLoad->generateSaveGameList()[slot]);
+ return _saveLoad->loadGame(slot);
}
Common::Error MohawkEngine_Riven::saveGameState(int slot, const Common::String &desc) {
- Common::StringArray saveList = _saveLoad->generateSaveGameList();
-
- if ((uint)slot < saveList.size())
- _saveLoad->deleteSave(saveList[slot]);
-
- return _saveLoad->saveGame(desc);
+ return _saveLoad->saveGame(slot, desc);
}
Common::String MohawkEngine_Riven::getStackName(uint16 stack) const {
diff --git a/engines/mohawk/riven_saveload.cpp b/engines/mohawk/riven_saveload.cpp
index 4d52179..755f877 100644
--- a/engines/mohawk/riven_saveload.cpp
+++ b/engines/mohawk/riven_saveload.cpp
@@ -62,11 +62,12 @@ RivenSaveLoad::RivenSaveLoad(MohawkEngine_Riven *vm, Common::SaveFileManager *sa
RivenSaveLoad::~RivenSaveLoad() {
}
-Common::StringArray RivenSaveLoad::generateSaveGameList() {
- return _saveFileMan->listSavefiles("*.rvn");
+Common::String RivenSaveLoad::buildSaveFilename(const int slot) {
+ return Common::String::format("riven-%03d.rvn", slot);
}
-Common::String RivenSaveLoad::querySaveDescription(const Common::String &filename) {
+Common::String RivenSaveLoad::querySaveDescription(const int slot) {
+ Common::String filename = buildSaveFilename(slot);
Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
if (!loadFile) {
return "";
@@ -99,7 +100,8 @@ Common::String RivenSaveLoad::querySaveDescription(const Common::String &filenam
return metadata.saveDescription;
}
-SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const Common::String &filename) {
+SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const int slot) {
+ Common::String filename = buildSaveFilename(slot);
Common::InSaveFile *loadFile = g_system->getSavefileManager()->openForLoading(filename);
if (!loadFile) {
return SaveStateDescriptor();
@@ -151,10 +153,11 @@ SaveStateDescriptor RivenSaveLoad::querySaveMetaInfos(const Common::String &file
return descriptor;
}
-Common::Error RivenSaveLoad::loadGame(Common::String filename) {
+Common::Error RivenSaveLoad::loadGame(const int slot) {
if (_vm->getFeatures() & GF_DEMO) // Don't load games in the demo
return Common::kNoError;
+ Common::String filename = buildSaveFilename(slot);
Common::InSaveFile *loadFile = _saveFileMan->openForLoading(filename);
if (!loadFile)
return Common::kReadingFailed;
@@ -388,7 +391,7 @@ Common::MemoryWriteStreamDynamic *RivenSaveLoad::genMETASection(const Common::St
return stream;
}
-Common::Error RivenSaveLoad::saveGame(Common::String filename) {
+Common::Error RivenSaveLoad::saveGame(const int slot, const Common::String &description) {
// NOTE: This code is designed to only output a Mohawk archive
// for a Riven saved game. It's hardcoded to do this because
// (as of right now) this is the only place in the engine
@@ -396,9 +399,7 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
// games need this, we should think about coming up with some
// more common way of outputting resources to an archive.
- // Make sure we have the right extension
- if (!filename.matchString("*.rvn", true))
- filename += ".rvn";
+ Common::String filename = buildSaveFilename(slot);
// Convert class variables to variable numbers
_vm->_vars["currentstackid"] = _vm->getCurStack();
@@ -410,7 +411,7 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
debug (0, "Saving game to \'%s\'", filename.c_str());
- Common::MemoryWriteStreamDynamic *metaSection = genMETASection(filename);
+ Common::MemoryWriteStreamDynamic *metaSection = genMETASection(description);
Common::MemoryWriteStreamDynamic *nameSection = genNAMESection();
Common::MemoryWriteStreamDynamic *thmbSection = genTHMBSection();
Common::MemoryWriteStreamDynamic *varsSection = genVARSSection();
@@ -576,9 +577,11 @@ Common::Error RivenSaveLoad::saveGame(Common::String filename) {
return Common::kNoError;
}
-void RivenSaveLoad::deleteSave(Common::String saveName) {
- debug (0, "Deleting save file \'%s\'", saveName.c_str());
- _saveFileMan->removeSavefile(saveName);
+void RivenSaveLoad::deleteSave(const int slot) {
+ Common::String filename = buildSaveFilename(slot);
+
+ debug (0, "Deleting save file \'%s\'", filename.c_str());
+ g_system->getSavefileManager()->removeSavefile(filename);
}
} // End of namespace Mohawk
diff --git a/engines/mohawk/riven_saveload.h b/engines/mohawk/riven_saveload.h
index 2ef4326..34bfbdc 100644
--- a/engines/mohawk/riven_saveload.h
+++ b/engines/mohawk/riven_saveload.h
@@ -60,18 +60,19 @@ public:
RivenSaveLoad(MohawkEngine_Riven*, Common::SaveFileManager*);
~RivenSaveLoad();
- Common::StringArray generateSaveGameList();
- Common::Error loadGame(Common::String);
- Common::Error saveGame(Common::String);
- void deleteSave(Common::String);
+ Common::Error loadGame(const int slot);
+ Common::Error saveGame(const int slot, const Common::String &description);
+ static void deleteSave(const int slot);
- static SaveStateDescriptor querySaveMetaInfos(const Common::String &filename);
- static Common::String querySaveDescription(const Common::String &filename);
+ static SaveStateDescriptor querySaveMetaInfos(const int slot);
+ static Common::String querySaveDescription(const int slot);
private:
MohawkEngine_Riven *_vm;
Common::SaveFileManager *_saveFileMan;
+ static Common::String buildSaveFilename(const int slot);
+
Common::MemoryWriteStreamDynamic *genNAMESection();
Common::MemoryWriteStreamDynamic *genMETASection(const Common::String &desc) const;
Common::MemoryWriteStreamDynamic *genTHMBSection() const;
More information about the Scummvm-git-logs
mailing list