From b05a16a0ad0dcc2881aeda81e0d1a84a752eccab Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 17 Nov 2018 16:52:47 -0800 Subject: GLK: Centralizing more of the savegame code in GlkEngine --- engines/glk/frotz/frotz.cpp | 169 ++++++++++++++++++++++++- engines/glk/frotz/frotz.h | 8 +- engines/glk/frotz/processor_streams.cpp | 211 +++----------------------------- engines/glk/glk.cpp | 52 ++++++++ engines/glk/glk.h | 35 +++++- engines/glk/scott/scott.cpp | 45 +------ engines/glk/scott/scott.h | 10 +- engines/glk/streams.h | 2 +- 8 files changed, 281 insertions(+), 251 deletions(-) diff --git a/engines/glk/frotz/frotz.cpp b/engines/glk/frotz/frotz.cpp index a6371b6ef3..344aa92b12 100644 --- a/engines/glk/frotz/frotz.cpp +++ b/engines/glk/frotz/frotz.cpp @@ -84,13 +84,174 @@ void Frotz::initialize() { z_restart(); } -Common::Error Frotz::loadGameState(int slot) { - // TODO +Common::Error Frotz::saveGameData(strid_t file) { +#ifdef TODO + long pc; + zword addr; + zword nsp, nfp; + int skip; + int i; + + /* Open game file */ + + if ((gfp = frotzopenprompt(FILE_SAVE)) == nullptr) + goto finished; + + if (_save_quetzal) { + success = save_quetzal(gfp, story_fp, blorb_ofs); + } + else { + /* Write game file */ + + fputc((int)hi(h_release), gfp); + fputc((int)lo(h_release), gfp); + fputc((int)hi(h_checksum), gfp); + fputc((int)lo(h_checksum), gfp); + + GET_PC(pc) + + fputc((int)(pc >> 16) & 0xff, gfp); + fputc((int)(pc >> 8) & 0xff, gfp); + fputc((int)(pc)& 0xff, gfp); + + nsp = (int)(_sp - _stack); + nfp = (int)(_fp - _stack); + + fputc((int)hi(nsp), gfp); + fputc((int)lo(nsp), gfp); + fputc((int)hi(nfp), gfp); + fputc((int)lo(nfp), gfp); + + for (i = nsp; i < STACK_SIZE; i++) { + fputc((int)hi(_stack[i]), gfp); + fputc((int)lo(_stack[i]), gfp); + } + + fseek(story_fp, blorb_ofs, SEEK_SET); + + for (addr = 0, skip = 0; addr < h_dynamic_size; addr++) + if (zmp[addr] != fgetc(story_fp) || skip == 255 || addr + 1 == h_dynamic_size) { + fputc(skip, gfp); + fputc(zmp[addr], gfp); + skip = 0; + } + else skip++; + } + + /* Close game file and check for errors */ + + if (fclose(gfp) == EOF || ferror(story_fp)) { + print_string("Error writing save file\n"); + goto finished; + } + + /* Success */ + + success = 1; +#endif return Common::kNoError; } -Common::Error Frotz::saveGameState(int slot, const Common::String &desc) { - // TODO +Common::Error Frotz::loadGameData(strid_t file) { +#ifdef TODO + long pc; + zword release; + zword addr; + int i; + + /* Open game file */ + + if ((gfp = frotzopenprompt(FILE_RESTORE)) == nullptr) + goto finished; + + if (_save_quetzal) { + success = restore_quetzal (gfp, story_fp, blorb_ofs); + + } else { + /* Load game file */ + + release = (unsigned) fgetc (gfp) << 8; + release |= fgetc (gfp); + + () fgetc (gfp); + () fgetc (gfp); + + /* Check the release number */ + + if (release == h_release) { + + pc = (long) fgetc (gfp) << 16; + pc |= (unsigned) fgetc (gfp) << 8; + pc |= fgetc (gfp); + + SET_PC (pc); + + _sp = _stack + (fgetc (gfp) << 8); + _sp += fgetc (gfp); + _fp = _stack + (fgetc (gfp) << 8); + _fp += fgetc (gfp); + + for (i = (int) (_sp - _stack); i < STACK_SIZE; i++) { + _stack[i] = (unsigned) fgetc (gfp) << 8; + _stack[i] |= fgetc (gfp); + } + + fseek (story_fp, blorb_ofs, SEEK_SET); + + for (addr = 0; addr < h_dynamic_size; addr++) { + int skip = fgetc (gfp); + for (i = 0; i < skip; i++) + zmp[addr++] = fgetc (story_fp); + zmp[addr] = fgetc (gfp); + () fgetc (story_fp); + } + + /* Check for errors */ + + if (ferror (gfp) || ferror (story_fp) || addr != h_dynamic_size) + success = -1; + else + + /* Success */ + + success = 2; + + } else print_string ("Invalid save file\n"); + } + + if ((short) success >= 0) { + + /* Close game file */ + + fclose (gfp); + + if ((short) success > 0) { + zbyte old_screen_rows; + zbyte old_screen_cols; + + /* In V3, reset the upper window. */ + if (h_version == V3) + split_window (0); + + LOW_BYTE (H_SCREEN_ROWS, old_screen_rows); + LOW_BYTE (H_SCREEN_COLS, old_screen_cols); + + /* Reload cached header fields. */ + restart_header (); + + /* + * Since QUETZAL files may be saved on many different machines, + * the screen sizes may vary a lot. Erasing the status window + * seems to cover up most of the resulting badness. + */ + if (h_version > V3 && h_version != V6 + && (h_screen_rows != old_screen_rows + || h_screen_cols != old_screen_cols)) + erase_window (1); + } + } else + os_fatal ("Error reading save file"); +#endif return Common::kNoError; } diff --git a/engines/glk/frotz/frotz.h b/engines/glk/frotz/frotz.h index e45abc07a8..00aeb599fb 100644 --- a/engines/glk/frotz/frotz.h +++ b/engines/glk/frotz/frotz.h @@ -54,14 +54,14 @@ public: virtual void runGame(Common::SeekableReadStream *gameFile) override; /** - * Load a savegame + * Load a savegame from the passed stream */ - virtual Common::Error loadGameState(int slot) override; + virtual Common::Error loadGameData(strid_t file) override; /** - * Save the game + * Save the game to the passed stream */ - virtual Common::Error saveGameState(int slot, const Common::String &desc) override; + virtual Common::Error saveGameData(strid_t file) override; }; extern Frotz *g_vm; diff --git a/engines/glk/frotz/processor_streams.cpp b/engines/glk/frotz/processor_streams.cpp index 091165ed7c..cbef38aaa6 100644 --- a/engines/glk/frotz/processor_streams.cpp +++ b/engines/glk/frotz/processor_streams.cpp @@ -545,227 +545,54 @@ void Processor::z_restart() { } void Processor::z_save() { -#ifdef TODO bool success = false; if (zargc != 0) { // Open auxilary file frefid_t ref = glk_fileref_create_by_prompt(fileusage_Data | fileusage_BinaryMode, filemode_Write, 0); - if (ref == nullptr) - goto finished; + if (ref != nullptr) { + // Write data + strid_t f = glk_stream_open_file(ref, filemode_Write); - // Write data - strid_t f = glk_stream_open_file(ref, filemode_Write); + glk_put_buffer_stream(f, (const char *)zmp + zargs[0], zargs[1]); - glk_put_buffer_stream(f, (const char *)zmp + zargs[0], zargs[1]); - - glk_stream_close(f); - - } else { - long pc; - zword addr; - zword nsp, nfp; - int skip; - int i; - - /* Open game file */ - - if ((gfp = frotzopenprompt (FILE_SAVE)) == nullptr) - goto finished; - - if (_save_quetzal) { - success = save_quetzal (gfp, story_fp, blorb_ofs); - } else { - /* Write game file */ - - fputc ((int) hi (h_release), gfp); - fputc ((int) lo (h_release), gfp); - fputc ((int) hi (h_checksum), gfp); - fputc ((int) lo (h_checksum), gfp); - - GET_PC (pc) - - fputc ((int) (pc >> 16) & 0xff, gfp); - fputc ((int) (pc >> 8) & 0xff, gfp); - fputc ((int) (pc) & 0xff, gfp); - - nsp = (int) (_sp - _stack); - nfp = (int) (_fp - _stack); - - fputc ((int) hi (nsp), gfp); - fputc ((int) lo (nsp), gfp); - fputc ((int) hi (nfp), gfp); - fputc ((int) lo (nfp), gfp); - - for (i = nsp; i < STACK_SIZE; i++) { - fputc ((int) hi (_stack[i]), gfp); - fputc ((int) lo (_stack[i]), gfp); - } - - fseek (story_fp, blorb_ofs, SEEK_SET); - - for (addr = 0, skip = 0; addr < h_dynamic_size; addr++) - if (zmp[addr] != fgetc (story_fp) || skip == 255 || addr + 1 == h_dynamic_size) { - fputc (skip, gfp); - fputc (zmp[addr], gfp); - skip = 0; - } else skip++; + glk_stream_close(f); + success = true; } - - /* Close game file and check for errors */ - - if (fclose (gfp) == EOF || ferror (story_fp)) { - print_string ("Error writing save file\n"); - goto finished; - } - - /* Success */ - - success = 1; - + } else { + success = saveGame().getCode() == Common::kNoError; } -finished: - if (h_version <= V3) branch (success); else store (success); -#endif } void Processor::z_restore() { -#ifdef TODO - FILE *gfp; - - zword success = 0; + bool success = false; if (zargc != 0) { + frefid_t ref = glk_fileref_create_by_prompt(fileusage_Data | fileusage_BinaryMode, + filemode_Read, 0); + if (ref != nullptr) { + // Write data + strid_t f = glk_stream_open_file(ref, filemode_Read); - /* Get the file name */ - - /* Open auxilary file */ - - if ((gfp = frotzopenprompt(FILE_LOAD_AUX)) == nullptr) - goto finished; - - /* Load auxilary file */ - - success = fread (zmp + zargs[0], 1, zargs[1], gfp); - - /* Close auxilary file */ - - fclose (gfp); - - } else { - - long pc; - zword release; - zword addr; - int i; - - /* Open game file */ - - if ((gfp = frotzopenprompt(FILE_RESTORE)) == nullptr) - goto finished; - - if (_save_quetzal) { - success = restore_quetzal (gfp, story_fp, blorb_ofs); - - } else { - /* Load game file */ - - release = (unsigned) fgetc (gfp) << 8; - release |= fgetc (gfp); - - () fgetc (gfp); - () fgetc (gfp); - - /* Check the release number */ - - if (release == h_release) { - - pc = (long) fgetc (gfp) << 16; - pc |= (unsigned) fgetc (gfp) << 8; - pc |= fgetc (gfp); - - SET_PC (pc); - - _sp = _stack + (fgetc (gfp) << 8); - _sp += fgetc (gfp); - _fp = _stack + (fgetc (gfp) << 8); - _fp += fgetc (gfp); - - for (i = (int) (_sp - _stack); i < STACK_SIZE; i++) { - _stack[i] = (unsigned) fgetc (gfp) << 8; - _stack[i] |= fgetc (gfp); - } - - fseek (story_fp, blorb_ofs, SEEK_SET); - - for (addr = 0; addr < h_dynamic_size; addr++) { - int skip = fgetc (gfp); - for (i = 0; i < skip; i++) - zmp[addr++] = fgetc (story_fp); - zmp[addr] = fgetc (gfp); - () fgetc (story_fp); - } - - /* Check for errors */ - - if (ferror (gfp) || ferror (story_fp) || addr != h_dynamic_size) - success = -1; - else - - /* Success */ - - success = 2; + glk_get_buffer_stream(f, (char *)zmp + zargs[0], zargs[1]); - } else print_string ("Invalid save file\n"); + glk_stream_close(f); + success = true; } - - if ((short) success >= 0) { - - /* Close game file */ - - fclose (gfp); - - if ((short) success > 0) { - zbyte old_screen_rows; - zbyte old_screen_cols; - - /* In V3, reset the upper window. */ - if (h_version == V3) - split_window (0); - - LOW_BYTE (H_SCREEN_ROWS, old_screen_rows); - LOW_BYTE (H_SCREEN_COLS, old_screen_cols); - - /* Reload cached header fields. */ - restart_header (); - - /* - * Since QUETZAL files may be saved on many different machines, - * the screen sizes may vary a lot. Erasing the status window - * seems to cover up most of the resulting badness. - */ - if (h_version > V3 && h_version != V6 - && (h_screen_rows != old_screen_rows - || h_screen_cols != old_screen_cols)) - erase_window (1); - } - } else - os_fatal ("Error reading save file"); + } else { + success = loadGame().getCode() == Common::kNoError; } -finished: - if (h_version <= V3) branch (success); else store (success); -#endif } void Processor::z_verify() { diff --git a/engines/glk/glk.cpp b/engines/glk/glk.cpp index 987fbc894a..a3cd167ae7 100644 --- a/engines/glk/glk.cpp +++ b/engines/glk/glk.cpp @@ -117,4 +117,56 @@ void GlkEngine::GUIError(const char *msg, ...) { GUIErrorMessage(buffer); } +Common::Error GlkEngine::loadGame() { + frefid_t ref = _streams->createByPrompt(fileusage_BinaryMode | fileusage_SavedGame, + filemode_Read, 0); + if (ref == nullptr) + return Common::kReadingFailed; + + int slotNumber = ref->_slotNumber; + _streams->deleteRef(ref); + + return loadGameState(slotNumber); +} + +Common::Error GlkEngine::saveGame() { + frefid_t ref = _streams->createByPrompt(fileusage_BinaryMode | fileusage_SavedGame, + filemode_Write, 0); + if (ref == nullptr) + return Common::kWritingFailed; + + int slot = ref->_slotNumber; + Common::String desc = ref->_description; + _streams->deleteRef(ref); + + return saveGameState(slot, desc); +} + +Common::Error GlkEngine::loadGameState(int slot) { + FileReference ref(slot, "", fileusage_SavedGame | fileusage_TextMode); + + strid_t file = _streams->openFileStream(&ref, filemode_Read); + if (file == nullptr) + return Common::kReadingFailed; + + Common::Error result = saveGameData(file); + + file->close(); + return result; +} + +Common::Error GlkEngine::saveGameState(int slot, const Common::String &desc) { + Common::String msg; + FileReference ref(slot, desc, fileusage_BinaryMode | fileusage_SavedGame); + + strid_t file = _streams->openFileStream(&ref, filemode_Write); + if (file == nullptr) + return Common::kWritingFailed; + + Common::Error result = loadGameData(file); + + file->close(); + return result; +} + } // End of namespace Glk diff --git a/engines/glk/glk.h b/engines/glk/glk.h index 8dce78f085..f925fd0cc3 100644 --- a/engines/glk/glk.h +++ b/engines/glk/glk.h @@ -30,6 +30,7 @@ #include "engines/advancedDetector.h" #include "engines/engine.h" #include "glk/glk_types.h" +#include "glk/streams.h" namespace Glk { @@ -180,6 +181,11 @@ public: return _targetName; } + /** + * Display a message in a GUI dialog + */ + void GUIError(const char *msg, ...); + /** * Return the filename for a given save slot */ @@ -188,9 +194,34 @@ public: } /** - * Display a message in a GUI dialog + * Prompt the user for a savegame to load, and then load it */ - void GUIError(const char *msg, ...); + Common::Error loadGame(); + + /** + * Prompt the user to save their game, and then save it + */ + Common::Error saveGame(); + + /** + * Load a savegame from a given slot + */ + virtual Common::Error loadGameState(int slot) override; + + /** + * Save the game to a given slot + */ + virtual Common::Error saveGameState(int slot, const Common::String &desc) override; + + /** + * Load a savegame from the passed file + */ + virtual Common::Error loadGameData(strid_t file) = 0; + + /** + * Save the game to the passed file + */ + virtual Common::Error saveGameData(strid_t file) = 0; }; extern GlkEngine *g_vm; diff --git a/engines/glk/scott/scott.cpp b/engines/glk/scott/scott.cpp index fed31f014e..cbc5886130 100644 --- a/engines/glk/scott/scott.cpp +++ b/engines/glk/scott/scott.cpp @@ -309,7 +309,7 @@ void Scott::loadDatabase(Common::SeekableReadStream *f, bool loud) { if (loud) debug("Reading %d actions.", na); - for (uint idx = 0; idx < na + 1; ++idx) { + for (int idx = 0; idx < na + 1; ++idx) { Action &a = _actions[idx]; readInts(f, 8, &a._vocab, &a._condition[0], &a._condition[1], &a._condition[2], @@ -503,26 +503,8 @@ void Scott::lineInput(char *buf, size_t n) { buf[ev.val1] = 0; } -void Scott::saveGame(void) { - frefid_t ref = glk_fileref_create_by_prompt(fileusage_TextMode | fileusage_SavedGame, - filemode_Write, 0); - if (ref == nullptr) - return; - - int slot = ref->_slotNumber; - Common::String desc = ref->_description; - glk_fileref_destroy(ref); - - saveGameState(slot, desc); -} - -Common::Error Scott::saveGameState(int slot, const Common::String &desc) { +Common::Error Scott::saveGameData(strid_t file) { Common::String msg; - FileReference ref(slot, desc, fileusage_TextMode | fileusage_SavedGame); - - strid_t file = glk_stream_open_file(&ref, filemode_Write, 0); - if (file == nullptr) - return Common::kWritingFailed; for (int ct = 0; ct < 16; ct++) { msg = Common::String::format("%d %d\n", _counters[ct], _roomSaved[ct]); @@ -539,37 +521,16 @@ Common::Error Scott::saveGameState(int slot, const Common::String &desc) { glk_put_string_stream(file, msg.c_str()); } - glk_stream_close(file, nullptr); output("Saved.\n"); - return Common::kNoError; } -void Scott::loadGame(void) { - frefid_t ref = glk_fileref_create_by_prompt(fileusage_TextMode | fileusage_SavedGame, - filemode_Read, 0); - if (ref == nullptr) - return; - - int slotNumber = ref->_slotNumber; - glk_fileref_destroy(ref); - - loadGameState(slotNumber); -} - -Common::Error Scott::loadGameState(int slot) { - strid_t file; +Common::Error Scott::loadGameData(strid_t file) { char buf[128]; int ct = 0; short lo; short darkFlag; - FileReference ref(slot, "", fileusage_SavedGame | fileusage_TextMode); - - file = glk_stream_open_file(&ref, filemode_Read, 0); - if (file == nullptr) - return Common::kReadingFailed; - for (ct = 0; ct < 16; ct++) { glk_get_line_stream(file, buf, sizeof buf); sscanf(buf, "%d %d", &_counters[ct], &_roomSaved[ct]); diff --git a/engines/glk/scott/scott.h b/engines/glk/scott/scott.h index 4741892687..a22f88bf94 100644 --- a/engines/glk/scott/scott.h +++ b/engines/glk/scott/scott.h @@ -153,8 +153,6 @@ private: void look(void); int whichWord(const char *word, const Common::StringArray &list); void lineInput(char *buf, size_t n); - void saveGame(void); - void loadGame(void); int getInput(int *vb, int *no); int performLine(int ct); int performActions(int vb, int no); @@ -174,14 +172,14 @@ public: virtual void runGame(Common::SeekableReadStream *gameFile) override; /** - * Load a savegame + * Load a savegame from the passed stream */ - virtual Common::Error loadGameState(int slot) override; + virtual Common::Error loadGameData(strid_t file) override; /** - * Save the game + * Save the game to the passed stream */ - virtual Common::Error saveGameState(int slot, const Common::String &desc) override; + virtual Common::Error saveGameData(strid_t file) override; }; } // End of namespace Scott diff --git a/engines/glk/streams.h b/engines/glk/streams.h index 22a0a59602..3150ce9c38 100644 --- a/engines/glk/streams.h +++ b/engines/glk/streams.h @@ -563,7 +563,7 @@ public: /** * Open a file stream */ - FileStream *openFileStream(frefid_t fref, glui32 fmode, glui32 rock, bool unicode); + FileStream *openFileStream(frefid_t fref, glui32 fmode, glui32 rock = 0, bool unicode = false); /** * Open a window stream -- cgit v1.2.3