SCI: Fix auto-saving in the fan-made Cascade Quest

Script patch to change the fixed slot 999 to fixed slot 99 in the
game scripts and additional code for kSaveGame, that checks for
Cascade Quest + slot 99 and will then use ScummVM slot 0, which
is our auto-save slot.

Fixes bug #7007

Also added the game name to the other fan-made script patch.
This commit is contained in:
Martin Kiewitz 2016-06-25 23:58:16 +02:00
parent 2e58e6d09f
commit 80462b3f87
2 changed files with 70 additions and 19 deletions

View file

@ -806,25 +806,47 @@ reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) {
return NULL_REG;
} else if (virtualId < SAVEGAMEID_OFFICIALRANGE_START) {
// virtualId is low, we assume that scripts expect us to create new slot
if (g_sci->getGameId() == GID_JONES) {
switch (g_sci->getGameId()) {
case GID_JONES:
// Jones has one save slot only
savegameId = 0;
} else if (virtualId == s->_lastSaveVirtualId) {
// if last virtual id is the same as this one, we assume that caller wants to overwrite last save
savegameId = s->_lastSaveNewId;
} else {
uint savegameNr;
// savegameId is in lower range, scripts expect us to create a new slot
for (savegameId = SAVEGAMESLOT_FIRST; savegameId <= SAVEGAMESLOT_LAST; savegameId++) {
for (savegameNr = 0; savegameNr < saves.size(); savegameNr++) {
if (savegameId == saves[savegameNr].id)
break;
case GID_FANMADE: {
// Fanmade game, try to identify the game
const char *gameName = g_sci->getGameObjectName();
if (strcmp(gameName, "CascadeQuest") == 0) {
// Cascade Quest calls us directly to auto-save and uses slot 99,
// put that save into slot 0 (ScummVM auto-save slot) see bug #7007
if (virtualId == (SAVEGAMEID_OFFICIALRANGE_START - 1)) {
savegameId = 0;
}
}
break;
}
default:
break;
}
if (savegameId < 0) {
// savegameId not set yet
if (virtualId == s->_lastSaveVirtualId) {
// if last virtual id is the same as this one, we assume that caller wants to overwrite last save
savegameId = s->_lastSaveNewId;
} else {
uint savegameNr;
// savegameId is in lower range, scripts expect us to create a new slot
for (savegameId = SAVEGAMESLOT_FIRST; savegameId <= SAVEGAMESLOT_LAST; savegameId++) {
for (savegameNr = 0; savegameNr < saves.size(); savegameNr++) {
if (savegameId == saves[savegameNr].id)
break;
}
if (savegameNr == saves.size()) // Slot not found, seems to be good to go
break;
}
if (savegameNr == saves.size()) // Slot not found, seems to be good to go
break;
if (savegameId > SAVEGAMESLOT_LAST)
error("kSavegame: no more savegame slots available");
}
if (savegameId > SAVEGAMESLOT_LAST)
error("kSavegame: no more savegame slots available");
}
} else {
error("kSaveGame: invalid savegameId used");

View file

@ -379,12 +379,40 @@ static const SciScriptPatcherEntry ecoquest2Signatures[] = {
};
// ===========================================================================
// Fan-made games
// Attention: Try to make script patches as specific as possible
// CascadeQuest::autosave in script 994 is called various times to auto-save the game.
// The script use a fixed slot "999" for this purpose. This doesn't work in ScummVM, because we do not let
// scripts save directly into specific slots, but instead use virtual slots / detect scripts wanting to
// create a new slot.
//
// For this game we patch the code to use slot 99 instead. kSaveGame also checks for Cascade Quest,
// will then check, if slot 99 is asked for and will then use the actual slot 0, which is the official
// ScummVM auto-save slot.
//
// Responsible method: CascadeQuest::autosave
// Fixes bug: #7007
static const uint16 fanmadeSignatureCascadeQuestFixAutoSaving[] = {
SIG_MAGICDWORD,
0x38, SIG_UINT16(0x03e7), // pushi 3E7 (999d) -> save game slot 999
0x74, SIG_UINT16(0x06f8), // lofss "AutoSave"
0x89, 0x1e, // lsg global[1E]
0x43, 0x2d, 0x08, // callk SaveGame
SIG_END
};
static const uint16 fanmadePatchCascadeQuestFixAutoSaving[] = {
0x38, PATCH_UINT16((SAVEGAMEID_OFFICIALRANGE_START - 1)), // fix slot
PATCH_END
};
// EventHandler::handleEvent in Demo Quest has a bug, and it jumps to the
// wrong address when an incorrect word is typed, therefore leading to an
// infinite loop. This script bug was not apparent in SSCI, probably because
// event handling was slightly different there, so it was never discovered.
// Fixes bug: #5120
static const uint16 fanmadeSignatureInfiniteLoop[] = {
static const uint16 fanmadeSignatureDemoQuestInfiniteLoop[] = {
0x38, SIG_UINT16(0x004c), // pushi 004c
0x39, 0x00, // pushi 00
0x87, 0x01, // lap 01
@ -395,15 +423,16 @@ static const uint16 fanmadeSignatureInfiniteLoop[] = {
SIG_END
};
static const uint16 fanmadePatchInfiniteLoop[] = {
static const uint16 fanmadePatchDemoQuestInfiniteLoop[] = {
PATCH_ADDTOOFFSET(+10),
0x30, SIG_UINT16(0x0032), // bnt 0032 [06a8] --> pushi 004c
0x30, PATCH_UINT16(0x0032), // bnt 0032 [06a8] --> pushi 004c
PATCH_END
};
// script, description, signature patch
// script, description, signature patch
static const SciScriptPatcherEntry fanmadeSignatures[] = {
{ true, 999, "infinite loop on typo", 1, fanmadeSignatureInfiniteLoop, fanmadePatchInfiniteLoop },
{ true, 994, "Cascade Quest: fix auto-saving", 1, fanmadeSignatureCascadeQuestFixAutoSaving, fanmadePatchCascadeQuestFixAutoSaving },
{ true, 999, "Demo Quest: infinite loop on typo", 1, fanmadeSignatureDemoQuestInfiniteLoop, fanmadePatchDemoQuestInfiniteLoop },
SCI_SIGNATUREENTRY_TERMINATOR
};