aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/scumm/saveload.cpp4
-rw-r--r--engines/scumm/script_v0.cpp4
-rw-r--r--engines/scumm/script_v2.cpp4
-rw-r--r--engines/scumm/script_v4.cpp319
-rw-r--r--engines/scumm/script_v5.cpp328
-rw-r--r--engines/scumm/scumm.cpp15
-rw-r--r--engines/scumm/scumm_v3.h15
-rw-r--r--engines/scumm/scumm_v4.h25
-rw-r--r--engines/scumm/scumm_v5.h8
9 files changed, 370 insertions, 352 deletions
diff --git a/engines/scumm/saveload.cpp b/engines/scumm/saveload.cpp
index ff359e2efc..4fd1b40134 100644
--- a/engines/scumm/saveload.cpp
+++ b/engines/scumm/saveload.cpp
@@ -179,7 +179,7 @@ bool ScummEngine::saveState(int slot, bool compat) {
}
-void ScummEngine_v3::prepareSavegame() {
+void ScummEngine_v4::prepareSavegame() {
Common::MemoryWriteStreamDynamic *memStream;
Common::WriteStream *writeStream;
@@ -205,7 +205,7 @@ void ScummEngine_v3::prepareSavegame() {
delete writeStream;
}
-bool ScummEngine_v3::savePreparedSavegame(int slot, char *desc) {
+bool ScummEngine_v4::savePreparedSavegame(int slot, char *desc) {
bool success;
Common::String filename;
Common::OutSaveFile *out;
diff --git a/engines/scumm/script_v0.cpp b/engines/scumm/script_v0.cpp
index f43d3ae26b..23f1ef7de2 100644
--- a/engines/scumm/script_v0.cpp
+++ b/engines/scumm/script_v0.cpp
@@ -78,7 +78,7 @@ void ScummEngine_v0::setupOpcodes() {
/* 20 */
OPCODE(0x20, o5_stopMusic);
OPCODE(0x21, o2_putActor);
- OPCODE(0x22, o5_saveLoadGame);
+ OPCODE(0x22, o4_saveLoadGame);
OPCODE(0x23, o_stopCurrentScript);
/* 24 */
OPCODE(0x24, o_unknown2);
@@ -238,7 +238,7 @@ void ScummEngine_v0::setupOpcodes() {
/* A0 */
OPCODE(0xa0, o5_stopObjectCode);
OPCODE(0xa1, o2_putActor);
- OPCODE(0xa2, o5_saveLoadGame);
+ OPCODE(0xa2, o4_saveLoadGame);
OPCODE(0xa3, o_stopCurrentScript);
/* A4 */
OPCODE(0xa4, o_unknown2);
diff --git a/engines/scumm/script_v2.cpp b/engines/scumm/script_v2.cpp
index 5a7a3f138a..941c3246b1 100644
--- a/engines/scumm/script_v2.cpp
+++ b/engines/scumm/script_v2.cpp
@@ -80,7 +80,7 @@ void ScummEngine_v2::setupOpcodes() {
/* 20 */
OPCODE(0x20, o5_stopMusic);
OPCODE(0x21, o2_putActor);
- OPCODE(0x22, o5_saveLoadGame);
+ OPCODE(0x22, o4_saveLoadGame);
OPCODE(0x23, o2_getActorY);
/* 24 */
OPCODE(0x24, o2_loadRoomWithEgo);
@@ -240,7 +240,7 @@ void ScummEngine_v2::setupOpcodes() {
/* A0 */
OPCODE(0xa0, o5_stopObjectCode);
OPCODE(0xa1, o2_putActor);
- OPCODE(0xa2, o5_saveLoadGame);
+ OPCODE(0xa2, o4_saveLoadGame);
OPCODE(0xa3, o2_getActorY);
/* A4 */
OPCODE(0xa4, o2_loadRoomWithEgo);
diff --git a/engines/scumm/script_v4.cpp b/engines/scumm/script_v4.cpp
index 08df1e4653..b8964c4194 100644
--- a/engines/scumm/script_v4.cpp
+++ b/engines/scumm/script_v4.cpp
@@ -47,13 +47,19 @@ void ScummEngine_v4::setupOpcodes() {
OPCODE(0xdc, o4_oldRoomEffect);
OPCODE(0x0f, o4_ifState);
- OPCODE(0x2f, o4_ifNotState);
OPCODE(0x4f, o4_ifState);
- OPCODE(0x6f, o4_ifNotState);
OPCODE(0x8f, o4_ifState);
- OPCODE(0xaf, o4_ifNotState);
OPCODE(0xcf, o4_ifState);
+
+ OPCODE(0x2f, o4_ifNotState);
+ OPCODE(0x6f, o4_ifNotState);
+ OPCODE(0xaf, o4_ifNotState);
OPCODE(0xef, o4_ifNotState);
+
+ OPCODE(0xa7, o4_saveLoadVars);
+
+ OPCODE(0x22, o4_saveLoadGame);
+ OPCODE(0xa2, o4_saveLoadGame);
}
void ScummEngine_v4::o4_ifState() {
@@ -171,4 +177,311 @@ void ScummEngine_v4::o4_oldRoomEffect() {
}
}
+void ScummEngine_v4::o4_saveLoadVars() {
+ if (fetchScriptByte() == 1)
+ saveVars();
+ else
+ loadVars();
+}
+
+enum StringIds {
+ // The string IDs used by Indy3 to store the episode resp. series IQ points.
+ // Note that we save the episode IQ points but load the series IQ points,
+ // which matches the original Indy3 save/load code. See also the notes
+ // on Feature Request #1666521.
+ STRINGID_IQ_EPISODE = 7,
+ 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_v4::saveVars() {
+ int a, b;
+
+ while ((_opcode = fetchScriptByte()) != 0) {
+ switch (_opcode & 0x1F) {
+ case 0x01: // write a range of variables
+ getResultPos();
+ a = _resultVarNumber;
+ getResultPos();
+ b = _resultVarNumber;
+ debug(0, "stub saveVars: vars %d -> %d", a, b);
+ break;
+ case 0x02: // write a range of string variables
+ a = getVarOrDirectByte(PARAM_1);
+ b = getVarOrDirectByte(PARAM_2);
+
+ if (a == STRINGID_IQ_EPISODE && b == STRINGID_IQ_EPISODE) {
+ if (_game.id == GID_INDY3) {
+ saveIQPoints();
+ }
+ break;
+ }
+ // FIXME: changing savegame-names not supported
+ break;
+ case 0x03: // open file
+ a = resStrLen(_scriptPointer);
+ strncpy(_saveLoadVarsFilename, (const char *)_scriptPointer, a);
+ _saveLoadVarsFilename[a] = '\0';
+ _scriptPointer += a + 1;
+ break;
+ case 0x04:
+ return;
+ case 0x1F: // close file
+ _saveLoadVarsFilename[0] = '\0';
+ return;
+ }
+ }
+}
+
+void ScummEngine_v4::loadVars() {
+ int a, b;
+
+ while ((_opcode = fetchScriptByte()) != 0) {
+ switch (_opcode & 0x1F) {
+ case 0x01: // read a range of variables
+ getResultPos();
+ a = _resultVarNumber;
+ getResultPos();
+ b = _resultVarNumber;
+ debug(0, "stub loadVars: vars %d -> %d", a, b);
+ break;
+ case 0x02: // read a range of string variables
+ a = getVarOrDirectByte(PARAM_1);
+ b = getVarOrDirectByte(PARAM_2);
+
+ int slot;
+ int slotSize;
+ byte* slotContent;
+ int savegameId;
+ bool avail_saves[100];
+
+ if (a == STRINGID_IQ_SERIES && b == STRINGID_IQ_SERIES) {
+ // Zak256 loads the IQ script-slot but does not use it -> ignore it
+ if (_game.id == GID_INDY3) {
+ byte *ptr = getResourceAddress(rtString, STRINGID_IQ_SERIES);
+ if (ptr) {
+ int size = getResourceSize(rtString, STRINGID_IQ_SERIES);
+ loadIQPoints(ptr, size);
+ }
+ }
+ break;
+ }
+
+ listSavegames(avail_saves, ARRAYSIZE(avail_saves));
+ for (slot = a; slot <= b; ++slot) {
+ slotSize = getResourceSize(rtString, slot);
+ slotContent = getResourceAddress(rtString, slot);
+
+ // load savegame names
+ savegameId = slot - a + 1;
+ Common::String name;
+ if (avail_saves[savegameId] && getSavegameName(savegameId, name)) {
+ int pos;
+ const char *ptr = name.c_str();
+ // slotContent ends with {'\0','@'} -> max. length = slotSize-2
+ for (pos = 0; pos < slotSize - 2; ++pos) {
+ if (!ptr[pos])
+ break;
+ // replace special characters
+ if (ptr[pos] >= 32 && ptr[pos] <= 122 && ptr[pos] != 64)
+ slotContent[pos] = ptr[pos];
+ else
+ slotContent[pos] = '_';
+ }
+ slotContent[pos] = '\0';
+ } else {
+ slotContent[0] = '\0';
+ }
+ }
+ break;
+ case 0x03: // open file
+ a = resStrLen(_scriptPointer);
+ strncpy(_saveLoadVarsFilename, (const char *)_scriptPointer, a);
+ _saveLoadVarsFilename[a] = '\0';
+ _scriptPointer += a + 1;
+ break;
+ case 0x04:
+ return;
+ case 0x1F: // close file
+ _saveLoadVarsFilename[0] = '\0';
+ return;
+ }
+ }
+}
+
+/**
+ * IQ Point calculation for Indy3.
+ * The scripts that perform this task are
+ * - script-9 (save/load dialog initialization, loads room 14),
+ * - room-14-204 (load series IQ string),
+ * - room-14-205 (save series IQ string),
+ * - room-14-206 (calculate series IQ string).
+ * Unfortunately script-9 contains lots of GUI stuff so calling this script
+ * directly is not possible. The other scripts depend on script-9.
+ */
+void ScummEngine_v4::updateIQPoints() {
+ int seriesIQ;
+ // IQString[0..72] corresponds to each puzzle's IQ.
+ // IQString[73] indicates that the IQ-file was loaded successfully and is always 0 when
+ // the IQ is calculated, hence it will be ignored here.
+ const int NUM_PUZZLES = 73;
+ byte seriesIQString[NUM_PUZZLES];
+ byte *episodeIQString;
+ int episodeIQStringSize;
+
+ // load string with IQ points given per puzzle in any savegame
+ // IMPORTANT: the resource string STRINGID_IQ_SERIES is only valid while
+ // the original save/load dialog is executed, so do not use it here.
+ memset(seriesIQString, 0, sizeof(seriesIQString));
+ loadIQPoints(seriesIQString, sizeof(seriesIQString));
+
+ // string with IQ points given per puzzle in current savegame
+ episodeIQString = getResourceAddress(rtString, STRINGID_IQ_EPISODE);
+ if (!episodeIQString)
+ return;
+ episodeIQStringSize = getResourceSize(rtString, STRINGID_IQ_EPISODE);
+ if (episodeIQStringSize < NUM_PUZZLES)
+ return;
+
+ // merge episode and series IQ strings and calculate series IQ
+ seriesIQ = 0;
+ // iterate over puzzles
+ for (int i = 0; i < NUM_PUZZLES ; ++i) {
+ byte puzzleIQ = seriesIQString[i];
+ // if puzzle is solved copy points to episode string
+ if (puzzleIQ > 0)
+ episodeIQString[i] = puzzleIQ;
+ // add puzzle's IQ-points to series IQ
+ seriesIQ += episodeIQString[i];
+ }
+ _scummVars[245] = seriesIQ;
+
+ // save series IQ string
+ saveIQPoints();
+}
+
+void ScummEngine_v4::saveIQPoints() {
+ // save Indy3 IQ-points
+ Common::OutSaveFile *file;
+ Common::String filename = _targetName + ".iq";
+
+ file = _saveFileMan->openForSaving(filename.c_str());
+ if (file != NULL) {
+ byte *ptr = getResourceAddress(rtString, STRINGID_IQ_EPISODE);
+ if (ptr) {
+ int size = getResourceSize(rtString, STRINGID_IQ_EPISODE);
+ file->write(ptr, size);
+ }
+ delete file;
+ }
+}
+
+void ScummEngine_v4::loadIQPoints(byte *ptr, int size) {
+ // load Indy3 IQ-points
+ Common::InSaveFile *file;
+ Common::String filename = _targetName + ".iq";
+
+ file = _saveFileMan->openForLoading(filename.c_str());
+ if (file != NULL) {
+ byte *tmp = (byte*)malloc(size);
+ int nread = file->read(tmp, size);
+ if (nread == size) {
+ memcpy(ptr, tmp, size);
+ }
+ free(tmp);
+ delete file;
+ }
+}
+
+void ScummEngine_v4::o4_saveLoadGame() {
+ getResultPos();
+ byte a = getVarOrDirectByte(PARAM_1);
+ byte slot = a & 0x1F;
+ byte result = 0;
+
+ // Slot numbers in older games start with 0, in newer games with 1
+ if (_game.version <= 2)
+ slot++;
+
+ if ((_game.id == GID_MANIAC) && (_game.version <= 1)) {
+ // Convert older load/save screen
+ // 1 Load
+ // 2 Save
+ slot = 1;
+ if (a == 1)
+ _opcode = 0x40;
+ else if ((a == 2) || (_game.platform == Common::kPlatformNES))
+ _opcode = 0x80;
+ } else {
+ _opcode = a & 0xE0;
+ }
+
+ switch (_opcode) {
+ case 0x00: // num slots available
+ result = 100;
+ break;
+ case 0x20: // drive
+ 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, false))
+ result = 3; // sucess
+ else
+ result = 5; // failed to load
+ break;
+ case 0x80: // save
+ 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 (savePreparedSavegame(slot, name))
+ result = 0;
+ else
+ result = 2;
+ } else {
+ result = 2; // failed to save
+ }
+ break;
+ case 0xC0: // test if save exists
+ {
+ Common::InSaveFile *file;
+ bool avail_saves[100];
+
+ listSavegames(avail_saves, ARRAYSIZE(avail_saves));
+ Common::String filename = makeSavegameName(slot, false);
+ if (avail_saves[slot] && (file = _saveFileMan->openForLoading(filename.c_str()))) {
+ result = 6; // save file exists
+ delete file;
+ } else
+ result = 7; // save file does not exist
+ }
+ break;
+ default:
+ error("o4_saveLoadGame: unknown subopcode %d", _opcode);
+ }
+
+ setResult(result);
+}
+
} // End of namespace Scumm
diff --git a/engines/scumm/script_v5.cpp b/engines/scumm/script_v5.cpp
index b8930463d3..84c299183c 100644
--- a/engines/scumm/script_v5.cpp
+++ b/engines/scumm/script_v5.cpp
@@ -248,7 +248,7 @@ void ScummEngine_v5::setupOpcodes() {
OPCODE(0xa4, o5_loadRoomWithEgo);
OPCODE(0xa5, o5_pickupObject);
OPCODE(0xa6, o5_setVarRange);
- OPCODE(0xa7, o5_saveLoadVars);
+ OPCODE(0xa7, o5_dummy);
/* A8 */
OPCODE(0xa8, o5_notEqualZero);
OPCODE(0xa9, o5_setOwnerOf);
@@ -831,6 +831,13 @@ void ScummEngine_v5::o5_drawObject() {
putState(obj, state);
}
+void ScummEngine_v5::o5_dummy() {
+ // The KIXX XL release of Monkey Island 2 (Amiga disk) used opcode 0xa7
+ // as dummy, in order to remove copy protection and keep level selection.
+ if (_opcode != 0xa7 || _game.id == GID_MONKEY2)
+ warning("o5_dummy invoked (opcode %d)", _opcode);
+}
+
void ScummEngine_v5::o5_getStringWidth() {
int string, width = 0;
byte *ptr;
@@ -845,231 +852,6 @@ void ScummEngine_v5::o5_getStringWidth() {
setResult(width);
}
-enum StringIds {
- // The string IDs used by Indy3 to store the episode resp. series IQ points.
- // Note that we save the episode IQ points but load the series IQ points,
- // which matches the original Indy3 save/load code. See also the notes
- // on Feature Request #1666521.
- STRINGID_IQ_EPISODE = 7,
- 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() {
- // The KIXX XL release of Monkey Island 2 (Amiga disk) used this opcode
- // as dummy, in order to remove copy protection and keep level selection.
- if (_game.version == 5)
- return;
-
- if (fetchScriptByte() == 1)
- saveVars();
- else
- loadVars();
-}
-
-void ScummEngine_v5::saveVars() {
- int a, b;
-
- while ((_opcode = fetchScriptByte()) != 0) {
- switch (_opcode & 0x1F) {
- case 0x01: // write a range of variables
- getResultPos();
- a = _resultVarNumber;
- getResultPos();
- b = _resultVarNumber;
- debug(0, "stub saveVars: vars %d -> %d", a, b);
- break;
- case 0x02: // write a range of string variables
- a = getVarOrDirectByte(PARAM_1);
- b = getVarOrDirectByte(PARAM_2);
-
- if (a == STRINGID_IQ_EPISODE && b == STRINGID_IQ_EPISODE) {
- if (_game.id == GID_INDY3) {
- saveIQPoints();
- }
- break;
- }
- // FIXME: changing savegame-names not supported
- break;
- case 0x03: // open file
- a = resStrLen(_scriptPointer);
- strncpy(_saveLoadVarsFilename, (const char *)_scriptPointer, a);
- _saveLoadVarsFilename[a] = '\0';
- _scriptPointer += a + 1;
- break;
- case 0x04:
- return;
- case 0x1F: // close file
- _saveLoadVarsFilename[0] = '\0';
- return;
- }
- }
-}
-
-void ScummEngine_v5::loadVars() {
- int a, b;
-
- while ((_opcode = fetchScriptByte()) != 0) {
- switch (_opcode & 0x1F) {
- case 0x01: // read a range of variables
- getResultPos();
- a = _resultVarNumber;
- getResultPos();
- b = _resultVarNumber;
- debug(0, "stub loadVars: vars %d -> %d", a, b);
- break;
- case 0x02: // read a range of string variables
- a = getVarOrDirectByte(PARAM_1);
- b = getVarOrDirectByte(PARAM_2);
-
- int slot;
- int slotSize;
- byte* slotContent;
- int savegameId;
- bool avail_saves[100];
-
- if (a == STRINGID_IQ_SERIES && b == STRINGID_IQ_SERIES) {
- // Zak256 loads the IQ script-slot but does not use it -> ignore it
- if (_game.id == GID_INDY3) {
- byte *ptr = getResourceAddress(rtString, STRINGID_IQ_SERIES);
- if (ptr) {
- int size = getResourceSize(rtString, STRINGID_IQ_SERIES);
- loadIQPoints(ptr, size);
- }
- }
- break;
- }
-
- listSavegames(avail_saves, ARRAYSIZE(avail_saves));
- for (slot = a; slot <= b; ++slot) {
- slotSize = getResourceSize(rtString, slot);
- slotContent = getResourceAddress(rtString, slot);
-
- // load savegame names
- savegameId = slot - a + 1;
- Common::String name;
- if (avail_saves[savegameId] && getSavegameName(savegameId, name)) {
- int pos;
- const char *ptr = name.c_str();
- // slotContent ends with {'\0','@'} -> max. length = slotSize-2
- for (pos = 0; pos < slotSize - 2; ++pos) {
- if (!ptr[pos])
- break;
- // replace special characters
- if (ptr[pos] >= 32 && ptr[pos] <= 122 && ptr[pos] != 64)
- slotContent[pos] = ptr[pos];
- else
- slotContent[pos] = '_';
- }
- slotContent[pos] = '\0';
- } else {
- slotContent[0] = '\0';
- }
- }
- break;
- case 0x03: // open file
- a = resStrLen(_scriptPointer);
- strncpy(_saveLoadVarsFilename, (const char *)_scriptPointer, a);
- _saveLoadVarsFilename[a] = '\0';
- _scriptPointer += a + 1;
- break;
- case 0x04:
- return;
- case 0x1F: // close file
- _saveLoadVarsFilename[0] = '\0';
- return;
- }
- }
-}
-
-/**
- * IQ Point calculation for Indy3.
- * The scripts that perform this task are
- * - script-9 (save/load dialog initialization, loads room 14),
- * - room-14-204 (load series IQ string),
- * - room-14-205 (save series IQ string),
- * - room-14-206 (calculate series IQ string).
- * Unfortunately script-9 contains lots of GUI stuff so calling this script
- * directly is not possible. The other scripts depend on script-9.
- */
-void ScummEngine_v5::updateIQPoints() {
- int seriesIQ;
- // IQString[0..72] corresponds to each puzzle's IQ.
- // IQString[73] indicates that the IQ-file was loaded successfully and is always 0 when
- // the IQ is calculated, hence it will be ignored here.
- const int NUM_PUZZLES = 73;
- byte seriesIQString[NUM_PUZZLES];
- byte *episodeIQString;
- int episodeIQStringSize;
-
- // load string with IQ points given per puzzle in any savegame
- // IMPORTANT: the resource string STRINGID_IQ_SERIES is only valid while
- // the original save/load dialog is executed, so do not use it here.
- memset(seriesIQString, 0, sizeof(seriesIQString));
- loadIQPoints(seriesIQString, sizeof(seriesIQString));
-
- // string with IQ points given per puzzle in current savegame
- episodeIQString = getResourceAddress(rtString, STRINGID_IQ_EPISODE);
- if (!episodeIQString)
- return;
- episodeIQStringSize = getResourceSize(rtString, STRINGID_IQ_EPISODE);
- if (episodeIQStringSize < NUM_PUZZLES)
- return;
-
- // merge episode and series IQ strings and calculate series IQ
- seriesIQ = 0;
- // iterate over puzzles
- for (int i = 0; i < NUM_PUZZLES ; ++i) {
- byte puzzleIQ = seriesIQString[i];
- // if puzzle is solved copy points to episode string
- if (puzzleIQ > 0)
- episodeIQString[i] = puzzleIQ;
- // add puzzle's IQ-points to series IQ
- seriesIQ += episodeIQString[i];
- }
- _scummVars[245] = seriesIQ;
-
- // save series IQ string
- saveIQPoints();
-}
-
-void ScummEngine_v5::saveIQPoints() {
- // save Indy3 IQ-points
- Common::OutSaveFile *file;
- Common::String filename = _targetName + ".iq";
-
- file = _saveFileMan->openForSaving(filename.c_str());
- if (file != NULL) {
- byte *ptr = getResourceAddress(rtString, STRINGID_IQ_EPISODE);
- if (ptr) {
- int size = getResourceSize(rtString, STRINGID_IQ_EPISODE);
- file->write(ptr, size);
- }
- delete file;
- }
-}
-
-void ScummEngine_v5::loadIQPoints(byte *ptr, int size) {
- // load Indy3 IQ-points
- Common::InSaveFile *file;
- Common::String filename = _targetName + ".iq";
-
- file = _saveFileMan->openForLoading(filename.c_str());
- if (file != NULL) {
- byte *tmp = (byte*)malloc(size);
- int nread = file->read(tmp, size);
- if (nread == size) {
- memcpy(ptr, tmp, size);
- }
- free(tmp);
- delete file;
- }
-}
-
void ScummEngine_v5::o5_expression() {
int dst, i;
@@ -1249,99 +1031,7 @@ void ScummEngine_v5::o5_getActorY() {
setResult(getObjY(a));
}
-void ScummEngine_v5::o5_saveLoadGame() {
- getResultPos();
- byte a = getVarOrDirectByte(PARAM_1);
- byte slot = a & 0x1F;
- byte result = 0;
-
- // Slot numbers in older games start with 0, in newer games with 1
- if (_game.version <= 2)
- slot++;
-
- if ((_game.id == GID_MANIAC) && (_game.version <= 1)) {
- // Convert older load/save screen
- // 1 Load
- // 2 Save
- slot = 1;
- if (a == 1)
- _opcode = 0x40;
- else if ((a == 2) || (_game.platform == Common::kPlatformNES))
- _opcode = 0x80;
- } else {
- _opcode = a & 0xE0;
- }
-
- switch (_opcode) {
- case 0x00: // num slots available
- result = 100;
- break;
- case 0x20: // drive
- 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, false))
- result = 3; // sucess
- else
- result = 5; // failed to load
- break;
- case 0x80: // save
- 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
- {
- Common::InSaveFile *file;
- bool avail_saves[100];
-
- listSavegames(avail_saves, ARRAYSIZE(avail_saves));
- Common::String filename = makeSavegameName(slot, false);
- if (avail_saves[slot] && (file = _saveFileMan->openForLoading(filename.c_str()))) {
- result = 6; // save file exists
- delete file;
- } else
- result = 7; // save file does not exist
- }
- break;
- default:
- error("o5_saveLoadGame: unknown subopcode %d", _opcode);
- }
-
- setResult(result);
-}
-
void ScummEngine_v5::o5_getAnimCounter() {
- if (_game.version == 3) {
- o5_saveLoadGame();
- return;
- }
-
getResultPos();
int act = getVarOrDirectByte(PARAM_1);
@@ -2407,7 +2097,7 @@ void ScummEngine_v5::o5_startScript() {
// WORKAROUND: Indy3 does not save the series IQ automatically after changing it.
// Save on IQ increment (= script 125 was executed).
if (_game.id == GID_INDY3 && script == 125)
- updateIQPoints();
+ ((ScummEngine_v4 *)this)->updateIQPoints();
}
void ScummEngine_v5::o5_stopObjectCode() {
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 1443f2e6df..1f63a4cd1f 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2082,16 +2082,27 @@ void ScummEngine::scummLoop_handleSaveLoad() {
}
}
-void ScummEngine_v5::scummLoop_handleSaveLoad() {
+void ScummEngine_v4::scummLoop_handleSaveLoad() {
// copy saveLoadFlag as handleSaveLoad() resets it
byte saveLoad = _saveLoadFlag;
- ScummEngine::scummLoop_handleSaveLoad();
+ ScummEngine_v5::scummLoop_handleSaveLoad();
// update IQ points after loading
if (saveLoad == 2) {
if (_game.id == GID_INDY3)
updateIQPoints();
+ }
+}
+
+void ScummEngine_v5::scummLoop_handleSaveLoad() {
+ // copy saveLoadFlag as handleSaveLoad() resets it
+ byte saveLoad = _saveLoadFlag;
+
+ ScummEngine::scummLoop_handleSaveLoad();
+
+ // update IQ points after loading
+ if (saveLoad == 2) {
if (_game.id == GID_INDY4)
runScript(145, 0, 0, 0);
}
diff --git a/engines/scumm/scumm_v3.h b/engines/scumm/scumm_v3.h
index 87d92216a7..767069d1bc 100644
--- a/engines/scumm/scumm_v3.h
+++ b/engines/scumm/scumm_v3.h
@@ -35,21 +35,6 @@ namespace Scumm {
*/
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();
diff --git a/engines/scumm/scumm_v4.h b/engines/scumm/scumm_v4.h
index 6e0326ed17..be3f6cb47e 100644
--- a/engines/scumm/scumm_v4.h
+++ b/engines/scumm/scumm_v4.h
@@ -34,6 +34,21 @@ namespace Scumm {
* Engine for version 4 SCUMM games; GF_SMALL_HEADER is always set for these.
*/
class ScummEngine_v4 : public ScummEngine_v5 {
+ friend class ScummEngine_v5;
+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_v4(OSystem *syst, const DetectorResult &dr);
@@ -42,6 +57,8 @@ public:
protected:
virtual void setupOpcodes();
+ virtual void scummLoop_handleSaveLoad();
+
virtual void readResTypeList(int id);
virtual void readIndexFile();
virtual void loadCharset(int no);
@@ -51,11 +68,19 @@ protected:
virtual void resetRoomObject(ObjectData *od, const byte *room, const byte *searchptr = NULL);
+ void saveVars();
+ void loadVars();
+ void saveIQPoints();
+ void loadIQPoints(byte *ptr, int size);
+ void updateIQPoints();
+
/* Version 4 script opcodes */
void o4_ifState();
void o4_ifNotState();
void o4_oldRoomEffect();
void o4_pickupObject();
+ void o4_saveLoadGame();
+ void o4_saveLoadVars();
};
diff --git a/engines/scumm/scumm_v5.h b/engines/scumm/scumm_v5.h
index 4ff51868ff..a8e2417017 100644
--- a/engines/scumm/scumm_v5.h
+++ b/engines/scumm/scumm_v5.h
@@ -72,11 +72,6 @@ protected:
virtual void readMAXS(int blockSize);
int getWordVararg(int *ptr);
- void saveVars();
- void loadVars();
- void saveIQPoints();
- void loadIQPoints(byte *ptr, int size);
- void updateIQPoints();
virtual int getVar();
virtual int getVarOrDirectByte(byte mask);
@@ -109,6 +104,7 @@ protected:
void o5_doSentence();
void o5_drawBox();
void o5_drawObject();
+ void o5_dummy();
void o5_endCutscene();
void o5_equalZero();
void o5_expression();
@@ -167,8 +163,6 @@ protected:
void o5_systemOps();
void o5_resourceRoutines();
void o5_roomOps();
- void o5_saveLoadGame();
- void o5_saveLoadVars();
void o5_saveRestoreVerbs();
void o5_setCameraAt();
void o5_setClass();