Exemple #1
0
extern "C" int scummvm_main(int argc, const char * const argv[]) {
	Common::String specialDebug;
	Common::String command;

	// Verify that the backend has been initialized (i.e. g_system has been set).
	assert(g_system);
	OSystem &system = *g_system;

	// Register config manager defaults
	Base::registerDefaults();

	// Parse the command line
	Common::StringMap settings;
	command = Base::parseCommandLine(settings, argc, argv);

	// Load the config file (possibly overridden via command line):
	if (settings.contains("config")) {
		ConfMan.loadConfigFile(settings["config"]);
		settings.erase("config");
	} else {
		ConfMan.loadDefaultConfigFile();
	}

	// Update the config file
	ConfMan.set("versioninfo", Cabal::getVersion(), Common::ConfigManager::kApplicationDomain);

	// Load and setup the debuglevel and the debug flags. We do this at the
	// soonest possible moment to ensure debug output starts early on, if
	// requested.
	if (settings.contains("debuglevel")) {
		gDebugLevel = (int)strtol(settings["debuglevel"].c_str(), 0, 10);
		printf("Debuglevel (from command line): %d\n", gDebugLevel);
		settings.erase("debuglevel");	// This option should not be passed to ConfMan.
	} else if (ConfMan.hasKey("debuglevel"))
		gDebugLevel = ConfMan.getInt("debuglevel");

	if (settings.contains("debugflags")) {
		specialDebug = settings["debugflags"];
		settings.erase("debugflags");
	}

	PluginManager::instance().init();
 	PluginManager::instance().loadAllPlugins(); // load plugins for cached plugin manager

	// If we received an invalid music parameter via command line we check this here.
	// We can't check this before loading the music plugins.
	// On the other hand we cannot load the plugins before we know the file paths (in case of external plugins).
	if (settings.contains("music-driver")) {
		if (MidiDriver::getMusicType(MidiDriver::getDeviceHandle(settings["music-driver"])) == MT_INVALID) {
			warning("Unrecognized music driver '%s'. Switching to default device", settings["music-driver"].c_str());
			settings["music-driver"] = "auto";
		}
	}

	// Process the remaining command line settings. Must be done after the
	// config file and the plugins have been loaded.
	Common::Error res;

	// TODO: deal with settings that require plugins to be loaded
	if (Base::processSettings(command, settings, res)) {
		if (res.getCode() != Common::kNoError)
			warning("%s", res.getDesc().c_str());
		return res.getCode();
	}

	// Init the backend. Must take place after all config data (including
	// the command line params) was read.
	system.initBackend();

	// If we received an invalid graphics mode parameter via command line
	// we check this here. We can't do it until after the backend is inited,
	// or there won't be a graphics manager to ask for the supported modes.

	if (settings.contains("gfx-mode")) {
		const OSystem::GraphicsMode *gm = g_system->getSupportedGraphicsModes();
		Common::String option = settings["gfx-mode"];
		bool isValid = false;

		while (gm->name && !isValid) {
			isValid = !scumm_stricmp(gm->name, option.c_str());
			gm++;
		}
		if (!isValid) {
			warning("Unrecognized graphics mode '%s'. Switching to default mode", option.c_str());
			settings["gfx-mode"] = "default";
		}
	}
	if (settings.contains("disable-display")) {
		ConfMan.setInt("disable-display", 1, Common::ConfigManager::kTransientDomain);
	}
	setupGraphics(system);

	// Init the different managers that are used by the engines.
	// Do it here to prevent fragmentation later
	system.getAudioCDManager();
	MusicManager::instance();
	Common::DebugManager::instance();

	// Init the event manager. As the virtual keyboard is loaded here, it must
	// take place after the backend is initiated and the screen has been setup
	system.getEventManager()->init();

	// Now as the event manager is created, setup the keymapper
	setupKeymapper(system);

	// Unless a game was specified, show the launcher dialog
	if (0 == ConfMan.getActiveDomain())
		launcherDialog();

	// FIXME: We're now looping the launcher. This, of course, doesn't
	// work as well as it should. In theory everything should be destroyed
	// cleanly, so this is now enabled to encourage people to fix bits :)
	while (0 != ConfMan.getActiveDomain()) {
		// Try to find a plugin which feels responsible for the specified game.
		const EnginePlugin *plugin = detectPlugin();
		if (plugin) {
			// Unload all plugins not needed for this game,
			// to save memory
			PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, plugin);

			// Try to run the game
			Common::Error result = runGame(plugin, system, specialDebug);

		#if defined(UNCACHED_PLUGINS) && defined(DYNAMIC_MODULES)
			// do our best to prevent fragmentation by unloading as soon as we can
			PluginManager::instance().unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL, false);
			// reallocate the config manager to get rid of any fragmentation
			ConfMan.defragment();
		#endif

			// Did an error occur ?
			if (result.getCode() != Common::kNoError && result.getCode() != Common::kUserCanceled) {
				// Shows an informative error dialog if starting the selected game failed.
				GUI::displayErrorDialog(result, _("Error running game:"));
			}

			// Quit unless an error occurred, or Return to launcher was requested
			#ifndef FORCE_RTL
			if (result.getCode() == Common::kNoError && !g_system->getEventManager()->shouldRTL())
				break;
			#endif
			// Reset RTL flag in case we want to load another engine
			g_system->getEventManager()->resetRTL();
			#ifdef FORCE_RTL
			g_system->getEventManager()->resetQuit();
			#endif

			// At this point, we usually return to the launcher. However, the
			// game may have requested that one or more other games be "chained"
			// to the current one, with optional save slots to start the games
			// at. At the time of writing, this is used for the Maniac Mansion
			// easter egg in Day of the Tentacle.

			Common::String chainedGame;
			int saveSlot = -1;

			ChainedGamesMan.pop(chainedGame, saveSlot);

			// Discard any command line options. It's unlikely that the user
			// wanted to apply them to *all* games ever launched.
			ConfMan.getDomain(Common::ConfigManager::kTransientDomain)->clear();

			if (!chainedGame.empty()) {
				if (saveSlot != -1) {
					ConfMan.setInt("save_slot", saveSlot, Common::ConfigManager::kTransientDomain);
				}
				// Start the chained game
				ConfMan.setActiveDomain(chainedGame);
			} else {
				// Clear the active config domain
				ConfMan.setActiveDomain("");
			}

			PluginManager::instance().loadAllPlugins(); // only for cached manager
		} else {
			GUI::displayErrorDialog(_("Could not find any engine capable of running the selected game"));

			// Clear the active domain
			ConfMan.setActiveDomain("");
		}

		// reset the graphics to default
		setupGraphics(system);
		if (0 == ConfMan.getActiveDomain()) {
			launcherDialog();
		}
	}
	PluginManager::instance().unloadAllPlugins();
	PluginManager::destroy();
	GUI::GuiManager::destroy();
	Common::ConfigManager::destroy();
	Common::DebugManager::destroy();
	Common::SearchManager::destroy();
