diff options
author | Max Horn | 2009-03-16 04:45:12 +0000 |
---|---|---|
committer | Max Horn | 2009-03-16 04:45:12 +0000 |
commit | e44f07f988ee6a2a7574a42169d08b3d7a112eba (patch) | |
tree | 56ba5688d855def4850a890029ef1805db9cc576 | |
parent | ffa97e6626e43adf9c94de9a7322138e46436af4 (diff) | |
download | scummvm-rg350-e44f07f988ee6a2a7574a42169d08b3d7a112eba.tar.gz scummvm-rg350-e44f07f988ee6a2a7574a42169d08b3d7a112eba.tar.bz2 scummvm-rg350-e44f07f988ee6a2a7574a42169d08b3d7a112eba.zip |
SCUMM: Modified version of patch #1687041 (Scumm: Load-/Save-support for the original save-dialog)
svn-id: r39438
-rw-r--r-- | engines/scumm/input.cpp | 16 | ||||
-rw-r--r-- | engines/scumm/intern.h | 18 | ||||
-rw-r--r-- | engines/scumm/saveload.cpp | 124 | ||||
-rw-r--r-- | engines/scumm/script_v5.cpp | 40 | ||||
-rw-r--r-- | engines/scumm/scumm.cpp | 15 | ||||
-rw-r--r-- | engines/scumm/scumm.h | 2 |
6 files changed, 190 insertions, 25 deletions
diff --git a/engines/scumm/input.cpp b/engines/scumm/input.cpp index 27d56f62f3..73ac38b814 100644 --- a/engines/scumm/input.cpp +++ b/engines/scumm/input.cpp @@ -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; diff --git a/engines/scumm/intern.h b/engines/scumm/intern.h index 2dfbcdcdbb..1381a036b8 100644 --- a/engines/scumm/intern.h +++ b/engines/scumm/intern.h @@ -238,7 +238,25 @@ protected: */ 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(); diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp index 577c465bdd..55880766d9 100644 --- a/engines/scumm/saveload.cpp +++ b/engines/scumm/saveload.cpp @@ -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(); diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp index b984f56ab0..a6c8df2031 100644 --- a/engines/scumm/script_v5.cpp +++ b/engines/scumm/script_v5.cpp @@ -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 { diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp index d29db052f3..cb24c38099 100644 --- a/engines/scumm/scumm.cpp +++ b/engines/scumm/scumm.cpp @@ -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(); diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index 7a6339bcc9..bd1ea0791f 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -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); |