[Scummvm-cvs-logs] scummvm master -> 045613af95b84b6a57526125da35b949d0f431ea
bluegr
md5 at scummvm.org
Wed Jun 13 11:56:31 CEST 2012
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
045613af95 SCI: Shuffle the kernel functions inside kfile.cpp
Commit: 045613af95b84b6a57526125da35b949d0f431ea
https://github.com/scummvm/scummvm/commit/045613af95b84b6a57526125da35b949d0f431ea
Author: Filippos Karapetis (md5 at scummvm.org)
Date: 2012-06-13T02:55:07-07:00
Commit Message:
SCI: Shuffle the kernel functions inside kfile.cpp
This puts them in the order that they are defined in the kernel tables
Changed paths:
engines/sci/engine/kfile.cpp
diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp
index 0523329..445a019 100644
--- a/engines/sci/engine/kfile.cpp
+++ b/engines/sci/engine/kfile.cpp
@@ -152,18 +152,6 @@ reg_t kDeviceInfo(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-reg_t kGetSaveDir(EngineState *s, int argc, reg_t *argv) {
-#ifdef ENABLE_SCI32
- // SCI32 uses a parameter here. It is used to modify a string, stored in a
- // global variable, so that game scripts store the save directory. We
- // don't really set a save game directory, thus not setting the string to
- // anything is the correct thing to do here.
- //if (argc > 0)
- // warning("kGetSaveDir called with %d parameter(s): %04x:%04x", argc, PRINT_REG(argv[0]));
-#endif
- return s->_segMan->getSaveDirPtr();
-}
-
reg_t kCheckFreeSpace(EngineState *s, int argc, reg_t *argv) {
if (argc > 1) {
// SCI1.1/SCI32
@@ -194,292 +182,187 @@ reg_t kCheckFreeSpace(EngineState *s, int argc, reg_t *argv) {
return make_reg(0, 1);
}
-reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) {
- Common::String game_id = s->_segMan->getString(argv[0]);
- uint16 virtualId = argv[1].toUint16();
-
- debug(3, "kCheckSaveGame(%s, %d)", game_id.c_str(), virtualId);
+reg_t kValidPath(EngineState *s, int argc, reg_t *argv) {
+ Common::String path = s->_segMan->getString(argv[0]);
- Common::Array<SavegameDesc> saves;
- listSavegames(saves);
+ debug(3, "kValidPath(%s) -> %d", path.c_str(), s->r_acc.offset);
- // we allow 0 (happens in QfG2 when trying to restore from an empty saved game list) and return false in that case
- if (virtualId == 0)
- return NULL_REG;
+ // Always return true
+ return make_reg(0, 1);
+}
- // Find saved-game
- if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END))
- error("kCheckSaveGame: called with invalid savegameId");
- uint savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START;
- int savegameNr = findSavegame(saves, savegameId);
- if (savegameNr == -1)
- return NULL_REG;
+#ifdef ENABLE_SCI32
- // Check for compatible savegame version
- int ver = saves[savegameNr].version;
- if (ver < MINIMUM_SAVEGAME_VERSION || ver > CURRENT_SAVEGAME_VERSION)
- return NULL_REG;
+reg_t kCD(EngineState *s, int argc, reg_t *argv) {
+ // TODO: Stub
+ switch (argv[0].toUint16()) {
+ case 0:
+ // Return whether the contents of disc argv[1] is available.
+ return TRUE_REG;
+ default:
+ warning("CD(%d)", argv[0].toUint16());
+ }
- // Otherwise we assume the savegame is OK
- return TRUE_REG;
+ return NULL_REG;
}
-reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) {
- Common::String game_id = s->_segMan->getString(argv[0]);
-
- debug(3, "kGetSaveFiles(%s)", game_id.c_str());
+#endif
- // Scripts ask for current save files, we can assume that if afterwards they ask us to create a new slot they really
- // mean new slot instead of overwriting the old one
- s->_lastSaveVirtualId = SAVEGAMEID_OFFICIALRANGE_START;
+// ---- FileIO operations -----------------------------------------------------
- Common::Array<SavegameDesc> saves;
- listSavegames(saves);
- uint totalSaves = MIN<uint>(saves.size(), MAX_SAVEGAME_NR);
+reg_t kFileIO(EngineState *s, int argc, reg_t *argv) {
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
- reg_t *slot = s->_segMan->derefRegPtr(argv[2], totalSaves);
+reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
+ Common::String name = s->_segMan->getString(argv[0]);
- if (!slot) {
- warning("kGetSaveFiles: %04X:%04X invalid or too small to hold slot data", PRINT_REG(argv[2]));
- totalSaves = 0;
+#ifdef ENABLE_SCI32
+ if (name == PHANTASMAGORIA_SAVEGAME_INDEX) {
+ if (s->_virtualIndexFile) {
+ return make_reg(0, VIRTUALFILE_HANDLE);
+ } else {
+ Common::String englishName = g_sci->getSciLanguageString(name, K_LANG_ENGLISH);
+ Common::String wrappedName = g_sci->wrapFilename(englishName);
+ if (!g_sci->getSaveFileManager()->listSavefiles(wrappedName).empty()) {
+ s->_virtualIndexFile = new VirtualIndexFile(wrappedName);
+ return make_reg(0, VIRTUALFILE_HANDLE);
+ }
+ }
}
+#endif
- const uint bufSize = (totalSaves * SCI_MAX_SAVENAME_LENGTH) + 1;
- char *saveNames = new char[bufSize];
- char *saveNamePtr = saveNames;
+ // SCI32 can call K_FILEIO_OPEN with only one argument. It seems to
+ // just be checking if it exists.
+ int mode = (argc < 2) ? (int)_K_FILE_MODE_OPEN_OR_FAIL : argv[1].toUint16();
+ bool unwrapFilename = true;
- for (uint i = 0; i < totalSaves; i++) {
- *slot++ = make_reg(0, saves[i].id + SAVEGAMEID_OFFICIALRANGE_START); // Store the virtual savegame ID ffs. see above
- strcpy(saveNamePtr, saves[i].name);
- saveNamePtr += SCI_MAX_SAVENAME_LENGTH;
+ // SQ4 floppy prepends /\ to the filenames
+ if (name.hasPrefix("/\\")) {
+ name.deleteChar(0);
+ name.deleteChar(0);
}
- *saveNamePtr = 0; // Terminate list
+ // SQ4 floppy attempts to update the savegame index file sq4sg.dir when
+ // deleting saved games. We don't use an index file for saving or loading,
+ // so just stop the game from modifying the file here in order to avoid
+ // having it saved in the ScummVM save directory.
+ if (name == "sq4sg.dir") {
+ debugC(kDebugLevelFile, "Not opening unused file sq4sg.dir");
+ return SIGNAL_REG;
+ }
- s->_segMan->memcpy(argv[1], (byte *)saveNames, bufSize);
- delete[] saveNames;
+ if (name.empty()) {
+ // Happens many times during KQ1 (e.g. when typing something)
+ debugC(kDebugLevelFile, "Attempted to open a file with an empty filename");
+ return SIGNAL_REG;
+ }
+ debugC(kDebugLevelFile, "kFileIO(open): %s, 0x%x", name.c_str(), mode);
- return make_reg(0, totalSaves);
+ // QFG import rooms get a virtual filelisting instead of an actual one
+ if (g_sci->inQfGImportRoom()) {
+ // We need to find out what the user actually selected, "savedHeroes" is
+ // already destroyed when we get here. That's why we need to remember
+ // selection via kDrawControl.
+ name = s->_dirseeker.getVirtualFilename(s->_chosenQfGImportItem);
+ unwrapFilename = false;
+ }
+
+ return file_open(s, name, mode, unwrapFilename);
}
-reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) {
- Common::String game_id;
- int16 virtualId = argv[1].toSint16();
- int16 savegameId = -1;
- Common::String game_description;
- Common::String version;
+reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
+ debugC(kDebugLevelFile, "kFileIO(close): %d", argv[0].toUint16());
- if (argc > 3)
- version = s->_segMan->getString(argv[3]);
+ if (argv[0] == SIGNAL_REG)
+ return s->r_acc;
+
+ uint16 handle = argv[0].toUint16();
- // We check here, we don't want to delete a users save in case we are within a kernel function
- if (s->executionStackBase) {
- warning("kSaveGame - won't save from within kernel function");
- return NULL_REG;
+#ifdef ENABLE_SCI32
+ if (handle == VIRTUALFILE_HANDLE) {
+ s->_virtualIndexFile->close();
+ return SIGNAL_REG;
}
+#endif
- if (argv[0].isNull()) {
- // Direct call, from a patched Game::save
- if ((argv[1] != SIGNAL_REG) || (!argv[2].isNull()))
- error("kSaveGame: assumed patched call isn't accurate");
-
- // we are supposed to show a dialog for the user and let him choose where to save
- g_sci->_soundCmd->pauseAll(true); // pause music
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
- savegameId = dialog->runModalWithCurrentTarget();
- game_description = dialog->getResultString();
- if (game_description.empty()) {
- // create our own description for the saved game, the user didnt enter it
- game_description = dialog->createDefaultSaveDescription(savegameId);
- }
- delete dialog;
- g_sci->_soundCmd->pauseAll(false); // unpause music ( we can't have it paused during save)
- if (savegameId < 0)
- return NULL_REG;
-
- } else {
- // Real call from script
- game_id = s->_segMan->getString(argv[0]);
- if (argv[2].isNull())
- error("kSaveGame: called with description being NULL");
- game_description = s->_segMan->getString(argv[2]);
-
- debug(3, "kSaveGame(%s,%d,%s,%s)", game_id.c_str(), virtualId, game_description.c_str(), version.c_str());
+ FileHandle *f = getFileFromHandle(s, handle);
+ if (f) {
+ f->close();
+ if (getSciVersion() <= SCI_VERSION_0_LATE)
+ return s->r_acc; // SCI0 semantics: no value returned
+ return SIGNAL_REG;
+ }
- Common::Array<SavegameDesc> saves;
- listSavegames(saves);
+ if (getSciVersion() <= SCI_VERSION_0_LATE)
+ return s->r_acc; // SCI0 semantics: no value returned
+ return NULL_REG;
+}
- if ((virtualId >= SAVEGAMEID_OFFICIALRANGE_START) && (virtualId <= SAVEGAMEID_OFFICIALRANGE_END)) {
- // savegameId is an actual Id, so search for it just to make sure
- savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START;
- if (findSavegame(saves, savegameId) == -1)
- return NULL_REG;
- } else if (virtualId < SAVEGAMEID_OFFICIALRANGE_START) {
- // virtualId is low, we assume that scripts expect us to create new slot
- 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 = 0; savegameId < SAVEGAMEID_OFFICIALRANGE_START; savegameId++) {
- for (savegameNr = 0; savegameNr < saves.size(); savegameNr++) {
- if (savegameId == saves[savegameNr].id)
- break;
- }
- if (savegameNr == saves.size())
- break;
- }
- if (savegameId == SAVEGAMEID_OFFICIALRANGE_START)
- error("kSavegame: no more savegame slots available");
- }
- } else {
- error("kSaveGame: invalid savegameId used");
- }
+reg_t kFileIOReadRaw(EngineState *s, int argc, reg_t *argv) {
+ uint16 handle = argv[0].toUint16();
+ uint16 size = argv[2].toUint16();
+ int bytesRead = 0;
+ char *buf = new char[size];
+ debugC(kDebugLevelFile, "kFileIO(readRaw): %d, %d", handle, size);
- // Save in case caller wants to overwrite last newly created save
- s->_lastSaveVirtualId = virtualId;
- s->_lastSaveNewId = savegameId;
+#ifdef ENABLE_SCI32
+ if (handle == VIRTUALFILE_HANDLE) {
+ bytesRead = s->_virtualIndexFile->read(buf, size);
+ } else {
+#endif
+ FileHandle *f = getFileFromHandle(s, handle);
+ if (f)
+ bytesRead = f->_in->read(buf, size);
+#ifdef ENABLE_SCI32
}
+#endif
- s->r_acc = NULL_REG;
+ // TODO: What happens if less bytes are read than what has
+ // been requested? (i.e. if bytesRead is non-zero, but still
+ // less than size)
+ if (bytesRead > 0)
+ s->_segMan->memcpy(argv[1], (const byte*)buf, size);
- Common::String filename = g_sci->getSavegameName(savegameId);
- Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
- Common::OutSaveFile *out;
+ delete[] buf;
+ return make_reg(0, bytesRead);
+}
- out = saveFileMan->openForSaving(filename);
- if (!out) {
- warning("Error opening savegame \"%s\" for writing", filename.c_str());
- } else {
- if (!gamestate_save(s, out, game_description, version)) {
- warning("Saving the game failed");
- } else {
- s->r_acc = TRUE_REG; // save successful
- }
-
- out->finalize();
- if (out->err()) {
- warning("Writing the savegame failed");
- s->r_acc = NULL_REG; // write failure
- }
- delete out;
- }
-
- return s->r_acc;
-}
-
-reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) {
- Common::String game_id = !argv[0].isNull() ? s->_segMan->getString(argv[0]) : "";
- int16 savegameId = argv[1].toSint16();
- bool pausedMusic = false;
-
- debug(3, "kRestoreGame(%s,%d)", game_id.c_str(), savegameId);
-
- if (argv[0].isNull()) {
- // Direct call, either from launcher or from a patched Game::restore
- if (savegameId == -1) {
- // we are supposed to show a dialog for the user and let him choose a saved game
- g_sci->_soundCmd->pauseAll(true); // pause music
- GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
- savegameId = dialog->runModalWithCurrentTarget();
- delete dialog;
- if (savegameId < 0) {
- g_sci->_soundCmd->pauseAll(false); // unpause music
- return s->r_acc;
- }
- pausedMusic = true;
- }
- // don't adjust ID of the saved game, it's already correct
- } else {
- if (argv[2].isNull())
- error("kRestoreGame: called with parameter 2 being NULL");
- // Real call from script, we need to adjust ID
- if ((savegameId < SAVEGAMEID_OFFICIALRANGE_START) || (savegameId > SAVEGAMEID_OFFICIALRANGE_END)) {
- warning("Savegame ID %d is not allowed", savegameId);
- return TRUE_REG;
- }
- savegameId -= SAVEGAMEID_OFFICIALRANGE_START;
- }
-
- s->r_acc = NULL_REG; // signals success
+reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) {
+ uint16 handle = argv[0].toUint16();
+ uint16 size = argv[2].toUint16();
+ char *buf = new char[size];
+ bool success = false;
+ s->_segMan->memcpy((byte *)buf, argv[1], size);
+ debugC(kDebugLevelFile, "kFileIO(writeRaw): %d, %d", handle, size);
- Common::Array<SavegameDesc> saves;
- listSavegames(saves);
- if (findSavegame(saves, savegameId) == -1) {
- s->r_acc = TRUE_REG;
- warning("Savegame ID %d not found", savegameId);
+#ifdef ENABLE_SCI32
+ if (handle == VIRTUALFILE_HANDLE) {
+ s->_virtualIndexFile->write(buf, size);
+ success = true;
} else {
- Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
- Common::String filename = g_sci->getSavegameName(savegameId);
- Common::SeekableReadStream *in;
-
- in = saveFileMan->openForLoading(filename);
- if (in) {
- // found a savegame file
-
- gamestate_restore(s, in);
- delete in;
-
- if (g_sci->getGameId() == GID_MOTHERGOOSE256) {
- // WORKAROUND: Mother Goose SCI1/SCI1.1 does some weird things for
- // saving a previously restored game.
- // We set the current savedgame-id directly and remove the script
- // code concerning this via script patch.
- s->variables[VAR_GLOBAL][0xB3].offset = SAVEGAMEID_OFFICIALRANGE_START + savegameId;
- }
- } else {
- s->r_acc = TRUE_REG;
- warning("Savegame #%d not found", savegameId);
+#endif
+ FileHandle *f = getFileFromHandle(s, handle);
+ if (f) {
+ f->_out->write(buf, size);
+ success = true;
}
+#ifdef ENABLE_SCI32
}
+#endif
- if (!s->r_acc.isNull()) {
- // no success?
- if (pausedMusic)
- g_sci->_soundCmd->pauseAll(false); // unpause music
- }
-
- return s->r_acc;
-}
-
-reg_t kValidPath(EngineState *s, int argc, reg_t *argv) {
- Common::String path = s->_segMan->getString(argv[0]);
-
- debug(3, "kValidPath(%s) -> %d", path.c_str(), s->r_acc.offset);
-
- // Always return true
- return make_reg(0, 1);
-}
-
-reg_t kFileIO(EngineState *s, int argc, reg_t *argv) {
- if (!s)
- return make_reg(0, getSciVersion());
- error("not supposed to call this");
+ delete[] buf;
+ if (success)
+ return NULL_REG;
+ return make_reg(0, 6); // DOS - invalid handle
}
-reg_t kFileIOOpen(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]);
-
-#ifdef ENABLE_SCI32
- if (name == PHANTASMAGORIA_SAVEGAME_INDEX) {
- if (s->_virtualIndexFile) {
- return make_reg(0, VIRTUALFILE_HANDLE);
- } else {
- Common::String englishName = g_sci->getSciLanguageString(name, K_LANG_ENGLISH);
- Common::String wrappedName = g_sci->wrapFilename(englishName);
- if (!g_sci->getSaveFileManager()->listSavefiles(wrappedName).empty()) {
- s->_virtualIndexFile = new VirtualIndexFile(wrappedName);
- return make_reg(0, VIRTUALFILE_HANDLE);
- }
- }
- }
-#endif
-
- // SCI32 can call K_FILEIO_OPEN with only one argument. It seems to
- // just be checking if it exists.
- int mode = (argc < 2) ? (int)_K_FILE_MODE_OPEN_OR_FAIL : argv[1].toUint16();
- bool unwrapFilename = true;
+ Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+ bool result;
// SQ4 floppy prepends /\ to the filenames
if (name.hasPrefix("/\\")) {
@@ -487,407 +370,546 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) {
name.deleteChar(0);
}
- // SQ4 floppy attempts to update the savegame index file sq4sg.dir when
- // deleting saved games. We don't use an index file for saving or loading,
- // so just stop the game from modifying the file here in order to avoid
- // having it saved in the ScummVM save directory.
- if (name == "sq4sg.dir") {
- debugC(kDebugLevelFile, "Not opening unused file sq4sg.dir");
- return SIGNAL_REG;
- }
-
- if (name.empty()) {
- // Happens many times during KQ1 (e.g. when typing something)
- debugC(kDebugLevelFile, "Attempted to open a file with an empty filename");
- return SIGNAL_REG;
- }
- debugC(kDebugLevelFile, "kFileIO(open): %s, 0x%x", name.c_str(), mode);
+ // Special case for SQ4 floppy: This game has hardcoded names for all of
+ // its savegames, and they are all named "sq4sg.xxx", where xxx is the
+ // slot. We just take the slot number here, and delete the appropriate
+ // save game.
+ if (name.hasPrefix("sq4sg.")) {
+ // Special handling for SQ4... get the slot number and construct the
+ // save game name.
+ int slotNum = atoi(name.c_str() + name.size() - 3);
+ Common::Array<SavegameDesc> saves;
+ listSavegames(saves);
+ int savedir_nr = saves[slotNum].id;
+ name = g_sci->getSavegameName(savedir_nr);
+ result = saveFileMan->removeSavefile(name);
+ } else if (getSciVersion() >= SCI_VERSION_2) {
+ // The file name may be already wrapped, so check both cases
+ result = saveFileMan->removeSavefile(name);
+ if (!result) {
+ const Common::String wrappedName = g_sci->wrapFilename(name);
+ result = saveFileMan->removeSavefile(wrappedName);
+ }
- // QFG import rooms get a virtual filelisting instead of an actual one
- if (g_sci->inQfGImportRoom()) {
- // We need to find out what the user actually selected, "savedHeroes" is
- // already destroyed when we get here. That's why we need to remember
- // selection via kDrawControl.
- name = s->_dirseeker.getVirtualFilename(s->_chosenQfGImportItem);
- unwrapFilename = false;
+#ifdef ENABLE_SCI32
+ if (name == PHANTASMAGORIA_SAVEGAME_INDEX) {
+ delete s->_virtualIndexFile;
+ s->_virtualIndexFile = 0;
+ }
+#endif
+ } else {
+ const Common::String wrappedName = g_sci->wrapFilename(name);
+ result = saveFileMan->removeSavefile(wrappedName);
}
- return file_open(s, name, mode, unwrapFilename);
+ debugC(kDebugLevelFile, "kFileIO(unlink): %s", name.c_str());
+ if (result)
+ return NULL_REG;
+ return make_reg(0, 2); // DOS - file not found error code
}
-reg_t kFileIOClose(EngineState *s, int argc, reg_t *argv) {
- debugC(kDebugLevelFile, "kFileIO(close): %d", argv[0].toUint16());
+reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) {
+ uint16 maxsize = argv[1].toUint16();
+ char *buf = new char[maxsize];
+ uint16 handle = argv[2].toUint16();
+ debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, maxsize);
+ uint32 bytesRead;
- if (argv[0] == SIGNAL_REG)
- return s->r_acc;
-
- uint16 handle = argv[0].toUint16();
+#ifdef ENABLE_SCI32
+ if (handle == VIRTUALFILE_HANDLE)
+ bytesRead = s->_virtualIndexFile->readLine(buf, maxsize);
+ else
+#endif
+ bytesRead = fgets_wrapper(s, buf, maxsize, handle);
+
+ s->_segMan->memcpy(argv[0], (const byte*)buf, maxsize);
+ delete[] buf;
+ return bytesRead ? argv[0] : NULL_REG;
+}
+
+reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
+ int handle = argv[0].toUint16();
+ Common::String str = s->_segMan->getString(argv[1]);
+ debugC(kDebugLevelFile, "kFileIO(writeString): %d", handle);
#ifdef ENABLE_SCI32
if (handle == VIRTUALFILE_HANDLE) {
- s->_virtualIndexFile->close();
- return SIGNAL_REG;
+ s->_virtualIndexFile->write(str.c_str(), str.size());
+ return NULL_REG;
}
#endif
FileHandle *f = getFileFromHandle(s, handle);
+
if (f) {
- f->close();
+ f->_out->write(str.c_str(), str.size());
if (getSciVersion() <= SCI_VERSION_0_LATE)
return s->r_acc; // SCI0 semantics: no value returned
- return SIGNAL_REG;
+ return NULL_REG;
}
if (getSciVersion() <= SCI_VERSION_0_LATE)
return s->r_acc; // SCI0 semantics: no value returned
- return NULL_REG;
+ return make_reg(0, 6); // DOS - invalid handle
}
-reg_t kFileIOReadRaw(EngineState *s, int argc, reg_t *argv) {
+reg_t kFileIOSeek(EngineState *s, int argc, reg_t *argv) {
uint16 handle = argv[0].toUint16();
- uint16 size = argv[2].toUint16();
- int bytesRead = 0;
- char *buf = new char[size];
- debugC(kDebugLevelFile, "kFileIO(readRaw): %d, %d", handle, size);
+ uint16 offset = ABS<int16>(argv[1].toSint16()); // can be negative
+ uint16 whence = argv[2].toUint16();
+ debugC(kDebugLevelFile, "kFileIO(seek): %d, %d, %d", handle, offset, whence);
#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE) {
- bytesRead = s->_virtualIndexFile->read(buf, size);
- } else {
+ if (handle == VIRTUALFILE_HANDLE)
+ return make_reg(0, s->_virtualIndexFile->seek(offset, whence));
#endif
- FileHandle *f = getFileFromHandle(s, handle);
- if (f)
- bytesRead = f->_in->read(buf, size);
-#ifdef ENABLE_SCI32
+
+ FileHandle *f = getFileFromHandle(s, handle);
+
+ if (f && f->_in) {
+ // Backward seeking isn't supported in zip file streams, thus adapt the
+ // parameters accordingly if games ask for such a seek mode. A known
+ // case where this is requested is the save file manager in Phantasmagoria
+ if (whence == SEEK_END) {
+ whence = SEEK_SET;
+ offset = f->_in->size() - offset;
+ }
+
+ return make_reg(0, f->_in->seek(offset, whence));
+ } else if (f && f->_out) {
+ error("kFileIOSeek: Unsupported seek operation on a writeable stream (offset: %d, whence: %d)", offset, whence);
}
-#endif
- // TODO: What happens if less bytes are read than what has
- // been requested? (i.e. if bytesRead is non-zero, but still
- // less than size)
- if (bytesRead > 0)
- s->_segMan->memcpy(argv[1], (const byte*)buf, size);
+ return SIGNAL_REG;
+}
- delete[] buf;
- return make_reg(0, bytesRead);
+reg_t kFileIOFindFirst(EngineState *s, int argc, reg_t *argv) {
+ Common::String mask = s->_segMan->getString(argv[0]);
+ reg_t buf = argv[1];
+ int attr = argv[2].toUint16(); // We won't use this, Win32 might, though...
+ debugC(kDebugLevelFile, "kFileIO(findFirst): %s, 0x%x", mask.c_str(), attr);
+
+ // We remove ".*". mask will get prefixed, so we will return all additional files for that gameid
+ if (mask == "*.*")
+ mask = "*";
+ return s->_dirseeker.firstFile(mask, buf, s->_segMan);
}
-reg_t kFileIOWriteRaw(EngineState *s, int argc, reg_t *argv) {
- uint16 handle = argv[0].toUint16();
- uint16 size = argv[2].toUint16();
- char *buf = new char[size];
- bool success = false;
- s->_segMan->memcpy((byte *)buf, argv[1], size);
- debugC(kDebugLevelFile, "kFileIO(writeRaw): %d, %d", handle, size);
+reg_t kFileIOFindNext(EngineState *s, int argc, reg_t *argv) {
+ debugC(kDebugLevelFile, "kFileIO(findNext)");
+ return s->_dirseeker.nextFile(s->_segMan);
+}
+
+reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) {
+ Common::String name = s->_segMan->getString(argv[0]);
#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE) {
- s->_virtualIndexFile->write(buf, size);
- success = true;
- } else {
+ // Cache the file existence result for the Phantasmagoria
+ // save index file, as the game scripts keep checking for
+ // its existence.
+ if (name == PHANTASMAGORIA_SAVEGAME_INDEX && s->_virtualIndexFile)
+ return TRUE_REG;
#endif
- FileHandle *f = getFileFromHandle(s, handle);
- if (f) {
- f->_out->write(buf, size);
- success = true;
- }
-#ifdef ENABLE_SCI32
+
+ bool exists = false;
+
+ // Check for regular file
+ exists = Common::File::exists(name);
+
+ // Check for a savegame with the name
+ Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+ if (!exists)
+ exists = !saveFileMan->listSavefiles(name).empty();
+
+ // Try searching for the file prepending "target-"
+ const Common::String wrappedName = g_sci->wrapFilename(name);
+ if (!exists) {
+ exists = !saveFileMan->listSavefiles(wrappedName).empty();
}
-#endif
- delete[] buf;
- if (success)
- return NULL_REG;
- return make_reg(0, 6); // DOS - invalid handle
-}
+ // SCI2+ debug mode
+ if (DebugMan.isDebugChannelEnabled(kDebugLevelDebugMode)) {
+ if (!exists && name == "1.scr") // PQ4
+ exists = true;
+ if (!exists && name == "18.scr") // QFG4
+ exists = true;
+ if (!exists && name == "99.scr") // GK1, KQ7
+ exists = true;
+ if (!exists && name == "classes") // GK2, SQ6, LSL7
+ exists = true;
+ }
-reg_t kFileIOReadString(EngineState *s, int argc, reg_t *argv) {
- uint16 maxsize = argv[1].toUint16();
- char *buf = new char[maxsize];
- uint16 handle = argv[2].toUint16();
- debugC(kDebugLevelFile, "kFileIO(readString): %d, %d", handle, maxsize);
- uint32 bytesRead;
+ // Special case for non-English versions of LSL5: The English version of
+ // LSL5 calls kFileIO(), case K_FILEIO_OPEN for reading to check if
+ // memory.drv exists (which is where the game's password is stored). If
+ // it's not found, it calls kFileIO() again, case K_FILEIO_OPEN for
+ // writing and creates a new file. Non-English versions call kFileIO(),
+ // case K_FILEIO_FILE_EXISTS instead, and fail if memory.drv can't be
+ // found. We create a default memory.drv file with no password, so that
+ // the game can continue.
+ if (!exists && name == "memory.drv") {
+ // Create a new file, and write the bytes for the empty password
+ // string inside
+ byte defaultContent[] = { 0xE9, 0xE9, 0xEB, 0xE1, 0x0D, 0x0A, 0x31, 0x30, 0x30, 0x30 };
+ Common::WriteStream *outFile = saveFileMan->openForSaving(wrappedName);
+ for (int i = 0; i < 10; i++)
+ outFile->writeByte(defaultContent[i]);
+ outFile->finalize();
+ exists = !outFile->err(); // check whether we managed to create the file.
+ delete outFile;
+ }
-#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE)
- bytesRead = s->_virtualIndexFile->readLine(buf, maxsize);
- else
-#endif
- bytesRead = fgets_wrapper(s, buf, maxsize, handle);
+ // Special case for KQ6 Mac: The game checks for two video files to see
+ // if they exist before it plays them. Since we support multiple naming
+ // schemes for resource fork files, we also need to support that here in
+ // case someone has a "HalfDome.bin" file, etc.
+ if (!exists && g_sci->getGameId() == GID_KQ6 && g_sci->getPlatform() == Common::kPlatformMacintosh &&
+ (name == "HalfDome" || name == "Kq6Movie"))
+ exists = Common::MacResManager::exists(name);
- s->_segMan->memcpy(argv[0], (const byte*)buf, maxsize);
- delete[] buf;
- return bytesRead ? argv[0] : NULL_REG;
+ debugC(kDebugLevelFile, "kFileIO(fileExists) %s -> %d", name.c_str(), exists);
+ return make_reg(0, exists);
}
-reg_t kFileIOWriteString(EngineState *s, int argc, reg_t *argv) {
- int handle = argv[0].toUint16();
- Common::String str = s->_segMan->getString(argv[1]);
- debugC(kDebugLevelFile, "kFileIO(writeString): %d", handle);
+reg_t kFileIORename(EngineState *s, int argc, reg_t *argv) {
+ Common::String oldName = s->_segMan->getString(argv[0]);
+ Common::String newName = s->_segMan->getString(argv[1]);
+
+ // SCI1.1 returns 0 on success and a DOS error code on fail. SCI32
+ // returns -1 on fail. We just return -1 for all versions.
+ if (g_sci->getSaveFileManager()->renameSavefile(oldName, newName))
+ return NULL_REG;
+ else
+ return SIGNAL_REG;
+}
#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE) {
- s->_virtualIndexFile->write(str.c_str(), str.size());
+reg_t kFileIOReadByte(EngineState *s, int argc, reg_t *argv) {
+ // Read the byte into the low byte of the accumulator
+ FileHandle *f = getFileFromHandle(s, argv[0].toUint16());
+ if (!f)
return NULL_REG;
- }
-#endif
+ return make_reg(0, (s->r_acc.toUint16() & 0xff00) | f->_in->readByte());
+}
- FileHandle *f = getFileFromHandle(s, handle);
+reg_t kFileIOWriteByte(EngineState *s, int argc, reg_t *argv) {
+ FileHandle *f = getFileFromHandle(s, argv[0].toUint16());
+ if (f)
+ f->_out->writeByte(argv[1].toUint16() & 0xff);
+ return s->r_acc; // FIXME: does this really not return anything?
+}
- if (f) {
- f->_out->write(str.c_str(), str.size());
- if (getSciVersion() <= SCI_VERSION_0_LATE)
- return s->r_acc; // SCI0 semantics: no value returned
+reg_t kFileIOReadWord(EngineState *s, int argc, reg_t *argv) {
+ FileHandle *f = getFileFromHandle(s, argv[0].toUint16());
+ if (!f)
return NULL_REG;
- }
+ return make_reg(0, f->_in->readUint16LE());
+}
- if (getSciVersion() <= SCI_VERSION_0_LATE)
- return s->r_acc; // SCI0 semantics: no value returned
- return make_reg(0, 6); // DOS - invalid handle
+reg_t kFileIOWriteWord(EngineState *s, int argc, reg_t *argv) {
+ FileHandle *f = getFileFromHandle(s, argv[0].toUint16());
+ if (f)
+ f->_out->writeUint16LE(argv[1].toUint16());
+ return s->r_acc; // FIXME: does this really not return anything?
}
-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;
+reg_t kFileIOCreateSaveSlot(EngineState *s, int argc, reg_t *argv) {
+ // Used in Shivers when the user enters his name on the guest book
+ // in the beginning to start the game.
- // SQ4 floppy prepends /\ to the filenames
- if (name.hasPrefix("/\\")) {
- name.deleteChar(0);
- name.deleteChar(0);
- }
+ // Creates a new save slot, and returns if the operation was successful
- // Special case for SQ4 floppy: This game has hardcoded names for all of
- // its savegames, and they are all named "sq4sg.xxx", where xxx is the
- // slot. We just take the slot number here, and delete the appropriate
- // save game.
- if (name.hasPrefix("sq4sg.")) {
- // Special handling for SQ4... get the slot number and construct the
- // save game name.
- int slotNum = atoi(name.c_str() + name.size() - 3);
- Common::Array<SavegameDesc> saves;
- listSavegames(saves);
- int savedir_nr = saves[slotNum].id;
- name = g_sci->getSavegameName(savedir_nr);
- result = saveFileMan->removeSavefile(name);
- } else if (getSciVersion() >= SCI_VERSION_2) {
- // The file name may be already wrapped, so check both cases
- result = saveFileMan->removeSavefile(name);
- if (!result) {
- const Common::String wrappedName = g_sci->wrapFilename(name);
- result = saveFileMan->removeSavefile(wrappedName);
- }
+ // Argument 0 denotes the save slot as a negative integer, 2 means "0"
+ // Argument 1 is a string, with the file name, obtained from kSave(5).
+ // The interpreter checks if it can be written to (by checking for free
+ // disk space and write permissions)
-#ifdef ENABLE_SCI32
- if (name == PHANTASMAGORIA_SAVEGAME_INDEX) {
- delete s->_virtualIndexFile;
- s->_virtualIndexFile = 0;
- }
-#endif
- } else {
- const Common::String wrappedName = g_sci->wrapFilename(name);
- result = saveFileMan->removeSavefile(wrappedName);
- }
+ // We don't really use or need any of this...
- debugC(kDebugLevelFile, "kFileIO(unlink): %s", name.c_str());
- if (result)
- return NULL_REG;
- return make_reg(0, 2); // DOS - file not found error code
+ uint16 saveSlot = argv[0].toUint16();
+ char* fileName = s->_segMan->lookupString(argv[1])->getRawData();
+ warning("kFileIOCreateSaveSlot(%d, '%s')", saveSlot, fileName);
+
+ return TRUE_REG; // slot creation was successful
}
-reg_t kFileIOSeek(EngineState *s, int argc, reg_t *argv) {
- uint16 handle = argv[0].toUint16();
- uint16 offset = ABS<int16>(argv[1].toSint16()); // can be negative
- uint16 whence = argv[2].toUint16();
- debugC(kDebugLevelFile, "kFileIO(seek): %d, %d, %d", handle, offset, whence);
+#endif
+
+// ---- Save operations -------------------------------------------------------
#ifdef ENABLE_SCI32
- if (handle == VIRTUALFILE_HANDLE)
- return make_reg(0, s->_virtualIndexFile->seek(offset, whence));
+
+reg_t kSave(EngineState *s, int argc, reg_t *argv) {
+ if (!s)
+ return make_reg(0, getSciVersion());
+ error("not supposed to call this");
+}
+
#endif
- FileHandle *f = getFileFromHandle(s, handle);
+reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) {
+ Common::String game_id;
+ int16 virtualId = argv[1].toSint16();
+ int16 savegameId = -1;
+ Common::String game_description;
+ Common::String version;
- if (f && f->_in) {
- // Backward seeking isn't supported in zip file streams, thus adapt the
- // parameters accordingly if games ask for such a seek mode. A known
- // case where this is requested is the save file manager in Phantasmagoria
- if (whence == SEEK_END) {
- whence = SEEK_SET;
- offset = f->_in->size() - offset;
+ if (argc > 3)
+ version = s->_segMan->getString(argv[3]);
+
+ // We check here, we don't want to delete a users save in case we are within a kernel function
+ if (s->executionStackBase) {
+ warning("kSaveGame - won't save from within kernel function");
+ return NULL_REG;
+ }
+
+ if (argv[0].isNull()) {
+ // Direct call, from a patched Game::save
+ if ((argv[1] != SIGNAL_REG) || (!argv[2].isNull()))
+ error("kSaveGame: assumed patched call isn't accurate");
+
+ // we are supposed to show a dialog for the user and let him choose where to save
+ g_sci->_soundCmd->pauseAll(true); // pause music
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true);
+ savegameId = dialog->runModalWithCurrentTarget();
+ game_description = dialog->getResultString();
+ if (game_description.empty()) {
+ // create our own description for the saved game, the user didnt enter it
+ game_description = dialog->createDefaultSaveDescription(savegameId);
}
+ delete dialog;
+ g_sci->_soundCmd->pauseAll(false); // unpause music ( we can't have it paused during save)
+ if (savegameId < 0)
+ return NULL_REG;
- return make_reg(0, f->_in->seek(offset, whence));
- } else if (f && f->_out) {
- error("kFileIOSeek: Unsupported seek operation on a writeable stream (offset: %d, whence: %d)", offset, whence);
+ } else {
+ // Real call from script
+ game_id = s->_segMan->getString(argv[0]);
+ if (argv[2].isNull())
+ error("kSaveGame: called with description being NULL");
+ game_description = s->_segMan->getString(argv[2]);
+
+ debug(3, "kSaveGame(%s,%d,%s,%s)", game_id.c_str(), virtualId, game_description.c_str(), version.c_str());
+
+ Common::Array<SavegameDesc> saves;
+ listSavegames(saves);
+
+ if ((virtualId >= SAVEGAMEID_OFFICIALRANGE_START) && (virtualId <= SAVEGAMEID_OFFICIALRANGE_END)) {
+ // savegameId is an actual Id, so search for it just to make sure
+ savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START;
+ if (findSavegame(saves, savegameId) == -1)
+ return NULL_REG;
+ } else if (virtualId < SAVEGAMEID_OFFICIALRANGE_START) {
+ // virtualId is low, we assume that scripts expect us to create new slot
+ 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 = 0; savegameId < SAVEGAMEID_OFFICIALRANGE_START; savegameId++) {
+ for (savegameNr = 0; savegameNr < saves.size(); savegameNr++) {
+ if (savegameId == saves[savegameNr].id)
+ break;
+ }
+ if (savegameNr == saves.size())
+ break;
+ }
+ if (savegameId == SAVEGAMEID_OFFICIALRANGE_START)
+ error("kSavegame: no more savegame slots available");
+ }
+ } else {
+ error("kSaveGame: invalid savegameId used");
+ }
+
+ // Save in case caller wants to overwrite last newly created save
+ s->_lastSaveVirtualId = virtualId;
+ s->_lastSaveNewId = savegameId;
}
- return SIGNAL_REG;
-}
+ s->r_acc = NULL_REG;
-reg_t kFileIOFindFirst(EngineState *s, int argc, reg_t *argv) {
- Common::String mask = s->_segMan->getString(argv[0]);
- reg_t buf = argv[1];
- int attr = argv[2].toUint16(); // We won't use this, Win32 might, though...
- debugC(kDebugLevelFile, "kFileIO(findFirst): %s, 0x%x", mask.c_str(), attr);
+ Common::String filename = g_sci->getSavegameName(savegameId);
+ Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+ Common::OutSaveFile *out;
+
+ out = saveFileMan->openForSaving(filename);
+ if (!out) {
+ warning("Error opening savegame \"%s\" for writing", filename.c_str());
+ } else {
+ if (!gamestate_save(s, out, game_description, version)) {
+ warning("Saving the game failed");
+ } else {
+ s->r_acc = TRUE_REG; // save successful
+ }
+
+ out->finalize();
+ if (out->err()) {
+ warning("Writing the savegame failed");
+ s->r_acc = NULL_REG; // write failure
+ }
+ delete out;
+ }
- // We remove ".*". mask will get prefixed, so we will return all additional files for that gameid
- if (mask == "*.*")
- mask = "*";
- return s->_dirseeker.firstFile(mask, buf, s->_segMan);
+ return s->r_acc;
}
-reg_t kFileIOFindNext(EngineState *s, int argc, reg_t *argv) {
- debugC(kDebugLevelFile, "kFileIO(findNext)");
- return s->_dirseeker.nextFile(s->_segMan);
-}
+reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) {
+ Common::String game_id = !argv[0].isNull() ? s->_segMan->getString(argv[0]) : "";
+ int16 savegameId = argv[1].toSint16();
+ bool pausedMusic = false;
-reg_t kFileIOExists(EngineState *s, int argc, reg_t *argv) {
- Common::String name = s->_segMan->getString(argv[0]);
+ debug(3, "kRestoreGame(%s,%d)", game_id.c_str(), savegameId);
-#ifdef ENABLE_SCI32
- // Cache the file existence result for the Phantasmagoria
- // save index file, as the game scripts keep checking for
- // its existence.
- if (name == PHANTASMAGORIA_SAVEGAME_INDEX && s->_virtualIndexFile)
- return TRUE_REG;
-#endif
+ if (argv[0].isNull()) {
+ // Direct call, either from launcher or from a patched Game::restore
+ if (savegameId == -1) {
+ // we are supposed to show a dialog for the user and let him choose a saved game
+ g_sci->_soundCmd->pauseAll(true); // pause music
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false);
+ savegameId = dialog->runModalWithCurrentTarget();
+ delete dialog;
+ if (savegameId < 0) {
+ g_sci->_soundCmd->pauseAll(false); // unpause music
+ return s->r_acc;
+ }
+ pausedMusic = true;
+ }
+ // don't adjust ID of the saved game, it's already correct
+ } else {
+ if (argv[2].isNull())
+ error("kRestoreGame: called with parameter 2 being NULL");
+ // Real call from script, we need to adjust ID
+ if ((savegameId < SAVEGAMEID_OFFICIALRANGE_START) || (savegameId > SAVEGAMEID_OFFICIALRANGE_END)) {
+ warning("Savegame ID %d is not allowed", savegameId);
+ return TRUE_REG;
+ }
+ savegameId -= SAVEGAMEID_OFFICIALRANGE_START;
+ }
- bool exists = false;
+ s->r_acc = NULL_REG; // signals success
- // Check for regular file
- exists = Common::File::exists(name);
+ Common::Array<SavegameDesc> saves;
+ listSavegames(saves);
+ if (findSavegame(saves, savegameId) == -1) {
+ s->r_acc = TRUE_REG;
+ warning("Savegame ID %d not found", savegameId);
+ } else {
+ Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
+ Common::String filename = g_sci->getSavegameName(savegameId);
+ Common::SeekableReadStream *in;
- // Check for a savegame with the name
- Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager();
- if (!exists)
- exists = !saveFileMan->listSavefiles(name).empty();
+ in = saveFileMan->openForLoading(filename);
+ if (in) {
+ // found a savegame file
- // Try searching for the file prepending "target-"
- const Common::String wrappedName = g_sci->wrapFilename(name);
- if (!exists) {
- exists = !saveFileMan->listSavefiles(wrappedName).empty();
- }
+ gamestate_restore(s, in);
+ delete in;
- // SCI2+ debug mode
- if (DebugMan.isDebugChannelEnabled(kDebugLevelDebugMode)) {
- if (!exists && name == "1.scr") // PQ4
- exists = true;
- if (!exists && name == "18.scr") // QFG4
- exists = true;
- if (!exists && name == "99.scr") // GK1, KQ7
- exists = true;
- if (!exists && name == "classes") // GK2, SQ6, LSL7
- exists = true;
+ if (g_sci->getGameId() == GID_MOTHERGOOSE256) {
+ // WORKAROUND: Mother Goose SCI1/SCI1.1 does some weird things for
+ // saving a previously restored game.
+ // We set the current savedgame-id directly and remove the script
+ // code concerning this via script patch.
+ s->variables[VAR_GLOBAL][0xB3].offset = SAVEGAMEID_OFFICIALRANGE_START + savegameId;
+ }
+ } else {
+ s->r_acc = TRUE_REG;
+ warning("Savegame #%d not found", savegameId);
+ }
}
- // Special case for non-English versions of LSL5: The English version of
- // LSL5 calls kFileIO(), case K_FILEIO_OPEN for reading to check if
- // memory.drv exists (which is where the game's password is stored). If
- // it's not found, it calls kFileIO() again, case K_FILEIO_OPEN for
- // writing and creates a new file. Non-English versions call kFileIO(),
- // case K_FILEIO_FILE_EXISTS instead, and fail if memory.drv can't be
- // found. We create a default memory.drv file with no password, so that
- // the game can continue.
- if (!exists && name == "memory.drv") {
- // Create a new file, and write the bytes for the empty password
- // string inside
- byte defaultContent[] = { 0xE9, 0xE9, 0xEB, 0xE1, 0x0D, 0x0A, 0x31, 0x30, 0x30, 0x30 };
- Common::WriteStream *outFile = saveFileMan->openForSaving(wrappedName);
- for (int i = 0; i < 10; i++)
- outFile->writeByte(defaultContent[i]);
- outFile->finalize();
- exists = !outFile->err(); // check whether we managed to create the file.
- delete outFile;
+ if (!s->r_acc.isNull()) {
+ // no success?
+ if (pausedMusic)
+ g_sci->_soundCmd->pauseAll(false); // unpause music
}
- // Special case for KQ6 Mac: The game checks for two video files to see
- // if they exist before it plays them. Since we support multiple naming
- // schemes for resource fork files, we also need to support that here in
- // case someone has a "HalfDome.bin" file, etc.
- if (!exists && g_sci->getGameId() == GID_KQ6 && g_sci->getPlatform() == Common::kPlatformMacintosh &&
- (name == "HalfDome" || name == "Kq6Movie"))
- exists = Common::MacResManager::exists(name);
+ return s->r_acc;
+}
- debugC(kDebugLevelFile, "kFileIO(fileExists) %s -> %d", name.c_str(), exists);
- return make_reg(0, exists);
+reg_t kGetSaveDir(EngineState *s, int argc, reg_t *argv) {
+#ifdef ENABLE_SCI32
+ // SCI32 uses a parameter here. It is used to modify a string, stored in a
+ // global variable, so that game scripts store the save directory. We
+ // don't really set a save game directory, thus not setting the string to
+ // anything is the correct thing to do here.
+ //if (argc > 0)
+ // warning("kGetSaveDir called with %d parameter(s): %04x:%04x", argc, PRINT_REG(argv[0]));
+#endif
+ return s->_segMan->getSaveDirPtr();
}
-reg_t kFileIORename(EngineState *s, int argc, reg_t *argv) {
- Common::String oldName = s->_segMan->getString(argv[0]);
- Common::String newName = s->_segMan->getString(argv[1]);
+reg_t kCheckSaveGame(EngineState *s, int argc, reg_t *argv) {
+ Common::String game_id = s->_segMan->getString(argv[0]);
+ uint16 virtualId = argv[1].toUint16();
- // SCI1.1 returns 0 on success and a DOS error code on fail. SCI32
- // returns -1 on fail. We just return -1 for all versions.
- if (g_sci->getSaveFileManager()->renameSavefile(oldName, newName))
- return NULL_REG;
- else
- return SIGNAL_REG;
-}
+ debug(3, "kCheckSaveGame(%s, %d)", game_id.c_str(), virtualId);
-#ifdef ENABLE_SCI32
-reg_t kFileIOReadByte(EngineState *s, int argc, reg_t *argv) {
- // Read the byte into the low byte of the accumulator
- FileHandle *f = getFileFromHandle(s, argv[0].toUint16());
- if (!f)
+ Common::Array<SavegameDesc> saves;
+ listSavegames(saves);
+
+ // we allow 0 (happens in QfG2 when trying to restore from an empty saved game list) and return false in that case
+ if (virtualId == 0)
return NULL_REG;
- return make_reg(0, (s->r_acc.toUint16() & 0xff00) | f->_in->readByte());
-}
-reg_t kFileIOWriteByte(EngineState *s, int argc, reg_t *argv) {
- FileHandle *f = getFileFromHandle(s, argv[0].toUint16());
- if (f)
- f->_out->writeByte(argv[1].toUint16() & 0xff);
- return s->r_acc; // FIXME: does this really not return anything?
-}
+ // Find saved-game
+ if ((virtualId < SAVEGAMEID_OFFICIALRANGE_START) || (virtualId > SAVEGAMEID_OFFICIALRANGE_END))
+ error("kCheckSaveGame: called with invalid savegameId");
+ uint savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START;
+ int savegameNr = findSavegame(saves, savegameId);
+ if (savegameNr == -1)
+ return NULL_REG;
-reg_t kFileIOReadWord(EngineState *s, int argc, reg_t *argv) {
- FileHandle *f = getFileFromHandle(s, argv[0].toUint16());
- if (!f)
+ // Check for compatible savegame version
+ int ver = saves[savegameNr].version;
+ if (ver < MINIMUM_SAVEGAME_VERSION || ver > CURRENT_SAVEGAME_VERSION)
return NULL_REG;
- return make_reg(0, f->_in->readUint16LE());
-}
-reg_t kFileIOWriteWord(EngineState *s, int argc, reg_t *argv) {
- FileHandle *f = getFileFromHandle(s, argv[0].toUint16());
- if (f)
- f->_out->writeUint16LE(argv[1].toUint16());
- return s->r_acc; // FIXME: does this really not return anything?
+ // Otherwise we assume the savegame is OK
+ return TRUE_REG;
}
-reg_t kFileIOCreateSaveSlot(EngineState *s, int argc, reg_t *argv) {
- // Used in Shivers when the user enters his name on the guest book
- // in the beginning to start the game.
+reg_t kGetSaveFiles(EngineState *s, int argc, reg_t *argv) {
+ Common::String game_id = s->_segMan->getString(argv[0]);
- // Creates a new save slot, and returns if the operation was successful
+ debug(3, "kGetSaveFiles(%s)", game_id.c_str());
- // Argument 0 denotes the save slot as a negative integer, 2 means "0"
- // Argument 1 is a string, with the file name, obtained from kSave(5).
- // The interpreter checks if it can be written to (by checking for free
- // disk space and write permissions)
+ // Scripts ask for current save files, we can assume that if afterwards they ask us to create a new slot they really
+ // mean new slot instead of overwriting the old one
+ s->_lastSaveVirtualId = SAVEGAMEID_OFFICIALRANGE_START;
- // We don't really use or need any of this...
+ Common::Array<SavegameDesc> saves;
+ listSavegames(saves);
+ uint totalSaves = MIN<uint>(saves.size(), MAX_SAVEGAME_NR);
- uint16 saveSlot = argv[0].toUint16();
- char* fileName = s->_segMan->lookupString(argv[1])->getRawData();
- warning("kFileIOCreateSaveSlot(%d, '%s')", saveSlot, fileName);
+ reg_t *slot = s->_segMan->derefRegPtr(argv[2], totalSaves);
- return TRUE_REG; // slot creation was successful
-}
+ if (!slot) {
+ warning("kGetSaveFiles: %04X:%04X invalid or too small to hold slot data", PRINT_REG(argv[2]));
+ totalSaves = 0;
+ }
-reg_t kCD(EngineState *s, int argc, reg_t *argv) {
- // TODO: Stub
- switch (argv[0].toUint16()) {
- case 0:
- // Return whether the contents of disc argv[1] is available.
- return TRUE_REG;
- default:
- warning("CD(%d)", argv[0].toUint16());
+ const uint bufSize = (totalSaves * SCI_MAX_SAVENAME_LENGTH) + 1;
+ char *saveNames = new char[bufSize];
+ char *saveNamePtr = saveNames;
+
+ for (uint i = 0; i < totalSaves; i++) {
+ *slot++ = make_reg(0, saves[i].id + SAVEGAMEID_OFFICIALRANGE_START); // Store the virtual savegame ID ffs. see above
+ strcpy(saveNamePtr, saves[i].name);
+ saveNamePtr += SCI_MAX_SAVENAME_LENGTH;
}
- return NULL_REG;
+ *saveNamePtr = 0; // Terminate list
+
+ s->_segMan->memcpy(argv[1], (byte *)saveNames, bufSize);
+ delete[] saveNames;
+
+ return make_reg(0, totalSaves);
}
+#ifdef ENABLE_SCI32
+
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
@@ -928,12 +950,6 @@ reg_t kAutoSave(EngineState *s, int argc, reg_t *argv) {
return s->r_acc;
}
-reg_t kSave(EngineState *s, int argc, reg_t *argv) {
- if (!s)
- return make_reg(0, getSciVersion());
- error("not supposed to call this");
-}
-
#endif
} // End of namespace Sci
More information about the Scummvm-git-logs
mailing list