SCI32: Implement kSave for standard-save SCI32 games

Games with custom save code (KQ7, MGDX, PQ:SWAT, Shivers) are not
fully supported yet.
This commit is contained in:
Colin Snover 2016-09-13 10:32:41 -05:00
parent a22bfb0db2
commit 10f450917c
3 changed files with 39 additions and 29 deletions

View file

@ -484,11 +484,12 @@ reg_t kShowMovieWinPlayUntilEvent(EngineState *s, int argc, reg_t *argv);
reg_t kShowMovieWinInitDouble(EngineState *s, int argc, reg_t *argv);
reg_t kSave(EngineState *s, int argc, reg_t *argv);
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 kSaveGame32(EngineState *s, int argc, reg_t *argv);
reg_t kRestoreGame32(EngineState *s, int argc, reg_t *argv);
reg_t kGetSaveFiles32(EngineState *s, int argc, reg_t *argv);
reg_t kCheckSaveGame32(EngineState *s, int argc, reg_t *argv);
reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv);
reg_t kMakeSaveFileName(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);
@ -591,8 +592,6 @@ reg_t kListFirstTrue(EngineState *s, int argc, reg_t *argv);
reg_t kListAllTrue(EngineState *s, int argc, reg_t *argv);
reg_t kEditText(EngineState *s, int argc, reg_t *argv);
reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv);
reg_t kMakeSaveFileName(EngineState *s, int argc, reg_t *argv);
reg_t kSetScroll(EngineState *s, int argc, reg_t *argv);
reg_t kPaletteSetFromResource32(EngineState *s, int argc, reg_t *argv);

View file

@ -351,18 +351,18 @@ static const SciKernelMapSubEntry kPalCycle_subops[] = {
// version, subId, function-mapping, signature, workarounds
static const SciKernelMapSubEntry kSave_subops[] = {
{ SIG_SCI32, 0, MAP_CALL(SaveSave32), "rir[r0]", NULL },
{ SIG_SCI32, 1, MAP_CALL(SaveRestore32), "ri[r0]", NULL },
{ SIG_SCI32, 0, MAP_CALL(SaveGame32), "rir[r0]", NULL },
{ SIG_SCI32, 1, MAP_CALL(RestoreGame32), "ri[r0]", NULL },
// System script 64994 in several SCI2.1mid games (KQ7 2.00b, Phant1,
// PQ:SWAT, SQ6, Torin) calls GetSaveDir with an extra unused argument, and
// it is easier to just handle it here than to bother with creating
// workarounds
{ SIG_SCI32, 2, MAP_CALL(GetSaveDir), "(r)", NULL },
{ SIG_SCI32, 3, MAP_CALL(SaveCheck32), "ri[r0]", NULL },
{ SIG_SCI32, 3, MAP_CALL(CheckSaveGame32), "ri[r0]", NULL },
// Subop 4 hasn't been encountered yet
{ SIG_SCI32, 5, MAP_CALL(SaveList32), "rrr", NULL },
{ SIG_SCI32, 5, MAP_CALL(GetSaveFiles32), "rrr", NULL },
{ SIG_SCI32, 6, MAP_CALL(MakeSaveCatName), "rr", NULL },
{ SIG_SCI32, 7, MAP_CALL(SaveMakeFileName32), "rri", NULL },
{ SIG_SCI32, 7, MAP_CALL(MakeSaveFileName), "rri", NULL },
{ SIG_SCI32, 8, MAP_EMPTY(GameIsRestarting), ".*", NULL },
SCI_SUBOPENTRY_TERMINATOR
};
@ -633,7 +633,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(CheckFreeSpace), SIG_SCI11, SIGFOR_ALL, "r(i)", NULL, NULL },
{ MAP_CALL(CheckFreeSpace), SIG_SCI16, SIGFOR_ALL, "r", NULL, NULL },
#ifdef ENABLE_SCI32
{ "CheckSaveGame", kSaveCheck32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "ri[r0]", NULL, NULL },
{ "CheckSaveGame", kCheckSaveGame32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "ri[r0]", NULL, NULL },
#endif
{ MAP_CALL(CheckSaveGame), SIG_SCI16, SIGFOR_ALL, ".*", NULL, NULL },
{ MAP_CALL(Clone), SIG_EVERYWHERE, "o", NULL, NULL },
@ -690,7 +690,7 @@ static SciKernelMapEntry s_kernelMap[] = {
#endif
{ MAP_CALL(GetSaveDir), SIG_SCI16, SIGFOR_ALL, "", NULL, NULL },
#ifdef ENABLE_SCI32
{ "GetSaveFiles", kSaveList32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "rrr", NULL, NULL },
{ "GetSaveFiles", kGetSaveFiles32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "rrr", NULL, NULL },
#endif
{ MAP_CALL(GetSaveFiles), SIG_EVERYWHERE, "rrr", NULL, NULL },
{ MAP_CALL(GetTime), SIG_EVERYWHERE, "(i)", NULL, NULL },
@ -754,12 +754,12 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(RespondsTo), SIG_EVERYWHERE, ".i", NULL, NULL },
{ MAP_CALL(RestartGame), SIG_EVERYWHERE, "", NULL, NULL },
#ifdef ENABLE_SCI32
{ "RestoreGame", kSaveRestore32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "ri[r0]", NULL, NULL },
{ "RestoreGame", kRestoreGame32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "ri[r0]", NULL, NULL },
#endif
{ MAP_CALL(RestoreGame), SIG_EVERYWHERE, "[r0]i[r0]", NULL, NULL },
{ MAP_CALL(Said), SIG_EVERYWHERE, "[r0]", NULL, NULL },
#ifdef ENABLE_SCI32
{ "SaveGame", kSaveSave32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "rir[r0]", NULL, NULL },
{ "SaveGame", kSaveGame32, SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "rir[r0]", NULL, NULL },
#endif
{ MAP_CALL(SaveGame), SIG_SCI16, SIGFOR_ALL, "[r0]i[r0](r0)", NULL, NULL },
{ MAP_CALL(ScriptID), SIG_EVERYWHERE, "[io](i)", NULL, NULL },
@ -870,8 +870,8 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(UpdateScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(ObjectIntersect), SIG_EVERYWHERE, "oo", NULL, NULL },
{ MAP_CALL(EditText), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(MakeSaveCatName), SIG_EVERYWHERE, "rr", NULL, NULL },
{ "MakeSaveFileName", kSaveMakeFileName32, SIG_UNTIL_SCI21MID, SIGFOR_ALL, "rri", NULL, NULL },
{ MAP_CALL(MakeSaveCatName), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "rr", NULL, NULL },
{ MAP_CALL(MakeSaveFileName), SIG_UNTIL_SCI21EARLY, SIGFOR_ALL, "rri", NULL, NULL },
{ MAP_CALL(SetScroll), SIG_EVERYWHERE, "oiiii(i)(i)", NULL, NULL },
{ MAP_CALL(PalCycle), SIG_EVERYWHERE, "(.*)", kPalCycle_subops, NULL },

