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; }
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); }
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; }
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; }
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; } }
Common::String SaveLoad::getSlotSaveName(const Common::String &target, int slot) { Common::String fileName = Common::String::format("%s.%03d", target.c_str(), slot); return fileName; }
ActionTimer::ActionTimer(const Common::String &line) { sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%u)", &_key, &_time); }
ActionAssign::ActionAssign(const Common::String &line) { sscanf(line.c_str(), "%*[^(](%u, %u)", &_key, &_value); }
ActionRandom::ActionRandom(const Common::String &line) { sscanf(line.c_str(), "%*[^:]:%*[^:]:%u, %u)", &_key, &_max); }
ActionSetScreen::ActionSetScreen(const Common::String &line) { char fileName[25]; sscanf(line.c_str(), "%*[^(](%25[^)])", fileName); _fileName = Common::String(fileName); }
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); }
ActionEnableControl::ActionEnableControl(const Common::String &line) { sscanf(line.c_str(), "%*[^(](%u)", &_key); }
ActionCrossfade::ActionCrossfade(const Common::String &line) { sscanf(line.c_str(), "%*[^(](%u %u %u %u %u %u %u)", &_keyOne, &_keyTwo, &_oneStartVolume, &_twoStartVolume, &_oneEndVolume, &_twoEndVolume, &_timeInMillis); }
const char *slide() const { return _slide.c_str(); }
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()); }
ActionChangeLocation::ActionChangeLocation(const Common::String &line) { sscanf(line.c_str(), "%*[^(](%c,%c,%c%c,%u)", &_world, &_room, &_node, &_view, &_offset); }
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(); } }
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); }
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; }
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]; } } } }
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; }
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()); } } }
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()); }
const char *character() const { return _character.c_str(); }
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; }
// 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; }