From e3d13d06ee32fa1cb3663c0e9c46f356f08b5c9b Mon Sep 17 00:00:00 2001 From: Walter van Niftrik Date: Mon, 29 Feb 2016 00:32:47 +0100 Subject: ADL: Add save game support --- engines/adl/adl.cpp | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++- engines/adl/adl.h | 6 +++ engines/adl/hires1.h | 1 + 3 files changed, 123 insertions(+), 2 deletions(-) (limited to 'engines/adl') diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp index 24a18d62ac..9c86b3a022 100644 --- a/engines/adl/adl.cpp +++ b/engines/adl/adl.cpp @@ -28,6 +28,7 @@ #include "common/system.h" #include "common/events.h" #include "common/stream.h" +#include "common/savefile.h" #include "engines/util.h" @@ -261,18 +262,21 @@ void AdlEngine::doActions(const Command &command, byte noun, byte offset) { ++offset; break; case IDO_ACT_SAVE: - warning("Save game not implemented"); + saveState(0); ++offset; break; case IDO_ACT_LOAD: - warning("Load game not implemented"); + loadState(0); ++offset; + // Original engine continues processing here (?) break; case IDO_ACT_RESTART: { _display->printString(_strings[IDI_STR_PLAY_AGAIN]); Common::String input = _display->inputString(); if (input.size() == 0 || input[0] != APPLECHAR('N')) { _isRestarting = true; + _display->clear(0x00); + _display->decodeFrameBuffer(); restartGame(); return; } @@ -451,6 +455,116 @@ void AdlEngine::showRoom() { printMessage(_state.rooms[_state.room].description, false); } +bool AdlEngine::saveState(uint slot) { + Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot); + Common::OutSaveFile *outFile = getSaveFileManager()->openForSaving(fileName); + + if (!outFile) { + warning("Failed to open file '%s'", fileName.c_str()); + return false; + } + + outFile->writeUint32BE(getTag()); + outFile->writeByte(SAVEGAME_VERSION); + + outFile->writeByte(_state.room); + outFile->writeByte(_state.moves); + outFile->writeByte(_state.isDark); + + outFile->writeUint32BE(_state.rooms.size()); + for (uint i = 0; i < _state.rooms.size(); ++i) { + outFile->writeByte(_state.rooms[i].picture); + outFile->writeByte(_state.rooms[i].curPicture); + } + + outFile->writeUint32BE(_state.items.size()); + for (uint i = 0; i < _state.items.size(); ++i) { + outFile->writeByte(_state.items[i].room); + outFile->writeByte(_state.items[i].picture); + outFile->writeByte(_state.items[i].position.x); + outFile->writeByte(_state.items[i].position.y); + outFile->writeByte(_state.items[i].state); + } + + outFile->writeUint32BE(_state.vars.size()); + for (uint i = 0; i < _state.vars.size(); ++i) + outFile->writeByte(_state.vars[i]); + + outFile->finalize(); + + if (outFile->err()) { + delete outFile; + warning("Failed to save game '%s'", fileName.c_str()); + return false; + } + + delete outFile; + return true; +} + +bool AdlEngine::loadState(uint slot) { + Common::String fileName = Common::String::format("%s.s%02d", _targetName.c_str(), slot); + Common::InSaveFile *inFile = getSaveFileManager()->openForLoading(fileName); + + if (!inFile) { + warning("Failed to open file '%s'", fileName.c_str()); + return false; + } + + if (inFile->readUint32BE() != getTag()) { + warning("No header found in '%s'", fileName.c_str()); + delete inFile; + return false; + } + + byte saveVersion = inFile->readByte(); + if (saveVersion != SAVEGAME_VERSION) { + warning("Save game version %i not supported", saveVersion); + delete inFile; + return false; + } + + initState(); + + _state.room = inFile->readByte(); + _state.moves = inFile->readByte(); + _state.isDark = inFile->readByte(); + + uint32 size = inFile->readUint32BE(); + if (size != _state.rooms.size()) + error("Room count mismatch (expected %i; found %i)", _state.rooms.size(), size); + + for (uint i = 0; i < size; ++i) { + _state.rooms[i].picture = inFile->readByte(); + _state.rooms[i].curPicture = inFile->readByte(); + } + + size = inFile->readUint32BE(); + if (size != _state.items.size()) + error("Item count mismatch (expected %i; found %i)", _state.items.size(), size); + + for (uint i = 0; i < size; ++i) { + _state.items[i].room = inFile->readByte(); + _state.items[i].picture = inFile->readByte(); + _state.items[i].position.x = inFile->readByte(); + _state.items[i].position.y = inFile->readByte(); + _state.items[i].state = inFile->readByte(); + } + + size = inFile->readUint32BE(); + if (size != _state.vars.size()) + error("Variable count mismatch (expected %i; found %i)", _state.vars.size(), size); + + for (uint i = 0; i < size; ++i) + _state.vars[i] = inFile->readByte(); + + if (inFile->err() || inFile->eos()) + error("Failed to load game '%s'", fileName.c_str()); + + delete inFile; + return true; +} + 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 8b0aa45937..abb62ee8b2 100644 --- a/engines/adl/adl.h +++ b/engines/adl/adl.h @@ -37,6 +37,8 @@ class SeekableReadStream; namespace Adl { +#define SAVEGAME_VERSION 0 + class Display; class Parser; class Console; @@ -178,6 +180,7 @@ protected: virtual void initState() = 0; virtual void restartGame() = 0; virtual uint getEngineMessage(EngineMessage msg) = 0; + virtual uint32 getTag() = 0; 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); @@ -211,6 +214,9 @@ protected: private: void printEngineMessage(EngineMessage); + bool saveState(uint slot); + bool loadState(uint slot); + Common::String getTargetName() { return _targetName; } }; AdlEngine *HiRes1Engine__create(OSystem *syst, const AdlGameDescription *gd); diff --git a/engines/adl/hires1.h b/engines/adl/hires1.h index a378dc9423..ab26b2c87d 100644 --- a/engines/adl/hires1.h +++ b/engines/adl/hires1.h @@ -52,6 +52,7 @@ private: void restartGame(); void printMessage(uint idx, bool wait = true); uint getEngineMessage(EngineMessage msg); + uint32 getTag() { return MKTAG('H', 'R', 'A', '1'); } void initState(); void runIntro(); -- cgit v1.2.3