diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/sci/detection.cpp | 7 | ||||
-rw-r--r-- | engines/sci/engine/game.cpp | 151 | ||||
-rw-r--r-- | engines/sci/engine/vm.cpp | 51 | ||||
-rw-r--r-- | engines/sci/engine/vm.h | 59 | ||||
-rw-r--r-- | engines/sci/module.mk | 1 | ||||
-rw-r--r-- | engines/sci/sci.cpp | 132 | ||||
-rw-r--r-- | engines/sci/sci.h | 41 |
7 files changed, 177 insertions, 265 deletions
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index 1ccfc6bf02..f36bae2d6d 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -36,7 +36,6 @@ #include "sci/engine/script.h" #include "sci/engine/seg_manager.h" #include "sci/engine/state.h" -#include "sci/engine/vm.h" // for convertSierraGameId namespace Sci { @@ -198,6 +197,12 @@ static const OldNewIdTableEntry s_oldNewTable[] = { { "", "", SCI_VERSION_NONE } }; +/** + * Converts the builtin Sierra game IDs to the ones we use in ScummVM + * @param[in] gameId The internal game ID + * @param[in] gameFlags The game's flags, which are adjusted accordingly for demos + * @return The equivalent ScummVM game id + */ Common::String convertSierraGameId(Common::String sierraId, uint32 *gameFlags, ResourceManager *resMan) { // Convert the id to lower case, so that we match all upper/lower case variants. sierraId.toLowercase(); diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp deleted file mode 100644 index 04f8501027..0000000000 --- a/engines/sci/engine/game.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ - -#include "common/system.h" -#include "common/file.h" - -#include "engines/advancedDetector.h" // for ADGF_DEMO - -#include "sci/sci.h" -#include "sci/resource.h" -#include "sci/engine/features.h" -#include "sci/engine/state.h" -#include "sci/engine/kernel.h" -#include "sci/engine/message.h" -#include "sci/graphics/gui.h" -#include "sci/graphics/menu.h" -#include "sci/sound/audio.h" -#include "sci/sound/music.h" - -namespace Sci { - -#ifdef USE_OLD_MUSIC_FUNCTIONS -int game_init_sound(EngineState *s, int sound_flags, SciVersion soundVersion) { - if (getSciVersion() > SCI_VERSION_0_LATE) - sound_flags |= SFX_STATE_FLAG_MULTIPLAY; - - s->sfx_init_flags = sound_flags; - s->_sound.sfx_init(g_sci->getResMan(), sound_flags, soundVersion); - - return 0; -} -#endif - -/*************************************************************/ -/* Game instance stuff: Init/Unitialize state-dependant data */ -/*************************************************************/ - -int game_init(EngineState *s) { - // FIXME Use new VM instantiation code all over the place - // Script 0 needs to be allocated here before anything else! - int script0Segment = s->_segMan->getScriptSegment(0, SCRIPT_GET_LOCK); - DataStack *stack = s->_segMan->allocateStack(VM_STACK_SIZE, NULL); - - s->_msgState = new MessageState(s->_segMan); - s->gc_countdown = GC_INTERVAL - 1; - - // Script 0 should always be at segment 1 - if (script0Segment != 1) { - debug(2, "Failed to instantiate script.000"); - return 1; - } - - s->initGlobals(); - - if (s->abortScriptProcessing == kAbortRestartGame && g_sci->_gfxMenu) - g_sci->_gfxMenu->reset(); - - s->_segMan->initSysStrings(); - - s->r_acc = s->r_prev = NULL_REG; - - s->_executionStack.clear(); // Start without any execution stack - s->execution_stack_base = -1; // No vm is running yet - s->_executionStackPosChanged = false; - - s->abortScriptProcessing = kAbortNone; - s->gameWasRestarted = false; - - s->stack_base = stack->_entries; - s->stack_top = stack->_entries + stack->_capacity; - - if (!script_instantiate(g_sci->getResMan(), s->_segMan, 0)) { - warning("game_init(): Could not instantiate script 0"); - return 1; - } - - // Reset parser - Vocabulary *voc = g_sci->getVocabulary(); - if (voc) { - voc->parserIsValid = false; // Invalidate parser - voc->parser_event = NULL_REG; // Invalidate parser event - voc->parser_base = make_reg(s->_segMan->getSysStringsSegment(), SYS_STRING_PARSER_BASE); - } - - s->game_start_time = g_system->getMillis(); - s->last_wait_time = s->game_start_time; - - srand(g_system->getMillis()); // Initialize random number generator - - s->_gameObj = g_sci->getResMan()->findGameObject(); - -#ifdef USE_OLD_MUSIC_FUNCTIONS - if (s->sfx_init_flags & SFX_STATE_FLAG_NOSOUND) - game_init_sound(s, 0, g_sci->_features->detectDoSoundType()); -#endif - - // Load game language into printLang property of game object - // FIXME: It's evil to achieve this as a side effect of a getter. - // Much better to have an explicit init method for this. - g_sci->getSciLanguage(); - - return 0; -} - -int game_exit(EngineState *s) { - if (s->abortScriptProcessing != kAbortLoadGame) { - s->_executionStack.clear(); -#ifdef USE_OLD_MUSIC_FUNCTIONS - s->_sound.sfx_exit(); - // Reinit because some other code depends on having a valid state - game_init_sound(s, SFX_STATE_FLAG_NOSOUND, g_sci->_features->detectDoSoundType()); -#else - g_sci->_audio->stopAllAudio(); - s->_soundCmd->clearPlayList(); -#endif - } - - // TODO Free parser segment here - - // TODO Free scripts here - - // Close all opened file handles - s->_fileHandles.clear(); - s->_fileHandles.resize(5); - - return 0; -} - -} // End of namespace Sci diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index eb2824d9c7..2c92bdadc3 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -1664,57 +1664,6 @@ void run_vm(EngineState *s, bool restoring) { } } -static void _init_stack_base_with_selector(EngineState *s, Selector selector) { - s->stack_base[0] = make_reg(0, (uint16)selector); - s->stack_base[1] = NULL_REG; -} - -void game_run(EngineState **_s) { - EngineState *s = *_s; - - debugC(2, kDebugLevelVM, "Calling %s::play()", g_sci->getGameID()); - _init_stack_base_with_selector(s, g_sci->getKernel()->_selectorCache.play); // Call the play selector - - // Now: Register the first element on the execution stack - if (!send_selector(s, s->_gameObj, s->_gameObj, s->stack_base, 2, s->stack_base)) { - g_sci->getSciDebugger()->printObject(s->_gameObj); - error("Failed to run the game! Aborting..."); - return; - } - - // and ENGAGE! - - // Attach the debug console on game startup, if requested - if (DebugMan.isDebugChannelEnabled(kDebugLevelOnStartup)) - g_sci->getSciDebugger()->attach(); - - do { - s->_executionStackPosChanged = false; - run_vm(s, (s->abortScriptProcessing == kAbortLoadGame)); - game_exit(s); - - if (s->abortScriptProcessing == kAbortRestartGame) { - s->_segMan->resetSegMan(); - game_init(s); -#ifdef USE_OLD_MUSIC_FUNCTIONS - s->_sound.sfx_reset_player(); -#endif - _init_stack_base_with_selector(s, g_sci->getKernel()->_selectorCache.play); - send_selector(s, s->_gameObj, s->_gameObj, s->stack_base, 2, s->stack_base); - s->gameWasRestarted = true; - } else if (s->abortScriptProcessing == kAbortLoadGame) { - s->abortScriptProcessing = kAbortNone; - // Insert a replay selector - _init_stack_base_with_selector(s, g_sci->getKernel()->_selectorCache.replay); - send_selector(s, s->_gameObj, s->_gameObj, s->stack_base, 2, s->stack_base); - } else { - break; // exit loop - } - } while (true); - - debugC(2, kDebugLevelVM, "Game::play() finished."); -} - reg_t *ObjVarRef::getPointer(SegManager *segMan) const { Object *o = segMan->getObject(obj); return o ? &o->getVariableRef(varindex) : 0; diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 1764284dae..fa57a1151c 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -330,65 +330,6 @@ int script_instantiate(ResourceManager *resMan, SegManager *segMan, int script_n void script_uninstantiate(SegManager *segMan, int script_nr); /** - * Converts the builtin Sierra game IDs to the ones we use in ScummVM - * @param[in] gameId The internal game ID - * @param[in] gameFlags The game's flags, which are adjusted accordingly for demos - * @return The equivalent ScummVM game id - */ -Common::String convertSierraGameId(const char *gameId, uint32 *gameFlags, ResourceManager *resMan); - -/** - * Initializes an SCI game - * This function must be run before script_run() is executed. Graphics data - * is initialized iff s->gfx_state != NULL. - * @param[in] s The state to operate on - * @return 0 on success, 1 if an error occured. - */ -int game_init(EngineState *s); - -#ifdef USE_OLD_MUSIC_FUNCTIONS -/** - * Initializes the sound part of an SCI game - * This function may only be called if game_init() did not initialize - * the sound data. - * @param[in] s The state to initialize the sound in - * @param[in] sound_flags Flags to pass to the sound subsystem - * @param[in] soundVersion sound-version that got detected during game init - * @return 0 on success, 1 if an error occured - */ -int game_init_sound(EngineState *s, int sound_flags, SciVersion soundVersion); -#endif - -/** - * Runs an SCI game - * This is the main function for SCI games. It takes a valid state, loads - * script 0 to it, finds the game object, allocates a stack, and runs the - * init method of the game object. In layman's terms, this runs an SCI game. - * Note that, EngineState *s may be changed during the game, e.g. if a game - * state is restored. - * @param[in] s Pointer to the pointer of the state to operate on - */ -void game_run(EngineState **s); - -/** - * Restores an SCI game state and runs the game - * This restores a savegame; otherwise, it behaves just like game_run(). - * @param[in] s Pointer to the pointer of the state to - * operate on - * @param[in] savegame_name Name of the savegame to restore - * @return 0 on success, 1 if an error occured. - */ -int game_restore(EngineState **s, char *savegame_name); - -/** - * Uninitializes an initialized SCI game - * This function should be run after each script_run() call. - * @param[in] s The state to operate on - * @return 0 on success, 1 if an error occured. - */ -int game_exit(EngineState *s); - -/** * Read a PMachine instruction from a memory buffer and return its length. * * @param[in] src address from which to start parsing diff --git a/engines/sci/module.mk b/engines/sci/module.mk index a2cfd38f95..4860ac7c2f 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -10,7 +10,6 @@ MODULE_OBJS := \ sci.o \ util.o \ engine/features.o \ - engine/game.o \ engine/gc.o \ engine/kernel.o \ engine/kevent.o \ diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index d5cab1adc9..08236597b4 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -36,6 +36,7 @@ #include "sci/event.h" #include "sci/engine/features.h" +#include "sci/engine/message.h" #include "sci/engine/state.h" #include "sci/engine/kernel.h" #include "sci/engine/script.h" // for script_adjust_opcode_formats @@ -197,7 +198,7 @@ Common::Error SciEngine::run() { // The game needs to be initialized before the graphics system is initialized, as // the graphics code checks parts of the seg manager upon initialization (e.g. for // the presence of the fastCast object) - if (game_init(_gamestate)) { /* Initialize */ + if (!initGame()) { /* Initialize */ warning("Game initialization failed: Aborting..."); // TODO: Add an "init failed" error? return Common::kUnknownError; @@ -259,7 +260,7 @@ Common::Error SciEngine::run() { _gamestate->loadFromLauncher = -1; } - game_run(&_gamestate); // Run the game + runGame(); ConfMan.flushToDisk(); @@ -280,6 +281,133 @@ Common::Error SciEngine::run() { return Common::kNoError; } +bool SciEngine::initGame() { + // Script 0 needs to be allocated here before anything else! + int script0Segment = _gamestate->_segMan->getScriptSegment(0, SCRIPT_GET_LOCK); + DataStack *stack = _gamestate->_segMan->allocateStack(VM_STACK_SIZE, NULL); + + _gamestate->_msgState = new MessageState(_gamestate->_segMan); + _gamestate->gc_countdown = GC_INTERVAL - 1; + + // Script 0 should always be at segment 1 + if (script0Segment != 1) { + debug(2, "Failed to instantiate script.000"); + return false; + } + + _gamestate->initGlobals(); + + if (_gamestate->abortScriptProcessing == kAbortRestartGame && _gfxMenu) + _gfxMenu->reset(); + + _gamestate->_segMan->initSysStrings(); + + _gamestate->r_acc = _gamestate->r_prev = NULL_REG; + + _gamestate->_executionStack.clear(); // Start without any execution stack + _gamestate->execution_stack_base = -1; // No vm is running yet + _gamestate->_executionStackPosChanged = false; + + _gamestate->abortScriptProcessing = kAbortNone; + _gamestate->gameWasRestarted = false; + + _gamestate->stack_base = stack->_entries; + _gamestate->stack_top = stack->_entries + stack->_capacity; + + if (!script_instantiate(_resMan, _gamestate->_segMan, 0)) { + warning("initGame(): Could not instantiate script 0"); + return false; + } + + // Reset parser + if (_vocabulary) { + _vocabulary->parserIsValid = false; // Invalidate parser + _vocabulary->parser_event = NULL_REG; // Invalidate parser event + _vocabulary->parser_base = make_reg(_gamestate->_segMan->getSysStringsSegment(), SYS_STRING_PARSER_BASE); + } + + _gamestate->game_start_time = _gamestate->last_wait_time = g_system->getMillis(); + + srand(g_system->getMillis()); // Initialize random number generator + + _gamestate->_gameObj = _resMan->findGameObject(); + +#ifdef USE_OLD_MUSIC_FUNCTIONS + if (_gamestate->sfx_init_flags & SFX_STATE_FLAG_NOSOUND) + game_init_sound(_gamestate, 0, _features->detectDoSoundType()); +#endif + + // Load game language into printLang property of game object + // FIXME: It's evil to achieve this as a side effect of a getter. + // Much better to have an explicit init method for this. + getSciLanguage(); + + return true; +} + +void SciEngine::initStackBaseWithSelector(Selector selector) { + _gamestate->stack_base[0] = make_reg(0, (uint16)selector); + _gamestate->stack_base[1] = NULL_REG; + + // Register the first element on the execution stack + if (!send_selector(_gamestate, _gamestate->_gameObj, _gamestate->_gameObj, _gamestate->stack_base, 2, _gamestate->stack_base)) { + _console->printObject(_gamestate->_gameObj); + error("initStackBaseWithSelector: error while registering the first selector in the call stack"); + } + +} + +void SciEngine::runGame() { + initStackBaseWithSelector(_kernel->_selectorCache.play); // Call the play selector + + // Attach the debug console on game startup, if requested + if (DebugMan.isDebugChannelEnabled(kDebugLevelOnStartup)) + _console->attach(); + + do { + _gamestate->_executionStackPosChanged = false; + run_vm(_gamestate, (_gamestate->abortScriptProcessing == kAbortLoadGame)); + exitGame(); + + if (_gamestate->abortScriptProcessing == kAbortRestartGame) { + _gamestate->_segMan->resetSegMan(); + initGame(); +#ifdef USE_OLD_MUSIC_FUNCTIONS + _gamestate->_sound.sfx_reset_player(); +#endif + initStackBaseWithSelector(_kernel->_selectorCache.play); + _gamestate->gameWasRestarted = true; + } else if (_gamestate->abortScriptProcessing == kAbortLoadGame) { + _gamestate->abortScriptProcessing = kAbortNone; + initStackBaseWithSelector(_kernel->_selectorCache.replay); + } else { + break; // exit loop + } + } while (true); +} + +void SciEngine::exitGame() { + if (_gamestate->abortScriptProcessing != kAbortLoadGame) { + _gamestate->_executionStack.clear(); +#ifdef USE_OLD_MUSIC_FUNCTIONS + _gamestate->_sound.sfx_exit(); + // Reinit because some other code depends on having a valid state + game_init_sound(_gamestate, SFX_STATE_FLAG_NOSOUND, _features->detectDoSoundType()); +#else + _audio->stopAllAudio(); + _gamestate->_soundCmd->clearPlayList(); +#endif + } + + // TODO Free parser segment here + + // TODO Free scripts here + + // Close all opened file handles + _gamestate->_fileHandles.clear(); + _gamestate->_fileHandles.resize(5); +} + // Invoked by error() when a severe error occurs GUI::Debugger *SciEngine::getDebugger() { if (_gamestate) { diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 0902a41139..0bcff8a02e 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -28,6 +28,7 @@ #include "engines/engine.h" #include "common/util.h" +#include "engine/vm_types.h" // for Selector struct ADGameDescription; @@ -219,6 +220,46 @@ public: GameFeatures *_features; private: + /** + * Initializes a SCI game + * This function must be run before script_run() is executed. Graphics data + * is initialized iff s->gfx_state != NULL. + * @param[in] s The state to operate on + * @return true on success, false if an error occured. + */ + bool initGame(); + + /** + * Runs a SCI game + * This is the main function for SCI games. It takes a valid state, loads + * script 0 to it, finds the game object, allocates a stack, and runs the + * init method of the game object. In layman's terms, this runs a SCI game. + * @param[in] s Pointer to the pointer of the state to operate on + */ + void runGame(); + + /** + * Uninitializes an initialized SCI game + * This function should be run after each script_run() call. + * @param[in] s The state to operate on + */ + void exitGame(); + +#ifdef USE_OLD_MUSIC_FUNCTIONS + /** + * Initializes the sound part of a SCI game + * This function may only be called if game_init() did not initialize + * the sound data. + * @param[in] s The state to initialize the sound in + * @param[in] sound_flags Flags to pass to the sound subsystem + * @param[in] soundVersion sound-version that got detected during game init + * @return 0 on success, 1 if an error occured + */ + int game_init_sound(EngineState *s, int sound_flags, SciVersion soundVersion); +#endif + + void initStackBaseWithSelector(Selector selector); + const ADGameDescription *_gameDescription; ResourceManager *_resMan; /**< The resource manager */ EngineState *_gamestate; |