#ifdef USE_TRANSLATION
	Common::TranslationManager::destroy();
#endif
	MusicManager::destroy();
	Graphics::CursorManager::destroy();
	Graphics::FontManager::destroy();
	Graphics::SystemFontManager::destroy();
#ifdef USE_FREETYPE2
	Graphics::shutdownTTF();
#endif
	EngineManager::destroy();
	Graphics::YUVToRGBManager::destroy();
	Audio::PCSpeakerFactoryManager::destroy();

	return 0;
}
Exemple #2
0
void Dialog::show(Scene *scene, uint16 addr, uint16 animation1, uint16 animation2, byte color1, byte color2, byte slot1, byte slot2) {
	debug(0, "Dialog::show(%04x, %u:%u, %u:%u)", addr, slot1, animation1, slot2, animation2);
	Resources *res = Resources::instance();
	int n = 0;
	Common::String message;
	byte color = color1;

	if (animation1 != 0) {
		SceneEvent e(SceneEvent::kPlayAnimation);
		e.animation = animation1;
		e.slot = 0xc0 | slot1; //looped, paused
		scene->push(e);
	}

	if (animation2 != 0) {
		SceneEvent e(SceneEvent::kPlayAnimation);
		e.animation = animation2;
		e.slot = 0xc0 | slot2; //looped, paused
		scene->push(e);
	}

	while (n < 4) {
		byte c = res->eseg.get_byte(addr++);
		//debug(0, "%02x: %c", c, c > 0x20? c: '.');

		switch (c) {
		case 0:
			++n;
			switch (n) {
			case 1:
				//debug(0, "new line\n");
				if (!message.empty())
					message += '\n';
				break;
			case 2:
				//debug(0, "displaymessage %s", message.c_str());
				if (color == color2) {
					//pause animation in other slot
					{
						SceneEvent e(SceneEvent::kPauseAnimation);
						e.slot = 0x80 | slot1;
						scene->push(e);
					}
					{
						SceneEvent e(SceneEvent::kPlayAnimation);
						e.animation = animation2;
						e.slot = 0x80 | slot2;
						scene->push(e);
					}
				} else if (color == color1) {
					//pause animation in other slot
					{
						SceneEvent e(SceneEvent::kPauseAnimation);
						e.slot = 0x80 | slot2;
						scene->push(e);
					}
					{
						SceneEvent e(SceneEvent::kPlayAnimation);
						e.animation = animation1;
						e.slot = 0x80 | slot1;
						scene->push(e);
					}
				}

				{
					message.trim();
					if (message.empty())
						break;

					SceneEvent e(SceneEvent::kMessage);
					e.message = message;
					e.color = color;
					if (color == color1)
						e.slot = slot1;
					if (color == color2)
						e.slot = slot2;
					scene->push(e);
					message.clear();
				}
				break;

			case 3:
				color = color == color1 ? color2 : color1;
				//debug(0, "changing color to %02x", color);
				break;
			}
			break;

		case 0xff: {
			//fixme : wait for the next cycle of the animation
		}
		break;

		default:
			message += c;
			n = 0;
		}
	}

	SceneEvent e(SceneEvent::kClearAnimations);
	scene->push(e);
}
Exemple #3
0
bool Console::Cmd_TestDecompiler(int argc, const char **argv) {
	_testDecompilerTotalScripts = 0;
	_testDecompilerOKScripts = 0;

	ArchiveLoader *archiveLoader = new ArchiveLoader();

	// Temporarily replace the global archive loader with our instance
	ArchiveLoader *gameArchiveLoader = StarkArchiveLoader;
	StarkArchiveLoader = archiveLoader;

	archiveLoader->load("x.xarc");
	Resources::Root *root = archiveLoader->useRoot<Resources::Root>("x.xarc");

	// Find all the levels
	Common::Array<Resources::Level *> levels = root->listChildren<Resources::Level>();

	// Loop over the levels
	for (uint i = 0; i < levels.size(); i++) {
		Resources::Level *level = levels[i];

		Common::String levelArchive = archiveLoader->buildArchiveName(level);
		debug("%s - %s", levelArchive.c_str(), level->getName().c_str());

		// Load the detailed level archive
		archiveLoader->load(levelArchive);
		level = archiveLoader->useRoot<Resources::Level>(levelArchive);

		// Decompile all the scripts in the level archive
		decompileScriptChildren(level);

		Common::Array<Resources::Location *> locations = level->listChildren<Resources::Location>();

		// Loop over the locations
		for (uint j = 0; j < locations.size(); j++) {
			Resources::Location *location = locations[j];

			Common::String locationArchive = archiveLoader->buildArchiveName(level, location);
			debug("%s - %s", locationArchive.c_str(), location->getName().c_str());

			// Load the detailed location archive
			archiveLoader->load(locationArchive);
			location = archiveLoader->useRoot<Resources::Location>(locationArchive);

			// Decompile all the scripts in the location archive
			decompileScriptChildren(location);

			archiveLoader->returnRoot(locationArchive);
			archiveLoader->unloadUnused();
		}

		archiveLoader->returnRoot(levelArchive);
		archiveLoader->unloadUnused();
	}

	// Restore the global archive loader
	StarkArchiveLoader = gameArchiveLoader;

	delete archiveLoader;

	debugPrintf("Successfully decompiled %d scripts out of %d\n", _testDecompilerOKScripts, _testDecompilerTotalScripts);

	return true;
}
Exemple #4
0
reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) {
	uint16 operation = argv[0].toUint16();
	Graphics::VideoDecoder *videoDecoder = 0;
	bool reshowCursor = g_sci->_gfxCursor->isVisible();
	Common::String warningMsg;

	switch (operation) {
	case 0:	// init
		s->_videoState.reset();
		s->_videoState.fileName = s->_segMan->derefString(argv[1]);
		// TODO: argv[2] (usually null). When it exists, it points to an "Event" object,
		// that holds no data initially (e.g. in the intro of Phantasmagoria 1 demo).
		// Perhaps it's meant for syncing
		if (argv[2] != NULL_REG)
			warning("kPlayVMD: third parameter isn't 0 (it's %04x:%04x - %s)", PRINT_REG(argv[2]), s->_segMan->getObjectName(argv[2]));
		break;
	case 1:
	{
		// Set VMD parameters. Called with a maximum of 6 parameters:
		//
		// x, y, flags, gammaBoost, gammaFirst, gammaLast
		//
		// gammaBoost boosts palette colors in the range gammaFirst to
		// gammaLast, but only if bit 4 in flags is set. Percent value such that
		// 0% = no amplification These three parameters are optional if bit 4 is
		// clear. Also note that the x, y parameters play subtle games if used
		// with subfx 21. The subtleness has to do with creation of temporary
		// planes and positioning relative to such planes.

		uint16 flags = argv[3].offset;
		Common::String flagspec;

		if (argc > 3) {
			if (flags & kDoubled)
				flagspec += "doubled ";
			if (flags & kDropFrames)
				flagspec += "dropframes ";
			if (flags & kBlackLines)
				flagspec += "blacklines ";
			if (flags & kUnkBit3)
				flagspec += "bit3 ";
			if (flags & kGammaBoost)
				flagspec += "gammaboost ";
			if (flags & kHoldBlackFrame)
				flagspec += "holdblack ";
			if (flags & kHoldLastFrame)
				flagspec += "holdlast ";
			if (flags & kUnkBit7)
				flagspec += "bit7 ";
			if (flags & kStretch)
				flagspec += "stretch";

			warning("VMDFlags: %s", flagspec.c_str());

			s->_videoState.flags = flags;
		}

		warning("x, y: %d, %d", argv[1].offset, argv[2].offset);
		s->_videoState.x = argv[1].offset;
		s->_videoState.y = argv[2].offset;

		if (argc > 4 && flags & 16)
			warning("gammaBoost: %d%% between palette entries %d and %d", argv[4].offset, argv[5].offset, argv[6].offset);
		break;
	}
	case 6:	// Play
		videoDecoder = new Graphics::VMDDecoder(g_system->getMixer());

		if (!videoDecoder->loadFile(s->_videoState.fileName)) {
			warning("Could not open VMD %s", s->_videoState.fileName.c_str());
			break;
		}

		if (reshowCursor)
			g_sci->_gfxCursor->kernelHide();

		playVideo(videoDecoder, s->_videoState);

		if (reshowCursor)
			g_sci->_gfxCursor->kernelShow();
		break;
	case 14:
		// Takes an additional integer parameter (e.g. 3)
	case 16:
		// Takes an additional parameter, usually 0
	case 21:
		// Looks to be setting the video size and position. Called with 4 extra integer
		// parameters (e.g. 86, 41, 235, 106)
	default:
		warningMsg = Common::String::format("PlayVMD - unsupported subop %d. Params: %d (", operation, argc);

		for (int i = 0; i < argc; i++) {
			warningMsg +=  Common::String::format("%04x:%04x", PRINT_REG(argv[i]));
			warningMsg += (i == argc - 1 ? ")" : ", ");
		}

		warning("%s", warningMsg.c_str());
		break;
	}

	return s->r_acc;
}
Exemple #5
0
void Init::initGame() {
	initVideo();
	updateConfig();

	if (!_vm->isDemo()) {
		if (_vm->_dataIO->hasFile(_vm->_startStk))
			_vm->_dataIO->openArchive(_vm->_startStk, true);
	}

	_vm->_util->initInput();

	_vm->_video->initPrimary(_vm->_global->_videoMode);
	_vm->_global->_mouseXShift = 1;
	_vm->_global->_mouseYShift = 1;

	_palDesc = new Video::PalDesc;

	_vm->validateVideoMode(_vm->_global->_videoMode);

	_vm->_global->_setAllPalette = true;
	_palDesc->vgaPal = _vm->_draw->_vgaPalette;
	_palDesc->unused1 = _vm->_draw->_unusedPalette1;
	_palDesc->unused2 = _vm->_draw->_unusedPalette2;
	_vm->_video->setFullPalette(_palDesc);

	for (int i = 0; i < 10; i++)
		_vm->_draw->_fascinWin[i].id = -1;

	_vm->_draw->_winCount = 0;

	for (int i = 0; i < 8; i++)
		_vm->_draw->_fonts[i] = 0;

	if (_vm->isDemo()) {
		doDemo();
		delete _palDesc;
		_vm->_video->initPrimary(-1);
		cleanup();
		return;
	}

	Common::SeekableReadStream *infFile = _vm->_dataIO->getFile("intro.inf");
	if (!infFile) {

		for (int i = 0; i < 4; i++)
			_vm->_draw->loadFont(i, _fontNames[i]);

	} else {

		for (int i = 0; i < 8; i++) {
			if (infFile->eos())
				break;

			Common::String font = infFile->readLine();
			if (infFile->eos() && font.empty())
				break;

			font += ".let";

			_vm->_draw->loadFont(i, font.c_str());
		}

		delete infFile;
	}

	if (_vm->_dataIO->hasFile(_vm->_startTot)) {
		_vm->_inter->allocateVars(Script::getVariablesCount(_vm->_startTot.c_str(), _vm));

		_vm->_game->_curTotFile = _vm->_startTot;

		_vm->_sound->cdTest(1, "GOB");
		_vm->_sound->cdLoadLIC("gob.lic");

		// Search for a Coktel logo animation or image to display
		if (_vm->_dataIO->hasFile("coktel.imd")) {
			_vm->_draw->initScreen();
			_vm->_draw->_cursorIndex = -1;

			_vm->_util->longDelay(200); // Letting everything settle

			VideoPlayer::Properties props;
			int slot;
			if ((slot = _vm->_vidPlayer->openVideo(true, "coktel.imd", props)) >= 0) {
				_vm->_vidPlayer->play(slot, props);
				_vm->_vidPlayer->closeVideo(slot);
			}

			_vm->_draw->closeScreen();
		} else if (_vm->_dataIO->hasFile("coktel.clt")) {
			Common::SeekableReadStream *stream = _vm->_dataIO->getFile("coktel.clt");
			if (stream) {
				_vm->_draw->initScreen();
				_vm->_util->clearPalette();

				stream->read((byte *)_vm->_draw->_vgaPalette, 768);
				delete stream;

				int32 size;
				byte *sprite = _vm->_dataIO->getFile("coktel.ims", size);
				if (sprite) {
					_vm->_video->drawPackedSprite(sprite, 320, 200, 0, 0, 0,
							*_vm->_draw->_frontSurface);
					_vm->_palAnim->fade(_palDesc, 0, 0);
					_vm->_util->delay(500);

					delete[] sprite;
				}

				_vm->_draw->closeScreen();
			}
		}

		_vm->_game->start();

		_vm->_sound->cdStop();
		_vm->_sound->cdUnloadLIC();

	}

	delete _palDesc;
	_vm->_dataIO->closeArchive(true);
	_vm->_video->initPrimary(-1);
	cleanup();
}
void Parallaction_br::setCounterValue(const Common::String &name, int value) {
	int index = _countersNames->lookup(name.c_str());
	if (index != Table::notFound) {
		_counters[index - 1] = value;
	}
}
Exemple #7
0
Common::String SaveLoad::getSlotSaveName(const Common::String &target, int slot) {
	Common::String fileName = Common::String::format("%s.%03d", target.c_str(), slot);
	return fileName;
}
Exemple #8
0
ActionTimer::ActionTimer(const Common::String &line) {
	sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%u)", &_key, &_time);
}
Exemple #9
0
ActionAssign::ActionAssign(const Common::String &line) {
	sscanf(line.c_str(), "%*[^(](%u, %u)", &_key, &_value);
}
Exemple #10
0
ActionRandom::ActionRandom(const Common::String &line) {
	sscanf(line.c_str(), "%*[^:]:%*[^:]:%u, %u)", &_key, &_max);
}
Exemple #11
0
ActionSetScreen::ActionSetScreen(const Common::String &line) {
	char fileName[25];
	sscanf(line.c_str(), "%*[^(](%25[^)])", fileName);

	_fileName = Common::String(fileName);
}
Exemple #12
0
ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(const Common::String &line) {
	sscanf(line.c_str(),
		   "%*[^:]:%*[^:]:%u(%u %u %u %u %u %u %u %u)",
		   &_animationKey, &_controlKey, &_x1, &_y1, &_x2, &_y2, &_startFrame, &_endFrame, &_loopCount);
}
Exemple #13
0
ActionEnableControl::ActionEnableControl(const Common::String &line) {
	sscanf(line.c_str(), "%*[^(](%u)", &_key);
}
Exemple #14
0
ActionCrossfade::ActionCrossfade(const Common::String &line) {
	sscanf(line.c_str(),
           "%*[^(](%u %u %u %u %u %u %u)",
           &_keyOne, &_keyTwo, &_oneStartVolume, &_twoStartVolume, &_oneEndVolume, &_twoEndVolume, &_timeInMillis);
}
Exemple #15
0
	const char *slide() const {
		return _slide.c_str();
	}
