Skip to content

Commit

Permalink
SCI: Fix the loading screen and the loading functionality in Shivers
Browse files Browse the repository at this point in the history
Shivers uses extra special hardcoded save files together with the normal
ones that are used to store slot names and spot descriptions. The scheme
is a bit odd, and since the names of the extra save files are hardcoded,
this scheme is problematic to use. We skip the creation of these files
altogether and use virtual files instead, which means that the
(broken) spot descriptions won't be visible next to each save
description. This isn't a major issue for now, and it's left as a future
TODO to implement this feature in a cleaner way, and not with extra save
files. This scheme fixes the slot descriptions in the loading screen.
Also, kCD(1) has been implemented, which fixes loading of the save
states themselves
  • Loading branch information
bluegr committed Jun 13, 2012
1 parent 179427c commit e4f08a4
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 16 deletions.
8 changes: 7 additions & 1 deletion engines/sci/engine/file.cpp
Expand Up @@ -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();

Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions engines/sci/engine/file.h
Expand Up @@ -115,6 +115,7 @@ class DirSeeker {
class VirtualIndexFile {
public:
VirtualIndexFile(Common::String fileName);
VirtualIndexFile(uint32 initialSize);
~VirtualIndexFile();

uint32 read(char *buffer, uint32 size);
Expand Down
85 changes: 70 additions & 15 deletions engines/sci/engine/kfile.cpp
Expand Up @@ -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());
}
Expand All @@ -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();
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit e4f08a4

Please sign in to comment.