diff options
author | Max Horn | 2009-04-19 01:01:54 +0000 |
---|---|---|
committer | Max Horn | 2009-04-19 01:01:54 +0000 |
commit | 3044593da01c055ad274b2ae552b8a285ce4fdb0 (patch) | |
tree | cfea7dd1e502ab5fba1f3e472693b6617f353eb7 /engines | |
parent | 0e82403daa80424fb9c6089632f7dcfd9015689d (diff) | |
download | scummvm-rg350-3044593da01c055ad274b2ae552b8a285ce4fdb0.tar.gz scummvm-rg350-3044593da01c055ad274b2ae552b8a285ce4fdb0.tar.bz2 scummvm-rg350-3044593da01c055ad274b2ae552b8a285ce4fdb0.zip |
SCUMM: Moved o5_saveLoadGame and o5_saveLoadVars to ScummEngine_v4 (the highest SCUMM version to implement these opcodes. Actually, our code was bugged in so far as we only ever invoked o5_saveLoadGame in V3 games, never in V4 games (but this properly never mattered ;)
svn-id: r40014
Diffstat (limited to 'engines')
-rw-r--r-- | engines/scumm/saveload.cpp | 4 | ||||
-rw-r--r-- | engines/scumm/script_v0.cpp | 4 | ||||
-rw-r--r-- | engines/scumm/script_v2.cpp | 4 | ||||
-rw-r--r-- | engines/scumm/script_v4.cpp | 319 | ||||
-rw-r--r-- | engines/scumm/script_v5.cpp | 328 | ||||
-rw-r--r-- | engines/scumm/scumm.cpp | 15 | ||||
-rw-r--r-- | engines/scumm/scumm_v3.h | 15 | ||||
-rw-r--r-- | engines/scumm/scumm_v4.h | 25 | ||||
-rw-r--r-- | engines/scumm/scumm_v5.h | 8 |
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(); |