From 38577221c06910311902f4c6bb4984e6fce1f75d Mon Sep 17 00:00:00 2001 From: johndoe123 Date: Sat, 19 May 2018 08:12:16 +1000 Subject: ILLUSIONS: BBDOU: Implement savegame saving/loading from GUI and the launcher (cherry picked from commit 42f0bd4) --- engines/illusions/bbdou/bbdou_specialcode.cpp | 13 ++++++ engines/illusions/bbdou/bbdou_specialcode.h | 1 + engines/illusions/bbdou/gamestate_bbdou.cpp | 53 +++++++++++++++++++++ engines/illusions/bbdou/gamestate_bbdou.h | 44 ++++++++++++++++++ engines/illusions/bbdou/illusions_bbdou.cpp | 61 ++++++++++++++++++++++--- engines/illusions/bbdou/illusions_bbdou.h | 9 +++- engines/illusions/bbdou/scriptopcodes_bbdou.cpp | 40 ++++++++++++++-- engines/illusions/bbdou/scriptopcodes_bbdou.h | 5 ++ 8 files changed, 213 insertions(+), 13 deletions(-) create mode 100644 engines/illusions/bbdou/gamestate_bbdou.cpp create mode 100644 engines/illusions/bbdou/gamestate_bbdou.h (limited to 'engines/illusions/bbdou') diff --git a/engines/illusions/bbdou/bbdou_specialcode.cpp b/engines/illusions/bbdou/bbdou_specialcode.cpp index 0f3a264b85..8614fb68a9 100644 --- a/engines/illusions/bbdou/bbdou_specialcode.cpp +++ b/engines/illusions/bbdou/bbdou_specialcode.cpp @@ -214,6 +214,19 @@ void BbdouSpecialCode::run(uint32 specialCodeId, OpCall &opCall) { } } +void BbdouSpecialCode::resetBeforeResumeSavegame() { + if (_vm->getCurrentScene() == 0x00010032) + _inventory->close(); + _vm->_threads->terminateThreads(0); + _vm->reset(); + _vm->_input->activateButton(0xFFFF); + // TODO _vm->stopMusic(); + // TODO _vm->_gameStates->clear(); + _cursor->reset(0x0004001A); + setCursorControlRoutine(0x0004001A, 0); + _cursor->enable(0x0004001A); +} + // Special codes void BbdouSpecialCode::spcInitCursor(OpCall &opCall) { diff --git a/engines/illusions/bbdou/bbdou_specialcode.h b/engines/illusions/bbdou/bbdou_specialcode.h index df9b3f76c1..c281824077 100644 --- a/engines/illusions/bbdou/bbdou_specialcode.h +++ b/engines/illusions/bbdou/bbdou_specialcode.h @@ -110,6 +110,7 @@ public: virtual ~BbdouSpecialCode(); virtual void init(); virtual void run(uint32 specialCodeId, OpCall &opCall); + virtual void resetBeforeResumeSavegame(); public: typedef Common::HashMap Map; typedef Map::iterator MapIterator; diff --git a/engines/illusions/bbdou/gamestate_bbdou.cpp b/engines/illusions/bbdou/gamestate_bbdou.cpp new file mode 100644 index 0000000000..a20e2c4080 --- /dev/null +++ b/engines/illusions/bbdou/gamestate_bbdou.cpp @@ -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. + * + */ + +#include "illusions/bbdou/gamestate_bbdou.h" +#include "illusions/bbdou/illusions_bbdou.h" +#include "illusions/resources/scriptresource.h" + +namespace Illusions { + +BBDOU_GameState::BBDOU_GameState(IllusionsEngine_BBDOU *vm) + : _vm(vm) { +} + +uint32 BBDOU_GameState::calcWriteBufferSizeInternal() { + return + 4 + // uint32 prevSceneId + _vm->_scriptResource->_properties.getSize() + + _vm->_scriptResource->_blockCounters.getSize(); +} + +bool BBDOU_GameState::readStateInternal(Common::ReadStream *in) { + _vm->_prevSceneId = in->readUint32LE(); + return + _vm->_scriptResource->_properties.readFromStream(in) && + _vm->_scriptResource->_blockCounters.readFromStream(in); +} + +void BBDOU_GameState::writeStateInternal(Common::WriteStream *out) { + out->writeUint32LE(_vm->_prevSceneId); + _vm->_scriptResource->_properties.writeToStream(out); + _vm->_scriptResource->_blockCounters.writeToStream(out); +} + +} // End of namespace Illusions diff --git a/engines/illusions/bbdou/gamestate_bbdou.h b/engines/illusions/bbdou/gamestate_bbdou.h new file mode 100644 index 0000000000..2ef68b5b5e --- /dev/null +++ b/engines/illusions/bbdou/gamestate_bbdou.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_BBDOU_GAMESTATE_BBDOU_H +#define ILLUSIONS_BBDOU_GAMESTATE_BBDOU_H + +#include "illusions/gamestate.h" + +namespace Illusions { + +class IllusionsEngine_BBDOU; + +class BBDOU_GameState : public GameState { +public: + BBDOU_GameState(IllusionsEngine_BBDOU *vm); +protected: + IllusionsEngine_BBDOU *_vm; + uint32 calcWriteBufferSizeInternal(); + bool readStateInternal(Common::ReadStream *in); + void writeStateInternal(Common::WriteStream *out); +}; + +} // End of namespace Illusions + +#endif // ILLUSIONS_BBDOU_GAMESTATE_BBDOU_H diff --git a/engines/illusions/bbdou/illusions_bbdou.cpp b/engines/illusions/bbdou/illusions_bbdou.cpp index 7c129f12b6..78315c404c 100644 --- a/engines/illusions/bbdou/illusions_bbdou.cpp +++ b/engines/illusions/bbdou/illusions_bbdou.cpp @@ -23,6 +23,7 @@ #include "illusions/bbdou/illusions_bbdou.h" #include "illusions/bbdou/bbdou_menukeys.h" #include "illusions/bbdou/bbdou_videoplayer.h" +#include "illusions/bbdou/gamestate_bbdou.h" #include "illusions/bbdou/menusystem_bbdou.h" #include "illusions/actor.h" #include "illusions/camera.h" @@ -171,6 +172,7 @@ Common::Error IllusionsEngine_BBDOU::run() { _soundMan = new SoundMan(this); _menuSystem = new BBDOUMenuSystem(this); _videoPlayer = new BBDOUVideoPlayer(this); + _gameState = new BBDOU_GameState(this); _menuKeys = new BBDOUMenuKeys(this); _screen->setColorKey1(0xF81F); @@ -205,7 +207,12 @@ Common::Error IllusionsEngine_BBDOU::run() { startScriptThread(0x00020004, 0, 0, 0, 0); _doScriptThreadInit = true; + if (ConfMan.hasKey("save_slot")) { + loadGameState(ConfMan.getInt("save_slot")); + } + _walkthroughStarted = false; + _canResumeFromSavegame = false; while (!shouldQuit()) { if (_walkthroughStarted) { @@ -213,6 +220,10 @@ Common::Error IllusionsEngine_BBDOU::run() { startScriptThread(0x00020404, 0, 0, 0, 0); _walkthroughStarted = false; } + if (_resumeFromSavegameRequested && _canResumeFromSavegame) { + resumeFromSavegame(); + _resumeFromSavegameRequested = false; + } runUpdateFunctions(); _system->updateScreen(); updateEvents(); @@ -222,6 +233,7 @@ Common::Error IllusionsEngine_BBDOU::run() { delete _scriptOpcodes; delete _menuKeys; + delete _gameState; delete _videoPlayer; delete _menuSystem; delete _soundMan; @@ -248,12 +260,9 @@ Common::Error IllusionsEngine_BBDOU::run() { bool IllusionsEngine_BBDOU::hasFeature(EngineFeature f) const { return - false; - /* (f == kSupportsRTL) || (f == kSupportsLoadingDuringRuntime) || (f == kSupportsSavingDuringRuntime); - */ } void IllusionsEngine_BBDOU::initInput() { @@ -460,6 +469,11 @@ void IllusionsEngine_BBDOU::startScriptThreadSimple(uint32 threadId, uint32 call void IllusionsEngine_BBDOU::startScriptThread(uint32 threadId, uint32 callingThreadId, uint32 value8, uint32 valueC, uint32 value10) { + if (threadId == 0x0002041E && ConfMan.hasKey("save_slot")) { + // Skip intro videos when loading a savegame from the launcher (kludge) + notifyThreadId(callingThreadId); + return; + } debug(2, "Starting script thread %08X", threadId); byte *scriptCodeIp = _scriptResource->getThreadCode(threadId); newScriptThread(threadId, callingThreadId, 0, scriptCodeIp, value8, valueC, value10); @@ -503,10 +517,6 @@ uint32 IllusionsEngine_BBDOU::startTalkThread(int16 duration, uint32 objectId, u return tempThreadId; } -void IllusionsEngine_BBDOU::resumeFromSavegame(uint32 callingThreadId) { - // TODO -} - uint32 IllusionsEngine_BBDOU::startTempScriptThread(byte *scriptCodeIp, uint32 callingThreadId, uint32 value8, uint32 valueC, uint32 value10) { uint32 tempThreadId = newTempThreadId(); @@ -555,6 +565,13 @@ bool IllusionsEngine_BBDOU::enterScene(uint32 sceneId, uint32 threadId) { sceneId = _theSceneId; } _activeScenes.push(sceneId); + if (sceneId == 0x0001007D) { + // Savegame loading from the ScummVM GUI or command line is only + // possible after resources have been initialized by the startup script. + // Once that script is done, it switches to the start menu scene. + // After that the game is ready and a savegame can finally be loaded. + _canResumeFromSavegame = true; + } return sceneInfo != 0; } @@ -647,4 +664,34 @@ void IllusionsEngine_BBDOU::reset() { // TODO script_sub_417FF0(1, 0); } +void IllusionsEngine_BBDOU::loadSavegameFromScript(int16 slotNum, uint32 callingThreadId) { + // NOTE Just loads the savegame, doesn't activate it yet + const char *fileName = getSavegameFilename(_savegameSlotNum); + _loadGameResult = loadgame(fileName); +} + +void IllusionsEngine_BBDOU::saveSavegameFromScript(int16 slotNum, uint32 callingThreadId) { + // TODO + // const char *fileName = getSavegameFilename(slotNum); + _saveGameResult = false;//savegame(fileName, _savegameDescription.c_str()); +} + +void IllusionsEngine_BBDOU::activateSavegame(uint32 callingThreadId) { + uint32 sceneId, threadId; + _prevSceneId = 0x10000; + _gameState->readState(sceneId, threadId); + enterScene(sceneId, callingThreadId); + // TODO Check if value8, valueC, value10 are needed at all + startAnonScriptThread(threadId, 0, 0, 0, 0); + _gameState->deleteReadStream(); +} + +void IllusionsEngine_BBDOU::resumeFromSavegame() { + // Resetting the game is usually done by the script, when loading from the ScummVM menu or + // command line this has to be done manually. + _specialCode->resetBeforeResumeSavegame(); + dumpActiveScenes(0x00010003, 0); + activateSavegame(0); +} + } // End of namespace Illusions diff --git a/engines/illusions/bbdou/illusions_bbdou.h b/engines/illusions/bbdou/illusions_bbdou.h index 2bad993041..f9311e1723 100644 --- a/engines/illusions/bbdou/illusions_bbdou.h +++ b/engines/illusions/bbdou/illusions_bbdou.h @@ -75,11 +75,14 @@ public: uint32 _theThreadId; uint32 _globalSceneId; + bool _loadGameResult, _saveGameResult; + BBDOUMenuSystem *_menuSystem; BBDOUVideoPlayer *_videoPlayer; BBDOUMenuKeys *_menuKeys; bool _walkthroughStarted; + bool _canResumeFromSavegame; void initInput(); @@ -128,7 +131,6 @@ public: uint32 sequenceId2, uint32 namedPointId, uint32 callingThreadId); uint32 startTempScriptThread(byte *scriptCodeIp, uint32 callingThreadId, uint32 value8, uint32 valueC, uint32 value10); - void resumeFromSavegame(uint32 callingThreadId); void newScriptThread(uint32 threadId, uint32 callingThreadId, uint notifyFlags, byte *scriptCodeIp, uint32 value8, uint32 valueC, uint32 value10); @@ -151,6 +153,11 @@ public: bool findTriggerCause(uint32 sceneId, uint32 verbId, uint32 objectId2, uint32 objectId, uint32 &codeOffs); void reset(); + void loadSavegameFromScript(int16 slotNum, uint32 callingThreadId); + void saveSavegameFromScript(int16 slotNum, uint32 callingThreadId); + void activateSavegame(uint32 callingThreadId); + void resumeFromSavegame(); + }; } // End of namespace Illusions diff --git a/engines/illusions/bbdou/scriptopcodes_bbdou.cpp b/engines/illusions/bbdou/scriptopcodes_bbdou.cpp index e70be8fdb9..9dd9c9aac4 100644 --- a/engines/illusions/bbdou/scriptopcodes_bbdou.cpp +++ b/engines/illusions/bbdou/scriptopcodes_bbdou.cpp @@ -23,6 +23,7 @@ #include "illusions/bbdou/illusions_bbdou.h" #include "illusions/bbdou/scriptopcodes_bbdou.h" #include "illusions/bbdou/bbdou_menukeys.h" +#include "illusions/bbdou/gamestate_bbdou.h" #include "illusions/bbdou/menusystem_bbdou.h" #include "illusions/actor.h" #include "illusions/camera.h" @@ -140,8 +141,8 @@ void ScriptOpcodes_BBDOU::initOpcodes() { OPCODE(82, opSwitchMenuChoice); OPCODE(83, opQuitGame); OPCODE(84, opResetGame); - // TODO OPCODE(85, opSaveGame); - // TODO OPCODE(86, opRestoreGame); + OPCODE(85, opSaveGame); + OPCODE(86, opRestoreGameState); OPCODE(87, opDeactivateButton); OPCODE(88, opActivateButton); OPCODE(89, opNop); @@ -170,6 +171,10 @@ void ScriptOpcodes_BBDOU::initOpcodes() { OPCODE(161, opSetActorUsePan); OPCODE(168, opStartAbortableThread); OPCODE(169, opKillThread); + OPCODE(170, opLoadGame); + OPCODE(171, opPushLoadgameResult); + OPCODE(172, opPushSavegameResult); + // 173, 174 unused OPCODE(175, opSetSceneIdThreadId); OPCODE(176, opStackPush0); OPCODE(177, opSetFontId); @@ -342,7 +347,7 @@ void ScriptOpcodes_BBDOU::opChangeScene(ScriptThread *scriptThread, OpCall &opCa _vm->_prevSceneId = _vm->getCurrentScene(); _vm->exitScene(opCall._callerThreadId); _vm->enterScene(sceneId, opCall._callerThreadId); - // TODO _vm->_gameStates->writeStates(_vm->_prevSceneId, sceneId, threadId); + _vm->_gameState->writeState(sceneId, threadId); _vm->startAnonScriptThread(threadId, 0, scriptThread->_value8, scriptThread->_valueC, scriptThread->_value10); } @@ -740,6 +745,17 @@ void ScriptOpcodes_BBDOU::opResetGame(ScriptThread *scriptThread, OpCall &opCall // TODO _vm->_gameStates->clear(); } +void ScriptOpcodes_BBDOU::opSaveGame(ScriptThread *scriptThread, OpCall &opCall) { + ARG_SKIP(2); + ARG_INT16(bankNum) + ARG_INT16(slotNum) + _vm->saveSavegameFromScript(slotNum, opCall._callerThreadId); +} + +void ScriptOpcodes_BBDOU::opRestoreGameState(ScriptThread *scriptThread, OpCall &opCall) { + _vm->activateSavegame(opCall._callerThreadId); +} + void ScriptOpcodes_BBDOU::opDeactivateButton(ScriptThread *scriptThread, OpCall &opCall) { ARG_INT16(button) _vm->_input->deactivateButton(button); @@ -920,6 +936,21 @@ void ScriptOpcodes_BBDOU::opKillThread(ScriptThread *scriptThread, OpCall &opCal _vm->_threads->killThread(threadId); } +void ScriptOpcodes_BBDOU::opLoadGame(ScriptThread *scriptThread, OpCall &opCall) { + ARG_SKIP(2); + ARG_INT16(bankNum) + ARG_INT16(slotNum) + _vm->loadSavegameFromScript(slotNum, opCall._callerThreadId); +} + +void ScriptOpcodes_BBDOU::opPushLoadgameResult(ScriptThread *scriptThread, OpCall &opCall) { + _vm->_stack->push(_vm->_loadGameResult ? 1 : 0); +} + +void ScriptOpcodes_BBDOU::opPushSavegameResult(ScriptThread *scriptThread, OpCall &opCall) { + _vm->_stack->push(_vm->_saveGameResult ? 1 : 0); +} + void ScriptOpcodes_BBDOU::opSetSceneIdThreadId(ScriptThread *scriptThread, OpCall &opCall) { ARG_SKIP(2); ARG_UINT32(sceneId); @@ -941,7 +972,6 @@ void ScriptOpcodes_BBDOU::opAddMenuKey(ScriptThread *scriptThread, OpCall &opCal ARG_SKIP(2); ARG_UINT32(key); ARG_UINT32(threadId); - debug("addMenuKey(%08X; %08X)", key, threadId); _vm->_menuKeys->addMenuKey(key, threadId); } @@ -954,7 +984,7 @@ void ScriptOpcodes_BBDOU::opChangeSceneAll(ScriptThread *scriptThread, OpCall &o _vm->_prevSceneId = _vm->getCurrentScene(); _vm->dumpActiveScenes(_vm->_globalSceneId, opCall._callerThreadId); _vm->enterScene(sceneId, opCall._callerThreadId); - // TODO _vm->_gameStates->writeStates(_vm->_prevSceneId, sceneId, threadId); + _vm->_gameState->writeState(sceneId, threadId); _vm->startAnonScriptThread(threadId, 0, scriptThread->_value8, scriptThread->_valueC, scriptThread->_value10); } diff --git a/engines/illusions/bbdou/scriptopcodes_bbdou.h b/engines/illusions/bbdou/scriptopcodes_bbdou.h index a1118836e2..63731cf412 100644 --- a/engines/illusions/bbdou/scriptopcodes_bbdou.h +++ b/engines/illusions/bbdou/scriptopcodes_bbdou.h @@ -110,6 +110,8 @@ protected: void opSwitchMenuChoice(ScriptThread *scriptThread, OpCall &opCall); void opQuitGame(ScriptThread *scriptThread, OpCall &opCall); void opResetGame(ScriptThread *scriptThread, OpCall &opCall); + void opSaveGame(ScriptThread *scriptThread, OpCall &opCall); + void opRestoreGameState(ScriptThread *scriptThread, OpCall &opCall); void opDeactivateButton(ScriptThread *scriptThread, OpCall &opCall); void opActivateButton(ScriptThread *scriptThread, OpCall &opCall); void opNop(ScriptThread *scriptThread, OpCall &opCall); @@ -135,6 +137,9 @@ protected: void opSetActorUsePan(ScriptThread *scriptThread, OpCall &opCall); void opStartAbortableThread(ScriptThread *scriptThread, OpCall &opCall); void opKillThread(ScriptThread *scriptThread, OpCall &opCall); + void opLoadGame(ScriptThread *scriptThread, OpCall &opCall); + void opPushLoadgameResult(ScriptThread *scriptThread, OpCall &opCall); + void opPushSavegameResult(ScriptThread *scriptThread, OpCall &opCall); void opSetSceneIdThreadId(ScriptThread *scriptThread, OpCall &opCall); void opStackPush0(ScriptThread *scriptThread, OpCall &opCall); void opSetFontId(ScriptThread *scriptThread, OpCall &opCall); -- cgit v1.2.3