aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/scumm/input.cpp16
-rw-r--r--engines/scumm/intern.h18
-rw-r--r--engines/scumm/saveload.cpp124
-rw-r--r--engines/scumm/script_v5.cpp40
-rw-r--r--engines/scumm/scumm.cpp15
-rw-r--r--engines/scumm/scumm.h2
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);