From 93f5e36c9f9a75a2fa939408a76b0a2632c09425 Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Wed, 2 Mar 2016 11:38:01 +0100 Subject: ADL: Add GMM loading and saving --- engines/adl/adl.cpp | 105 +++++++++++++++++++++++++++++++++++++++++++------ engines/adl/adl.h | 12 ++++-- engines/adl/hires1.cpp | 50 ++++++++++++++++------- 3 files changed, 138 insertions(+), 29 deletions(-) (limited to 'engines') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 3c405b67b5..8ffb929e7a 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -43,13 +43,31 @@ AdlEngine::AdlEngine(OSystem *syst, const AdlGameDescription *gd) : Engine(syst), _gameDescription(gd), _display(nullptr), - _isRestarting(false) { + _isRestarting(false), + _isRestoring(false), + _saveVerb(0), + _saveNoun(0), + _restoreVerb(0), + _restoreNoun(0), + _canSaveNow(false), + _canRestoreNow(false) { } AdlEngine::~AdlEngine() { delete _display; } +bool AdlEngine::hasFeature(EngineFeature f) const { + switch (f) { + case kSupportsLoadingDuringRuntime: + case kSupportsSavingDuringRuntime: + case kSupportsRTL: + return true; + default: + return false; + } +} + Common::Error AdlEngine::run() { initGraphics(560, 384, true); @@ -71,6 +89,7 @@ Common::Error AdlEngine::run() { if (!loadState(saveSlot)) error("Failed to load save game from slot %i", saveSlot); _display->setCursorPos(Common::Point(0, 23)); + _isRestoring = true; } else { runIntro(); initState(); @@ -162,6 +181,16 @@ void AdlEngine::readCommands(Common::ReadStream &stream, Commands &commands) { if (stream.eos() || stream.err()) error("Failed to read commands"); + if (command.numCond == 0 && command.script[0] == IDO_ACT_SAVE) { + _saveVerb = command.verb; + _saveNoun = command.noun; + } + + if (command.numCond == 0 && command.script[0] == IDO_ACT_LOAD) { + _restoreVerb = command.verb; + _restoreNoun = command.noun; + } + commands.push_back(command); } } @@ -278,7 +307,15 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { break; case IDO_ACT_RESTART: { _display->printString(_strings[IDI_STR_PLAY_AGAIN]); + + // We allow restoring via GMM here + _canRestoreNow = true; Common::String input = inputString(); + _canRestoreNow = false; + + if (_isRestoring) + return; + if (input.size() == 0 || input[0] != APPLECHAR('N')) { _isRestarting = true; _display->clear(0x00); @@ -341,7 +378,7 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { } } -bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { +bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, bool run) { if (command.room != IDI_NONE && command.room != _state.room) return false; @@ -384,7 +421,8 @@ bool AdlEngine::checkCommand(const Command &command, byte verb, byte noun) { } } - doActions(command, noun, offset); + if (run) + doActions(command, noun, offset); return true; } @@ -395,7 +433,7 @@ bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { Commands::const_iterator cmd; for (cmd = commands.begin(); cmd != commands.end(); ++cmd) - if (checkCommand(*cmd, verb, noun)) + if (matchCommand(*cmd, verb, noun)) return true; return false; @@ -403,14 +441,43 @@ bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) { void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) { Commands::const_iterator cmd; + bool oldIsRestoring = _isRestoring; for (cmd = commands.begin(); cmd != commands.end(); ++cmd) { - checkCommand(*cmd, verb, noun); - if (_isRestarting) - return; + matchCommand(*cmd, verb, noun); + + // We assume no restarts happen in this command group. This + // simplifies enabling GMM savegame loading on the restart + // prompt. + if (_isRestarting || _isRestoring != oldIsRestoring) + error("Unexpected restart action encountered"); } } +bool AdlEngine::canSaveGameStateCurrently() { + if (!_canSaveNow) + return false; + + Commands::const_iterator cmd; + + // Here we check whether or not the game currently accepts the command + // "SAVE GAME". This prevents saving via the GMM in situations where + // it wouldn't otherwise be possible to do so. + for (cmd = _roomCommands.begin(); cmd != _roomCommands.end(); ++cmd) { + if (matchCommand(*cmd, _saveVerb, _saveNoun, false)) { + if (cmd->verb != _saveVerb || cmd->noun != _saveNoun) + return false; + return cmd->numCond == 0 && cmd->script[0] == IDO_ACT_SAVE; + } + } + + return false; +} + +bool AdlEngine::canLoadGameStateCurrently() { + return _canRestoreNow; +} + void AdlEngine::clearScreen() { _display->setMode(Display::kModeMixed); _display->clear(0x00); @@ -654,7 +721,7 @@ Common::String AdlEngine::getLine() { while (1) { Common::String line = inputString(APPLECHAR('?')); - if (shouldQuit()) + if (shouldQuit() || _isRestoring) return ""; if ((byte)line[0] == ('\r' | 0x80)) { @@ -703,7 +770,7 @@ void AdlEngine::getInput(uint &verb, uint &noun) { _display->printString(getEngineString(IDI_STR_ENTER_COMMAND)); Common::String line = getLine(); - if (shouldQuit()) + if (shouldQuit() || _isRestoring) return; uint index = 0; @@ -755,7 +822,7 @@ Common::String AdlEngine::inputString(byte prompt) { while (1) { byte b = inputKey(); - if (g_engine->shouldQuit()) + if (g_engine->shouldQuit() || _isRestoring) return 0; if (b == 0) @@ -805,7 +872,7 @@ byte AdlEngine::inputKey() { _display->showCursor(true); - while (!g_engine->shouldQuit() && key == 0) { + while (!g_engine->shouldQuit() && !_isRestoring && key == 0) { Common::Event event; if (ev->pollEvent(event)) { if (event.type != Common::EVENT_KEYDOWN) @@ -863,6 +930,22 @@ void AdlEngine::delay(uint32 ms) { } } +Common::Error AdlEngine::loadGameState(int slot) { + if (loadState(slot)) { + _isRestoring = true; + return Common::kNoError; + } + + return Common::kUnknownError; +} + +Common::Error AdlEngine::saveGameState(int slot, const Common::String &desc) { + if (saveState(slot, &desc)) + return Common::kNoError; + + return Common::kUnknownError; +} + AdlEngine *AdlEngine::create(GameType type, OSystem *syst, const AdlGameDescription *gd) { switch(type) { case kGameTypeHires1: diff --git a/engines/adl/adl.h b/engines/adl/adl.h index a9ac79d9f0..4d160f08b0 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -168,7 +168,7 @@ public: virtual ~AdlEngine(); const AdlGameDescription *_gameDescription; - uint32 getFeatures() const; + bool hasFeature(EngineFeature f) const; const char *getGameId() const; static AdlEngine *create(GameType type, OSystem *syst, const AdlGameDescription *gd); @@ -184,12 +184,14 @@ protected: virtual void initState() = 0; virtual void restartGame() = 0; virtual uint getEngineMessage(EngineMessage msg) = 0; + bool canSaveGameStateCurrently(); + bool canLoadGameStateCurrently(); Common::String readString(Common::ReadStream &stream, byte until = 0); void printStrings(Common::SeekableReadStream &stream, int count = 1); virtual void printMessage(uint idx, bool wait = true); void wordWrap(Common::String &str); void readCommands(Common::ReadStream &stream, Commands &commands); - bool checkCommand(const Command &command, byte verb, byte noun); + bool matchCommand(const Command &command, byte verb, byte noun, bool run = true); bool doOneCommand(const Commands &commands, byte verb, byte noun); void doAllCommands(const Commands &commands, byte verb, byte noun); void doActions(const Command &command, byte noun, byte offset); @@ -213,10 +215,14 @@ protected: Common::String inputString(byte prompt = 0); void delay(uint32 ms); byte inputKey(); + Common::Error loadGameState(int slot); + Common::Error saveGameState(int slot, const Common::String &desc); Display *_display; Parser *_parser; - bool _isRestarting; + bool _isRestarting, _isRestoring; + byte _saveVerb, _saveNoun, _restoreVerb, _restoreNoun; + bool _canSaveNow, _canRestoreNow; Common::Array _strings; Common::Array _messages; diff --git a/engines/adl/hires1.cpp b/engines/adl/hires1.cpp index 591216698b..db69a2d863 100644 --- a/engines/adl/hires1.cpp +++ b/engines/adl/hires1.cpp @@ -371,29 +371,49 @@ void HiRes1Engine::runGame() { printASCIIString("\r\r\r\r\r"); while (1) { - if (_isRestarting) - _isRestarting = false; - uint verb = 0, noun = 0; - clearScreen(); - showRoom(); - getInput(verb, noun); - if (!doOneCommand(_roomCommands, verb, noun)) - printMessage(37); + // When restoring from the launcher, we don't read + // input on the first iteration. This is needed to + // ensure that restoring from the launcher and + // restoring in-game brings us to the same game state. + // (Also see comment below.) + if (!_isRestoring) { + clearScreen(); + showRoom(); - if (_isRestarting) - continue; + _canSaveNow = _canRestoreNow = true; + getInput(verb, noun); + _canSaveNow = _canRestoreNow = false; - doAllCommands(_globalCommands, verb, noun); + if (shouldQuit()) + return; + + if (!doOneCommand(_roomCommands, verb, noun)) + printMessage(IDI_HR1_MSG_DONT_UNDERSTAND); + } - if (_isRestarting) + if (_isRestoring) { + // We restored from the GMM or launcher. As restoring + // with "RESTORE GAME" does not end command processing, + // we don't break it off here either. This essentially + // means that restoring a game will always run through + // the global commands and increase the move counter + // before the first user input. + printASCIIString("\r"); + _isRestoring = false; + verb = _restoreVerb; + noun = _restoreNoun; + } + + // Restarting does end command processing + if (_isRestarting) { + _isRestarting = false; continue; + } + doAllCommands(_globalCommands, verb, noun); _state.moves++; - - if (shouldQuit()) - return; } } -- cgit v1.2.3