aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjohndoe1232015-12-04 23:20:22 +0100
committerEugene Sandulenko2018-07-20 06:43:33 +0000
commitaed38527010e7b155af469d0521aa07e7fd7d12e (patch)
tree95a5ce5eb4ce90fe1500a6265090a5292c5faf17
parent6b36b750c2567c32d20f8f7868a8b664baac5cde (diff)
downloadscummvm-rg350-aed38527010e7b155af469d0521aa07e7fd7d12e.tar.gz
scummvm-rg350-aed38527010e7b155af469d0521aa07e7fd7d12e.tar.bz2
scummvm-rg350-aed38527010e7b155af469d0521aa07e7fd7d12e.zip
ILLUSIONS: Implement save/load functionality
- Only works in Duckman at the moment - Only via the ScummVM main menu for now, save/load via the game's menu to be implemented
-rw-r--r--engines/illusions/detection.cpp9
-rw-r--r--engines/illusions/duckman/gamestate_duckman.cpp50
-rw-r--r--engines/illusions/duckman/gamestate_duckman.h44
-rw-r--r--engines/illusions/duckman/illusions_duckman.cpp86
-rw-r--r--engines/illusions/duckman/illusions_duckman.h5
-rw-r--r--engines/illusions/duckman/scriptopcodes_duckman.cpp12
-rw-r--r--engines/illusions/gamestate.cpp75
-rw-r--r--engines/illusions/gamestate.h53
-rw-r--r--engines/illusions/illusions.cpp5
-rw-r--r--engines/illusions/illusions.h14
-rw-r--r--engines/illusions/module.mk3
-rw-r--r--engines/illusions/resources/scriptresource.cpp40
-rw-r--r--engines/illusions/resources/scriptresource.h7
-rw-r--r--engines/illusions/saveload.cpp162
-rw-r--r--engines/illusions/screen.cpp13
15 files changed, 511 insertions, 67 deletions
diff --git a/engines/illusions/detection.cpp b/engines/illusions/detection.cpp
index 53e7a4b1e5..a0e24886cc 100644
--- a/engines/illusions/detection.cpp
+++ b/engines/illusions/detection.cpp
@@ -95,29 +95,22 @@ public:
virtual bool hasFeature(MetaEngineFeature f) const;
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
-#if 0
virtual int getMaximumSaveSlot() const;
virtual SaveStateList listSaves(const char *target) const;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
virtual void removeSaveState(const char *target, int slot) const;
-#endif
};
bool IllusionsMetaEngine::hasFeature(MetaEngineFeature f) const {
return
- false;
- /*
(f == kSupportsListSaves) ||
(f == kSupportsDeleteSave) ||
(f == kSupportsLoadingDuringStartup) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSavesSupportCreationDate);
- */
}
-#if 0
-
void IllusionsMetaEngine::removeSaveState(const char *target, int slot) const {
Common::String fileName = Common::String::format("%s.%03d", target, slot);
g_system->getSavefileManager()->removeSavefile(fileName);
@@ -175,8 +168,6 @@ SaveStateDescriptor IllusionsMetaEngine::querySaveMetaInfos(const char *target,
return SaveStateDescriptor();
}
-#endif
-
bool IllusionsMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
const Illusions::IllusionsGameDescription *gd = (const Illusions::IllusionsGameDescription *)desc;
if (gd) {
diff --git a/engines/illusions/duckman/gamestate_duckman.cpp b/engines/illusions/duckman/gamestate_duckman.cpp
new file mode 100644
index 0000000000..8f4939f9dc
--- /dev/null
+++ b/engines/illusions/duckman/gamestate_duckman.cpp
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "illusions/duckman/gamestate_duckman.h"
+#include "illusions/duckman/illusions_duckman.h"
+#include "illusions/resources/scriptresource.h"
+
+namespace Illusions {
+
+Duckman_GameState::Duckman_GameState(IllusionsEngine_Duckman *vm)
+ : _vm(vm) {
+}
+
+uint32 Duckman_GameState::calcWriteBufferSizeInternal() {
+ return
+ _vm->_scriptResource->_properties.getSize() +
+ _vm->_scriptResource->_blockCounters.getSize();
+}
+
+bool Duckman_GameState::readStateInternal(Common::ReadStream *in) {
+ return
+ _vm->_scriptResource->_properties.readFromStream(in) &&
+ _vm->_scriptResource->_blockCounters.readFromStream(in);
+}
+
+void Duckman_GameState::writeStateInternal(Common::WriteStream *out) {
+ _vm->_scriptResource->_properties.writeToStream(out);
+ _vm->_scriptResource->_blockCounters.writeToStream(out);
+}
+
+} // End of namespace Illusions
diff --git a/engines/illusions/duckman/gamestate_duckman.h b/engines/illusions/duckman/gamestate_duckman.h
new file mode 100644
index 0000000000..36024c8d8e
--- /dev/null
+++ b/engines/illusions/duckman/gamestate_duckman.h
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ILLUSIONS_DUCKMAN_GAMESTATE_DUCKMAN_H
+#define ILLUSIONS_DUCKMAN_GAMESTATE_DUCKMAN_H
+
+#include "illusions/gamestate.h"
+
+namespace Illusions {
+
+class IllusionsEngine_Duckman;
+
+class Duckman_GameState : public GameState {
+public:
+ Duckman_GameState(IllusionsEngine_Duckman *vm);
+protected:
+ IllusionsEngine_Duckman *_vm;
+ uint32 calcWriteBufferSizeInternal();
+ bool readStateInternal(Common::ReadStream *in);
+ void writeStateInternal(Common::WriteStream *out);
+};
+
+} // End of namespace Illusions
+
+#endif // ILLUSIONS_DUCKMAN_GAMESTATE_DUCKMAN_H
diff --git a/engines/illusions/duckman/illusions_duckman.cpp b/engines/illusions/duckman/illusions_duckman.cpp
index ebfcdca4bd..c9233ae6d1 100644
--- a/engines/illusions/duckman/illusions_duckman.cpp
+++ b/engines/illusions/duckman/illusions_duckman.cpp
@@ -23,6 +23,7 @@
#include "illusions/duckman/illusions_duckman.h"
#include "illusions/duckman/duckman_dialog.h"
#include "illusions/duckman/duckman_specialcode.h"
+#include "illusions/duckman/gamestate_duckman.h"
#include "illusions/duckman/menusystem_duckman.h"
#include "illusions/duckman/scriptopcodes_duckman.h"
#include "illusions/actor.h"
@@ -114,6 +115,7 @@ Common::Error IllusionsEngine_Duckman::run() {
_updateFunctions = new UpdateFunctions();
_soundMan = new SoundMan(this);
_menuSystem = new DuckmanMenuSystem(this);
+ _gameState = new Duckman_GameState(this);
_fader = new Fader();
@@ -153,10 +155,7 @@ Common::Error IllusionsEngine_Duckman::run() {
_resSys->loadResource(0x120001, 0x00010001, 0);
_resSys->loadResource(0x120002, 0x00010001, 0);
_resSys->loadResource(0x120003, 0x00010001, 0);
-
_resSys->loadResource(0x000D0001, 0x00010001, 0);
- startScriptThread(0x00020004, 0);
- _doScriptThreadInit = true;
#if 0
//DEBUG
@@ -174,13 +173,28 @@ Common::Error IllusionsEngine_Duckman::run() {
_scriptResource->_blockCounters.set(238, 1);
#endif
-#if 1
+#if 0
// DEBUG Map / special code 0016001A
_scriptResource->_properties.set(0x000E0017, true);
_scriptResource->_properties.set(0x000E0022, false);
#endif
+ if (ConfMan.hasKey("save_slot")) {
+ _doScriptThreadInit = true;
+ // Load global resources manually, usually done by the game script
+ enterScene(0x00010003, 0);
+ loadGameState(ConfMan.getInt("save_slot"));
+ } else {
+ startScriptThread(0x00020004, 0);
+ _doScriptThreadInit = true;
+ }
+
while (!shouldQuit()) {
+ if (_resumeFromSavegameRequested) {
+ activateSavegame(0);
+ resumeFromSavegame(0);
+ _resumeFromSavegameRequested = false;
+ }
runUpdateFunctions();
_system->updateScreen();
updateEvents();
@@ -195,6 +209,7 @@ Common::Error IllusionsEngine_Duckman::run() {
delete _fader;
+ delete _gameState;
delete _menuSystem;
delete _soundMan;
delete _updateFunctions;
@@ -218,12 +233,9 @@ Common::Error IllusionsEngine_Duckman::run() {
bool IllusionsEngine_Duckman::hasFeature(EngineFeature f) const {
return
- false;
- /*
(f == kSupportsRTL) ||
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime);
- */
}
void IllusionsEngine_Duckman::initInput() {
@@ -793,7 +805,7 @@ bool IllusionsEngine_Duckman::changeScene(uint32 sceneId, uint32 threadId, uint3
_controls->destroyControls();
_resSys->unloadSceneResources(0x10003, 0x10001);
if (enterScene(sceneId, threadId)) {
- // TODO GameStates_writeStates(sceneId, threadId);
+ _gameState->writeState(sceneId, threadId);
return true;
}
return false;
@@ -1075,23 +1087,24 @@ uint32 IllusionsEngine_Duckman::runTriggerCause(uint32 verbId, uint32 objectId2,
if (!getTriggerCause(verbId, objectId2, objectId, triggerThreadId))
return 0;
- bool flag = false;
+ // TODO Extract sound effect playing to method
+ bool soundWasPlayed = false;
if (_scriptResource->_properties.get(0x000E003C)) {
if (verbId == 7 && objectId == 0x40003) {
playSoundEffect(7);
- flag = true;
+ soundWasPlayed = true;
} else if (objectId == 0x40003) {
playSoundEffect(14);
- flag = true;
+ soundWasPlayed = true;
} else if (verbId == 3) {
playSoundEffect(16);
- flag = true;
+ soundWasPlayed = true;
} else if (verbId == 2) {
- flag = true;
+ soundWasPlayed = true;
}
}
- if (!flag) {
+ if (!soundWasPlayed) {
if (objectId == 0x40003) {
playSoundEffect(14);
} else if ((verbId == 1 || verbId == 2) && _scriptResource->getMainActorObjectId() == objectId) {
@@ -1120,34 +1133,33 @@ uint32 IllusionsEngine_Duckman::runTriggerCause(uint32 verbId, uint32 objectId2,
return tempThreadId;
}
-bool IllusionsEngine_Duckman::loadSavegame(int16 slotNum, uint32 callingThreadId) {
-#if 0
- // TODO
- bool success = _gameStates->load(slotNum);
- if (success) {
- _vm->_screen->setDisplayOn(false);
- uint32 currSceneId = getCurrentScene();
- if (currSceneId != 0x10003)
- dumpCurrSceneFiles(currSceneId, callerThreadId);
- reset();
- stopMidi();
- clearMidiPlayList();
- _gameStates->readStates();
- pushActiveScene(0x10000);
- }
- _gameStates->freeGameStateReadBuffer();
+bool IllusionsEngine_Duckman::loadSavegameFromScript(int16 slotNum, uint32 callingThreadId) {
+ const char *fileName = getSavegameFilename(slotNum);
+ bool success = loadgame(fileName);
+ if (success)
+ activateSavegame(callingThreadId);
+ _gameState->deleteReadStream();
return success;
-#endif
- return true;
}
-bool IllusionsEngine_Duckman::saveSavegame(int16 slotNum, uint32 callingThreadId) {
-#if 0
+bool IllusionsEngine_Duckman::saveSavegameFromScript(int16 slotNum, uint32 callingThreadId) {
// TODO
- bool success = _gameStates->save(slotNum);
+ const char *fileName = getSavegameFilename(slotNum);
+ bool success = false;//savegame(fileName, _savegameDescription.c_str());
return success;
-#endif
- return true;
+}
+
+void IllusionsEngine_Duckman::activateSavegame(uint32 callingThreadId) {
+ // TODO _screen->setDisplayOn(false);
+ uint32 currSceneId = getCurrentScene();
+ if (currSceneId != 0x10003)
+ dumpCurrSceneFiles(currSceneId, callingThreadId);
+ reset();
+ // TODO stopMidi();
+ // TODO clearMidiPlayList();
+ _gameState->readState(_savegameSceneId, _savegameThreadId);
+ pushActiveScene(0x10000);
+ _gameState->deleteReadStream();
}
} // End of namespace Illusions
diff --git a/engines/illusions/duckman/illusions_duckman.h b/engines/illusions/duckman/illusions_duckman.h
index 87520d3a6a..1825123e5c 100644
--- a/engines/illusions/duckman/illusions_duckman.h
+++ b/engines/illusions/duckman/illusions_duckman.h
@@ -187,8 +187,9 @@ public:
bool getTriggerCause(uint32 verbId, uint32 objectId2, uint32 objectId, uint32 &outThreadId);
uint32 runTriggerCause(uint32 verbId, uint32 objectId2, uint32 objectId);
- bool loadSavegame(int16 slotNum, uint32 callingThreadId);
- bool saveSavegame(int16 slotNum, uint32 callingThreadId);
+ bool loadSavegameFromScript(int16 slotNum, uint32 callingThreadId);
+ bool saveSavegameFromScript(int16 slotNum, uint32 callingThreadId);
+ void activateSavegame(uint32 callingThreadId);
};
diff --git a/engines/illusions/duckman/scriptopcodes_duckman.cpp b/engines/illusions/duckman/scriptopcodes_duckman.cpp
index a62a78b46b..1456cfc0ee 100644
--- a/engines/illusions/duckman/scriptopcodes_duckman.cpp
+++ b/engines/illusions/duckman/scriptopcodes_duckman.cpp
@@ -259,7 +259,7 @@ void ScriptOpcodes_Duckman::opUnloadResourcesBySceneId(ScriptThread *scriptThrea
//static uint dsceneId = 0, dthreadId = 0;
//static uint dsceneId = 0x00010008, dthreadId = 0x00020029;//Beginning in Jac
-//static uint dsceneId = 0x0001000A, dthreadId = 0x00020043;//Home front
+static uint dsceneId = 0x0001000A, dthreadId = 0x00020043;//Home front
//static uint dsceneId = 0x0001000E, dthreadId = 0x0002007C;
//static uint dsceneId = 0x00010012, dthreadId = 0x0002009D;//Paramount
//static uint dsceneId = 0x00010020, dthreadId = 0x00020112;//Xmas
@@ -276,7 +276,7 @@ void ScriptOpcodes_Duckman::opUnloadResourcesBySceneId(ScriptThread *scriptThrea
//static uint dsceneId = 0x10002, dthreadId = 0x20001;//Debug menu, not supported
//static uint dsceneId = 0x10044, dthreadId = 0x000202B8; // Starship Enterprise
//static uint dsceneId = 0x00010039, dthreadId = 0x00020089; // Map
-static uint dsceneId = 0x00010052, dthreadId = 0x00020347; // Credits
+//static uint dsceneId = 0x00010052, dthreadId = 0x00020347; // Credits
void ScriptOpcodes_Duckman::opChangeScene(ScriptThread *scriptThread, OpCall &opCall) {
ARG_SKIP(2);
@@ -348,12 +348,12 @@ void ScriptOpcodes_Duckman::opLeaveScene24(ScriptThread *scriptThread, OpCall &o
void ScriptOpcodes_Duckman::opEnterDebugger(ScriptThread *scriptThread, OpCall &opCall) {
// Used for debugging purposes in the original engine
// This is not supported and only reachable by code not implemented here!
- error("ScriptOpcodes_Duckman::opEnterDebugger() Debugger function called");
+ //error("ScriptOpcodes_Duckman::opEnterDebugger() Debugger function called");
}
void ScriptOpcodes_Duckman::opLeaveDebugger(ScriptThread *scriptThread, OpCall &opCall) {
// See opEnterDebugger
- error("ScriptOpcodes_Duckman::opLeaveDebugger() Debugger function called");
+ //error("ScriptOpcodes_Duckman::opLeaveDebugger() Debugger function called");
}
void ScriptOpcodes_Duckman::opDumpCurrentSceneFiles(ScriptThread *scriptThread, OpCall &opCall) {
@@ -690,7 +690,7 @@ void ScriptOpcodes_Duckman::opLoadGame(ScriptThread *scriptThread, OpCall &opCal
ARG_SKIP(2);
ARG_INT16(bankNum)
ARG_INT16(slotNum)
- bool success = _vm->loadSavegame(slotNum, opCall._callerThreadId);
+ bool success = _vm->loadSavegameFromScript(slotNum, opCall._callerThreadId);
_vm->_stack->push(success ? 1 : 0);
}
@@ -698,7 +698,7 @@ void ScriptOpcodes_Duckman::opSaveGame(ScriptThread *scriptThread, OpCall &opCal
ARG_SKIP(2);
ARG_INT16(bankNum)
ARG_INT16(slotNum)
- bool success = _vm->saveSavegame(slotNum, opCall._callerThreadId);
+ bool success = _vm->saveSavegameFromScript(slotNum, opCall._callerThreadId);
_vm->_stack->push(success ? 1 : 0);
}
diff --git a/engines/illusions/gamestate.cpp b/engines/illusions/gamestate.cpp
new file mode 100644
index 0000000000..5f6e17cc76
--- /dev/null
+++ b/engines/illusions/gamestate.cpp
@@ -0,0 +1,75 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "illusions/gamestate.h"
+
+namespace Illusions {
+
+GameState::GameState()
+ : _writeBufferSize(0), _writeBuffer(0), _readStream(0) {
+}
+
+GameState::~GameState() {
+ free(_writeBuffer);
+}
+
+bool GameState::readState(uint32 &sceneId, uint32 &threadId) {
+ sceneId = _readStream->readUint32LE();
+ threadId = _readStream->readUint32LE();
+ return readStateInternal(_readStream);
+}
+
+void GameState::writeState(uint32 sceneId, uint32 threadId) {
+ Common::WriteStream *writeStream = newWriteStream();
+ writeStream->writeUint32LE(sceneId);
+ writeStream->writeUint32LE(threadId);
+ writeStateInternal(writeStream);
+}
+
+void GameState::read(Common::ReadStream *in) {
+ uint32 size = in->readUint32LE();
+ _readStream = in->readStream(size);
+}
+
+void GameState::write(Common::WriteStream *out) {
+ out->writeUint32LE(_writeBufferSize);
+ out->write(_writeBuffer, _writeBufferSize);
+}
+
+void GameState::deleteReadStream() {
+ delete _readStream;
+ _readStream = 0;
+}
+
+Common::WriteStream *GameState::newWriteStream() {
+ if (!_writeBufferSize == 0 || !_writeBuffer) {
+ _writeBufferSize = calcWriteBufferSize();
+ _writeBuffer = (byte*)malloc(_writeBufferSize);
+ }
+ return new Common::MemoryWriteStream(_writeBuffer, _writeBufferSize);
+}
+
+uint32 GameState::calcWriteBufferSize() {
+ return calcWriteBufferSizeInternal() + 4 + 4;
+}
+
+} // End of namespace Illusions
diff --git a/engines/illusions/gamestate.h b/engines/illusions/gamestate.h
new file mode 100644
index 0000000000..5f279ff0c3
--- /dev/null
+++ b/engines/illusions/gamestate.h
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ILLUSIONS_GAMESTATE_H
+#define ILLUSIONS_GAMESTATE_H
+
+#include "common/file.h"
+#include "common/memstream.h"
+
+namespace Illusions {
+
+class GameState {
+public:
+ GameState();
+ virtual ~GameState();
+ bool readState(uint32 &sceneId, uint32 &threadId);
+ void writeState(uint32 sceneId, uint32 threadId);
+ void read(Common::ReadStream *in);
+ void write(Common::WriteStream *out);
+ void deleteReadStream();
+protected:
+ uint32 _writeBufferSize;
+ byte *_writeBuffer;
+ Common::SeekableReadStream *_readStream;
+ Common::WriteStream *newWriteStream();
+ uint32 calcWriteBufferSize();
+ virtual uint32 calcWriteBufferSizeInternal() = 0;
+ virtual bool readStateInternal(Common::ReadStream *in) = 0;
+ virtual void writeStateInternal(Common::WriteStream *out) = 0;
+};
+
+} // End of namespace Illusions
+
+#endif // ILLUSIONS_GAMESTATE_H
diff --git a/engines/illusions/illusions.cpp b/engines/illusions/illusions.cpp
index c4af5b5449..e22ef0c316 100644
--- a/engines/illusions/illusions.cpp
+++ b/engines/illusions/illusions.cpp
@@ -66,6 +66,11 @@ IllusionsEngine::IllusionsEngine(OSystem *syst, const IllusionsGameDescription *
_rerunThreads = false;
+ _isSaveAllowed = true; // TODO
+ _resumeFromSavegameRequested = false;
+ _savegameSceneId = 0;
+ _savegameThreadId = 0;
+
Engine::syncSoundSettings();
}
diff --git a/engines/illusions/illusions.h b/engines/illusions/illusions.h
index 9914936add..784277f872 100644
--- a/engines/illusions/illusions.h
+++ b/engines/illusions/illusions.h
@@ -76,6 +76,7 @@ class SpecialCode;
class TalkInstanceList;
class ThreadList;
class UpdateFunctions;
+class GameState;
enum {
kGameIdBBDOU = 1,
@@ -102,6 +103,7 @@ public:
ResourceSystem *_resSys;
BaseResourceReader *_resReader;
UpdateFunctions *_updateFunctions;
+ GameState *_gameState;
void updateEvents();
@@ -132,7 +134,8 @@ public:
uint32 _resGetTime;
bool _unpauseControlActorFlag;
uint32 _lastUpdateTime;
-
+
+ int _resumeFromSavegameRequested;
uint32 _savegameSceneId;
uint32 _savegameThreadId;
@@ -201,8 +204,6 @@ public:
uint32 value8, uint32 valueC, uint32 value10) = 0;
virtual void resumeFromSavegame(uint32 callingThreadId) = 0;
-#if 0
-
// Savegame API
enum kReadSaveHeaderError {
@@ -229,15 +230,14 @@ public:
bool canSaveGameStateCurrently() { return _isSaveAllowed; }
Common::Error loadGameState(int slot);
Common::Error saveGameState(int slot, const Common::String &description);
- void savegame(const char *filename, const char *description);
- void loadgame(const char *filename);
+ Common::Error removeGameState(int slot);
+ bool savegame(const char *filename, const char *description);
+ bool loadgame(const char *filename);
const char *getSavegameFilename(int num);
bool existsSavegame(int num);
static Common::String getSavegameFilename(const Common::String &target, int num);
static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header);
-#endif
-
};
} // End of namespace Illusions
diff --git a/engines/illusions/module.mk b/engines/illusions/module.mk
index a5aa86d8cc..ad61eee5c8 100644
--- a/engines/illusions/module.mk
+++ b/engines/illusions/module.mk
@@ -17,6 +17,7 @@ MODULE_OBJS := \
duckman/duckman_inventory.o \
duckman/duckman_screenshakereffects.o \
duckman/duckman_specialcode.o \
+ duckman/gamestate_duckman.o \
duckman/illusions_duckman.o \
duckman/menusystem_duckman.o \
duckman/propertytimers.o \
@@ -24,6 +25,7 @@ MODULE_OBJS := \
fileresourcereader.o \
fixedpoint.o \
gamarchive.o \
+ gamestate.o \
gamresourcereader.o \
graphics.o \
illusions.o \
@@ -39,6 +41,7 @@ MODULE_OBJS := \
resources/soundresource.o \
resources/talkresource.o \
resourcesystem.o \
+ saveload.o \
screen.o \
screentext.o \
scriptstack.o \
diff --git a/engines/illusions/resources/scriptresource.cpp b/engines/illusions/resources/scriptresource.cpp
index 3038a8694d..5472d28658 100644
--- a/engines/illusions/resources/scriptresource.cpp
+++ b/engines/illusions/resources/scriptresource.cpp
@@ -50,8 +50,8 @@ void Properties::init(uint count, byte *properties) {
}
void Properties::clear() {
- uint size = (_count >> 3) + 1;
- for (uint i = 0; i < size; ++i)
+ uint32 size = getSize();
+ for (uint32 i = 0; i < size; ++i)
_properties[i] = 0;
}
@@ -72,6 +72,24 @@ void Properties::set(uint32 propertyId, bool value) {
_properties[index] &= ~mask;
}
+uint32 Properties::getSize() {
+ return (_count >> 3) + 1;
+}
+
+void Properties::writeToStream(Common::WriteStream *out) {
+ const uint32 size = getSize();
+ out->writeUint32LE(size);
+ out->write(_properties, size);
+}
+
+bool Properties::readFromStream(Common::ReadStream *in) {
+ uint32 size = in->readUint32LE();
+ if (size != getSize())
+ return false;
+ in->read(_properties, size);
+ return true;
+}
+
void Properties::getProperyPos(uint32 propertyId, uint &index, byte &mask) {
propertyId &= 0xFFFF;
index = propertyId >> 3;
@@ -113,6 +131,24 @@ void BlockCounters::setC0(uint index, byte value) {
_blockCounters[index - 1] = oldValue | (value & 0xC0);
}
+uint32 BlockCounters::getSize() {
+ return _count;
+}
+
+void BlockCounters::writeToStream(Common::WriteStream *out) {
+ const uint32 size = getSize();
+ out->writeUint32LE(size);
+ out->write(_blockCounters, size);
+}
+
+bool BlockCounters::readFromStream(Common::ReadStream *in) {
+ uint32 size = in->readUint32LE();
+ if (size != getSize())
+ return false;
+ in->read(_blockCounters, size);
+ return true;
+}
+
// TriggerCause
void TriggerCause::load(Common::SeekableReadStream &stream) {
diff --git a/engines/illusions/resources/scriptresource.h b/engines/illusions/resources/scriptresource.h
index 6debcb2efb..f185319f67 100644
--- a/engines/illusions/resources/scriptresource.h
+++ b/engines/illusions/resources/scriptresource.h
@@ -24,6 +24,7 @@
#define ILLUSIONS_SCRIPTRESOURCE_H
#include "illusions/resourcesystem.h"
+#include "common/file.h"
namespace Illusions {
@@ -46,6 +47,9 @@ public:
void clear();
bool get(uint32 propertyId);
void set(uint32 propertyId, bool value);
+ uint32 getSize();
+ void writeToStream(Common::WriteStream *out);
+ bool readFromStream(Common::ReadStream *in);
public:
uint _count;
byte *_properties;
@@ -61,6 +65,9 @@ public:
void set(uint index, byte value);
byte getC0(uint index);
void setC0(uint index, byte value);
+ uint32 getSize();
+ void writeToStream(Common::WriteStream *out);
+ bool readFromStream(Common::ReadStream *in);
public:
uint _count;
byte *_blockCounters;
diff --git a/engines/illusions/saveload.cpp b/engines/illusions/saveload.cpp
new file mode 100644
index 0000000000..751f6a600e
--- /dev/null
+++ b/engines/illusions/saveload.cpp
@@ -0,0 +1,162 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/savefile.h"
+
+#include "graphics/thumbnail.h"
+
+#include "illusions/illusions.h"
+#include "illusions/gamestate.h"
+
+namespace Illusions {
+
+#define ILLUSIONS_SAVEGAME_VERSION 0
+
+IllusionsEngine::kReadSaveHeaderError IllusionsEngine::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {
+
+ header.version = in->readUint32LE();
+ if (header.version > ILLUSIONS_SAVEGAME_VERSION)
+ return kRSHEInvalidVersion;
+
+ byte descriptionLen = in->readByte();
+ header.description = "";
+ while (descriptionLen--)
+ header.description += (char)in->readByte();
+
+ if (loadThumbnail) {
+ header.thumbnail = Graphics::loadThumbnail(*in);
+ } else {
+ Graphics::skipThumbnail(*in);
+ }
+
+ // Not used yet, reserved for future usage
+ header.gameID = in->readByte();
+ header.flags = in->readUint32LE();
+
+ header.saveDate = in->readUint32LE();
+ header.saveTime = in->readUint32LE();
+ header.playTime = in->readUint32LE();
+
+ return ((in->eos() || in->err()) ? kRSHEIoError : kRSHENoError);
+}
+
+bool IllusionsEngine::savegame(const char *filename, const char *description) {
+
+ Common::OutSaveFile *out;
+ if (!(out = g_system->getSavefileManager()->openForSaving(filename))) {
+ warning("Can't create file '%s', game not saved", filename);
+ return false;
+ }
+
+ TimeDate curTime;
+ g_system->getTimeAndDate(curTime);
+
+ // Header start
+ out->writeUint32LE(ILLUSIONS_SAVEGAME_VERSION);
+
+ byte descriptionLen = strlen(description);
+ out->writeByte(descriptionLen);
+ out->write(description, descriptionLen);
+
+ // TODO Probably pre-generate the thumbnail before the internal menu system is
+ // called to have a thumbnail without the menu system itself on it.
+ // Use the automatic thumbnail generation only when the ScummVM save dialog is used.
+ Graphics::saveThumbnail(*out);
+
+ // Not used yet, reserved for future usage
+ out->writeByte(0);
+ out->writeUint32LE(0);
+ uint32 saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
+ uint32 saveTime = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF);
+ uint32 playTime = g_engine->getTotalPlayTime() / 1000;
+ out->writeUint32LE(saveDate);
+ out->writeUint32LE(saveTime);
+ out->writeUint32LE(playTime);
+ // Header end
+
+ _gameState->write(out);
+
+ out->finalize();
+ delete out;
+ return true;
+}
+
+bool IllusionsEngine::loadgame(const char *filename) {
+ Common::InSaveFile *in;
+ if (!(in = g_system->getSavefileManager()->openForLoading(filename))) {
+ warning("Can't open file '%s', game not loaded", filename);
+ return false;
+ }
+
+ SaveHeader header;
+
+ kReadSaveHeaderError errorCode = readSaveHeader(in, false, header);
+
+ if (errorCode != kRSHENoError) {
+ warning("Error loading savegame '%s'", filename);
+ delete in;
+ return false;
+ }
+
+ g_engine->setTotalPlayTime(header.playTime * 1000);
+
+ _gameState->read(in);
+
+ delete in;
+ return true;
+}
+
+Common::Error IllusionsEngine::loadGameState(int slot) {
+ _resumeFromSavegameRequested = false;
+ const char *fileName = getSavegameFilename(slot);
+ if (!loadgame(fileName))
+ return Common::kReadingFailed;
+ _resumeFromSavegameRequested = true;
+ return Common::kNoError;
+}
+
+Common::Error IllusionsEngine::saveGameState(int slot, const Common::String &description) {
+ const char *fileName = getSavegameFilename(slot);
+ if (!savegame(fileName, description.c_str()))
+ return Common::kWritingFailed;
+ return Common::kNoError;
+}
+
+Common::Error IllusionsEngine::removeGameState(int slot) {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::String filename = Illusions::IllusionsEngine::getSavegameFilename(_targetName, slot);
+ saveFileMan->removeSavefile(filename.c_str());
+ return Common::kNoError;
+}
+
+const char *IllusionsEngine::getSavegameFilename(int num) {
+ static Common::String filename;
+ filename = getSavegameFilename(_targetName, num);
+ return filename.c_str();
+}
+
+Common::String IllusionsEngine::getSavegameFilename(const Common::String &target, int num) {
+ assert(num >= 0 && num <= 999);
+ return Common::String::format("%s.%03d", target.c_str(), num);
+}
+
+} // End of namespace Illusions
diff --git a/engines/illusions/screen.cpp b/engines/illusions/screen.cpp
index b9506f63d4..a4a3d27430 100644
--- a/engines/illusions/screen.cpp
+++ b/engines/illusions/screen.cpp
@@ -635,10 +635,10 @@ void Screen::drawSurface82(Common::Rect &dstRect, Graphics::Surface *surface, Co
const int srcWidth = srcRect.width(), srcHeight = srcRect.height();
const int errYStart = srcHeight / dstHeight;
const int errYIncr = srcHeight % dstHeight;
- const int midY = dstHeight / 2;
+// const int midY = dstHeight / 2;
const int errXStart = srcWidth / dstWidth;
const int errXIncr = srcWidth % dstWidth;
- const int midX = dstWidth / 2;
+// const int midX = dstWidth / 2;
int h = dstHeight, errY = 0, skipY, srcY = srcRect.top;
byte *dst = (byte*)_backSurface->getBasePtr(dstRect.left, dstRect.top);
skipY = (dstHeight < srcHeight) ? 0 : dstHeight / (2*srcHeight) + 1;
@@ -807,6 +807,8 @@ void Screen::drawSurface20(Common::Rect &dstRect, Graphics::Surface *surface, Co
//debug("Screen::drawSurface20");
}
+//#define TEST_SMOOTHING
+#ifdef TEST_SMOOTHING
static uint16 average(const uint16 a, const uint16 b) {
byte r1, g1, b1, r2, g2, b2;
g_system->getScreenFormat().colorToRGB(a, r1, g1, b1);
@@ -814,6 +816,7 @@ static uint16 average(const uint16 a, const uint16 b) {
// return g_system->getScreenFormat().RGBToColor((r1 + r1 + r2) / 3, (g1 + g1 + g2) / 3, (b1 + b1 + b2) / 3);
return g_system->getScreenFormat().RGBToColor((r1 + r2) / 2, (g1 + g2) / 2, (b1 + b2) / 2);
}
+#endif
void Screen::drawSurface21(Common::Rect &dstRect, Graphics::Surface *surface, Common::Rect &srcRect) {
// Scaled
@@ -821,10 +824,10 @@ void Screen::drawSurface21(Common::Rect &dstRect, Graphics::Surface *surface, Co
const int srcWidth = srcRect.width(), srcHeight = srcRect.height();
const int errYStart = srcHeight / dstHeight;
const int errYIncr = srcHeight % dstHeight;
- const int midY = dstHeight / 2;
+// const int midY = dstHeight / 2;
const int errXStart = srcWidth / dstWidth;
const int errXIncr = srcWidth % dstWidth;
- const int midX = dstWidth / 2;
+// const int midX = dstWidth / 2;
int h = dstHeight, errY = 0, skipY, srcY = srcRect.top;
byte *dst = (byte*)_backSurface->getBasePtr(dstRect.left, dstRect.top);
skipY = (dstHeight < srcHeight) ? 0 : dstHeight / (2*srcHeight) + 1;
@@ -838,12 +841,14 @@ void Screen::drawSurface21(Common::Rect &dstRect, Graphics::Surface *surface, Co
while (w-- > 0) {
uint16 pixel = READ_LE_UINT16(src);
if (pixel != _colorKey1) {
+#ifdef TEST_SMOOTHING
if (errX >= midX) {
uint16 npixel = READ_LE_UINT16(src + 2);
if (npixel == _colorKey1)
npixel = READ_LE_UINT16(dstRow);
pixel = average(pixel, npixel);
}
+#endif
WRITE_LE_UINT16(dstRow, pixel);
}
dstRow += 2;