2008-03-17 18:10:52 +00:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
* $URL$
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "common/endian.h"
|
|
|
|
#include "common/savefile.h"
|
|
|
|
#include "common/system.h"
|
2008-08-20 14:03:34 +00:00
|
|
|
#include "graphics/thumbnail.h"
|
2008-03-17 18:10:52 +00:00
|
|
|
|
2008-05-11 23:16:50 +00:00
|
|
|
#include "kyra/kyra_v1.h"
|
2009-06-21 01:15:47 +00:00
|
|
|
#include "kyra/util.h"
|
2008-03-17 18:10:52 +00:00
|
|
|
|
2009-06-07 20:43:43 +00:00
|
|
|
#define CURRENT_SAVE_VERSION 16
|
2008-03-17 18:13:28 +00:00
|
|
|
|
2008-03-27 18:03:00 +00:00
|
|
|
#define GF_FLOPPY (1 << 0)
|
|
|
|
#define GF_TALKIE (1 << 1)
|
2008-03-17 18:10:52 +00:00
|
|
|
#define GF_FMTOWNS (1 << 2)
|
|
|
|
|
|
|
|
namespace Kyra {
|
|
|
|
|
2008-08-20 14:03:34 +00:00
|
|
|
KyraEngine_v1::kReadSaveHeaderError KyraEngine_v1::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {
|
2008-03-27 18:03:00 +00:00
|
|
|
uint32 type = in->readUint32BE();
|
|
|
|
header.originalSave = false;
|
|
|
|
header.oldHeader = false;
|
|
|
|
header.flags = 0;
|
2008-09-14 16:29:14 +00:00
|
|
|
header.thumbnail = 0;
|
2008-03-27 18:03:00 +00:00
|
|
|
|
|
|
|
if (type == MKID_BE('KYRA') || type == MKID_BE('ARYK')) { // old Kyra1 header ID
|
|
|
|
header.gameID = GI_KYRA1;
|
|
|
|
header.oldHeader = true;
|
|
|
|
} else if (type == MKID_BE('HOFS')) { // old Kyra2 header ID
|
|
|
|
header.gameID = GI_KYRA2;
|
|
|
|
header.oldHeader = true;
|
|
|
|
} else if (type == MKID_BE('WWSV')) {
|
|
|
|
header.gameID = in->readByte();
|
|
|
|
} else {
|
|
|
|
// try checking for original save header
|
|
|
|
const int descriptionSize[2] = { 30, 80 };
|
|
|
|
char descriptionBuffer[81];
|
|
|
|
|
|
|
|
bool saveOk = false;
|
|
|
|
|
|
|
|
for (uint i = 0; i < ARRAYSIZE(descriptionSize) && !saveOk; ++i) {
|
|
|
|
in->seek(0, SEEK_SET);
|
|
|
|
in->read(descriptionBuffer, descriptionSize[i]);
|
|
|
|
descriptionBuffer[descriptionSize[i]] = 0;
|
2009-01-01 15:06:43 +00:00
|
|
|
|
2009-06-21 01:15:47 +00:00
|
|
|
Util::convertDOSToISO(descriptionBuffer);
|
|
|
|
|
2008-03-27 18:03:00 +00:00
|
|
|
type = in->readUint32BE();
|
|
|
|
header.version = in->readUint16LE();
|
|
|
|
if (type == MKID_BE('MBL3') && header.version == 100) {
|
|
|
|
saveOk = true;
|
|
|
|
header.description = descriptionBuffer;
|
|
|
|
header.gameID = GI_KYRA2;
|
|
|
|
break;
|
2008-05-11 17:20:23 +00:00
|
|
|
} else if (type == MKID_BE('MBL4') && header.version == 102) {
|
|
|
|
saveOk = true;
|
|
|
|
header.description = descriptionBuffer;
|
|
|
|
header.gameID = GI_KYRA3;
|
|
|
|
break;
|
2008-03-27 18:03:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (saveOk) {
|
|
|
|
header.originalSave = true;
|
|
|
|
header.description = descriptionBuffer;
|
|
|
|
return kRSHENoError;
|
|
|
|
} else {
|
|
|
|
return kRSHEInvalidType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
header.version = in->readUint32BE();
|
|
|
|
if (header.version > CURRENT_SAVE_VERSION || (header.oldHeader && header.version > 8) || (type == MKID_BE('ARYK') && header.version > 3))
|
|
|
|
return kRSHEInvalidVersion;
|
|
|
|
|
|
|
|
// Versions prior to 9 are using a fixed length description field
|
|
|
|
if (header.version <= 8) {
|
|
|
|
char buffer[31];
|
|
|
|
in->read(buffer, 31);
|
2008-08-02 11:40:09 +00:00
|
|
|
// WORKAROUND: Old savegames could contain a missing termination 0 at the
|
|
|
|
// end so we manually add it.
|
|
|
|
buffer[30] = 0;
|
2008-03-27 18:03:00 +00:00
|
|
|
header.description = buffer;
|
|
|
|
} else {
|
|
|
|
header.description = "";
|
|
|
|
for (char c = 0; (c = in->readByte()) != 0;)
|
|
|
|
header.description += c;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (header.version >= 2)
|
|
|
|
header.flags = in->readUint32BE();
|
|
|
|
|
2008-08-20 14:03:34 +00:00
|
|
|
if (header.version >= 14) {
|
|
|
|
if (loadThumbnail) {
|
|
|
|
header.thumbnail = new Graphics::Surface();
|
|
|
|
assert(header.thumbnail);
|
2008-08-20 14:24:16 +00:00
|
|
|
if (!Graphics::loadThumbnail(*in, *header.thumbnail)) {
|
|
|
|
delete header.thumbnail;
|
|
|
|
header.thumbnail = 0;
|
|
|
|
}
|
2008-08-20 14:03:34 +00:00
|
|
|
} else {
|
2010-08-02 22:28:30 +00:00
|
|
|
Graphics::skipThumbnail(*in);
|
2008-08-20 14:03:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-14 18:24:20 +00:00
|
|
|
return ((in->err() || in->eos()) ? kRSHEIoError : kRSHENoError);
|
2008-03-27 18:03:00 +00:00
|
|
|
}
|
|
|
|
|
2008-08-05 11:32:16 +00:00
|
|
|
Common::SeekableReadStream *KyraEngine_v1::openSaveForReading(const char *filename, SaveHeader &header) {
|
|
|
|
Common::SeekableReadStream *in = 0;
|
2008-03-30 18:27:46 +00:00
|
|
|
if (!(in = _saveFileMan->openForLoading(filename)))
|
2008-03-17 18:10:52 +00:00
|
|
|
return 0;
|
|
|
|
|
2008-08-20 14:03:34 +00:00
|
|
|
kReadSaveHeaderError errorCode = KyraEngine_v1::readSaveHeader(in, false, header);
|
2008-03-27 18:03:00 +00:00
|
|
|
if (errorCode != kRSHENoError) {
|
|
|
|
if (errorCode == kRSHEInvalidType)
|
|
|
|
warning("No ScummVM Kyra engine savefile header.");
|
|
|
|
else if (errorCode == kRSHEInvalidVersion)
|
|
|
|
warning("Savegame is not the right version (%u, '%s')", header.version, header.oldHeader ? "true" : "false");
|
|
|
|
else if (errorCode == kRSHEIoError)
|
2008-03-28 00:53:54 +00:00
|
|
|
warning("Load failed '%s'", filename);
|
2008-03-17 18:10:52 +00:00
|
|
|
|
|
|
|
delete in;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-03-27 18:03:00 +00:00
|
|
|
if (!header.originalSave) {
|
|
|
|
if (!header.oldHeader) {
|
|
|
|
if (header.gameID != _flags.gameID) {
|
|
|
|
warning("Trying to load game state from other game (save game: %u, running game: %u)", header.gameID, _flags.gameID);
|
|
|
|
delete in;
|
|
|
|
return 0;
|
|
|
|
}
|
2008-03-17 18:10:52 +00:00
|
|
|
}
|
|
|
|
|
2008-03-27 18:03:00 +00:00
|
|
|
if (header.version < 2) {
|
|
|
|
warning("Make sure your savefile was from this version! (too old savefile version to detect that)");
|
|
|
|
} else {
|
|
|
|
if ((header.flags & GF_FLOPPY) && (_flags.isTalkie || _flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) {
|
|
|
|
warning("Can not load DOS Floppy savefile for this (non DOS Floppy) gameversion");
|
|
|
|
delete in;
|
|
|
|
return 0;
|
|
|
|
} else if ((header.flags & GF_TALKIE) && !(_flags.isTalkie)) {
|
|
|
|
warning("Can not load DOS CD-ROM savefile for this (non DOS CD-ROM) gameversion");
|
|
|
|
delete in;
|
|
|
|
return 0;
|
|
|
|
} else if ((header.flags & GF_FMTOWNS) && !(_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)) {
|
2009-07-07 19:00:39 +00:00
|
|
|
warning("Can not load FM-TOWNS/PC98 savefile for this (non FM-TOWNS/PC98) gameversion");
|
2008-03-27 18:03:00 +00:00
|
|
|
delete in;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2008-03-17 18:10:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return in;
|
|
|
|
}
|
|
|
|
|
2008-08-20 14:03:34 +00:00
|
|
|
Common::WriteStream *KyraEngine_v1::openSaveForWriting(const char *filename, const char *saveName, const Graphics::Surface *thumbnail) const {
|
2008-09-30 12:27:38 +00:00
|
|
|
if (shouldQuit())
|
2008-03-17 18:10:52 +00:00
|
|
|
return 0;
|
|
|
|
|
2008-08-05 11:32:16 +00:00
|
|
|
Common::WriteStream *out = 0;
|
2008-03-17 18:10:52 +00:00
|
|
|
if (!(out = _saveFileMan->openForSaving(filename))) {
|
|
|
|
warning("Can't create file '%s', game not saved", filename);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Savegame version
|
2008-03-27 18:03:00 +00:00
|
|
|
out->writeUint32BE(MKID_BE('WWSV'));
|
|
|
|
out->writeByte(_flags.gameID);
|
2008-03-17 18:13:28 +00:00
|
|
|
out->writeUint32BE(CURRENT_SAVE_VERSION);
|
2008-03-27 18:03:00 +00:00
|
|
|
out->write(saveName, strlen(saveName)+1);
|
2008-03-17 18:10:52 +00:00
|
|
|
if (_flags.isTalkie)
|
|
|
|
out->writeUint32BE(GF_TALKIE);
|
|
|
|
else if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)
|
|
|
|
out->writeUint32BE(GF_FMTOWNS);
|
|
|
|
else
|
|
|
|
out->writeUint32BE(GF_FLOPPY);
|
|
|
|
|
2009-05-19 11:42:14 +00:00
|
|
|
if (out->err()) {
|
2008-03-17 18:10:52 +00:00
|
|
|
warning("Can't write file '%s'. (Disk full?)", filename);
|
|
|
|
delete out;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-10-04 17:38:15 +00:00
|
|
|
Graphics::Surface *genThumbnail = 0;
|
|
|
|
if (!thumbnail)
|
|
|
|
thumbnail = genThumbnail = generateSaveThumbnail();
|
|
|
|
|
2008-08-20 14:03:34 +00:00
|
|
|
if (thumbnail)
|
|
|
|
Graphics::saveThumbnail(*out, *thumbnail);
|
|
|
|
else
|
|
|
|
Graphics::saveThumbnail(*out);
|
|
|
|
|
2009-10-04 17:38:15 +00:00
|
|
|
if (genThumbnail) {
|
|
|
|
genThumbnail->free();
|
|
|
|
delete genThumbnail;
|
|
|
|
}
|
|
|
|
|
2008-03-17 18:10:52 +00:00
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2008-05-11 23:16:50 +00:00
|
|
|
const char *KyraEngine_v1::getSavegameFilename(int num) {
|
2008-03-17 21:56:37 +00:00
|
|
|
static Common::String filename;
|
2008-09-14 21:41:27 +00:00
|
|
|
filename = getSavegameFilename(_targetName, num);
|
|
|
|
return filename.c_str();
|
|
|
|
}
|
2008-04-29 14:33:29 +00:00
|
|
|
|
2008-09-14 21:41:27 +00:00
|
|
|
Common::String KyraEngine_v1::getSavegameFilename(const Common::String &target, int num) {
|
2008-04-29 14:33:29 +00:00
|
|
|
assert(num >= 0 && num <= 999);
|
2009-07-25 15:31:11 +00:00
|
|
|
return target + Common::String::printf(".%03d", num);
|
2008-03-17 21:56:37 +00:00
|
|
|
}
|
|
|
|
|
2008-05-11 23:16:50 +00:00
|
|
|
bool KyraEngine_v1::saveFileLoadable(int slot) {
|
2008-03-28 00:53:54 +00:00
|
|
|
if (slot < 0 || slot > 999)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SaveHeader header;
|
2008-08-05 11:32:16 +00:00
|
|
|
Common::SeekableReadStream *in = openSaveForReading(getSavegameFilename(slot), header);
|
2008-03-28 00:53:54 +00:00
|
|
|
|
|
|
|
if (in) {
|
|
|
|
delete in;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-09-14 19:48:40 +00:00
|
|
|
void KyraEngine_v1::checkAutosave() {
|
|
|
|
if (shouldPerformAutoSave(_lastAutosave)) {
|
2008-11-09 13:00:40 +00:00
|
|
|
saveGameState(999, "Autosave", 0);
|
2008-09-14 19:48:40 +00:00
|
|
|
_lastAutosave = _system->getMillis();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-09 13:12:38 +00:00
|
|
|
void KyraEngine_v1::loadGameStateCheck(int slot) {
|
|
|
|
if (loadGameState(slot) != Common::kNoError) {
|
|
|
|
const char *filename = getSavegameFilename(slot);
|
|
|
|
Common::String errorMessage = "Could not load savegame: '";
|
|
|
|
errorMessage += filename;
|
|
|
|
errorMessage += "'";
|
|
|
|
|
|
|
|
GUIErrorMessage(errorMessage);
|
2008-11-16 20:20:31 +00:00
|
|
|
error("%s", errorMessage.c_str());
|
2008-11-09 13:12:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-04 21:26:33 +00:00
|
|
|
} // End of namespace Kyra
|
2008-03-17 21:56:37 +00:00
|
|
|
|