SCI: Add support for KQ5 FM-Towns save/restore UI

This commit is contained in:
sluicebox 2024-07-11 22:28:17 -07:00
parent b29ffb2bfb
commit bc46925636
4 changed files with 73 additions and 28 deletions

View File

@ -727,7 +727,7 @@ static SciKernelMapEntry s_kernelMap[] = {
#ifdef ENABLE_SCI32
{ "GetSaveFiles", kGetSaveFiles32, SIG_THRU_SCI21EARLY, SIGFOR_ALL, "rrr", NULL, NULL },
#endif
{ MAP_CALL(GetSaveFiles), SIG_EVERYWHERE, "rrr", NULL, NULL },
{ MAP_CALL(GetSaveFiles), SIG_EVERYWHERE, "rrr", NULL, kGetSaveFiles_workarounds },
{ MAP_CALL(GetTime), SIG_EVERYWHERE, "(i)", NULL, NULL },
{ MAP_CALL(GlobalToLocal), SIG_SCI16, SIGFOR_ALL, "o", NULL, NULL },
#ifdef ENABLE_SCI32

View File

@ -663,7 +663,7 @@ reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) {
reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) {
Common::String name = s->_segMan->getString(argv[0]);
Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
bool result;
bool result = false;
// SQ4 floppy prepends /\ to the filenames
if (name.hasPrefix("/\\")) {
@ -671,7 +671,7 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) {
name.deleteChar(0);
}
if (name.hasPrefix("sq4sg.")) {
if (g_sci->getGameId() == GID_SQ4 && name.hasPrefix("sq4sg.")) {
// Special case for SQ4 floppy: This game has hardcoded save game names.
// They are named "sq4sg.xxx", where xxx is the virtual ID. We construct
// the appropriate save game name and delete it.
@ -698,6 +698,17 @@ reg_t kFileIOUnlink(EngineState *s, int argc, reg_t *argv) {
result = saveFileMan->removeSavefile(wrappedName);
}
#endif
} else if (g_sci->getGameId() == GID_KQ5 &&
g_sci->getPlatform() == Common::kPlatformFMTowns &&
name.hasPrefix("a:\\KQ5sg.")) {
// KQ5 FM-Towns uses a custom save/restore UI in script 764.
// It directly deletes save files using a hard-coded path.
int saveNo = 0;
sscanf(name.c_str(), "a:\\KQ5sg.%d", &saveNo);
if (1 <= saveNo && saveNo <= 10) { // UI has ten buttons
name = g_sci->getSavegameName(saveNo);
result = saveFileMan->removeSavefile(name);
}
} else {
const Common::String wrappedName = g_sci->wrapFilename(name);
result = saveFileMan->removeSavefile(wrappedName);
@ -807,8 +818,6 @@ reg_t kFileIOFindNext(EngineState *s, int argc, reg_t *argv) {
reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) {
Common::String name = s->_segMan->getString(argv[0]);
bool exists = false;
if (g_sci->getGameId() == GID_PEPPER) {
// HACK: Special case for Pepper's Adventure in Time
// The game checks like crazy for the file CDAUDIO when entering the game menu.
@ -820,36 +829,48 @@ reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) {
}
#ifdef ENABLE_SCI32
if (isSaveCatalogue(name)) {
return saveCatalogueExists(name) ? TRUE_REG : NULL_REG;
}
int findSaveNo = -1;
if (g_sci->getGameId() == GID_LSL7 && name == "autosvsg.000") {
// LSL7 checks to see if the autosave save exists when deciding whether
// to go to the main menu or not on startup
findSaveNo = kAutoSaveId;
} else if (g_sci->getGameId() == GID_RAMA) {
// RAMA checks to see if save game files exist before showing them in
// the native save/load dialogue
if (name == "autorama.sg") {
findSaveNo = kAutoSaveId;
} else if (sscanf(name.c_str(), "ramasg.%d", &findSaveNo) == 1) {
findSaveNo += kSaveIdShift;
if (getSciVersion() >= SCI_VERSION_2) {
if (isSaveCatalogue(name)) {
return saveCatalogueExists(name) ? TRUE_REG : NULL_REG;
}
}
if (findSaveNo != -1) {
return g_sci->getSaveFileManager()->listSavefiles(g_sci->getSavegameName(findSaveNo)).empty() ? NULL_REG : TRUE_REG;
int findSaveNo = -1;
if (g_sci->getGameId() == GID_LSL7 && name == "autosvsg.000") {
// LSL7 checks to see if the autosave save exists when deciding whether
// to go to the main menu or not on startup
findSaveNo = kAutoSaveId;
} else if (g_sci->getGameId() == GID_RAMA) {
// RAMA checks to see if save game files exist before showing them in
// the native save/load dialogue
if (name == "autorama.sg") {
findSaveNo = kAutoSaveId;
} else if (sscanf(name.c_str(), "ramasg.%d", &findSaveNo) == 1) {
findSaveNo += kSaveIdShift;
}
}
if (findSaveNo != -1) {
return g_sci->getSaveFileManager()->listSavefiles(g_sci->getSavegameName(findSaveNo)).empty() ? NULL_REG : TRUE_REG;
}
// TODO: It may apparently be worth caching the existence of
// phantsg.dir, and possibly even keeping it open persistently
}
#endif
// TODO: It may apparently be worth caching the existence of
// phantsg.dir, and possibly even keeping it open persistently
if (g_sci->getGameId() == GID_KQ5 && g_sci->getPlatform() == Common::kPlatformFMTowns) {
// KQ5 FM-Towns uses a custom save/restore UI in script 764.
// It directly tests for save files using a hard-coded path.
int saveNo = 0;
sscanf(name.c_str(), "a:\\KQ5sg.%d", &saveNo);
if (1 <= saveNo && saveNo <= 10) { // UI has ten buttons
Common::Array<SavegameDesc> saves;
listSavegames(saves);
return (findSavegame(saves, saveNo) != -1) ? TRUE_REG : NULL_REG;
}
}
// Check for regular file
exists = Common::File::exists(Common::Path(name));
bool exists = Common::File::exists(Common::Path(name));
// Check for a savegame with the name
Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
@ -1122,6 +1143,15 @@ reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) {
// Jones has one save slot only
savegameId = 0;
break;
case GID_KQ5:
if (g_sci->getPlatform() == Common::kPlatformFMTowns) {
// KQ5 FM-Towns uses custom save/restore code.
// Use the provided id.
savegameId = virtualId;
// Use a default description, game passes path since it wasn't displayed.
game_description = Common::String::format("Save %d", savegameId);
}
break;
case GID_QFG3: {
// Auto-save system used by QFG3
reg_t autoSaveNameId;
@ -1227,6 +1257,9 @@ reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) {
if (g_sci->getGameId() == GID_JONES) {
// Jones has one save slot only
savegameId = 0;
} else if (g_sci->getGameId() == GID_KQ5 && g_sci->getPlatform() == Common::kPlatformFMTowns) {
// KQ5 FM-Towns uses custom save/restore code.
// Use the provided id.
} else {
// Real call from script, we need to adjust ID
if ((savegameId < SAVEGAMEID_OFFICIALRANGE_START) || (savegameId > SAVEGAMEID_OFFICIALRANGE_END)) {
@ -1286,6 +1319,10 @@ reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) {
uint savegameId = 0;
if (g_sci->getGameId() == GID_JONES) {
// Jones has one save slot only
} else if (g_sci->getGameId() == GID_KQ5 && g_sci->getPlatform() == Common::kPlatformFMTowns) {
// KQ5 FM-Towns uses custom save/restore code.
// Use the provided id.
savegameId = virtualId;
} else {
// Find saved game
if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END))

View File

@ -359,6 +359,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_KQ5, 25, 25, 0, "rm025", "doit", nullptr, 0, 0, { WORKAROUND_FAKE, 0 } }, // inside witch forest, when going to the room where the walking rock is
{ GID_KQ5, 55, 55, 0, "helpScript", "doit", nullptr, 0, 0, { WORKAROUND_FAKE, 0 } }, // when giving the tambourine to the monster in the labyrinth (only happens at one of the locations) - bug #5198
{ GID_KQ5, -1, 755, 0, "gcWin", "open", nullptr, -1, -1, { WORKAROUND_FAKE, 0 } }, // when entering control menu in the FM-Towns version
{ GID_KQ5, -1, 764, 0, "trash", "select", nullptr, -1, -1, { WORKAROUND_FAKE, 0 } }, // when clicking delete button on save/restore dialog in the FM-Towns version
{ GID_KQ6, -1, 30, 0, "rats", "changeState", nullptr, 0, 5, { WORKAROUND_FAKE, 0 } }, // rats in the catacombs (temps 0-5, all temps!) - bugs #4958, #4998, #5017
{ GID_KQ6, 210, 210, 0, "rm210", "scriptCheck", nullptr, 0, 0, { WORKAROUND_FAKE, 1 } }, // using inventory in that room - bug #4953
{ GID_KQ6, 500, 500, 0, "rm500", "init", nullptr, 0, 0, { WORKAROUND_FAKE, 0 } }, // going to island of the beast
@ -705,6 +706,12 @@ const SciWorkaroundEntry kGetCWD_workarounds[] = {
SCI_WORKAROUNDENTRY_TERMINATOR
};
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index-range, workaround
const SciWorkaroundEntry kGetSaveFiles_workarounds[] = {
{ GID_KQ5, -1, 764, 0, "trash", "select", nullptr, 0, 0, { WORKAROUND_FAKE, 0 } }, // FM-Towns version when clicking delete save button, save-catalog code passes buffers by value instead of address
SCI_WORKAROUNDENTRY_TERMINATOR
};
// gameID, room,script,lvl, object-name, method-name, local-call-signature, index-range, workaround
const SciWorkaroundEntry kFileIOOpen_workarounds[] = {
{ GID_HOYLE5, -1, 64990, 0, "Restore", "doit", nullptr, 0, 0, { WORKAROUND_STILLCALL, 0 } }, // Missing second argument when checking for bridgesg.cat or poker.cat when showing restore dialog

View File

@ -81,6 +81,7 @@ extern const SciWorkaroundEntry kFrameOut_workarounds[];
extern const SciWorkaroundEntry kDeleteKey_workarounds[];
extern const SciWorkaroundEntry kGetAngle_workarounds[];
extern const SciWorkaroundEntry kGetCWD_workarounds[];
extern const SciWorkaroundEntry kGetSaveFiles_workarounds[];
extern const SciWorkaroundEntry kGraphDrawLine_workarounds[];
extern const SciWorkaroundEntry kGraphSaveBox_workarounds[];
extern const SciWorkaroundEntry kGraphRestoreBox_workarounds[];