Exemple #16
0
ActionAttenuate::ActionAttenuate(const Common::String &line) {
	sscanf(line.c_str(), "%*[^(](%u, %d)", &_key, &_attenuation);
}
bool Parallaction_br::counterExists(const Common::String &name) {
	return Table::notFound != _countersNames->lookup(name.c_str());
}
Exemple #18
0
ActionChangeLocation::ActionChangeLocation(const Common::String &line) {
	sscanf(line.c_str(), "%*[^(](%c,%c,%c%c,%u)", &_world, &_room, &_node, &_view, &_offset);
}
Exemple #19
0
void LeverControl::parseLevFile(const Common::String &fileName) {
	Common::File file;
	if (!file.open(fileName)) {
		warning("LEV file %s could could be opened", fileName.c_str());
		return;
	}

	Common::String line = file.readLine();

	while (!file.eos()) {
		if (line.matchString("*animation_id*", true)) {
			// Not used
		} else if (line.matchString("*filename*", true)) {
			char fileNameBuffer[25];
			sscanf(line.c_str(), "%*[^:]:%25[^~]~", fileNameBuffer);

			Common::String animationFileName(fileNameBuffer);

			if (animationFileName.hasSuffix(".avi")) {
				_animation.avi = new ZorkAVIDecoder();
				_animation.avi->loadFile(animationFileName);
				_fileType = AVI;
			} else if (animationFileName.hasSuffix(".rlf")) {
				_animation.rlf = new RlfAnimation(animationFileName, false);
				_fileType = RLF;
			}
		} else if (line.matchString("*skipcolor*", true)) {
			// Not used
		} else if (line.matchString("*anim_coords*", true)) {
			int left, top, right, bottom;
			sscanf(line.c_str(), "%*[^:]:%d %d %d %d~", &left, &top, &right, &bottom);

			_animationCoords.left = left;
			_animationCoords.top = top;
			_animationCoords.right = right;
			_animationCoords.bottom = bottom;
		} else if (line.matchString("*mirrored*", true)) {
			uint mirrored;
			sscanf(line.c_str(), "%*[^:]:%u~", &mirrored);

			_mirrored = mirrored == 0 ? false : true;
		} else if (line.matchString("*frames*", true)) {
			sscanf(line.c_str(), "%*[^:]:%u~", &_frameCount);

			_frameInfo = new FrameInfo[_frameCount];
		} else if (line.matchString("*elsewhere*", true)) {
			// Not used
		} else if (line.matchString("*out_of_control*", true)) {
			// Not used
		} else if (line.matchString("*start_pos*", true)) {
			sscanf(line.c_str(), "%*[^:]:%u~", &_startFrame);
			_currentFrame = _startFrame;
		} else if (line.matchString("*hotspot_deltas*", true)) {
			uint x;
			uint y;
			sscanf(line.c_str(), "%*[^:]:%u %u~", &x, &y);

			_hotspotDelta.x = x;
			_hotspotDelta.y = y;
		} else {
			uint frameNumber;
			uint x, y;

			if (sscanf(line.c_str(), "%u:%u %u", &frameNumber, &x, &y) == 3) {
				_frameInfo[frameNumber].hotspot.left = x;
				_frameInfo[frameNumber].hotspot.top = y;
				_frameInfo[frameNumber].hotspot.right = x + _hotspotDelta.x;
				_frameInfo[frameNumber].hotspot.bottom = y + _hotspotDelta.y;
			}

			Common::StringTokenizer tokenizer(line, " ^=()");
			tokenizer.nextToken();
			tokenizer.nextToken();

			Common::String token = tokenizer.nextToken();
			while (!tokenizer.empty()) {
				if (token == "D") {
					token = tokenizer.nextToken();

					uint angle;
					uint toFrame;
					sscanf(token.c_str(), "%u,%u", &toFrame, &angle);

					_frameInfo[frameNumber].directions.push_back(Direction(angle, toFrame));
				} else if (token.hasPrefix("P")) {
					// Format: P(<from> to <to>)
					tokenizer.nextToken();
					tokenizer.nextToken();
					token = tokenizer.nextToken();
					uint to = atoi(token.c_str());

					_frameInfo[frameNumber].returnRoute.push_back(to);
				}

				token = tokenizer.nextToken();
			}
		}

		line = file.readLine();
	}
}
Exemple #20
0
void HiRes1Engine::runIntro() const {
	StreamPtr stream(_files->createReadStream(IDS_HR1_EXE_0));

	stream->seek(IDI_HR1_OFS_LOGO_0);
	_display->setMode(DISPLAY_MODE_HIRES);
	_display->loadFrameBuffer(*stream);
	_display->updateHiResScreen();
	delay(4000);

	if (shouldQuit())
		return;

	_display->setMode(DISPLAY_MODE_TEXT);

	StreamPtr basic(_files->createReadStream(IDS_HR1_LOADER));
	Common::String str;

	str = readStringAt(*basic, IDI_HR1_OFS_PD_TEXT_0, '"');
	_display->printAsciiString(str + '\r');

	str = readStringAt(*basic, IDI_HR1_OFS_PD_TEXT_1, '"');
	_display->printAsciiString(str + "\r\r");

	str = readStringAt(*basic, IDI_HR1_OFS_PD_TEXT_2, '"');
	_display->printAsciiString(str + "\r\r");

	str = readStringAt(*basic, IDI_HR1_OFS_PD_TEXT_3, '"');
	_display->printAsciiString(str + '\r');

	inputKey();
	if (g_engine->shouldQuit())
		return;

	_display->setMode(DISPLAY_MODE_MIXED);

	str = readStringAt(*stream, IDI_HR1_OFS_GAME_OR_HELP);

	bool instructions = false;

	while (1) {
		_display->printString(str);
		Common::String s = inputString();

		if (g_engine->shouldQuit())
			break;

		if (s.empty())
			continue;

		if (s[0] == APPLECHAR('I')) {
			instructions = true;
			break;
		} else if (s[0] == APPLECHAR('G')) {
			break;
		}
	};

	if (instructions) {
		_display->setMode(DISPLAY_MODE_TEXT);
		stream->seek(IDI_HR1_OFS_INTRO_TEXT);

		const uint pages[] = { 6, 6, 4, 5, 8, 7, 0 };

		uint page = 0;
		while (pages[page] != 0) {
			_display->home();

			uint count = pages[page++];
			for (uint i = 0; i < count; ++i) {
				str = readString(*stream);
				_display->printString(str);
				stream->seek(3, SEEK_CUR);
			}

			inputString();

			if (g_engine->shouldQuit())
				return;

			stream->seek(6, SEEK_CUR);
		}
	}

	_display->printAsciiString("\r");

	_display->setMode(DISPLAY_MODE_MIXED);

	// Title screen shown during loading
	stream.reset(_files->createReadStream(IDS_HR1_EXE_1));
	stream->seek(IDI_HR1_OFS_LOGO_1);
	_display->loadFrameBuffer(*stream);
	_display->updateHiResScreen();
	delay(2000);
}
Exemple #21
0
reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) {
	// Hide the cursor if it's showing and then show it again if it was
	// previously visible.
	bool reshowCursor = g_sci->_gfxCursor->isVisible();
	if (reshowCursor)
		g_sci->_gfxCursor->kernelHide();

	uint16 screenWidth = g_system->getWidth();
	uint16 screenHeight = g_system->getHeight();
		
	Graphics::VideoDecoder *videoDecoder = 0;

	if (argv[0].segment != 0) {
		Common::String filename = s->_segMan->getString(argv[0]);

		if (g_sci->getPlatform() == Common::kPlatformMacintosh) {
			// Mac QuickTime
			// The only argument is the string for the video

			// HACK: Switch to 16bpp graphics for Cinepak.
			initGraphics(screenWidth, screenHeight, screenWidth > 320, NULL);

			if (g_system->getScreenFormat().bytesPerPixel == 1) {
				error("This video requires >8bpp color to be displayed, but could not switch to RGB color mode");
				return NULL_REG;
			}

			videoDecoder = new Graphics::QuickTimeDecoder();
			if (!videoDecoder->loadFile(filename))
				error("Could not open '%s'", filename.c_str());
		} else {
			// DOS SEQ
			// SEQ's are called with no subops, just the string and delay
			SeqDecoder *seqDecoder = new SeqDecoder();
			seqDecoder->setFrameDelay(argv[1].toUint16()); // Time between frames in ticks
			videoDecoder = seqDecoder;

			if (!videoDecoder->loadFile(filename)) {
				warning("Failed to open movie file %s", filename.c_str());
				delete videoDecoder;
				videoDecoder = 0;
			}
		}
	} else {
		// Windows AVI
		// TODO: This appears to be some sort of subop. case 0 contains the string
		// for the video, so we'll just play it from there for now.

#ifdef ENABLE_SCI32
		if (getSciVersion() >= SCI_VERSION_2_1) {
			// SCI2.1 always has argv[0] as 1, the rest of the arguments seem to
			// follow SCI1.1/2.
			if (argv[0].toUint16() != 1)
				error("SCI2.1 kShowMovie argv[0] not 1");
			argv++;
			argc--;
		}
#endif
		switch (argv[0].toUint16()) {
		case 0: {
			Common::String filename = s->_segMan->getString(argv[1]);
			videoDecoder = new Graphics::AviDecoder(g_system->getMixer());

			if (!videoDecoder->loadFile(filename.c_str())) {
				warning("Failed to open movie file %s", filename.c_str());
				delete videoDecoder;
				videoDecoder = 0;
			}
			break;
		}
		default:
			warning("Unhandled SCI kShowMovie subop %d", argv[0].toUint16());
		}
	}

	if (videoDecoder) {
		playVideo(videoDecoder, s->_videoState);

		// HACK: Switch back to 8bpp if we played a QuickTime video.
		// We also won't be copying the screen to the SCI screen...
		if (g_system->getScreenFormat().bytesPerPixel != 1)
			initGraphics(screenWidth, screenHeight, screenWidth > 320);
		else {
			g_sci->_gfxScreen->kernelSyncWithFramebuffer();
			g_sci->_gfxPalette->kernelSyncScreenPalette();
		}
	}

	if (reshowCursor)
		g_sci->_gfxCursor->kernelShow();

	return s->r_acc;
}
Exemple #22
0
void MacText::splitString(Common::String &str) {
	const char *s = str.c_str();

	Common::String tmp;
	bool prevCR = false;

	if (_textLines.empty()) {
		_textLines.resize(1);
		_textLines[0].chunks.push_back(_defaultFormatting);
	}

	int curLine = _textLines.size() - 1;
	int curChunk = _textLines[curLine].chunks.size() - 1;
	bool nextChunk = false;
	MacFontRun previousFormatting;

	while (*s) {
#if DEBUG
		for (uint i = 0; i < _textLines.size(); i++) {
			debugN(7, "%2d ", i);

			for (uint j = 0; j < _textLines[i].chunks.size(); j++)
				debugN(7, "[%d] \"%s\"", _textLines[i].chunks[j].fontId, _textLines[i].chunks[j].text.c_str());

			debug(7, " --> %c %d, '%s'", (*s > 0x20 ? *s : ' '), (byte)*s, tmp.c_str());
		}
#endif

		if (*s == '\001') {
			s++;
			if (*s == '\001') {
				// Copy it verbatim
			} else {
				if (*s++ != '\015')
					error("MacText: formatting error");

				uint16 fontId = *s++; fontId = (fontId << 8) | *s++;
				byte textSlant = *s++;
				byte unk3f = *s++;
				uint16 fontSize = *s++; fontSize = (fontSize << 8) | *s++;
				uint16 palinfo1 = *s++; palinfo1 = (palinfo1 << 8) | *s++;
				uint16 palinfo2 = *s++; palinfo2 = (palinfo2 << 8) | *s++;
				uint16 palinfo3 = *s++; palinfo3 = (palinfo3 << 8) | *s++;

				debug(8, "******** splitString: fontId: %d, textSlant: %d, unk3: %d, fontSize: %d, p0: %x p1: %x p2: %x",
						fontId, textSlant, unk3f, fontSize, palinfo1, palinfo2, palinfo3);

				previousFormatting = _currentFormatting;
				_currentFormatting.setValues(_wm, fontId, textSlant, unk3f, fontSize, palinfo1, palinfo2, palinfo3);

				if (curLine == 0 && curChunk == 0 && tmp.empty())
					previousFormatting = _currentFormatting;

				nextChunk = true;
			}
		} else if (*s == '\n' && prevCR) {	// trean \r\n as one
			prevCR = false;

			s++;
			continue;
		} else if (*s == '\r') {
			prevCR = true;
		}

		if (*s == '\r' || *s == '\n' || nextChunk) {
			Common::Array<Common::String> text;

			if (!nextChunk)
				previousFormatting = _currentFormatting;

			int w = getLineWidth(curLine, true);

			previousFormatting.getFont()->wordWrapText(tmp, _maxWidth, text, w);
			tmp.clear();

			if (text.size()) {
				for (uint i = 0; i < text.size(); i++) {
					_textLines[curLine].chunks[curChunk].text = text[i];

					if ((text.size() > 1 || !nextChunk) && !(i == text.size() - 1 && nextChunk)) {
						curLine++;
						_textLines.resize(curLine + 1);
						_textLines[curLine].chunks.push_back(previousFormatting);
						curChunk = 0;
					}
				}

				if (nextChunk) {
					curChunk++;

					_textLines[curLine].chunks.push_back(_currentFormatting);
				} else {
					_textLines[curLine].chunks[0] = _currentFormatting;
				}
			} else {
				if (nextChunk) { // No text, replacing formatting
					_textLines[curLine].chunks[curChunk] = _currentFormatting;
				} else { // Otherwise it is an empty line
					curLine++;
					_textLines.resize(curLine + 1);
					_textLines[curLine].chunks.push_back(previousFormatting);
					curChunk = 0;
				}
			}

			if (!nextChunk) // Don't skip next character
				s++;

			nextChunk = false;
			continue;
		}

		tmp += *s;
		s++;
	}

	if (tmp.size()) {
		Common::Array<Common::String> text;
		int w = getLineWidth(curLine, true);

		_currentFormatting.getFont()->wordWrapText(tmp, _maxWidth, text, w);

		_textLines[curLine].chunks[curChunk].text = text[0];

		if (text.size() > 1) {
			for (uint i = 1; i < text.size(); i++) {
				curLine++;
				_textLines.resize(curLine + 1);
				_textLines[curLine].chunks.push_back(_currentFormatting);
				_textLines[curLine].chunks[0].text = text[i];
			}
		}
	}
}
Exemple #23
0
Common::Error GroovieEngine::run() {
	// Initialize the graphics
	initGraphics(640, 480, true);

	// Create debugger. It requires GFX to be initialized
	_debugger = new Debugger(this);
	_script.setDebugger(_debugger);

	// Create the graphics manager
	_graphicsMan = new GraphicsMan(this);

	// Create the resource and cursor managers and the video player
	switch (_gameDescription->version) {
	case kGroovieT7G:
		_resMan = new ResMan_t7g();
		_grvCursorMan = new GrvCursorMan_t7g(_system);
		_videoPlayer = new VDXPlayer(this);
		break;
	case kGroovieV2:
		_resMan = new ResMan_v2();
		_grvCursorMan = new GrvCursorMan_v2(_system);
		_videoPlayer = new ROQPlayer(this);
		break;
	}

	// Create the music player
	if (_gameDescription->desc.platform == Common::kPlatformMacintosh) {
		_musicPlayer = new MusicPlayerMac(this);
	} else {
		_musicPlayer = new MusicPlayerXMI(this, _gameDescription->version == kGroovieT7G ? "fat" : "sample");
	}

	// Load volume levels
	syncSoundSettings();

	// Get the name of the main script
	Common::String filename = _gameDescription->desc.filesDescriptions[0].fileName;
	if (_gameDescription->version == kGroovieT7G) {
		// Run The 7th Guest's demo if requested
		if (ConfMan.hasKey("demo_mode") && ConfMan.getBool("demo_mode")) {
			filename = Common::String("demo.grv");
		}
	} else if (_gameDescription->version == kGroovieV2) {
		// Open the disk index
		Common::File disk;
		if (!disk.open(filename)) {
			error("Couldn't open %s", filename.c_str());
			return Common::kNoGameDataFoundError;
		}

		// Search the entry
		bool found = false;
		int index = 0;
		while (!found && !disk.eos()) {
			Common::String line = disk.readLine();
			if (line.hasPrefix("title: ")) {
				// A new entry
				index++;
			} else if (line.hasPrefix("boot: ") && index == _gameDescription->indexEntry) {
				// It's the boot of the entry we're looking for,
				// get the script filename
				filename = line.c_str() + 6;
				found = true;
			}
		}

		// Couldn't find the entry
		if (!found) {
			error("Couldn't find entry %d in %s", _gameDescription->indexEntry, filename.c_str());
			return Common::kUnknownError;
		}
	}

	// Check the script file extension
	if (!filename.hasSuffix(".grv")) {
		error("%s isn't a valid script filename", filename.c_str());
		return Common::kUnknownError;
	}

	// Load the script
	if (!_script.loadScript(filename)) {
		error("Couldn't load the script file %s", filename.c_str());
		return Common::kUnknownError;
	}

	// Should I load a saved game?
	if (ConfMan.hasKey("save_slot")) {
		// Get the requested slot
		int slot = ConfMan.getInt("save_slot");
		_script.directGameLoad(slot);
	}

	// Check that the game files and the audio tracks aren't together run from
	// the same cd
	checkCD();

	// Game timer counter
	uint16 tmr = 0;

	// Initialize the CD
	int cd_num = ConfMan.getInt("cdrom");
	if (cd_num >= 0)
		_system->openCD(cd_num);

	while (!shouldQuit()) {
		// Show the debugger if required
		if (_debugger->isAttached()) {
			_debugger->onFrame();
		}

		// Handle input
		Common::Event ev;
		while (_eventMan->pollEvent(ev)) {
			switch (ev.type) {
			case Common::EVENT_KEYDOWN:
				// CTRL-D: Attach the debugger
				if ((ev.kbd.flags & Common::KBD_CTRL) && ev.kbd.keycode == Common::KEYCODE_d)
					_debugger->attach();

				// Send the event to the scripts
				_script.setKbdChar(ev.kbd.ascii);

				// Continue the script execution to handle the key
				_waitingForInput = false;
				break;

			case Common::EVENT_MAINMENU:
				// Closing the GMM
			case Common::EVENT_MOUSEMOVE:
				// Continue the script execution, the mouse pointer
				// may fall inside a different hotspot now
				_waitingForInput = false;
				break;

			case Common::EVENT_LBUTTONDOWN:
				// Send the event to the scripts
				_script.setMouseClick();

				// Continue the script execution to handle
				// the click
				_waitingForInput = false;
				break;

			case Common::EVENT_QUIT:
				quitGame();
				break;

			default:
				break;
			}
		}

		// The event loop may have triggered the quit status. In this case,
		// stop the execution.
		if (shouldQuit()) {
			continue;
		}

		if (_waitingForInput) {
			// Still waiting for input, just update the mouse, game timer and then wait a bit more
			_grvCursorMan->animate();
			_system->updateScreen();
			tmr++;
			// Wait a little bit between increments.  While mouse is moving, this triggers
			// only negligably slower.
			if (tmr > 4) {
				_script.timerTick();
				tmr = 0;
			}

			_system->delayMillis(50);
		} else if (_graphicsMan->isFading()) {
			// We're waiting for a fading to end, let the CPU rest
			// for a while and continue
			_system->delayMillis(30);
		} else {
			// Everything's fine, execute another script step
			_script.step();
		}

		// Update the screen if required
		_graphicsMan->update();
	}

	return Common::kNoError;
}
bool InstallerArchive::open(const Common::String &filename) {
	close();

	_stream = SearchMan.createReadStreamForMember(filename);

	if (!_stream)
		return false;

	// Check for the magic uint32
	// No idea what it means, but it's how "file" recognizes them
	if (_stream->readUint32BE() != 0x135D658C) {
		close();
		return false;
	}

	// Let's move to the directory
	_stream->seek(41);
	uint32 offset = _stream->readUint32LE();
	_stream->seek(offset);

	// Now read in each file from the directory
	uint16 fileCount = _stream->readUint16LE();
	debug(2, "File count = %d", fileCount);

	_stream->skip(9);

	Common::Array<DirectoryEntry> directories;

	for (uint16 i = 0; i < fileCount;) {
		uint16 dirFileCount = _stream->readUint16LE();

		if (dirFileCount == 0) {
			// We've found a file
			FileEntry entry;

			_stream->skip(1); // Unknown

			entry.uncompressedSize = _stream->readUint32LE();
			entry.compressedSize = _stream->readUint32LE();
			entry.offset = _stream->readUint32LE();

			_stream->skip(14); // Unknown

			byte nameLength = _stream->readByte();
			Common::String name;
			while (nameLength--)
				name += _stream->readByte();

			_stream->skip(13); // Unknown

			_map[name] = entry;
			i++;

			debug(3, "Found file '%s' at 0x%08x (Comp: 0x%08x, Uncomp: 0x%08x)", name.c_str(),
					entry.offset, entry.compressedSize, entry.uncompressedSize);
		} else {
			// We've found a directory
			DirectoryEntry dirEntry;

			dirEntry.fileCount = dirFileCount;
			/* uint16 entrySize = */ _stream->readUint16LE();

			uint16 nameLength = _stream->readUint16LE();
			while (nameLength--)
				dirEntry.name += _stream->readByte();

			directories.push_back(dirEntry);

			_stream->skip(5);  // Unknown

			debug(3, "Ignoring directory '%s'", dirEntry.name.c_str());
		}
	}

	// TODO: Handle files in directories
	// Per directory found follows DirectoryEntry::fileCount files

	return true;
}
Exemple #25
0
void Lingo::addCode(const char *code, ScriptType type, uint16 id) {
	debugC(2, kDebugLingoCompile, "Add code \"%s\" for type %d with id %d", code, type, id);

	if (_scripts[type].contains(id)) {
		delete _scripts[type][id];
	}

	_currentScript = new ScriptData;
	_currentScriptType = type;
	_scripts[type][id] = _currentScript;

	_linenumber = _colnumber = 1;
	_hadError = false;

	const char *begin, *end;

	if (!strncmp(code, "menu:", 5)) {
		debugC(2, kDebugLingoCompile, "Parsing menu");
		parseMenu(code);

		return;
	}

	// macros and factories have conflicting grammar. Thus we ease life for the parser.
	if ((begin = findNextDefinition(code))) {
		bool first = true;

		while ((end = findNextDefinition(begin + 1))) {

			if (first) {
				begin = code;
				first = false;
			}
			Common::String chunk(begin, end);

			if (chunk.hasPrefix("factory") || chunk.hasPrefix("method"))
				_inFactory = true;
			else if (chunk.hasPrefix("macro"))
				_inFactory = false;
			else
				_inFactory = false;

			debugC(2, kDebugLingoCompile, "Code chunk:\n#####\n%s#####", chunk.c_str());

			parse(chunk.c_str());

			if (debugChannelSet(3, kDebugLingoCompile)) {
				uint pc = 0;
				while (pc < _currentScript->size()) {
					Common::String instr = decodeInstruction(pc, &pc);
					debugC(3, kDebugLingoCompile, "[%5d] %s", pc, instr.c_str());
				}
			}

			_currentScript->clear();

			begin = end;
		}

		_hadError = true; // HACK: This is for preventing test execution

		debugC(2, kDebugLingoCompile, "Code chunk:\n#####\n%s#####", begin);
		parse(begin);
	} else {
		parse(code);

		code1(STOP);
	}

	_inFactory = false;

	if (debugChannelSet(3, kDebugLingoCompile)) {
		if (_currentScript->size() && !_hadError)
			Common::hexdump((byte *)&_currentScript->front(), _currentScript->size() * sizeof(inst));

		uint pc = 0;
		while (pc < _currentScript->size()) {
			Common::String instr = decodeInstruction(pc, &pc);
			debugC(3, kDebugLingoCompile, "[%5d] %s", pc, instr.c_str());
		}
	}
}
Exemple #26
0
	const char *location() const {
		return _location.c_str();
	}
