Example #1
0
SciVersion GameFeatures::detectMessageFunctionType() {
	if (_messageFunctionType != SCI_VERSION_NONE)
		return _messageFunctionType;

	if (getSciVersion() > SCI_VERSION_1_1) {
		_messageFunctionType = SCI_VERSION_1_1;
		return _messageFunctionType;
	} else if (getSciVersion() < SCI_VERSION_1_1) {
		_messageFunctionType = SCI_VERSION_1_LATE;
		return _messageFunctionType;
	}

	Common::List<ResourceId> resources = g_sci->getResMan()->listResources(kResourceTypeMessage, -1);

	if (resources.empty()) {
		// No messages found, so this doesn't really matter anyway...
		_messageFunctionType = SCI_VERSION_1_1;
		return _messageFunctionType;
	}

	Resource *res = g_sci->getResMan()->findResource(*resources.begin(), false);
	assert(res);

	// Only v2 Message resources use the kGetMessage kernel function.
	// v3-v5 use the kMessage kernel function.

	if (READ_SCI11ENDIAN_UINT32(res->data) / 1000 == 2)
		_messageFunctionType = SCI_VERSION_1_LATE;
	else
		_messageFunctionType = SCI_VERSION_1_1;

	debugC(1, kDebugLevelVM, "Detected message function type: %s", getSciVersionDesc(_messageFunctionType));
	return _messageFunctionType;
}
Example #2
0
SciVersion GameFeatures::detectDoSoundType() {
	if (_doSoundType == SCI_VERSION_NONE) {
		if (getSciVersion() == SCI_VERSION_0_EARLY) {
			// Almost all of the SCI0EARLY games use different sound resources than
			//  SCI0LATE. Although the last SCI0EARLY game (lsl2) uses SCI0LATE resources
			_doSoundType = g_sci->getResMan()->detectEarlySound() ? SCI_VERSION_0_EARLY : SCI_VERSION_0_LATE;
#ifdef ENABLE_SCI32
		} else if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
			_doSoundType = SCI_VERSION_2_1_EARLY;
#endif
		} else if (SELECTOR(nodePtr) == -1) {
			// No nodePtr selector, so this game is definitely using newer
			// SCI0 sound code (i.e. SCI_VERSION_0_LATE)
			_doSoundType = SCI_VERSION_0_LATE;
		} else if (getSciVersion() >= SCI_VERSION_1_LATE) {
			// All SCI1 late games use the newer doSound semantics
			_doSoundType = SCI_VERSION_1_LATE;
		} else {
			if (!autoDetectSoundType()) {
				warning("DoSound detection failed, taking an educated guess");

				if (getSciVersion() >= SCI_VERSION_1_MIDDLE)
					_doSoundType = SCI_VERSION_1_LATE;
				else if (getSciVersion() > SCI_VERSION_01)
					_doSoundType = SCI_VERSION_1_EARLY;
			}
		}

		debugC(1, kDebugLevelSound, "Detected DoSound type: %s", getSciVersionDesc(_doSoundType));
	}

	return _doSoundType;
}
Example #3
0
SciVersion GameFeatures::detectSetCursorType() {
	if (_setCursorType == SCI_VERSION_NONE) {
		if (getSciVersion() <= SCI_VERSION_1_MIDDLE) {
			// SCI1 middle and older games never use cursor views
			_setCursorType = SCI_VERSION_0_EARLY;
		} else if (getSciVersion() >= SCI_VERSION_1_1) {
			// SCI1.1 games always use cursor views
			_setCursorType = SCI_VERSION_1_1;
		} else {	// SCI1 late game, detect cursor semantics
			// If the Cursor object doesn't exist, we're using the SCI0 early
			// kSetCursor semantics.
			if (_segMan->findObjectByName("Cursor") == NULL_REG) {
				_setCursorType = SCI_VERSION_0_EARLY;
				debugC(1, kDebugLevelGraphics, "Detected SetCursor type: %s", getSciVersionDesc(_setCursorType));
				return _setCursorType;
			}

			// Check for the existence of the handCursor object (first found).
			// This is based on KQ5.
			reg_t objAddr = _segMan->findObjectByName("handCursor", 0);

			// If that doesn't exist, we assume it uses SCI1.1 kSetCursor semantics
			if (objAddr == NULL_REG) {
				_setCursorType = SCI_VERSION_1_1;
				debugC(1, kDebugLevelGraphics, "Detected SetCursor type: %s", getSciVersionDesc(_setCursorType));
				return _setCursorType;
			}

			// Now we check what the number variable holds in the handCursor
			// object.
			uint16 number = readSelectorValue(_segMan, objAddr, SELECTOR(number));

			// If the number is 0, it uses views and therefore the SCI1.1
			// kSetCursor semantics, otherwise it uses the SCI0 early kSetCursor
			// semantics.
			if (number == 0)
				_setCursorType = SCI_VERSION_1_1;
			else
				_setCursorType = SCI_VERSION_0_EARLY;
		}

		debugC(1, kDebugLevelGraphics, "Detected SetCursor type: %s", getSciVersionDesc(_setCursorType));
	}

	return _setCursorType;
}
Example #4
0
SciVersion GameFeatures::detectSci21KernelType() {
	if (_sci21KernelType == SCI_VERSION_NONE) {
		if (!autoDetectSci21KernelType())
			error("Could not detect the SCI2.1 kernel table type");

		debugC(1, kDebugLevelVM, "Detected SCI2.1 kernel type: %s", getSciVersionDesc(_sci21KernelType));
	}
	return _sci21KernelType;
}
Example #5
0
SciVersion GameFeatures::detectLofsType() {
	if (_lofsType == SCI_VERSION_NONE) {
		// This detection only works (and is only needed) for SCI 1
		if (getSciVersion() <= SCI_VERSION_01) {
			_lofsType = SCI_VERSION_0_EARLY;
			return _lofsType;
		}

		if (getSciVersion() >= SCI_VERSION_1_1 && getSciVersion() <= SCI_VERSION_2_1) {
			// SCI1.1 type, i.e. we compensate for the fact that the heap is attached
			// to the end of the script
			_lofsType = SCI_VERSION_1_1;
			return _lofsType;
		}

		if (getSciVersion() == SCI_VERSION_3) {
			// SCI3 type, same as pre-SCI1.1, really, as there is no separate heap
			// resource
			_lofsType = SCI_VERSION_3;
			return _lofsType;
		}

		// Find a function of the "Game" object (which is the game super class) which invokes lofsa/lofss
		reg_t gameSuperClass = g_sci->getGameSuperClassAddress();
		bool found = false;
		if (!gameSuperClass.isNull()) {
			Common::String gameSuperClassName = _segMan->getObjectName(gameSuperClass);
			const Object *gameSuperObject = _segMan->getObject(gameSuperClass);

			if (gameSuperObject) {
				for (uint m = 0; m < gameSuperObject->getMethodCount(); m++) {
					found = autoDetectLofsType(gameSuperClassName, m);
					if (found)
						break;
				}
			} else {
				warning("detectLofsType(): Could not get superclass object");
			}
		} else {
			warning("detectLofsType(): Could not find superclass of game object");
		}

		if (!found) {
			warning("detectLofsType(): failed, taking an educated guess");

			if (getSciVersion() >= SCI_VERSION_1_MIDDLE)
				_lofsType = SCI_VERSION_1_MIDDLE;
			else
				_lofsType = SCI_VERSION_0_EARLY;
		}

		debugC(1, kDebugLevelVM, "Detected Lofs type: %s", getSciVersionDesc(_lofsType));
	}

	return _lofsType;
}
Example #6
0
Common::Error SciEngine::run() {
	g_eventRec.registerRandomSource(_rng, "sci");

	// Assign default values to the config manager, in case settings are missing
	ConfMan.registerDefault("sci_originalsaveload", "false");
	ConfMan.registerDefault("native_fb01", "false");
	ConfMan.registerDefault("windows_cursors", "false");	// Windows cursors for KQ6 Windows

	_resMan = new ResourceManager();
	assert(_resMan);
	_resMan->addAppropriateSources();
	_resMan->init();

	// TODO: Add error handling. Check return values of addAppropriateSources
	// and init. We first have to *add* sensible return values, though ;).
/*
	if (!_resMan) {
		warning("No resources found, aborting");
		return Common::kNoGameDataFoundError;
	}
*/

	// Reset, so that error()s before SoundCommandParser is initialized wont cause a crash
	_soundCmd = NULL;

	// Add the after market GM patches for the specified game, if they exist
	_resMan->addNewGMPatch(_gameId);
	_gameObjectAddress = _resMan->findGameObject();
	_gameSuperClassAddress = NULL_REG;

	SegManager *segMan = new SegManager(_resMan);

	// Initialize the game screen
	_gfxScreen = new GfxScreen(_resMan);
	_gfxScreen->debugUnditherSetState(ConfMan.getBool("disable_dithering"));

	// Create debugger console. It requires GFX to be initialized
	_console = new Console(this);
	_kernel = new Kernel(_resMan, segMan);

	_features = new GameFeatures(segMan, _kernel);
	// Only SCI0, SCI01 and SCI1 EGA games used a parser
	_vocabulary = (getSciVersion() <= SCI_VERSION_1_EGA) ? new Vocabulary(_resMan, false) : NULL;
	// Also, XMAS1990 apparently had a parser too. Refer to http://forums.scummvm.org/viewtopic.php?t=9135
	if (getGameId() == GID_CHRISTMAS1990)
		_vocabulary = new Vocabulary(_resMan, false);
	_audio = new AudioPlayer(_resMan);
	_gamestate = new EngineState(segMan);
	_eventMan = new EventManager(_resMan->detectFontExtended());

	// 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 (!initGame()) { /* Initialize */
		warning("Game initialization failed: Aborting...");
		// TODO: Add an "init failed" error?
		return Common::kUnknownError;
	}

	// we try to find the super class address of the game object, we can't do that earlier
	const Object *gameObject = segMan->getObject(_gameObjectAddress);
	if (!gameObject) {
		warning("Could not get game object, aborting...");
		return Common::kUnknownError;
	}
	_gameSuperClassAddress = gameObject->getSuperClassSelector();

	script_adjust_opcode_formats();

	// Must be called after game_init(), as they use _features
	_kernel->loadKernelNames(_features);
	_soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, _features->detectDoSoundType());

	syncSoundSettings();
	syncIngameAudioOptions();

	// Initialize all graphics related subsystems
	initGraphics();

	debug("Emulating SCI version %s\n", getSciVersionDesc(getSciVersion()));

	// Patch in our save/restore code, so that dialogs are replaced
	patchGameSaveRestore();
	setLauncherLanguage();

	// Check whether loading a savestate was requested
	int directSaveSlotLoading = ConfMan.getInt("save_slot");
	if (directSaveSlotLoading >= 0) {
		// call GameObject::play (like normally)
		initStackBaseWithSelector(SELECTOR(play));
		// We set this, so that the game automatically quit right after init
		_gamestate->variables[VAR_GLOBAL][4] = TRUE_REG;

		_gamestate->_executionStackPosChanged = false;
		run_vm(_gamestate);

		// As soon as we get control again, actually restore the game
		reg_t restoreArgv[2] = { NULL_REG, make_reg(0, directSaveSlotLoading) };	// special call (argv[0] is NULL)
		kRestoreGame(_gamestate, 2, restoreArgv);

		// this indirectly calls GameObject::init, which will setup menu, text font/color codes etc.
		//  without this games would be pretty badly broken
	}

	// Show any special warnings for buggy scripts with severe game bugs, 
	// which have been patched by Sierra
	if (getGameId() == GID_LONGBOW) {
		// Longbow 1.0 has a buggy script which prevents the game
		// from progressing during the Green Man riddle sequence.
		// A patch for this buggy script has been released by Sierra,
		// and is necessary to complete the game without issues.
		// The patched script is included in Longbow 1.1.
		// Refer to bug #3036609.
		Resource *buggyScript = _resMan->findResource(ResourceId(kResourceTypeScript, 180), 0);

		if (buggyScript && (buggyScript->size == 12354 || buggyScript->size == 12362)) {
			showScummVMDialog("A known buggy game script has been detected, which could "
			                  "prevent you from progressing later on in the game, during "
			                  "the sequence with the Green Man's riddles. Please, apply "
			                  "the latest patch for this game by Sierra to avoid possible "
			                  "problems");
		}
	}

	// Show a warning if the user has selected a General MIDI device, no GM patch exists
	// (i.e. patch 4) and the game is one of the known 8 SCI1 games that Sierra has provided
	// after market patches for in their "General MIDI Utility".
	if (_soundCmd->getMusicType() == MT_GM && !ConfMan.getBool("native_mt32")) {
		if (!_resMan->findResource(ResourceId(kResourceTypePatch, 4), 0)) {
			switch (getGameId()) {
			case GID_ECOQUEST:
			case GID_HOYLE3:
			case GID_LSL1:
			case GID_LSL5:
			case GID_LONGBOW:
			case GID_SQ1:
			case GID_SQ4:
			case GID_FAIRYTALES:
				showScummVMDialog("You have selected General MIDI as a sound device. Sierra "
				                  "has provided after-market support for General MIDI for this "
				                  "game in their \"General MIDI Utility\". Please, apply this "
				                  "patch in order to enjoy MIDI music with this game. Once you "
				                  "have obtained it, you can unpack all of the included *.PAT "
				                  "files in your ScummVM extras folder and ScummVM will add the "
				                  "appropriate patch automatically. Alternatively, you can follow "
				                  "the instructions in the READ.ME file included in the patch and "
				                  "rename the associated *.PAT file to 4.PAT and place it in the "
				                  "game folder. Without this patch, General MIDI music for this "
				                  "game will sound badly distorted.");
				break;
			default:
				break;
			}
		}
	}

	if (gameHasFanMadePatch()) {
		showScummVMDialog("Your game is patched with a fan made script patch. Such patches have "
		                  "been reported to cause issues, as they modify game scripts extensively. "
		                  "The issues that these patches fix do not occur in ScummVM, so you are "
		                  "advised to remove this patch from your game folder in order to avoid "
		                  "having unexpected errors and/or issues later on.");
	}

	runGame();

	ConfMan.flushToDisk();

	return Common::kNoError;
}
Example #7
0
SciVersion GameFeatures::detectGfxFunctionsType() {
	if (_gfxFunctionsType == SCI_VERSION_NONE) {
		if (getSciVersion() == SCI_VERSION_0_EARLY) {
			// Old SCI0 games always used old graphics functions
			_gfxFunctionsType = SCI_VERSION_0_EARLY;
		} else if (getSciVersion() >= SCI_VERSION_01) {
			// SCI01 and newer games always used new graphics functions
			_gfxFunctionsType = SCI_VERSION_0_LATE;
		} else {	// SCI0 late
			// Check if the game is using an overlay
			bool searchRoomObj = false;
			reg_t rmObjAddr = _segMan->findObjectByName("Rm");

			if (SELECTOR(overlay) != -1) {
				// The game has an overlay selector, check how it calls kDrawPic
				// to determine the graphics functions type used
				if (lookupSelector(_segMan, rmObjAddr, SELECTOR(overlay), NULL, NULL) == kSelectorMethod) {
					if (!autoDetectGfxFunctionsType()) {
						warning("Graphics functions detection failed, taking an educated guess");

						// Try detecting the graphics function types from the
						// existence of the motionCue selector (which is a bit
						// of a hack)
						if (_kernel->findSelector("motionCue") != -1)
							_gfxFunctionsType = SCI_VERSION_0_LATE;
						else
							_gfxFunctionsType = SCI_VERSION_0_EARLY;
					}
				} else {
					// The game has an overlay selector, but it's not a method
					// of the Rm object (like in Hoyle 1 and 2), so search for
					// other methods
					searchRoomObj = true;
				}
			} else {
				// The game doesn't have an overlay selector, so search for it
				// manually
				searchRoomObj = true;
			}

			if (searchRoomObj) {
				// If requested, check if any method of the Rm object is calling
				// kDrawPic, as the overlay selector might be missing in demos
				bool found = false;

				const Object *obj = _segMan->getObject(rmObjAddr);
				for (uint m = 0; m < obj->getMethodCount(); m++) {
					found = autoDetectGfxFunctionsType(m);
					if (found)
						break;
				}

				if (!found) {
					// No method of the Rm object is calling kDrawPic, thus the
					// game doesn't have overlays and is using older graphics
					// functions
					_gfxFunctionsType = SCI_VERSION_0_EARLY;
				}
			}
		}

		debugC(1, kDebugLevelVM, "Detected graphics functions type: %s", getSciVersionDesc(_gfxFunctionsType));
	}

	return _gfxFunctionsType;
}