aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Snover2016-09-12 11:08:02 -0500
committerColin Snover2016-09-29 19:39:16 -0500
commita22bfb0db22487537254dcb2e83dc02dc484d1fa (patch)
tree813f9fb7f8fd4e5b6b4706893348c28c534642ba
parent57c62c59f95701c99878ffed3c938f0e592c1fbb (diff)
downloadscummvm-rg350-a22bfb0db22487537254dcb2e83dc02dc484d1fa.tar.gz
scummvm-rg350-a22bfb0db22487537254dcb2e83dc02dc484d1fa.tar.bz2
scummvm-rg350-a22bfb0db22487537254dcb2e83dc02dc484d1fa.zip
SCI32: Fix "new game" and auto-save functionality
-rw-r--r--engines/sci/engine/kernel.h1
-rw-r--r--engines/sci/engine/kernel_tables.h6
-rw-r--r--engines/sci/engine/kfile.cpp70
3 files changed, 49 insertions, 28 deletions
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index f37d878d57..e1ec5c0dde 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -488,6 +488,7 @@ reg_t kSaveSave32(EngineState *s, int argc, reg_t *argv);
reg_t kSaveRestore32(EngineState *s, int argc, reg_t *argv);
reg_t kSaveList32(EngineState *s, int argc, reg_t *argv);
reg_t kSaveCheck32(EngineState *s, int argc, reg_t *argv);
+reg_t kSaveMakeFileName32(EngineState *s, int argc, reg_t *argv);
reg_t kSetHotRectangles(EngineState *s, int argc, reg_t *argv);
reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index d234edb67b..7244262b9d 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -362,7 +362,7 @@ static const SciKernelMapSubEntry kSave_subops[] = {
// Subop 4 hasn't been encountered yet
{ SIG_SCI32, 5, MAP_CALL(SaveList32), "rrr", NULL },
{ SIG_SCI32, 6, MAP_CALL(MakeSaveCatName), "rr", NULL },
- { SIG_SCI32, 7, MAP_CALL(MakeSaveFileName), "rri", NULL },
+ { SIG_SCI32, 7, MAP_CALL(SaveMakeFileName32), "rri", NULL },
{ SIG_SCI32, 8, MAP_EMPTY(GameIsRestarting), ".*", NULL },
SCI_SUBOPENTRY_TERMINATOR
};
@@ -686,7 +686,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(GetMessage), SIG_EVERYWHERE, "iiir", NULL, NULL },
{ MAP_CALL(GetPort), SIG_EVERYWHERE, "", NULL, NULL },
#ifdef ENABLE_SCI32
- { MAP_CALL(GetSaveDir), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "", NULL, NULL },
+ { MAP_CALL(GetSaveDir), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "(r)", NULL, NULL },
#endif
{ MAP_CALL(GetSaveDir), SIG_SCI16, SIGFOR_ALL, "", NULL, NULL },
#ifdef ENABLE_SCI32
@@ -871,7 +871,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(ObjectIntersect), SIG_EVERYWHERE, "oo", NULL, NULL },
{ MAP_CALL(EditText), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(MakeSaveCatName), SIG_EVERYWHERE, "rr", NULL, NULL },
- { MAP_CALL(MakeSaveFileName), SIG_EVERYWHERE, "rri", NULL, NULL },
+ { "MakeSaveFileName", kSaveMakeFileName32, SIG_UNTIL_SCI21MID, SIGFOR_ALL, "rri", NULL, NULL },
{ MAP_CALL(SetScroll), SIG_EVERYWHERE, "oiiii(i)(i)", NULL, NULL },
{ MAP_CALL(PalCycle), SIG_EVERYWHERE, "(.*)", kPalCycle_subops, NULL },
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index 00138ae224..797cd5d570 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -51,6 +51,7 @@ extern FileHandle *getFileFromHandle(EngineState *s, uint handle);
extern int fgets_wrapper(EngineState *s, char *dest, int maxsize, int handle);
extern void listSavegames(Common::Array<SavegameDesc> &saves);
extern int findSavegame(Common::Array<SavegameDesc> &saves, int16 savegameId);
+extern bool fillSavegameDesc(const Common::String &filename, SavegameDesc *desc);
/**
* Writes the cwd to the supplied address and returns the address in acc.
@@ -270,7 +271,10 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
if (name == "autosave.cat") {
exists = !saveFileMan->listSavefiles(g_sci->getSavegameName(0)).empty();
} else {
- exists = !saveFileMan->listSavefiles(g_sci->getSavegamePattern()).empty();
+ // There will always be one save game in Torin, the "new game" game,
+ // which should be ignored when deciding if there are any save games
+ // to open
+ exists = saveFileMan->listSavefiles(g_sci->getSavegamePattern()).size() > 1;
}
if (exists) {
@@ -1049,9 +1053,36 @@ reg_t kSaveSave32(EngineState *s, int argc, reg_t *argv) {
// Autosave slot 1 is a "new game" save
saveNo = kNewGameId;
}
- }
+ } else if (saveNo == 0) {
+ // SSCI save games normally start from save number 0, but this is
+ // reserved for the autosave game in ScummVM. So, any time a game tries
+ // to save to slot 0 (and it isn't an autosave), it should instead go to
+ // the next highest free ID
+ Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+ Common::StringArray saveNames = saveFileMan->listSavefiles(g_sci->getSavegamePattern());
+ Common::sort(saveNames.begin(), saveNames.end());
+ if (saveNames.size()) {
+ int lastId = 0;
+ for (int i = 0; i < (int)saveNames.size(); ++i) {
+ const int id = strtol(saveNames[i].end() - 3, NULL, 10);
+ if (id == 0) {
+ continue;
+ }
+
+ if (id != lastId + 1) {
+ saveNo = lastId + 1;
+ break;
+ }
- assert(gameName == "Autosave" || gameName == "Autosv" || saveNo > 0);
+ ++lastId;
+ }
+ }
+
+ // There was no gap, so this save goes to a brand new slot
+ if (saveNo == 0) {
+ saveNo = saveNames.size() + 1;
+ }
+ }
Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
const Common::String filename = g_sci->getSavegameName(saveNo);
@@ -1118,12 +1149,14 @@ reg_t kSaveCheck32(EngineState *s, int argc, reg_t *argv) {
Common::Array<SavegameDesc> saves;
listSavegames(saves);
- const int16 saveIndex = findSavegame(saves, saveNo);
- if (saveIndex == -1) {
- return NULL_REG;
+ if ((gameName == "Autosave" || gameName == "Autosv") && saveNo == 1) {
+ saveNo = kNewGameId;
}
- const SavegameDesc &save = saves[saveIndex];
+ SavegameDesc save;
+ if (!fillSavegameDesc(g_sci->getSavegameName(saveNo), &save)) {
+ return NULL_REG;
+ }
if (save.version < MINIMUM_SAVEGAME_VERSION ||
save.version > CURRENT_SAVEGAME_VERSION ||
@@ -1167,24 +1200,11 @@ reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv) {
return argv[0];
}
-reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv) {
- // Creates a savegame name from a slot number. Used when deleting saved games.
- // Param 0: the output buffer (same as in kMakeSaveCatName)
- // Param 1: a string with game parameters, ignored
- // Param 2: the selected slot
-
- SciArray *resultString = s->_segMan->lookupArray(argv[0]);
- uint16 virtualId = argv[2].toUint16();
- if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END))
- error("kMakeSaveFileName: invalid savegame ID specified");
- uint saveSlot = virtualId - SAVEGAMEID_OFFICIALRANGE_START;
-
- Common::Array<SavegameDesc> saves;
- listSavegames(saves);
-
- Common::String filename = g_sci->getSavegameName(saveSlot);
- resultString->fromString(filename);
-
+reg_t kSaveMakeFileName32(EngineState *s, int argc, reg_t *argv) {
+ SciArray &outFileName = *s->_segMan->lookupArray(argv[0]);
+ // argv[1] is the game name, which is not used by ScummVM
+ int16 saveNo = argv[2].toSint16();
+ outFileName.fromString(g_sci->getSavegameName(saveNo));
return argv[0];
}