diff options
| -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;  | 