View file

@ -256,6 +256,12 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
return SIGNAL_REG;
}
#ifdef ENABLE_SCI32
// See kMakeSaveCatName
if (name == "fake.cat") {
return make_reg(0, VIRTUALFILE_HANDLE_SCI32SAVE);
}
// Torin's autosave system checks for the presence of autosave.cat
// by opening it. Since we don't use .cat files, we instead check
// for the autosave game.
@ -285,6 +291,7 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
return SIGNAL_REG;
}
}
#endif
if (name.empty()) {
// Happens many times during KQ1 (e.g. when typing something)
@ -1039,7 +1046,7 @@ reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) {
}
#ifdef ENABLE_SCI32
reg_t kSaveSave32(EngineState *s, int argc, reg_t *argv) {
reg_t kSaveGame32(EngineState *s, int argc, reg_t *argv) {
const Common::String gameName = s->_segMan->getString(argv[0]);
int16 saveNo = argv[1].toSint16();
const Common::String saveDescription = s->_segMan->getString(argv[2]);
@ -1111,7 +1118,7 @@ reg_t kSaveSave32(EngineState *s, int argc, reg_t *argv) {
return TRUE_REG;
}
reg_t kSaveRestore32(EngineState *s, int argc, reg_t *argv) {
reg_t kRestoreGame32(EngineState *s, int argc, reg_t *argv) {
const Common::String gameName = s->_segMan->getString(argv[0]);
int16 saveNo = argv[1].toSint16();
const Common::String gameVersion = argv[2].isNull() ? "" : s->_segMan->getString(argv[2]);
@ -1141,7 +1148,7 @@ reg_t kSaveRestore32(EngineState *s, int argc, reg_t *argv) {
return TRUE_REG;
}
reg_t kSaveCheck32(EngineState *s, int argc, reg_t *argv) {
reg_t kCheckSaveGame32(EngineState *s, int argc, reg_t *argv) {
const Common::String gameName = s->_segMan->getString(argv[0]);
int16 saveNo = argv[1].toSint16();
const Common::String gameVersion = argv[2].isNull() ? "" : s->_segMan->getString(argv[2]);
@ -1168,7 +1175,7 @@ reg_t kSaveCheck32(EngineState *s, int argc, reg_t *argv) {
return TRUE_REG;
}
reg_t kSaveList32(EngineState *s, int argc, reg_t *argv) {
reg_t kGetSaveFiles32(EngineState *s, int argc, reg_t *argv) {
// argv[0] is gameName, used in SSCI as the name of the save game catalogue
// but unused here since ScummVM does not support multiple catalogues
SciArray &descriptions = *s->_segMan->lookupArray(argv[1]);
@ -1179,8 +1186,8 @@ reg_t kSaveList32(EngineState *s, int argc, reg_t *argv) {
// Normally SSCI limits to 20 games per directory, but ScummVM allows more
// than that
descriptions.resize(SCI_MAX_SAVENAME_LENGTH * saves.size() + 1);
saveIds.resize(saves.size());
descriptions.resize(SCI_MAX_SAVENAME_LENGTH * saves.size() + 1, true);
saveIds.resize(saves.size(), true);
for (uint i = 0; i < saves.size(); ++i) {
const SavegameDesc &save = saves[i];
@ -1189,18 +1196,22 @@ reg_t kSaveList32(EngineState *s, int argc, reg_t *argv) {
saveIds.int16At(i) = save.id;
}
descriptions.charAt(SCI_MAX_SAVENAME_LENGTH * saves.size()) = '\0';
return make_reg(0, saves.size());
}
reg_t kMakeSaveCatName(EngineState *s, int argc, reg_t *argv) {
// Normally, this creates the name of the save catalogue/directory to save into.
// First parameter is the string to save the result into. Second is a string
// with game parameters. We don't have a use for this at all, as we have our own
// savegame directory management, thus we always return an empty string.
// ScummVM does not use SCI catalogues for save games, but game scripts try
// to write out catalogues manually after a save game is deleted, so we need
// to be able to identify and ignore these IO operations by always giving
// back a fixed catalogue name and then ignoring it in kFileIO
SciArray &outCatName = *s->_segMan->lookupArray(argv[0]);
outCatName.fromString("fake.cat");
return argv[0];
}
reg_t kSaveMakeFileName32(EngineState *s, int argc, reg_t *argv) {
reg_t kMakeSaveFileName(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();