diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/sci/engine/file.cpp | 8 | ||||
-rw-r--r-- | engines/sci/engine/file.h | 1 | ||||
-rw-r--r-- | engines/sci/engine/kfile.cpp | 85 |
3 files changed, 78 insertions, 16 deletions
diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp index 66f54d67df..3470d23fe2 100644 --- a/engines/sci/engine/file.cpp +++ b/engines/sci/engine/file.cpp @@ -346,6 +346,12 @@ VirtualIndexFile::VirtualIndexFile(Common::String fileName) : _fileName(fileName delete inFile; } +VirtualIndexFile::VirtualIndexFile(uint32 initialSize) : _changed(false) { + _bufferSize = initialSize; + _buffer = new char[_bufferSize]; + _ptr = _buffer; +} + VirtualIndexFile::~VirtualIndexFile() { close(); @@ -430,7 +436,7 @@ bool VirtualIndexFile::seek(int32 offset, int whence) { } void VirtualIndexFile::close() { - if (_changed) { + if (_changed && !_fileName.empty()) { Common::WriteStream *outFile = g_sci->getSaveFileManager()->openForSaving(_fileName); outFile->write(_buffer, _bufferSize); delete outFile; diff --git a/engines/sci/engine/file.h b/engines/sci/engine/file.h index 896dcd2a42..1c8e302d15 100644 --- a/engines/sci/engine/file.h +++ b/engines/sci/engine/file.h @@ -115,6 +115,7 @@ private: class VirtualIndexFile { public: VirtualIndexFile(Common::String fileName); + VirtualIndexFile(uint32 initialSize); ~VirtualIndexFile(); uint32 read(char *buffer, uint32 size); diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index 445a019368..7a2f161829 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -199,6 +199,9 @@ reg_t kCD(EngineState *s, int argc, reg_t *argv) { case 0: // Return whether the contents of disc argv[1] is available. return TRUE_REG; + case 1: + // Return the current CD number + return make_reg(0, 1); default: warning("CD(%d)", argv[0].toUint16()); } @@ -219,21 +222,6 @@ reg_t kFileIO(EngineState *s, int argc, reg_t *argv) { reg_t kFileIOOpen(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(); @@ -261,6 +249,73 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) { } debugC(kDebugLevelFile, "kFileIO(open): %s, 0x%x", name.c_str(), mode); +#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); + } + } + } + + // Shivers is trying to store savegame descriptions and current spots in + // separate .SG files, which are hardcoded in the scripts. + // Essentially, there is a normal save file, created by the executable + // and an extra hardcoded save file, created by the game scripts, probably + // because they didn't want to modify the save/load code to add the extra + // information. + // Each slot in the book then has two strings, the save description and a + // description of the current spot that the player is at. Currently, the + // spot strings are always empty (probably related to the unimplemented + // kString subop 14, which gets called right before this call). + // For now, we don't allow the creation of these files, which means that + // all the spot descriptions next to each slot description will be empty + // (they are empty anyway). Until a viable solution is found to handle these + // extra files and until the spot description strings are initialized + // correctly, we resort to virtual files in order to make the load screen + // useable. Without this code it is unusable, as the extra information is + // always saved to 0.SG for some reason, but on restore the correct file is + // used. Perhaps the virtual ID is not taken into account when saving. + // + // Future TODO: maintain spot descriptions and show them too, ideally without + // having to return to this logic of extra hardcoded files. + if (g_sci->getGameId() == GID_SHIVERS && name.hasSuffix(".SG")) { + if (mode == _K_FILE_MODE_OPEN_OR_CREATE || mode == _K_FILE_MODE_CREATE) { + // Game scripts are trying to create a file with the save + // description, stop them here + debugC(kDebugLevelFile, "Not creating unused file %s", name.c_str()); + return SIGNAL_REG; + } else if (mode == _K_FILE_MODE_OPEN_OR_FAIL) { + // Create a virtual file containing the save game description + // and slot number, as the game scripts expect. + int slotNumber; + sscanf(name.c_str(), "%d.SG", &slotNumber); + + Common::Array<SavegameDesc> saves; + listSavegames(saves); + int savegameNr = findSavegame(saves, slotNumber - SAVEGAMEID_OFFICIALRANGE_START); + + if (!s->_virtualIndexFile) { + // Make the virtual file buffer big enough to avoid having it grow dynamically. + // 50 bytes should be more than enough. + s->_virtualIndexFile = new VirtualIndexFile(50); + } + + s->_virtualIndexFile->seek(0, SEEK_SET); + s->_virtualIndexFile->write(saves[savegameNr].name, strlen(saves[savegameNr].name)); + s->_virtualIndexFile->write("\0", 1); + s->_virtualIndexFile->write("\0", 1); // Spot description (empty) + s->_virtualIndexFile->seek(0, SEEK_SET); + return make_reg(0, VIRTUALFILE_HANDLE); + } + } +#endif + // 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 |