From 2629269212b9a5946e11cadf6abead7856b5fe58 Mon Sep 17 00:00:00 2001 From: Colin Snover Date: Thu, 15 Sep 2016 21:08:44 -0500 Subject: SCI32: Emulate Shivers 1 game score metadata --- engines/sci/engine/file.cpp | 1 + engines/sci/engine/file.h | 4 +++ engines/sci/engine/kfile.cpp | 60 ++++++++++++++++++----------------------- engines/sci/engine/savegame.cpp | 11 ++++++++ engines/sci/engine/savegame.h | 6 ++++- engines/sci/engine/vm.h | 4 ++- 6 files changed, 50 insertions(+), 36 deletions(-) diff --git a/engines/sci/engine/file.cpp b/engines/sci/engine/file.cpp index 74cd812f89..efeae63a09 100644 --- a/engines/sci/engine/file.cpp +++ b/engines/sci/engine/file.cpp @@ -335,6 +335,7 @@ bool fillSavegameDesc(const Common::String &filename, SavegameDesc *desc) { desc->time = meta.saveTime; desc->version = meta.version; desc->gameVersion = meta.gameVersion; + desc->score = meta.score; if (meta.name.lastChar() == '\n') meta.name.deleteLastChar(); diff --git a/engines/sci/engine/file.h b/engines/sci/engine/file.h index 88d483bab7..27250d3da9 100644 --- a/engines/sci/engine/file.h +++ b/engines/sci/engine/file.h @@ -59,6 +59,10 @@ struct SavegameDesc { int version; char name[SCI_MAX_SAVENAME_LENGTH]; Common::String gameVersion; +#ifdef ENABLE_SCI32 + // Used by Shivers 1 + uint32 score; +#endif }; class FileHandle { diff --git a/engines/sci/engine/kfile.cpp b/engines/sci/engine/kfile.cpp index b6fbd45562..33ddd1f6f8 100644 --- a/engines/sci/engine/kfile.cpp +++ b/engines/sci/engine/kfile.cpp @@ -328,50 +328,42 @@ reg_t kFileIOOpen(EngineState *s, int argc, reg_t *argv) { } #ifdef ENABLE_SCI32 - // 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. - // 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. - // 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. + // Shivers stores the name and score of save games in separate %d.SG files, + // which are used by the save/load screen 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 + // Suppress creation of the SG file, since it is not necessary 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 saves; - listSavegames(saves); - int savegameNr = findSavegame(saves, slotNumber); - assert(savegameNr >= 0); + int saveNo; + sscanf(name.c_str(), "%d.SG", &saveNo); + + SavegameDesc save; + fillSavegameDesc(g_sci->getSavegameName(saveNo), &save); + Common::String score; + const uint16 lowScore = save.score & 0xFFFF; + const uint16 highScore = save.score >> 16; + + if (!highScore) { + score = Common::String::format("%u", lowScore); + } else { + score = Common::String::format("%u%03u", highScore, lowScore); + } - int size = strlen(saves[savegameNr].name) + 2; - char *buf = (char *)malloc(size); - strcpy(buf, saves[savegameNr].name); - buf[size - 1] = 0; // Spot description (empty) + const uint nameLength = strlen(save.name); + const uint size = nameLength + /* \r\n */ 2 + score.size(); + char *buffer = (char *)malloc(size); + memcpy(buffer, save.name, nameLength); + buffer[nameLength] = '\r'; + buffer[nameLength + 1] = '\n'; + memcpy(buffer + nameLength + 2, score.c_str(), score.size()); - uint handle = findFreeFileHandle(s); + const uint handle = findFreeFileHandle(s); - s->_fileHandles[handle]._in = new Common::MemoryReadStream((byte *)buf, size, DisposeAfterUse::YES); + s->_fileHandles[handle]._in = new Common::MemoryReadStream((byte *)buffer, size, DisposeAfterUse::YES); s->_fileHandles[handle]._out = nullptr; s->_fileHandles[handle]._name = ""; diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp index 5a73526fb7..74493fcfde 100644 --- a/engines/sci/engine/savegame.cpp +++ b/engines/sci/engine/savegame.cpp @@ -330,6 +330,17 @@ static void sync_SavegameMetadata(Common::Serializer &s, SavegameMetadata &obj) } s.syncAsUint32LE(obj.playTime); } + + if (s.getVersion() >= 38) { + if (s.isSaving()) { + obj.score = g_sci->getEngineState()->variables[VAR_GLOBAL][kScore].toUint16(); + if (g_sci->getGameId() == GID_SHIVERS) { + obj.score |= g_sci->getEngineState()->variables[VAR_GLOBAL][kShivers1Score].toUint16() << 16; + } + } + + s.syncAsUint32LE(obj.score); + } } void EngineState::saveLoadWithSerializer(Common::Serializer &s) { diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h index 5995de7818..01f92ed342 100644 --- a/engines/sci/engine/savegame.h +++ b/engines/sci/engine/savegame.h @@ -37,7 +37,7 @@ struct EngineState; * * Version - new/changed feature * ============================= - * 38 - SCI32 cursor, accurate SCI32 arrays/strings + * 38 - SCI32 cursor, accurate SCI32 arrays/strings, score metadata * 37 - Segment entry data changed to pointers * 36 - SCI32 bitmap segment * 35 - SCI32 remap @@ -77,6 +77,10 @@ struct SavegameMetadata { uint32 playTime; uint16 gameObjectOffset; uint16 script0Size; +#ifdef ENABLE_SCI32 + // Used by Shivers 1 + uint32 score; +#endif }; /** diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index e127706d58..31433555e4 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -147,8 +147,10 @@ enum GlobalVar { kCurrentRoomNo = 11, kPreviousRoomNo = 12, kNewRoomNo = 13, + kScore = 15, kFastCast = 84, // SCI16 - kMessageType = 90 + kMessageType = 90, + kShivers1Score = 349 }; /** Number of kernel calls in between gcs; should be < 50000 */ -- cgit v1.2.3