void OutputPersistenceBlock::writeString(const Common::String &string) {
	writeMarker(STRING_MARKER);

	write(string.size());
	rawWrite(string.c_str(), string.size());
}
Exemple #28
0
	const char *character() const {
		return _character.c_str();
	}
Exemple #29
0
bool DownloadDialog::selectDirectories() {
	if (Networking::Connection::isLimited()) {
		MessageDialog alert(_("It looks like your connection is limited. "
			"Do you really want to download files with it?"), _("Yes"), _("No"));
		if (alert.runModal() != GUI::kMessageOK)
			return false;
	}

	//first user should select remote directory to download
	if (_remoteBrowser->runModal() <= 0)
		return false;

	Cloud::StorageFile remoteDirectory = _remoteBrowser->getResult();

	//now user should select local directory to download into
	if (_browser->runModal() <= 0)
		return false;

	Common::FSNode dir(_browser->getResult());
	Common::FSList files;
	if (!dir.getChildren(files, Common::FSNode::kListAll)) {
		MessageDialog alert(_("ScummVM couldn't open the specified directory!"));
		alert.runModal();
		return false;
	}

	//check that there is no file with the remote directory's name in the local one
	for (Common::FSList::iterator i = files.begin(); i != files.end(); ++i) {
		if (i->getName().equalsIgnoreCase(remoteDirectory.name())) {
			//if there is, ask user whether it's OK
			if (!i->isDirectory()) {
				GUI::MessageDialog alert(_("Cannot create a directory to download - the specified directory has a file with the same name."), _("OK"));
				alert.runModal();
				return false;
			}
			GUI::MessageDialog alert(
				Common::String::format(_("The \"%s\" already exists in the specified directory.\nDo you really want to download files into that directory?"), remoteDirectory.name().c_str()),
				_("Yes"),
				_("No")
				);
			if (alert.runModal() != GUI::kMessageOK)
				return false;
			break;
		}
	}

	//make a local path
	Common::String localPath = dir.getPath();

	//simple heuristic to determine which path separator to use
	if (localPath.size() && localPath.lastChar() != '/' && localPath.lastChar() != '\\') {
		int backslashes = 0;
		for (uint32 i = 0; i < localPath.size(); ++i)
			if (localPath[i] == '/')
				--backslashes;
			else if (localPath[i] == '\\')
				++backslashes;

		if (backslashes > 0)
			localPath += '\\' + remoteDirectory.name();
		else
			localPath += '/' + remoteDirectory.name();
	} else {
		localPath += remoteDirectory.name();
	}

	CloudMan.startDownload(remoteDirectory.path(), localPath);
	CloudMan.setDownloadTarget(this);
	_localDirectory = localPath;
	return true;
}
Exemple #30
0
// TODO: specify the possible return values here
static Common::Error runGame(const EnginePlugin *plugin, OSystem &system, const Common::String &edebuglevels) {
	// Determine the game data path, for validation and error messages
	Common::FSNode dir(ConfMan.get("path"));
	Common::Error err = Common::kNoError;
	Engine *engine = 0;

#if defined(SDL_BACKEND) && defined(USE_OPENGL)
	// HACK: We set up the requested graphics mode setting here to allow the
	// backend to switch from Surface SDL to OpenGL if necessary. This is
	// needed because otherwise the g_system->getSupportedFormats might return
	// bad values.
	g_system->beginGFXTransaction();
		g_system->setGraphicsMode(ConfMan.get("gfx_mode").c_str());
	if (g_system->endGFXTransaction() != OSystem::kTransactionSuccess) {
		warning("Switching graphics mode to '%s' failed", ConfMan.get("gfx_mode").c_str());
		return Common::kUnknownError;
	}
#endif

	// Verify that the game path refers to an actual directory
	if (!(dir.exists() && dir.isDirectory()))
		err = Common::kPathNotDirectory;

	// Create the game engine
	if (err.getCode() == Common::kNoError)
		err = (*plugin)->createInstance(&system, &engine);

	// Check for errors
	if (!engine || err.getCode() != Common::kNoError) {

		// Print a warning; note that scummvm_main will also
		// display an error dialog, so we don't have to do this here.
		warning("%s failed to instantiate engine: %s (target '%s', path '%s')",
			plugin->getName(),
			err.getDesc().c_str(),
			ConfMan.getActiveDomainName().c_str(),
			dir.getPath().c_str()
			);

		// Autoadded is set only when no path was provided and
		// the game is run from command line.
		//
		// Thus, we remove this garbage entry
		//
		// Fixes bug #1544799
		if (ConfMan.hasKey("autoadded")) {
			ConfMan.removeGameDomain(ConfMan.getActiveDomainName().c_str());
		}

		return err;
	}

	// Set the window caption to the game name
	Common::String caption(ConfMan.get("description"));

	if (caption.empty()) {
		caption = EngineMan.findGame(ConfMan.get("gameid")).description();
	}
	if (caption.empty())
		caption = ConfMan.getActiveDomainName();	// Use the domain (=target) name
	if (!caption.empty())	{
		system.setWindowCaption(caption.c_str());
	}

	//
	// Setup various paths in the SearchManager
	//

	// Add the game path to the directory search list
	engine->initializePath(dir);

	// Add extrapath (if any) to the directory search list
	if (ConfMan.hasKey("extrapath")) {
		dir = Common::FSNode(ConfMan.get("extrapath"));
		SearchMan.addDirectory(dir.getPath(), dir);
	}

	// If a second extrapath is specified on the app domain level, add that as well.
	// However, since the default hasKey() and get() check the app domain level,
	// verify that it's not already there before adding it. The search manager will
	// check for that too, so this check is mostly to avoid a warning message.
	if (ConfMan.hasKey("extrapath", Common::ConfigManager::kApplicationDomain)) {
		Common::String extraPath = ConfMan.get("extrapath", Common::ConfigManager::kApplicationDomain);
		if (!SearchMan.hasArchive(extraPath)) {
			dir = Common::FSNode(extraPath);
			SearchMan.addDirectory(dir.getPath(), dir);
		}
	}

	// On creation the engine should have set up all debug levels so we can use
	// the command line arguments here
	Common::StringTokenizer tokenizer(edebuglevels, " ,");
	while (!tokenizer.empty()) {
		Common::String token = tokenizer.nextToken();
		if (token.equalsIgnoreCase("all"))
			DebugMan.enableAllDebugChannels();
		else if (!DebugMan.enableDebugChannel(token))
			warning(_("Engine does not support debug level '%s'"), token.c_str());
	}

	// Initialize any game-specific keymaps
	engine->initKeymap();

	// Set default values for all of the custom engine options
	const ExtraGuiOptions engineOptions = (*plugin)->getExtraGuiOptions(Common::String());
	for (uint i = 0; i < engineOptions.size(); i++) {
		ConfMan.registerDefault(engineOptions[i].configOption, engineOptions[i].defaultState);
	}

	// Inform backend that the engine is about to be run
	system.engineInit();

	// Run the engine
	Common::Error result = engine->run();

	// Inform backend that the engine finished
	system.engineDone();

	// Clean up any game-specific keymaps
	engine->deinitKeymap();

	// Free up memory
	delete engine;

	// We clear all debug levels again even though the engine should do it
	DebugMan.clearAllDebugChannels();

	// Reset the file/directory mappings
	SearchMan.clear();

	// Return result (== 0 means no error)
	return result;
}