Example #1
0
bool ELFPluginProvider::isPluginFilename(const Common::FSNode &node) const {
	// Check the plugin suffix
	Common::String filename = node.getName();

	if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg") &&
			!filename.hasSuffix(".PLUGIN") && !filename.hasSuffix(".plugin"))
		return false;

	return true;
}
Example #2
0
bool Console::Cmd_DumpArchive(int argc, const char **argv) {
	if (argc != 2) {
		DebugPrintf("Extract all the files from a game archive.\n");
		DebugPrintf("The destination folder, named 'dump', must exist.\n");
		DebugPrintf("Usage :\n");
		DebugPrintf("dumpArchive [file name]\n");
		return true;
	}

	// Is the archive multi-room
	Common::String temp = Common::String(argv[1]);
	temp.toUppercase();

	bool multiRoom = !temp.hasSuffix(".M3A");
	if (!multiRoom) {
		temp = Common::String(argv[1], 4);
		temp.toUppercase();
	}

	Archive archive;
	if (!archive.open(argv[1], multiRoom ? 0 : temp.c_str())) {
		DebugPrintf("Can't open archive with name '%s'\n", argv[1]);
		return true;
	}

	archive.dumpToFiles();
	archive.close();

	return true;
}
Example #3
0
bool OSystem_Dreamcast::isPluginFilename(const Common::FSNode &node) const {
	// Check the plugin suffix
	Common::String filename = node.getName();
	if (!filename.hasSuffix(".PLG"))
		return false;

	return true;
}
Example #4
0
bool Resource::loadFileList(const Common::String &filedata) {
	Common::SeekableReadStream *f = createReadStream(filedata);

	if (!f)
		return false;

	uint32 filenameOffset = 0;
	while ((filenameOffset = f->readUint32LE()) != 0) {
		uint32 offset = f->pos();
		f->seek(filenameOffset, SEEK_SET);

		uint8 buffer[13];
		f->read(buffer, sizeof(buffer)-1);
		buffer[12] = 0;
		f->seek(offset + 16, SEEK_SET);

		Common::String filename = Common::String((char *)buffer);
		filename.toUppercase();

		if (filename.hasSuffix(".PAK")) {
			if (!exists(filename.c_str()) && _vm->gameFlags().isDemo) {
				// the demo version supplied with Kyra3 does not
				// contain all pak files listed in filedata.fdt
				// so we don't do anything here if they are non
				// existant.
			} else if (!loadPakFile(filename)) {
				delete f;
				error("couldn't load file '%s'", filename.c_str());
				return false;	// for compilers that don't support NORETURN
			}
		}
	}

	delete f;
	return true;
}
Example #5
0
Common::String Font::handleEllipsis(const Common::String &input, int w) const {
	Common::String s = input;
	int width = getStringWidth(s);

	if (width > w && s.hasSuffix("...")) {
		// String is too wide. Check whether it ends in an ellipsis
		// ("..."). If so, remove that and try again!
		s.deleteLastChar();
		s.deleteLastChar();
		s.deleteLastChar();
		width = getStringWidth(s);
	}

	if (width > w) {
		Common::String str;

		// String is too wide. So we shorten it "intelligently" by
		// replacing parts of the string by an ellipsis. There are
		// three possibilities for this: replace the start, the end, or
		// the middle of the string. What is best really depends on the
		// context; but unless we want to make this configurable,
		// replacing the middle seems to be a good compromise.

		const int ellipsisWidth = getStringWidth("...");

		// SLOW algorithm to remove enough of the middle. But it is good enough
		// for now.
		const int halfWidth = (w - ellipsisWidth) / 2;
		int w2 = 0;
		Common::String::unsigned_type last = 0;
		uint i = 0;

		for (; i < s.size(); ++i) {
			const Common::String::unsigned_type cur = s[i];
			int charWidth = getCharWidth(cur) + getKerningOffset(last, cur);
			if (w2 + charWidth > halfWidth)
				break;
			last = cur;
			w2 += charWidth;
			str += cur;
		}

		// At this point we know that the first 'i' chars are together 'w2'
		// pixels wide. We took the first i-1, and add "..." to them.
		str += "...";
		last = '.';

		// The original string is width wide. Of those we already skipped past
		// w2 pixels, which means (width - w2) remain.
		// The new str is (w2+ellipsisWidth) wide, so we can accommodate about
		// (w - (w2+ellipsisWidth)) more pixels.
		// Thus we skip ((width - w2) - (w - (w2+ellipsisWidth))) =
		// (width + ellipsisWidth - w)
		int skip = width + ellipsisWidth - w;
		for (; i < s.size() && skip > 0; ++i) {
			const Common::String::unsigned_type cur = s[i];
			skip -= getCharWidth(cur) + getKerningOffset(last, cur);
			last = cur;
		}

		// Append the remaining chars, if any
		for (; i < s.size(); ++i) {
			str += s[i];
		}

		return str;
	} else {
		return s;
	}
}
Example #6
0
const ADGameDescription *SciMetaEngine::fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const {
    bool foundResMap = false;
    bool foundRes000 = false;

    // Set some defaults
    s_fallbackDesc.extra = "";
    s_fallbackDesc.language = Common::EN_ANY;
    s_fallbackDesc.flags = ADGF_NO_FLAGS;
    s_fallbackDesc.platform = Common::kPlatformDOS;	// default to PC platform
    s_fallbackDesc.gameid = "sci";
    s_fallbackDesc.guioptions = GUIO3(GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI);

    if (allFiles.contains("resource.map") || allFiles.contains("Data1")
            || allFiles.contains("resmap.001") || allFiles.contains("resmap.001")) {
        foundResMap = true;
    }

    // Determine if we got a CD version and set the CD flag accordingly, by checking for
    // resource.aud for SCI1.1 CD games, or audio001.002 for SCI1 CD games. We assume that
    // the file should be over 10MB, as it contains all the game speech and is usually
    // around 450MB+. The size check is for some floppy game versions like KQ6 floppy, which
    // also have a small resource.aud file
    if (allFiles.contains("resource.aud") || allFiles.contains("audio001.002")) {
        Common::FSNode file = allFiles.contains("resource.aud") ? allFiles["resource.aud"] :  allFiles["audio001.002"];
        Common::SeekableReadStream *tmpStream = file.createReadStream();
        if (tmpStream->size() > 10 * 1024 * 1024) {
            // We got a CD version, so set the CD flag accordingly
            s_fallbackDesc.flags |= ADGF_CD;
        }
        delete tmpStream;
    }

    if (allFiles.contains("resource.000") || allFiles.contains("resource.001")
            || allFiles.contains("ressci.000") || allFiles.contains("ressci.001"))
        foundRes000 = true;

    // Data1 contains both map and volume for SCI1.1+ Mac games
    if (allFiles.contains("Data1")) {
        foundResMap = foundRes000 = true;
        s_fallbackDesc.platform = Common::kPlatformMacintosh;
    }

    // Determine the game platform
    // The existence of any of these files indicates an Amiga game
    if (allFiles.contains("9.pat") || allFiles.contains("spal") ||
            allFiles.contains("patch.005") || allFiles.contains("bank.001"))
        s_fallbackDesc.platform = Common::kPlatformAmiga;

    // The existence of 7.pat or patch.200 indicates a Mac game
    if (allFiles.contains("7.pat") || allFiles.contains("patch.200"))
        s_fallbackDesc.platform = Common::kPlatformMacintosh;

    // The data files for Atari ST versions are the same as their DOS counterparts


    // If these files aren't found, it can't be SCI
    if (!foundResMap && !foundRes000)
        return 0;

    ResourceManager resMan;
    resMan.addAppropriateSourcesForDetection(fslist);
    resMan.initForDetection();
    // TODO: Add error handling.

#ifndef ENABLE_SCI32
    // Is SCI32 compiled in? If not, and this is a SCI32 game,
    // stop here
    if (getSciVersionForDetection() >= SCI_VERSION_2)
        return 0;
#endif

    ViewType gameViews = resMan.getViewType();

    // Have we identified the game views? If not, stop here
    // Can't be SCI (or unsupported SCI views). Pinball Creep by Sierra also uses resource.map/resource.000 files
    // but doesn't share SCI format at all
    if (gameViews == kViewUnknown)
        return 0;

    // Set the platform to Amiga if the game is using Amiga views
    if (gameViews == kViewAmiga)
        s_fallbackDesc.platform = Common::kPlatformAmiga;

    // Determine the game id
    Common::String sierraGameId = resMan.findSierraGameId();

    // If we don't have a game id, the game is not SCI
    if (sierraGameId.empty())
        return 0;

    Common::String gameId = convertSierraGameId(sierraGameId, &s_fallbackDesc.flags, resMan);
    strncpy(s_fallbackGameIdBuf, gameId.c_str(), sizeof(s_fallbackGameIdBuf) - 1);
    s_fallbackGameIdBuf[sizeof(s_fallbackGameIdBuf) - 1] = 0;	// Make sure string is NULL terminated
    s_fallbackDesc.gameid = s_fallbackGameIdBuf;

    // Try to determine the game language
    // Load up text 0 and start looking for "#" characters
    // Non-English versions contain strings like XXXX#YZZZZ
    // Where XXXX is the English string, #Y a separator indicating the language
    // (e.g. #G for German) and ZZZZ is the translated text
    // NOTE: This doesn't work for games which use message instead of text resources
    // (like, for example, Eco Quest 1 and all SCI1.1 games and newer, e.g. Freddy Pharkas).
    // As far as we know, these games store the messages of each language in separate
    // resources, and it's not possible to detect that easily
    // Also look for "%J" which is used in japanese games
    Resource *text = resMan.findResource(ResourceId(kResourceTypeText, 0), 0);
    uint seeker = 0;
    if (text) {
        while (seeker < text->size) {
            if (text->data[seeker] == '#')  {
                if (seeker + 1 < text->size)
                    s_fallbackDesc.language = charToScummVMLanguage(text->data[seeker + 1]);
                break;
            }
            if (text->data[seeker] == '%') {
                if ((seeker + 1 < text->size) && (text->data[seeker + 1] == 'J')) {
                    s_fallbackDesc.language = charToScummVMLanguage(text->data[seeker + 1]);
                    break;
                }
            }
            seeker++;
        }
    }


    // Fill in "extra" field

    // Is this an EGA version that might have a VGA pendant? Then we want
    // to mark it as such in the "extra" field.
    const bool markAsEGA = (gameViews == kViewEga && s_fallbackDesc.platform != Common::kPlatformAmiga
                            && getSciVersion() > SCI_VERSION_1_EGA_ONLY);

    const bool isDemo = (s_fallbackDesc.flags & ADGF_DEMO);
    const bool isCD = (s_fallbackDesc.flags & ADGF_CD);

    if (!isCD)
        s_fallbackDesc.guioptions = GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI);

    if (gameId.hasSuffix("sci")) {
        s_fallbackDesc.extra = "SCI";

        // Differentiate EGA versions from the VGA ones, where needed
        if (markAsEGA)
            s_fallbackDesc.extra = "SCI/EGA";

        // Mark as demo.
        // Note: This overwrites the 'EGA' info, if it was previously set.
        if (isDemo)
            s_fallbackDesc.extra = "SCI/Demo";
    } else {
        if (markAsEGA)
            s_fallbackDesc.extra = "EGA";

        // Set "CD" and "Demo" as appropriate.
        // Note: This overwrites the 'EGA' info, if it was previously set.
        if (isDemo && isCD)
            s_fallbackDesc.extra = "CD Demo";
        else if (isDemo)
            s_fallbackDesc.extra = "Demo";
        else if (isCD)
            s_fallbackDesc.extra = "CD";
    }

    return &s_fallbackDesc;
}
Example #7
0
bool BaseFileManager::registerPackages() {
	debugC(kWintermuteDebugFileAccess | kWintermuteDebugLog, "Scanning packages");

	// We need the target name as a Common::String to perform some game-specific hacks.
	Common::String targetName = BaseEngine::instance().getGameTargetName();

	// Register without using SearchMan, as otherwise the FSNode-based lookup in openPackage will fail
	// and that has to be like that to support the detection-scheme.
	Common::FSList files;
	for (Common::FSList::const_iterator it = _packagePaths.begin(); it != _packagePaths.end(); ++it) {
		debugC(kWintermuteDebugFileAccess, "Should register folder: %s %s", it->getPath().c_str(), it->getName().c_str());
		if (!it->getChildren(files, Common::FSNode::kListFilesOnly)) {
			warning("getChildren() failed for path: %s", it->getDisplayName().c_str());
		}
		for (Common::FSList::const_iterator fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
			// To prevent any case sensitivity issues we make the filename
			// all lowercase here. This makes the code slightly prettier
			// than the equivalent of using equalsIgnoreCase.
			Common::String fileName = fileIt->getName();
			fileName.toLowercase();

			if (!fileName.hasSuffix(".dcp")) {
				continue;
			}
			// HACK: for Reversion1, avoid loading xlanguage_pt.dcp from the main folder:
			if (_language != Common::PT_BRA && targetName.hasPrefix("reversion1")) {
				if (fileName == "xlanguage_pt.dcp") {
					continue;
				}
			}

			// Again, make the parent's name all lowercase to avoid any case
			// issues.
			Common::String parentName = fileIt->getParent().getName();
			parentName.toLowercase();

			// Avoid registering all the language files
			// TODO: Select based on the gameDesc.
			if (_language != Common::UNK_LANG && (parentName == "language" || parentName == "languages")) {
				// English
				if (_language == Common::EN_ANY && (fileName != "english.dcp" && fileName != "xlanguage_en.dcp")) {
					continue;
				// Chinese
				} else if (_language == Common::ZH_CNA && (fileName != "chinese.dcp" && fileName != "xlanguage_nz.dcp")) {
					continue;
				// Czech
				} else if (_language == Common::CZ_CZE && (fileName != "czech.dcp" && fileName != "xlanguage_cz.dcp")) {
					continue;
				// French
				} else if (_language == Common::FR_FRA && (fileName != "french.dcp" && fileName != "xlanguage_fr.dcp")) {
					continue;
				// German
				} else if (_language == Common::DE_DEU && (fileName != "german.dcp" && fileName != "xlanguage_de.dcp")) {
					continue;
				// Italian
				} else if (_language == Common::IT_ITA && (fileName != "italian.dcp" && fileName != "xlanguage_it.dcp")) {
					continue;
				// Latvian
				} else if (_language == Common::LV_LAT && (fileName != "latvian.dcp" && fileName != "xlanguage_lv.dcp")) {
					// TODO: 'latvian.dcp' is just guesswork. Is there any
					// game using Latvian and using this filename?
					continue;
				// Polish
				} else if (_language == Common::PL_POL && (fileName != "polish.dcp" && fileName != "xlanguage_pl.dcp")) {
					continue;
				// Portuguese
				} else if (_language == Common::PT_BRA && (fileName != "portuguese.dcp" && fileName != "xlanguage_pt.dcp")) {
					continue;
				// Russian
				} else if (_language == Common::RU_RUS && (fileName != "russian.dcp" && fileName != "xlanguage_ru.dcp")) {
					continue;
				}
			}
			debugC(kWintermuteDebugFileAccess, "Registering %s %s", fileIt->getPath().c_str(), fileIt->getName().c_str());
			registerPackage((*fileIt));
		}
	}

//	debugC(kWintermuteDebugFileAccess | kWintermuteDebugLog, "  Registered %d files in %d package(s)", _files.size(), _packages.size());

	return STATUS_OK;
}
Example #8
0
bool GlulxeMetaEngine::detectGames(const Common::FSList &fslist, DetectedGames &gameList) {
	const char *const EXTENSIONS[] = { ".ulx", nullptr };

	// Loop through the files of the folder
	for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
		// Check for a recognised filename
		if (file->isDirectory())
			continue;
		Common::String filename = file->getName();
		bool hasExt = Blorb::hasBlorbExt(filename), isBlorb = false;
		for (const char *const *ext = &EXTENSIONS[0]; *ext && !hasExt; ++ext)
			hasExt = filename.hasSuffixIgnoreCase(*ext);
		if (!hasExt)
			continue;

		// Open up the file and calculate the md5
		Common::File gameFile;
		if (!gameFile.open(*file))
			continue;
		Common::String md5 = Common::computeStreamMD5AsString(gameFile, 5000);
		size_t filesize = gameFile.size();
		gameFile.seek(0);
		isBlorb = Blorb::isBlorb(gameFile, ID_GLUL);
		gameFile.close();

		if (!isBlorb && Blorb::hasBlorbExt(filename))
			continue;

		// Check for known games
		const GlulxeGameDescription *p = GLULXE_GAMES;
		while (p->_gameId && (md5 != p->_md5 || filesize != p->_filesize))
			++p;

		DetectedGame gd;
		if (!p->_gameId) {
			if (gDebugLevel > 0) {
				// Print an entry suitable for putting into the detection_tables.h, using the
				// name of the parent folder the game is in as the presumed game Id
				Common::String folderName = file->getParent().getName();
				if (folderName.hasSuffix("\\"))
					folderName.deleteLastChar();
				Common::String fname = filename;
				const char *dot = strchr(fname.c_str(), '.');
				if (dot)
					fname = Common::String(fname.c_str(), dot);

				debug("ENTRY0(\"%s\", \"%s\", %u),", fname.c_str(), md5.c_str(), (uint)filesize);
			}
			const PlainGameDescriptor &desc = GLULXE_GAME_LIST[0];
			gd = DetectedGame(desc.gameId, desc.description, Common::UNK_LANG, Common::kPlatformUnknown);
		} else {
			PlainGameDescriptor gameDesc = findGame(p->_gameId);
			gd = DetectedGame(p->_gameId, gameDesc.description, p->_language, Common::kPlatformUnknown, p->_extra);
			gd.setGUIOptions(GUIO4(GUIO_NOSPEECH, GUIO_NOSFX, GUIO_NOMUSIC, GUIO_NOSUBTITLES));
		}

		gd.addExtraEntry("filename", filename);
		gameList.push_back(gd);
	}

	return !gameList.empty();
}
Example #9
0
Common::Error GroovieEngine::run() {
	if (_gameDescription->version == kGroovieV2 && getPlatform() == Common::kPlatformMacintosh) {
		// Load the Mac installer with the lowest priority (in case the user has installed
		// the game and has the MIDI folder present; faster to just load them)
		Common::Archive *archive = createStuffItArchive("The 11th Hour Installer");

		if (archive)
			SearchMan.add("The 11th Hour Installer", archive);
	}

	_script = new Script(this, _gameDescription->version);

	// Initialize the graphics
	switch (_gameDescription->version) {
	case kGroovieV2: {
		// Request the mode with the highest precision available
		Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
		initGraphics(640, 480, true, &format);

		if (_system->getScreenFormat() != format)
			return Common::kUnsupportedColorMode;

		// Save the enabled mode
		_pixelFormat = format;
		break;
	}
	case kGroovieT7G:
		initGraphics(640, 480, true);
		_pixelFormat = Graphics::PixelFormat::createFormatCLUT8();
		break;
	}

	// 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
	// Prepare the font too
	switch (_gameDescription->version) {
	case kGroovieT7G:
		if (getPlatform() == Common::kPlatformMacintosh) {
			_macResFork = new Common::MacResManager();
			if (!_macResFork->open(_gameDescription->desc.filesDescriptions[0].fileName))
				error("Could not open %s as a resource fork", _gameDescription->desc.filesDescriptions[0].fileName);
			// The Macintosh release used system fonts. We use GUI fonts.
			_font = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
		} else {
			Common::File fontfile;
			if (!fontfile.open("sphinx.fnt")) {
				error("Couldn't open sphinx.fnt");
				return Common::kNoGameDataFoundError;
			} else if (!_sphinxFont.load(fontfile)) {
				error("Error loading sphinx.fnt");
				return Common::kUnknownError;
			}
			fontfile.close();
			_font = &_sphinxFont;
		}

		_resMan = new ResMan_t7g(_macResFork);
		_grvCursorMan = new GrvCursorMan_t7g(_system, _macResFork);
		_videoPlayer = new VDXPlayer(this);
		break;
	case kGroovieV2:
		_resMan = new ResMan_v2();
		_grvCursorMan = new GrvCursorMan_v2(_system);
#ifdef ENABLE_GROOVIE2
		_videoPlayer = new ROQPlayer(this);
#endif
		break;
	}

	// Detect ScummVM Music Enhancement Project presence (T7G only)
	if (Common::File::exists("gu16.ogg") && _gameDescription->version == kGroovieT7G) {
		// Load player for external files
		_musicPlayer = new MusicPlayerIOS(this);
	} else {
		// Create the music player
		switch (getPlatform()) {
		case Common::kPlatformMacintosh:
			if (_gameDescription->version == kGroovieT7G)
				_musicPlayer = new MusicPlayerMac_t7g(this);
			else
				_musicPlayer = new MusicPlayerMac_v2(this);
			break;
		case Common::kPlatformIOS:
			_musicPlayer = new MusicPlayerIOS(this);
			break;
		default:
			_musicPlayer = new MusicPlayerXMI(this, _gameDescription->version == kGroovieT7G ? "fat" : "sample");
			break;
		}
	}

	// 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 = "demo.grv";
		else if (getPlatform() == Common::kPlatformMacintosh)
			filename = "script.grv"; // Stored inside the executable's resource fork
	} 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);
	}

	// Game timer counter
	uint16 tmr = 0;

	// Check that the game files and the audio tracks aren't together run from
	// the same cd
	if (getPlatform() != Common::kPlatformIOS) {
		checkCD();

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

	while (!shouldQuit()) {
		// Give the debugger a chance to act
		_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(1);

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

			case Common::EVENT_RBUTTONDOWN:
				// Send the event to the scripts (to skip the video)
				_script->setMouseClick(2);
				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;
}