SCUMM: Modified version of patch #1687041 (Scumm: Load-/Save-support for the original save-dialog)

svn-id: r39438
This commit is contained in:
Max Horn 2009-03-16 04:45:12 +00:00
parent ffa97e6626
commit e44f07f988
6 changed files with 190 additions and 25 deletions

View File

@ -410,6 +410,11 @@ void ScummEngine_v2::processKeyboard(Common::KeyState lastKeyHit) {
// Fall back to default behavior
ScummEngine::processKeyboard(lastKeyHit);
// On Alt-F5 prepare savegame for the original save/load dialog.
if (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.flags == Common::KBD_ALT) {
prepareSavegame();
}
if (VAR_KEYPRESS != 0xFF && _mouseAndKeyboardStat) { // Key Input
if (315 <= _mouseAndKeyboardStat && _mouseAndKeyboardStat <= 323) {
// Convert F-Keys for V1/V2 games (they start at 1)
@ -424,8 +429,13 @@ void ScummEngine_v3::processKeyboard(Common::KeyState lastKeyHit) {
// Fall back to default behavior
ScummEngine::processKeyboard(lastKeyHit);
// 'i' brings up an IQ dialog in Indy3
if (lastKeyHit.ascii == 'i' && _game.id == GID_INDY3) {
// On Alt-F5 prepare savegame for the original save/load dialog.
if (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.flags == Common::KBD_ALT) {
prepareSavegame();
}
// 'i' brings up an IQ dialog in Indy3 (disabled in save/load dialog for input)
if (lastKeyHit.ascii == 'i' && _game.id == GID_INDY3 && _currentRoom != 14) {
// SCUMM var 244 is the episode score
// and var 245 is the series score
char text[50];
@ -496,7 +506,7 @@ void ScummEngine::processKeyboard(Common::KeyState lastKeyHit) {
messageDialog("Snap scroll on");
} else {
messageDialog("Snap scroll off");
}
}
if (VAR_CAMERA_FAST_X != 0xFF)
VAR(VAR_CAMERA_FAST_X) = _snapScroll;

View File

@ -237,8 +237,26 @@ protected:
* Engine for version 3 SCUMM games; GF_SMALL_NAMES is always set for these.
*/
class ScummEngine_v3 : public ScummEngine_v4 {
public:
/**
* Prepared savegame used by the orginal save/load dialog.
* Must be valid as long as the savescreen is active. As we are not
* notified when the savescreen is closed, memory is only freed on a game
* reset, at the destruction of the engine or when the original save/load
* dialog is entered the next time.
*/
Common::SeekableReadStream *_savePreparedSavegame;
void prepareSavegame();
bool savePreparedSavegame(int slot, char *desc);
public:
ScummEngine_v3(OSystem *syst, const DetectorResult &dr);
~ScummEngine_v3();
virtual void resetScumm();
protected:
virtual void readRoomsOffsets();

View File

@ -28,6 +28,7 @@
#include "common/config-manager.h"
#include "common/savefile.h"
#include "common/system.h"
#include "common/zlib.h"
#include "scumm/actor.h"
#include "scumm/charset.h"
@ -129,10 +130,27 @@ static bool saveSaveGameHeader(Common::OutSaveFile *out, SaveGameHeader &hdr) {
return true;
}
bool ScummEngine::saveState(Common::OutSaveFile *out, bool writeHeader) {
SaveGameHeader hdr;
if (writeHeader) {
memcpy(hdr.name, _saveLoadName, sizeof(hdr.name));
saveSaveGameHeader(out, hdr);
}
#if !defined(__DS__)
Graphics::saveThumbnail(*out);
#endif
saveInfos(out);
Serializer ser(0, out, CURRENT_VER);
saveOrLoad(&ser);
return true;
}
bool ScummEngine::saveState(int slot, bool compat) {
bool saveFailed;
Common::String filename;
Common::OutSaveFile *out;
SaveGameHeader hdr;
if (_saveLoadSlot == 255) {
// Allow custom filenames for save game system in HE Games
@ -143,26 +161,108 @@ bool ScummEngine::saveState(int slot, bool compat) {
if (!(out = _saveFileMan->openForSaving(filename.c_str())))
return false;
memcpy(hdr.name, _saveLoadName, sizeof(hdr.name));
saveSaveGameHeader(out, hdr);
#if !defined(__DS__)
Graphics::saveThumbnail(*out);
#endif
saveInfos(out);
saveFailed = false;
if (!saveState(out))
saveFailed = true;
Serializer ser(0, out, CURRENT_VER);
saveOrLoad(&ser);
out->finalize();
if (out->err()) {
delete out;
if (out->err())
saveFailed = true;
delete out;
if (saveFailed) {
debug(1, "State save as '%s' FAILED", filename.c_str());
return false;
}
delete out;
debug(1, "State saved as '%s'", filename.c_str());
return true;
}
void ScummEngine_v3::prepareSavegame() {
Common::MemoryWriteStreamDynamic *memStream;
Common::WriteStream *writeStream;
// free memory of the last prepared savegame
delete _savePreparedSavegame;
_savePreparedSavegame = NULL;
// store headerless savegame in a compressed memory stream
memStream = new Common::MemoryWriteStreamDynamic();
writeStream = Common::wrapCompressedWriteStream(memStream);
if (saveState(writeStream, false)) {
// we have to finalize the compression-stream first, otherwise the internal
// memory-stream pointer will be zero (Important: flush() does not work here!).
writeStream->finalize();
if (!writeStream->err()) {
// wrap uncompressing MemoryReadStream around the savegame data
_savePreparedSavegame = Common::wrapCompressedReadStream(
new Common::MemoryReadStream(memStream->getData(), memStream->size(), true));
}
}
// free the CompressedWriteStream and MemoryWriteStreamDynamic
// but not the memory stream's internal buffer
delete writeStream;
}
bool ScummEngine_v3::savePreparedSavegame(int slot, char *desc) {
bool success;
Common::String filename;
Common::OutSaveFile *out;
SaveGameHeader hdr;
uint32 nread, nwritten;
out = 0;
success = true;
// check if savegame was successfully stored in memory
if (!_savePreparedSavegame)
success = false;
// open savegame file
if (success) {
filename = makeSavegameName(slot, false);
if (!(out = _saveFileMan->openForSaving(filename.c_str()))) {
success = false;
}
}
// write header to file
if (success) {
memset(hdr.name, 0, sizeof(hdr.name));
strncpy(hdr.name, desc, sizeof(hdr.name)-1);
success = saveSaveGameHeader(out, hdr);
}
// copy savegame from memory-stream to file
if (success) {
_savePreparedSavegame->seek(0, SEEK_SET);
byte buffer[1024];
while ((nread = _savePreparedSavegame->read(buffer, sizeof(buffer)))) {
nwritten = out->write(buffer, nread);
if (nwritten < nread) {
success = false;
break;
}
}
}
if (out) {
out->finalize();
if (out->err())
success = false;
delete out;
}
if (!success) {
debug(1, "State save as '%s' FAILED", filename.c_str());
return false;
} else {
debug(1, "State saved as '%s'", filename.c_str());
return true;
}
}
static bool loadSaveGameHeader(Common::SeekableReadStream *in, SaveGameHeader &hdr) {
hdr.type = in->readUint32BE();
hdr.size = in->readUint32LE();

View File

@ -869,7 +869,12 @@ enum StringIds {
// which matches the original Indy3 save/load code. See also the notes
// on Feature Request #1666521.
STRINGID_IQ_EPISODE = 7,
STRINGID_IQ_SERIES = 9
STRINGID_IQ_SERIES = 9,
// The string IDs of the first savegame name, used as an offset to determine
// the IDs of all savenames.
// Loom is the only game whose savenames start with a different ID.
STRINGID_SAVENAME1 = 10,
STRINGID_SAVENAME1_LOOM = 9
};
void ScummEngine_v5::o5_saveLoadVars() {
@ -1235,26 +1240,43 @@ void ScummEngine_v5::o5_saveLoadGame() {
result = 100;
break;
case 0x20: // drive
if (_game.id == GID_INDY3) {
// 0 = hard drive
// 1 = disk drive
result = 0;
if (_game.version <= 3) {
// 0 = ???
// [1,2] = disk drive [A:,B:]
// 3 = hard drive
result = 3;
} else {
// set current drive
result = 1;
}
break;
case 0x40: // load
if (loadState(slot, _saveTemporaryState))
if (loadState(slot, false))
result = 3; // sucess
else
result = 5; // failed to load
break;
case 0x80: // save
//if (saveState(slot, _saveTemporaryState))
// result = 0; // sucess
//else
if (_game.version <= 3) {
char name[32];
if (_game.version <= 2) {
// use generic name
sprintf(name, "Game %c", 'A'+slot-1);
} else {
// use name entered by the user
char* ptr;
int firstSlot = (_game.id == GID_LOOM) ? STRINGID_SAVENAME1_LOOM : STRINGID_SAVENAME1;
ptr = (char*)getStringAddress(slot + firstSlot - 1);
strncpy(name, ptr, sizeof(name));
}
if (((ScummEngine_v3 *)this)->savePreparedSavegame(slot, name))
result = 0;
else
result = 2;
} else {
result = 2; // failed to save
}
break;
case 0xC0: // test if save exists
{

View File

@ -631,6 +631,12 @@ ScummEngine_v3::ScummEngine_v3(OSystem *syst, const DetectorResult &dr)
// All v3 and older games only used 16 colors with exception of the GF_OLD256 games.
if (!(_game.features & GF_OLD256))
_game.features |= GF_16COLOR;
_savePreparedSavegame = NULL;
}
ScummEngine_v3::~ScummEngine_v3() {
delete _savePreparedSavegame;
}
ScummEngine_v3old::ScummEngine_v3old(OSystem *syst, const DetectorResult &dr)
@ -1426,7 +1432,7 @@ void ScummEngine_v0::resetScumm() {
}
void ScummEngine_v2::resetScumm() {
ScummEngine::resetScumm();
ScummEngine_v3::resetScumm();
if (_game.platform == Common::kPlatformNES) {
initNESMouseOver();
@ -1442,6 +1448,13 @@ void ScummEngine_v2::resetScumm() {
_inventoryOffset = 0;
}
void ScummEngine_v3::resetScumm() {
ScummEngine_v4::resetScumm();
delete _savePreparedSavegame;
_savePreparedSavegame = NULL;
}
void ScummEngine_v4::resetScumm() {
ScummEngine::resetScumm();

View File

@ -29,6 +29,7 @@
#include "engines/engine.h"
#include "common/endian.h"
#include "common/file.h"
#include "common/savefile.h"
#include "common/keyboard.h"
#include "common/rect.h"
#include "common/str.h"
@ -628,6 +629,7 @@ protected:
char _saveLoadFileName[32];
char _saveLoadName[32];
bool saveState(Common::OutSaveFile *out, bool writeHeader = true);
bool saveState(int slot, bool compat);
bool loadState(int slot, bool compat);
virtual void saveOrLoad(Serializer *s);