void AGOSEngine_PuzzlePack::handleMouseMoved() { uint x; if (getGameId() != GID_DIMP && _mouseHideCount) { CursorMan.showMouse(false); return; } CursorMan.showMouse(true); _mouse = _eventMan->getMousePos(); x = 0; if (_lastHitArea3 == 0 && _leftButtonDown) { _verbHitArea = 300; _leftButtonDown = false; x = 1; } if (_rightButtonDown) { _verbHitArea = (getGameId() == GID_DIMP) ? 301 : 300; _rightButtonDown = false; x = 1; } boxController(_mouse.x, _mouse.y, x); _lastHitArea3 = _lastHitArea; if (x == 1 && _lastHitArea == NULL) _lastHitArea3 = (HitArea *) -1; drawMousePointer(); }
void SciEngine::syncIngameAudioOptions() { // Now, sync the in-game speech/subtitles settings for SCI1.1 CD games if (isCD() && getSciVersion() == SCI_VERSION_1_1) { bool subtitlesOn = ConfMan.getBool("subtitles"); bool speechOn = !ConfMan.getBool("speech_mute"); if (subtitlesOn && !speechOn) { _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 1); // subtitles } else if (!subtitlesOn && speechOn) { _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 2); // speech } else if (subtitlesOn && speechOn) { // Is it a game that supports simultaneous speech and subtitles? if (getGameId() == GID_SQ4 || getGameId() == GID_FREDDYPHARKAS // TODO: The following need script patches for simultaneous speech and subtitles //|| getGameId() == GID_KQ6 //|| getGameId() == GID_LAURABOW2 ) { _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 3); // speech + subtitles } else { // Game does not support speech and subtitles, set it to speech _gamestate->variables[VAR_GLOBAL][90] = make_reg(0, 2); // speech } } } }
void AGOSEngine_PuzzlePack::setupGame() { if (getGameId() == GID_DIMP) { gss = &dimp_settings; } else if (getGameId() == GID_JUMBLE) { gss = &jumble_settings; } else if (getGameId() == GID_PUZZLE) { gss = &puzzle_settings; } else if (getGameId() == GID_SWAMPY) { gss = &swampy_settings; } _numVideoOpcodes = 85; _vgaMemSize = 7500000; _itemMemSize = 20000; _tableMemSize = 200000; _frameCount = 1; _vgaBaseDelay = 5; _vgaPeriod = (getGameId() == GID_DIMP) ? 35 : 30; _numBitArray1 = 128; _numItemStore = 10; _numTextBoxes = 40; _numVars = 2048; _numZone = 450; AGOSEngine::setupGame(); }
const char *SagaEngine::getObjectName(uint16 objectId) const { ActorData *actor; ObjectData *obj; const HitZone *hitZone; // Disable the object names in IHNM when the chapter is 8 if (getGameId() == GID_IHNM && _scene->currentChapterNumber() == 8) return ""; switch (objectTypeId(objectId)) { case kGameObjectObject: obj = _actor->getObj(objectId); if (getGameId() == GID_ITE) return _script->_mainStrings.getString(obj->_nameIndex); return _actor->_objectsStrings.getString(obj->_nameIndex); case kGameObjectActor: actor = _actor->getActor(objectId); return _actor->_actorsStrings.getString(actor->_nameIndex); case kGameObjectHitZone: hitZone = _scene->_objectMap->getHitZone(objectIdToIndex(objectId)); if (hitZone == NULL) return ""; return _scene->_sceneStrings.getString(hitZone->getNameIndex()); } warning("SagaEngine::getObjectName name not found for 0x%X", objectId); return NULL; }
void ZVision::initialize() { const Common::FSNode gameDataDir(ConfMan.get("path")); _searchManager = new SearchManager(ConfMan.get("path"), 6); _searchManager->addDir("FONTS"); _searchManager->addDir("addon"); if (getGameId() == GID_GRANDINQUISITOR) { if (!_searchManager->loadZix("INQUIS.ZIX")) error("Unable to load file INQUIS.ZIX"); } else if (getGameId() == GID_NEMESIS) { if (!_searchManager->loadZix("NEMESIS.ZIX")) { // The game might not be installed, try MEDIUM.ZIX instead if (!_searchManager->loadZix("ZNEMSCR/MEDIUM.ZIX")) error("Unable to load the file ZNEMSCR/MEDIUM.ZIX"); } } initScreen(); // Register random source _rnd = new Common::RandomSource("zvision"); // Create managers _scriptManager = new ScriptManager(this); _renderManager = new RenderManager(this, WINDOW_WIDTH, WINDOW_HEIGHT, _workingWindow, _resourcePixelFormat, _doubleFPS); _saveManager = new SaveManager(this); _stringManager = new StringManager(this); _cursorManager = new CursorManager(this, _resourcePixelFormat); _textRenderer = new TextRenderer(this); _midiManager = new MidiManager(); if (getGameId() == GID_GRANDINQUISITOR) _menu = new MenuZGI(this); else _menu = new MenuNemesis(this); // Initialize the managers _cursorManager->initialize(); _scriptManager->initialize(); _stringManager->initialize(getGameId()); registerDefaultSettings(); loadSettings(); #ifndef USE_MPEG2 // libmpeg2 not loaded, disable the MPEG2 movies option _scriptManager->setStateValue(StateKey_MPEGMovies, 2); #endif // Create debugger console. It requires GFX to be initialized _console = new Console(this); _doubleFPS = ConfMan.getBool("doublefps"); // Initialize FPS timer callback getTimerManager()->installTimerProc(&fpsTimerCallback, 1000000, this, "zvisionFPS"); }
void ZVision::initScreen() { uint16 workingWindowWidth = (getGameId() == GID_NEMESIS) ? ZNM_WORKING_WINDOW_WIDTH : ZGI_WORKING_WINDOW_WIDTH; uint16 workingWindowHeight = (getGameId() == GID_NEMESIS) ? ZNM_WORKING_WINDOW_HEIGHT : ZGI_WORKING_WINDOW_HEIGHT; _workingWindow = Common::Rect( (WINDOW_WIDTH - workingWindowWidth) / 2, (WINDOW_HEIGHT - workingWindowHeight) / 2, ((WINDOW_WIDTH - workingWindowWidth) / 2) + workingWindowWidth, ((WINDOW_HEIGHT - workingWindowHeight) / 2) + workingWindowHeight ); initGraphics(WINDOW_WIDTH, WINDOW_HEIGHT, true, &_screenPixelFormat); }
void SciEngine::loadMacExecutable() { if (getPlatform() != Common::kPlatformMacintosh || getSciVersion() < SCI_VERSION_1_EARLY || getSciVersion() > SCI_VERSION_1_1) return; Common::String filename; switch (getGameId()) { case GID_KQ6: filename = "King's Quest VI"; break; case GID_FREDDYPHARKAS: filename = "Freddy Pharkas"; break; default: break; } if (filename.empty()) return; if (!_macExecutable.open(filename) || !_macExecutable.hasResFork()) { // KQ6/Freddy require the executable to load their icon bar palettes if (hasMacIconBar()) error("Could not load Mac resource fork '%s'", filename.c_str()); // TODO: Show some sort of warning dialog saying they can't get any // high-res Mac fonts, when we get to that point ;) } }
void AGOSEngine_PuzzlePack::vc3_loadSprite() { if (getGameId() != GID_DIMP && getBitFlag(100)) { startAnOverlayAnim(); return; } AGOSEngine::vc3_loadSprite(); }
void AGOSEngine_PuzzlePack::initMouse() { if (getGameId() == GID_DIMP) { AGOSEngine_Simon1::initMouse(); } else { _maxCursorWidth = 75; _maxCursorHeight = 97; _mouseData = (byte *)calloc(_maxCursorWidth * _maxCursorHeight, 1); } }
void AGOSEngine_Simon1::os1_playEffect() { // 163: play sound uint16 soundId = getVarOrWord(); if (getGameId() == GID_SIMON1DOS) playSting(soundId); else _sound->playEffects(soundId); }
void AGOSEngine::o_loadUserGame() { // 133: load user game if (getGameId() == GID_SIMON1CD32) { // The Amiga CD32 version of Simon the Sorcerer 1 uses a single slot if (!loadGame(genSaveName(0))) { vc33_setMouseOn(); fileError(_windowArray[5], false); } } else { _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); userGame(true); _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); } }
void AGOSEngine::o_saveUserGame() { // 132: save user game if (getGameId() == GID_SIMON1CD32) { // The Amiga CD32 version of Simon the Sorcerer 1 uses a single slot if (!saveGame(0, "Default Saved Game")) { vc33_setMouseOn(); fileError(_windowArray[5], true); } } else { _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true); userGame(false); _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false); } }
void AGOSEngine::loadSound(uint16 sound, int16 pan, int16 vol, uint16 type) { byte *dst; if (getGameId() == GID_DIMP) { Common::File in; char filename[15]; assert(sound >= 1 && sound <= 32); sprintf(filename, "%s.wav", dimpSoundList[sound - 1]); in.open(filename); if (in.isOpen() == false) error("loadSound: Can't load %s", filename); uint32 dstSize = in.size(); dst = (byte *)malloc(dstSize); if (in.read(dst, dstSize) != dstSize) error("loadSound: Read failed"); in.close(); } else if (getFeatures() & GF_ZLIBCOMP) { char filename[15]; uint32 file, offset, srcSize, dstSize; if (getPlatform() == Common::kPlatformAmiga) { loadOffsets((const char*)"sfxindex.dat", _zoneNumber * 22 + sound, file, offset, srcSize, dstSize); } else { loadOffsets((const char*)"effects.wav", _zoneNumber * 22 + sound, file, offset, srcSize, dstSize); } if (getPlatform() == Common::kPlatformAmiga) sprintf(filename, "sfx%d.wav", file); else sprintf(filename, "effects.wav"); dst = (byte *)malloc(dstSize); decompressData(filename, dst, offset, srcSize, dstSize); } else { if (_curSfxFile == NULL) return; dst = _curSfxFile + READ_LE_UINT32(_curSfxFile + sound * 4); } if (type == Sound::TYPE_AMBIENT) _sound->playAmbientData(dst, sound, pan, vol); else if (type == Sound::TYPE_SFX) _sound->playSfxData(dst, sound, pan, vol); else if (type == Sound::TYPE_SFX5) _sound->playSfx5Data(dst, sound, pan, vol); }
void AGOSEngine_PuzzlePack::vc63_fastFadeIn() { _fastFadeInFlag = 256; _fastFadeOutFlag = false; if (getGameId() == GID_DIMP) return; if (getBitFlag(100)) { startOverlayAnims(); } else if (getBitFlag(103)) { debug("vc63_fastFadeIn: NameAndTime"); } else if (getBitFlag(104)) { debug("vc63_fastFadeIn: HiScoreTable"); } }
void AGOSEngine_PuzzlePack::setupGame() { gss = &puzzlepack_settings; _numVideoOpcodes = 85; _vgaMemSize = 7500000; _itemMemSize = 20000; _tableMemSize = 200000; _frameCount = 1; _vgaBaseDelay = 5; _vgaPeriod = (getGameId() == GID_DIMP) ? 35 : 30; _numBitArray1 = 128; _numItemStore = 10; _numTextBoxes = 40; _numVars = 2048; AGOSEngine::setupGame(); }
void AGOSEngine::addTimeEvent(uint16 timeout, uint16 subroutine_id) { TimeEvent *te = (TimeEvent *)malloc(sizeof(TimeEvent)), *first, *last = NULL; uint32 cur_time = getTime(); if (getGameId() == GID_DIMP) { timeout /= 2; } te->time = cur_time + timeout - _gameStoppedClock; if (getGameType() == GType_FF && _clockStopped) te->time -= (getTime() - _clockStopped); te->subroutine_id = subroutine_id; first = _firstTimeStruct; while (first) { if (te->time <= first->time) { if (last) { last->next = te; te->next = first; return; } te->next = _firstTimeStruct; _firstTimeStruct = te; return; } last = first; first = first->next; } if (last) { last->next = te; te->next = NULL; } else { _firstTimeStruct = te; te->next = NULL; } }
void AGOSEngine::o_picture() { // 96 uint vga_res = getVarOrWord(); uint mode = getVarOrByte(); // WORKAROUND: For a script bug in the Amiga AGA/CD32 versions // When selecting locations on the magical map, the script looks // for vga_res 12701, but only vga_res 12700 exists. if (getGameType() == GType_SIMON1 && getPlatform() == Common::kPlatformAmiga && vga_res == 12701) { return; } if (getGameType() == GType_PP && getGameId() != GID_DIMP) { if (vga_res == 8700 && getBitFlag(107)) { _vgaPeriod = 30; } _picture8600 = (vga_res == 8600); } setWindowImageEx(mode, vga_res); }
void SciEngine::initGraphics() { // Reset all graphics objects _gfxAnimate = 0; _gfxCache = 0; _gfxCompare = 0; _gfxControls16 = 0; _gfxCoordAdjuster = 0; _gfxCursor = 0; _gfxMacIconBar = 0; _gfxMenu = 0; _gfxPaint16 = 0; _gfxPalette16 = 0; _gfxRemap16 = 0; _gfxPorts = 0; _gfxText16 = 0; _gfxTransitions = 0; #ifdef ENABLE_SCI32 _gfxControls32 = 0; _gfxText32 = 0; _gfxFrameout = 0; _gfxPaint32 = 0; _gfxPalette32 = 0; _gfxRemap32 = 0; _gfxTransitions32 = 0; _gfxCursor32 = 0; #endif if (hasMacIconBar()) _gfxMacIconBar = new GfxMacIconBar(); #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { _gfxPalette32 = new GfxPalette32(_resMan); _gfxRemap32 = new GfxRemap32(); } else { #endif _gfxPalette16 = new GfxPalette(_resMan, _gfxScreen); if (getGameId() == GID_QFG4DEMO) _gfxRemap16 = new GfxRemap(_gfxPalette16); #ifdef ENABLE_SCI32 } #endif _gfxCache = new GfxCache(_resMan, _gfxScreen, _gfxPalette16); #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { // SCI32 graphic objects creation _gfxCursor32 = new GfxCursor32(); _gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, nullptr, _gfxCoordAdjuster); _gfxPaint32 = new GfxPaint32(_gamestate->_segMan); _gfxTransitions32 = new GfxTransitions32(_gamestate->_segMan); _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _gfxPalette32, _gfxTransitions32, _gfxCursor32); _gfxCursor32->init(_gfxFrameout->getCurrentBuffer()); _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache); _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32); _gfxFrameout->run(); } else { #endif // SCI0-SCI1.1 graphic objects creation _gfxCursor = new GfxCursor(_resMan, _gfxPalette16, _gfxScreen); _gfxPorts = new GfxPorts(_gamestate->_segMan, _gfxScreen); _gfxCoordAdjuster = new GfxCoordAdjuster16(_gfxPorts); _gfxCursor->init(_gfxCoordAdjuster, _eventMan); _gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster); _gfxTransitions = new GfxTransitions(_gfxScreen, _gfxPalette16); _gfxPaint16 = new GfxPaint16(_resMan, _gamestate->_segMan, _gfxCache, _gfxPorts, _gfxCoordAdjuster, _gfxScreen, _gfxPalette16, _gfxTransitions, _audio); _gfxAnimate = new GfxAnimate(_gamestate, _scriptPatcher, _gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen, _gfxPalette16, _gfxCursor, _gfxTransitions); _gfxText16 = new GfxText16(_gfxCache, _gfxPorts, _gfxPaint16, _gfxScreen); _gfxControls16 = new GfxControls16(_gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen); _gfxMenu = new GfxMenu(_eventMan, _gamestate->_segMan, _gfxPorts, _gfxPaint16, _gfxText16, _gfxScreen, _gfxCursor); _gfxMenu->reset(); _gfxPorts->init(_features->usesOldGfxFunctions(), _gfxPaint16, _gfxText16); _gfxPaint16->init(_gfxAnimate, _gfxText16); #ifdef ENABLE_SCI32 } #endif if (getSciVersion() < SCI_VERSION_2) { // Set default (EGA, amiga or resource 999) palette _gfxPalette16->setDefault(); } }
bool SciEngine::gameHasFanMadePatch() { struct FanMadePatchInfo { SciGameId gameID; uint16 targetScript; uint16 targetSize; uint16 patchedByteOffset; byte patchedByte; }; const FanMadePatchInfo patchInfo[] = { // game script size offset byte // ** NRS Patches ************************** { GID_HOYLE3, 994, 2580, 656, 0x78 }, { GID_KQ1, 85, 5156, 631, 0x02 }, { GID_LAURABOW2, 994, 4382, 0, 0x00 }, { GID_LONGBOW, 994, 4950, 1455, 0x78 }, // English { GID_LONGBOW, 994, 5020, 1469, 0x78 }, // German { GID_LSL1, 803, 592, 342, 0x01 }, { GID_LSL3, 380, 6148, 195, 0x35 }, { GID_LSL5, 994, 4810, 1342, 0x78 }, // English { GID_LSL5, 994, 4942, 1392, 0x76 }, // German { GID_PQ1, 994, 4332, 1473, 0x78 }, { GID_PQ2, 200, 10614, 0, 0x00 }, { GID_PQ3, 994, 4686, 1291, 0x78 }, // English { GID_PQ3, 994, 4734, 1283, 0x78 }, // German { GID_QFG1VGA, 994, 4388, 0, 0x00 }, { GID_QFG3, 994, 4714, 2, 0x48 }, // TODO: Disabled, as it fixes a whole lot of bugs which can't be tested till SCI2.1 support is finished //{ GID_QFG4, 710, 11477, 0, 0x00 }, { GID_SQ1, 994, 4740, 0, 0x00 }, { GID_SQ5, 994, 4142, 1496, 0x78 }, // English/German/French // TODO: Disabled, till we can test the Italian version //{ GID_SQ5, 994, 4148, 0, 0x00 }, // Italian - patched file is the same size as the original // TODO: The bugs in SQ6 can't be tested till SCI2.1 support is finished //{ GID_SQ6, 380, 16308, 15042, 0x0C }, // English //{ GID_SQ6, 380, 11652, 0, 0x00 }, // German - patched file is the same size as the original // ** End marker *************************** { GID_FANMADE, 0, 0, 0, 0x00 } }; int curEntry = 0; while (true) { if (patchInfo[curEntry].targetSize == 0) break; if (patchInfo[curEntry].gameID == getGameId()) { Resource *targetScript = _resMan->findResource(ResourceId(kResourceTypeScript, patchInfo[curEntry].targetScript), 0); if (targetScript && targetScript->size + 2 == patchInfo[curEntry].targetSize) { if (patchInfo[curEntry].patchedByteOffset == 0) return true; else if (targetScript->data[patchInfo[curEntry].patchedByteOffset - 2] == patchInfo[curEntry].patchedByte) return true; } } curEntry++; } return false; }
Common::Error SciEngine::run() { _resMan = new ResourceManager(); assert(_resMan); _resMan->addAppropriateSources(); _resMan->init(); // TODO: Add error handling. Check return values of addAppropriateSources // and init. We first have to *add* sensible return values, though ;). /* if (!_resMan) { warning("No resources found, aborting"); return Common::kNoGameDataFoundError; } */ // Reset, so that error()s before SoundCommandParser is initialized wont cause a crash _soundCmd = NULL; // Add the after market GM patches for the specified game, if they exist _resMan->addNewGMPatch(_gameId); _gameObjectAddress = _resMan->findGameObject(); _scriptPatcher = new ScriptPatcher(); SegManager *segMan = new SegManager(_resMan, _scriptPatcher); // Read user option for forcing hires graphics // Only show/selectable for: // - King's Quest 6 CD // - King's Quest 6 CD demo // - Gabriel Knight 1 CD // - Police Quest 4 CD // TODO: Check, if Gabriel Knight 1 floppy supports high resolution // // Gabriel Knight 1 on Mac is hi-res only, so it should NOT get this option. // Confirmed by [md5] and originally by clone2727. if (Common::checkGameGUIOption(GAMEOPTION_HIGH_RESOLUTION_GRAPHICS, ConfMan.get("guioptions"))) { // GAMEOPTION_HIGH_RESOLUTION_GRAPHICS is available for the currently detected game, // so read the user option now. // We need to do this, because the option's default is "true", but we don't want "true" // for any game that does not have this option. _forceHiresGraphics = ConfMan.getBool("enable_high_resolution_graphics"); } if (getSciVersion() < SCI_VERSION_2) { // Initialize the game screen _gfxScreen = new GfxScreen(_resMan); _gfxScreen->enableUndithering(ConfMan.getBool("disable_dithering")); } else { _gfxScreen = nullptr; } _kernel = new Kernel(_resMan, segMan); _kernel->init(); _features = new GameFeatures(segMan, _kernel); // Only SCI0, SCI01 and SCI1 EGA games used a parser _vocabulary = (getSciVersion() <= SCI_VERSION_1_EGA_ONLY) ? new Vocabulary(_resMan, false) : NULL; // Also, XMAS1990 apparently had a parser too. Refer to http://forums.scummvm.org/viewtopic.php?t=9135 if (getGameId() == GID_CHRISTMAS1990) _vocabulary = new Vocabulary(_resMan, false); _gamestate = new EngineState(segMan); _eventMan = new EventManager(_resMan->detectFontExtended()); #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2_1_EARLY) { _audio32 = new Audio32(_resMan); } else #endif _audio = new AudioPlayer(_resMan); #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { _video32 = new Video32(segMan, _eventMan); } #endif _sync = new Sync(_resMan, segMan); // Create debugger console. It requires GFX and _gamestate to be initialized _console = new Console(this); // The game needs to be initialized before the graphics system is initialized, as // the graphics code checks parts of the seg manager upon initialization (e.g. for // the presence of the fastCast object) if (!initGame()) { /* Initialize */ warning("Game initialization failed: Aborting..."); // TODO: Add an "init failed" error? return Common::kUnknownError; } // we try to find the super class address of the game object, we can't do that earlier const Object *gameObject = segMan->getObject(_gameObjectAddress); if (!gameObject) { warning("Could not get game object, aborting..."); return Common::kUnknownError; } script_adjust_opcode_formats(); // Must be called after game_init(), as they use _features _kernel->loadKernelNames(_features); // Load our Mac executable here for icon bar palettes and high-res fonts loadMacExecutable(); // Initialize all graphics related subsystems initGraphics(); // Sound must be initialized after graphics because SysEx transfers at the // start of the game must pump the event loop to avoid making the OS think // that ScummVM is hanged, and pumping the event loop requires GfxCursor to // be initialized _soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, _features->detectDoSoundType()); syncSoundSettings(); syncIngameAudioOptions(); // Patch in our save/restore code, so that dialogs are replaced patchGameSaveRestore(); setLauncherLanguage(); // Check whether loading a savestate was requested int directSaveSlotLoading = ConfMan.getInt("save_slot"); if (directSaveSlotLoading >= 0) { _gamestate->_delayedRestoreGame = true; _gamestate->_delayedRestoreGameId = directSaveSlotLoading; _gamestate->_delayedRestoreFromLauncher = true; // Jones only initializes its menus when restarting/restoring, thus set // the gameIsRestarting flag here before initializing. Fixes bug #6536. if (g_sci->getGameId() == GID_JONES) _gamestate->gameIsRestarting = GAMEISRESTARTING_RESTORE; } // Show any special warnings for buggy scripts with severe game bugs, // which have been patched by Sierra if (getGameId() == GID_LONGBOW) { // Longbow 1.0 has a buggy script which prevents the game // from progressing during the Green Man riddle sequence. // A patch for this buggy script has been released by Sierra, // and is necessary to complete the game without issues. // The patched script is included in Longbow 1.1. // Refer to bug #3036609. Resource *buggyScript = _resMan->findResource(ResourceId(kResourceTypeScript, 180), 0); if (buggyScript && (buggyScript->size == 12354 || buggyScript->size == 12362)) { showScummVMDialog("A known buggy game script has been detected, which could " "prevent you from progressing later on in the game, during " "the sequence with the Green Man's riddles. Please, apply " "the latest patch for this game by Sierra to avoid possible " "problems"); } } if (getGameId() == GID_KQ7 && ConfMan.getBool("subtitles")) { showScummVMDialog("Subtitles are enabled, but subtitling in King's" " Quest 7 was unfinished and disabled in the release" " version of the game. ScummVM allows the subtitles" " to be re-enabled, but because they were removed from" " the original game, they do not always render" " properly or reflect the actual game speech." " This is not a ScummVM bug -- it is a problem with" " the game's assets."); } // Show a warning if the user has selected a General MIDI device, no GM patch exists // (i.e. patch 4) and the game is one of the known 8 SCI1 games that Sierra has provided // after market patches for in their "General MIDI Utility". if (_soundCmd->getMusicType() == MT_GM && !ConfMan.getBool("native_mt32")) { if (!_resMan->findResource(ResourceId(kResourceTypePatch, 4), 0)) { switch (getGameId()) { case GID_ECOQUEST: case GID_HOYLE3: case GID_LSL1: case GID_LSL5: case GID_LONGBOW: case GID_SQ1: case GID_SQ4: case GID_FAIRYTALES: showScummVMDialog("You have selected General MIDI as a sound device. Sierra " "has provided after-market support for General MIDI for this " "game in their \"General MIDI Utility\". Please, apply this " "patch in order to enjoy MIDI music with this game. Once you " "have obtained it, you can unpack all of the included *.PAT " "files in your ScummVM extras folder and ScummVM will add the " "appropriate patch automatically. Alternatively, you can follow " "the instructions in the READ.ME file included in the patch and " "rename the associated *.PAT file to 4.PAT and place it in the " "game folder. Without this patch, General MIDI music for this " "game will sound badly distorted."); break; default: break; } } } if (gameHasFanMadePatch()) { showScummVMDialog("Your game is patched with a fan made script patch. Such patches have " "been reported to cause issues, as they modify game scripts extensively. " "The issues that these patches fix do not occur in ScummVM, so you are " "advised to remove this patch from your game folder in order to avoid " "having unexpected errors and/or issues later on."); } runGame(); ConfMan.flushToDisk(); return Common::kNoError; }
ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) { ColorId colorId = kITEColorTransBlack; if (getGameId() == GID_ITE) { switch (knownColor) { case(kKnownColorTransparent): colorId = kITEColorTransBlack; break; case (kKnownColorBrightWhite): colorId = kITEColorBrightWhite; break; case (kKnownColorWhite): colorId = kITEColorWhite; break; case (kKnownColorBlack): colorId = kITEColorBlack; break; case (kKnownColorSubtitleTextColor): colorId = (ColorId)255; break; case (kKnownColorVerbText): colorId = kITEColorBlue; break; case (kKnownColorVerbTextShadow): colorId = kITEColorBlack; break; case (kKnownColorVerbTextActive): colorId = (ColorId)96; break; default: error("SagaEngine::KnownColor2ColorId unknown color %i", knownColor); } #ifdef ENABLE_IHNM } else if (getGameId() == GID_IHNM) { // The default colors in the Spanish, version of IHNM are shifted by one // Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)". This // also applies to the German and French versions (bug #7064 - "IHNM: // text mistake in german version"). int offset = (getFeatures() & GF_IHNM_COLOR_FIX) ? 1 : 0; switch (knownColor) { case(kKnownColorTransparent): colorId = (ColorId)(249 - offset); break; case (kKnownColorBrightWhite): colorId = (ColorId)(251 - offset); break; case (kKnownColorWhite): colorId = (ColorId)(251 - offset); break; case (kKnownColorBlack): colorId = (ColorId)(249 - offset); break; case (kKnownColorVerbText): colorId = (ColorId)(253 - offset); break; case (kKnownColorVerbTextShadow): colorId = (ColorId)(15 - offset); break; case (kKnownColorVerbTextActive): colorId = (ColorId)(252 - offset); break; default: error("SagaEngine::KnownColor2ColorId unknown color %i", knownColor); } #endif } return colorId; }
Common::Error SciEngine::run() { g_eventRec.registerRandomSource(_rng, "sci"); // Assign default values to the config manager, in case settings are missing ConfMan.registerDefault("sci_originalsaveload", "false"); ConfMan.registerDefault("native_fb01", "false"); ConfMan.registerDefault("windows_cursors", "false"); // Windows cursors for KQ6 Windows _resMan = new ResourceManager(); assert(_resMan); _resMan->addAppropriateSources(); _resMan->init(); // TODO: Add error handling. Check return values of addAppropriateSources // and init. We first have to *add* sensible return values, though ;). /* if (!_resMan) { warning("No resources found, aborting"); return Common::kNoGameDataFoundError; } */ // Reset, so that error()s before SoundCommandParser is initialized wont cause a crash _soundCmd = NULL; // Add the after market GM patches for the specified game, if they exist _resMan->addNewGMPatch(_gameId); _gameObjectAddress = _resMan->findGameObject(); _gameSuperClassAddress = NULL_REG; SegManager *segMan = new SegManager(_resMan); // Initialize the game screen _gfxScreen = new GfxScreen(_resMan); _gfxScreen->debugUnditherSetState(ConfMan.getBool("disable_dithering")); // Create debugger console. It requires GFX to be initialized _console = new Console(this); _kernel = new Kernel(_resMan, segMan); _features = new GameFeatures(segMan, _kernel); // Only SCI0, SCI01 and SCI1 EGA games used a parser _vocabulary = (getSciVersion() <= SCI_VERSION_1_EGA) ? new Vocabulary(_resMan, false) : NULL; // Also, XMAS1990 apparently had a parser too. Refer to http://forums.scummvm.org/viewtopic.php?t=9135 if (getGameId() == GID_CHRISTMAS1990) _vocabulary = new Vocabulary(_resMan, false); _audio = new AudioPlayer(_resMan); _gamestate = new EngineState(segMan); _eventMan = new EventManager(_resMan->detectFontExtended()); // The game needs to be initialized before the graphics system is initialized, as // the graphics code checks parts of the seg manager upon initialization (e.g. for // the presence of the fastCast object) if (!initGame()) { /* Initialize */ warning("Game initialization failed: Aborting..."); // TODO: Add an "init failed" error? return Common::kUnknownError; } // we try to find the super class address of the game object, we can't do that earlier const Object *gameObject = segMan->getObject(_gameObjectAddress); if (!gameObject) { warning("Could not get game object, aborting..."); return Common::kUnknownError; } _gameSuperClassAddress = gameObject->getSuperClassSelector(); script_adjust_opcode_formats(); // Must be called after game_init(), as they use _features _kernel->loadKernelNames(_features); _soundCmd = new SoundCommandParser(_resMan, segMan, _kernel, _audio, _features->detectDoSoundType()); syncSoundSettings(); syncIngameAudioOptions(); // Initialize all graphics related subsystems initGraphics(); debug("Emulating SCI version %s\n", getSciVersionDesc(getSciVersion())); // Patch in our save/restore code, so that dialogs are replaced patchGameSaveRestore(); setLauncherLanguage(); // Check whether loading a savestate was requested int directSaveSlotLoading = ConfMan.getInt("save_slot"); if (directSaveSlotLoading >= 0) { // call GameObject::play (like normally) initStackBaseWithSelector(SELECTOR(play)); // We set this, so that the game automatically quit right after init _gamestate->variables[VAR_GLOBAL][4] = TRUE_REG; _gamestate->_executionStackPosChanged = false; run_vm(_gamestate); // As soon as we get control again, actually restore the game reg_t restoreArgv[2] = { NULL_REG, make_reg(0, directSaveSlotLoading) }; // special call (argv[0] is NULL) kRestoreGame(_gamestate, 2, restoreArgv); // this indirectly calls GameObject::init, which will setup menu, text font/color codes etc. // without this games would be pretty badly broken } // Show any special warnings for buggy scripts with severe game bugs, // which have been patched by Sierra if (getGameId() == GID_LONGBOW) { // Longbow 1.0 has a buggy script which prevents the game // from progressing during the Green Man riddle sequence. // A patch for this buggy script has been released by Sierra, // and is necessary to complete the game without issues. // The patched script is included in Longbow 1.1. // Refer to bug #3036609. Resource *buggyScript = _resMan->findResource(ResourceId(kResourceTypeScript, 180), 0); if (buggyScript && (buggyScript->size == 12354 || buggyScript->size == 12362)) { showScummVMDialog("A known buggy game script has been detected, which could " "prevent you from progressing later on in the game, during " "the sequence with the Green Man's riddles. Please, apply " "the latest patch for this game by Sierra to avoid possible " "problems"); } } // Show a warning if the user has selected a General MIDI device, no GM patch exists // (i.e. patch 4) and the game is one of the known 8 SCI1 games that Sierra has provided // after market patches for in their "General MIDI Utility". if (_soundCmd->getMusicType() == MT_GM && !ConfMan.getBool("native_mt32")) { if (!_resMan->findResource(ResourceId(kResourceTypePatch, 4), 0)) { switch (getGameId()) { case GID_ECOQUEST: case GID_HOYLE3: case GID_LSL1: case GID_LSL5: case GID_LONGBOW: case GID_SQ1: case GID_SQ4: case GID_FAIRYTALES: showScummVMDialog("You have selected General MIDI as a sound device. Sierra " "has provided after-market support for General MIDI for this " "game in their \"General MIDI Utility\". Please, apply this " "patch in order to enjoy MIDI music with this game. Once you " "have obtained it, you can unpack all of the included *.PAT " "files in your ScummVM extras folder and ScummVM will add the " "appropriate patch automatically. Alternatively, you can follow " "the instructions in the READ.ME file included in the patch and " "rename the associated *.PAT file to 4.PAT and place it in the " "game folder. Without this patch, General MIDI music for this " "game will sound badly distorted."); break; default: break; } } } if (gameHasFanMadePatch()) { showScummVMDialog("Your game is patched with a fan made script patch. Such patches have " "been reported to cause issues, as they modify game scripts extensively. " "The issues that these patches fix do not occur in ScummVM, so you are " "advised to remove this patch from your game folder in order to avoid " "having unexpected errors and/or issues later on."); } runGame(); ConfMan.flushToDisk(); return Common::kNoError; }
ColorId SagaEngine::KnownColor2ColorId(KnownColor knownColor) { ColorId colorId = kITEColorTransBlack; if (getGameId() == GID_ITE) { switch (knownColor) { case(kKnownColorTransparent): colorId = kITEColorTransBlack; break; case (kKnownColorBrightWhite): colorId = kITEColorBrightWhite; break; case (kKnownColorWhite): colorId = kITEColorWhite; break; case (kKnownColorBlack): colorId = kITEColorBlack; break; case (kKnownColorSubtitleTextColor): colorId = (ColorId)255; break; case (kKnownColorVerbText): colorId = kITEColorBlue; break; case (kKnownColorVerbTextShadow): colorId = kITEColorBlack; break; case (kKnownColorVerbTextActive): colorId = (ColorId)96; break; default: error("SagaEngine::KnownColor2ColorId unknown color %i", knownColor); } #ifdef ENABLE_IHNM } else if (getGameId() == GID_IHNM) { // The default colors in the Spanish version of IHNM are shifted by one // Fixes bug #1848016 - "IHNM: Wrong Subtitles Color (Spanish)" int offset = (getLanguage() == Common::ES_ESP) ? 1 : 0; switch (knownColor) { case(kKnownColorTransparent): colorId = (ColorId)(249 - offset); break; case (kKnownColorBrightWhite): colorId = (ColorId)(251 - offset); break; case (kKnownColorWhite): colorId = (ColorId)(251 - offset); break; case (kKnownColorBlack): colorId = (ColorId)(249 - offset); break; case (kKnownColorVerbText): colorId = (ColorId)(253 - offset); break; case (kKnownColorVerbTextShadow): colorId = (ColorId)(15 - offset); break; case (kKnownColorVerbTextActive): colorId = (ColorId)(252 - offset); break; default: error("SagaEngine::KnownColor2ColorId unknown color %i", knownColor); } #endif } return colorId; }
void ZVision::processEvents() { while (_eventMan->pollEvent(_event)) { switch (_event.type) { case Common::EVENT_LBUTTONDOWN: _cursorManager->cursorDown(true); _scriptManager->setStateValue(StateKey_LMouse, 1); _menu->onMouseDown(_event.mouse); _scriptManager->addEvent(_event); break; case Common::EVENT_LBUTTONUP: _cursorManager->cursorDown(false); _scriptManager->setStateValue(StateKey_LMouse, 0); _menu->onMouseUp(_event.mouse); _scriptManager->addEvent(_event); break; case Common::EVENT_RBUTTONDOWN: _cursorManager->cursorDown(true); _scriptManager->setStateValue(StateKey_RMouse, 1); if (getGameId() == GID_NEMESIS) _scriptManager->inventoryCycle(); break; case Common::EVENT_RBUTTONUP: _cursorManager->cursorDown(false); _scriptManager->setStateValue(StateKey_RMouse, 0); break; case Common::EVENT_MOUSEMOVE: onMouseMove(_event.mouse); break; case Common::EVENT_KEYDOWN: { switch (_event.kbd.keycode) { case Common::KEYCODE_d: if (_event.kbd.hasFlags(Common::KBD_CTRL)) { // Start the debugger _console->attach(); _console->onFrame(); } break; case Common::KEYCODE_LEFT: case Common::KEYCODE_RIGHT: if (_renderManager->getRenderTable()->getRenderState() == RenderTable::PANORAMA) _keyboardVelocity = (_event.kbd.keycode == Common::KEYCODE_LEFT ? -_scriptManager->getStateValue(StateKey_KbdRotateSpeed) : _scriptManager->getStateValue(StateKey_KbdRotateSpeed)) * 2; break; case Common::KEYCODE_UP: case Common::KEYCODE_DOWN: if (_renderManager->getRenderTable()->getRenderState() == RenderTable::TILT) _keyboardVelocity = (_event.kbd.keycode == Common::KEYCODE_UP ? -_scriptManager->getStateValue(StateKey_KbdRotateSpeed) : _scriptManager->getStateValue(StateKey_KbdRotateSpeed)) * 2; break; case Common::KEYCODE_F10: { Common::String fpsStr = Common::String::format("FPS: %d", getFPS()); _renderManager->showDebugMsg(fpsStr); } break; default: break; } uint8 vkKey = getZvisionKey(_event.kbd.keycode); _scriptManager->setStateValue(StateKey_KeyPress, vkKey); _scriptManager->addEvent(_event); shortKeys(_event); cheatCodes(vkKey); } break; case Common::EVENT_KEYUP: _scriptManager->addEvent(_event); switch (_event.kbd.keycode) { case Common::KEYCODE_LEFT: case Common::KEYCODE_RIGHT: if (_renderManager->getRenderTable()->getRenderState() == RenderTable::PANORAMA) _keyboardVelocity = 0; break; case Common::KEYCODE_UP: case Common::KEYCODE_DOWN: if (_renderManager->getRenderTable()->getRenderState() == RenderTable::TILT) _keyboardVelocity = 0; break; default: break; } break; default: break; } } }
Common::Error AGOSEngine::init() { if (getGameId() == GID_DIMP) { _screenWidth = 496; _screenHeight = 400; } else if (getGameType() == GType_FF || getGameType() == GType_PP) { _screenWidth = 640; _screenHeight = 480; } else { _screenWidth = 320; _screenHeight = 200; } initGraphics(_screenWidth, _screenHeight, getGameType() == GType_FF || getGameType() == GType_PP); if ((getGameType() == GType_SIMON2 && getPlatform() == Common::kPlatformWindows) || (getGameType() == GType_SIMON1 && getPlatform() == Common::kPlatformWindows) || ((getFeatures() & GF_TALKIE) && getPlatform() == Common::kPlatformAcorn) || (getPlatform() == Common::kPlatformPC)) { int ret = _midi.open(getGameType()); if (ret) warning("MIDI Player init failed: \"%s\"", MidiDriver::getErrorName(ret)); _midi.setVolume(ConfMan.getInt("music_volume"), ConfMan.getInt("sfx_volume")); _midiEnabled = true; } // Setup mixer syncSoundSettings(); // allocate buffers _backGroundBuf = new Graphics::Surface(); _backGroundBuf->create(_screenWidth, _screenHeight, 1); if (getGameType() == GType_FF || getGameType() == GType_PP) { _backBuf = new Graphics::Surface(); _backBuf->create(_screenWidth, _screenHeight, 1); _scaleBuf = new Graphics::Surface(); _scaleBuf->create(_screenWidth, _screenHeight, 1); } if (getGameType() == GType_SIMON2) { _window4BackScn = new Graphics::Surface(); _window4BackScn->create(_screenWidth, _screenHeight, 1); } else if (getGameType() == GType_SIMON1) { _window4BackScn = new Graphics::Surface(); _window4BackScn->create(_screenWidth, 134, 1); } else if (getGameType() == GType_WW || getGameType() == GType_ELVIRA2) { _window4BackScn = new Graphics::Surface(); _window4BackScn->create(224, 127, 1); } else if (getGameType() == GType_ELVIRA1) { _window4BackScn = new Graphics::Surface(); if (getPlatform() == Common::kPlatformAmiga && (getFeatures() & GF_DEMO)) { _window4BackScn->create(224, 196, 1); } else { _window4BackScn->create(224, 144, 1); } _window6BackScn = new Graphics::Surface(); _window6BackScn->create(48, 80, 1); } setupGame(); _debugger = new Debugger(this); _sound = new Sound(this, gss, _mixer); if (ConfMan.hasKey("music_mute") && ConfMan.getBool("music_mute") == 1) { _musicPaused = true; if (_midiEnabled) { _midi.pause(_musicPaused); } _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, 0); } if (ConfMan.hasKey("sfx_mute") && ConfMan.getBool("sfx_mute") == 1) { if (getGameId() == GID_SIMON1DOS) _midi._enable_sfx = !_midi._enable_sfx; else { _effectsPaused = !_effectsPaused; _sound->effectsPause(_effectsPaused); } } _copyProtection = ConfMan.getBool("copy_protection"); _language = Common::parseLanguage(ConfMan.get("language")); if (getGameType() == GType_PP) { _speech = true; _subtitles = false; } else if (getFeatures() & GF_TALKIE) { _speech = !ConfMan.getBool("speech_mute"); _subtitles = ConfMan.getBool("subtitles"); if (getGameType() == GType_SIMON1) { // English and German versions don't have full subtitles if (_language == Common::EN_ANY || _language == Common::DE_DEU) _subtitles = false; // Other versions require speech to be enabled else _speech = true; } // Default to speech only, if both speech and subtitles disabled if (!_speech && !_subtitles) _speech = true; } else { _speech = false; _subtitles = true; } // TODO: Use special debug levels instead of the following hack. _debugMode = (gDebugLevel >= 0); if (gDebugLevel == 2) _dumpOpcodes = true; if (gDebugLevel == 3) _dumpVgaOpcodes = true; if (gDebugLevel == 4) _dumpScripts = true; if (gDebugLevel == 5) _dumpVgaScripts = true; return Common::kNoError; }
SagaEngine::~SagaEngine() { if (_scene != NULL) { if (_scene->isSceneLoaded()) { _scene->endScene(); } } if (getGameId() == GID_ITE) { delete _isoMap; _isoMap = NULL; delete _puzzle; _puzzle = NULL; } delete _sndRes; _sndRes = NULL; delete _events; _events = NULL; if (!isSaga2()) { delete _font; _font = NULL; delete _sprite; _sprite = NULL; } delete _anim; _anim = NULL; delete _script; _script = NULL; if (!isSaga2()) { delete _interface; _interface = NULL; } delete _actor; _actor = NULL; delete _palanim; _palanim = NULL; delete _scene; _scene = NULL; delete _render; _render = NULL; delete _music; _music = NULL; delete _sound; _sound = NULL; delete _gfx; _gfx = NULL; delete _console; _console = NULL; delete _resource; _resource = NULL; }
bool SciEngine::hasMacIconBar() const { return _resMan->isSci11Mac() && getSciVersion() == SCI_VERSION_1_1 && (getGameId() == GID_KQ6 || getGameId() == GID_FREDDYPHARKAS); }
void ZVision::cheatCodes(uint8 key) { Location loc = _scriptManager->getCurrentLocation(); // Do not process cheat codes while in the game menus if (loc.world == 'g' && loc.room == 'j') return; pushKeyToCheatBuf(key); if (getGameId() == GID_GRANDINQUISITOR) { if (checkCode("IMNOTDEAF")) { // Unknown cheat _renderManager->showDebugMsg(Common::String::format("IMNOTDEAF cheat or debug, not implemented")); } if (checkCode("3100OPB")) { _renderManager->showDebugMsg(Common::String::format("Current location: %c%c%c%c", _scriptManager->getStateValue(StateKey_World), _scriptManager->getStateValue(StateKey_Room), _scriptManager->getStateValue(StateKey_Node), _scriptManager->getStateValue(StateKey_View))); } if (checkCode("KILLMENOW")) { _scriptManager->changeLocation('g', 'j', 'd', 'e', 0); _scriptManager->setStateValue(2201, 35); } if (checkCode("MIKESPANTS")) { _scriptManager->changeLocation('g', 'j', 't', 'm', 0); } // There are 3 more cheats in script files: // - "WHOAMI": gjcr.scr // - "HUISOK": hp1e.scr // - "EAT ME": uh1f.scr } else if (getGameId() == GID_NEMESIS) { if (checkCode("CHLOE")) { _scriptManager->changeLocation('t', 'm', '2', 'g', 0); _scriptManager->setStateValue(224, 1); } if (checkCode("77MASSAVE")) { _renderManager->showDebugMsg(Common::String::format("Current location: %c%c%c%c", _scriptManager->getStateValue(StateKey_World), _scriptManager->getStateValue(StateKey_Room), _scriptManager->getStateValue(StateKey_Node), _scriptManager->getStateValue(StateKey_View))); } if (checkCode("IDKFA")) { _scriptManager->changeLocation('t', 'w', '3', 'f', 0); _scriptManager->setStateValue(249, 1); } if (checkCode("309NEWDORMA")) { _scriptManager->changeLocation('g', 'j', 'g', 'j', 0); } if (checkCode("HELLOSAILOR")) { Audio::AudioStream *soundStream; if (loc == "vb10") { soundStream = makeRawZorkStream("v000hpta.raw", this); } else { soundStream = makeRawZorkStream("v000hnta.raw", this); } Audio::SoundHandle handle; _mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, soundStream); } } if (checkCode("FRAME")) { Common::String fpsStr = Common::String::format("FPS: %d", getFPS()); _renderManager->showDebugMsg(fpsStr); } if (checkCode("COMPUTERARCH")) _renderManager->showDebugMsg("COMPUTERARCH: var-viewer not implemented"); // This cheat essentially toggles the GOxxxx cheat below if (checkCode("XYZZY")) _scriptManager->setStateValue(StateKey_DebugCheats, 1 - _scriptManager->getStateValue(StateKey_DebugCheats)); if (_scriptManager->getStateValue(StateKey_DebugCheats) == 1) if (checkCode("GO????")) _scriptManager->changeLocation(getBufferedKey(3), getBufferedKey(2), getBufferedKey(1), getBufferedKey(0), 0); // Show the Venus screen when "?" or "/" is pressed while inside the temple world if (_scriptManager->getStateValue(StateKey_VenusEnable) == 1) if (getBufferedKey(0) == 0xBF && _scriptManager->getStateValue(StateKey_World) == 't') _scriptManager->changeLocation('g', 'j', 'h', 'e', 0); }
void AGOSEngine::displayScreen() { if (_fastFadeInFlag == 0 && _paletteFlag == 1) { _paletteFlag = 0; if (memcmp(_displayPalette, _currentPalette, sizeof(_currentPalette))) { memcpy(_currentPalette, _displayPalette, sizeof(_displayPalette)); _system->getPaletteManager()->setPalette(_displayPalette, 0, 256); } } Graphics::Surface *screen = _system->lockScreen(); if (getGameType() == GType_PP || getGameType() == GType_FF) { byte *src = getBackBuf(); byte *dst = (byte *)screen->pixels; for (int i = 0; i < _screenHeight; i++) { memcpy(dst, src, _screenWidth); src += _backBuf->pitch; dst += screen->pitch; } if (getGameId() != GID_DIMP) fillBackFromBackGround(_screenHeight, _screenWidth); } else { if (_window4Flag == 2) { _window4Flag = 0; uint16 srcWidth, width, height; byte *dst = (byte *)screen->pixels; const byte *src = (const byte *)_window4BackScn->pixels; if (_window3Flag == 1) { src = getBackGround(); } dst += (_moveYMin + _videoWindows[17]) * screen->pitch; dst += (_videoWindows[16] * 16) + _moveXMin; src += (_videoWindows[18] * 16 * _moveYMin); src += _moveXMin; srcWidth = _videoWindows[18] * 16; width = _moveXMax - _moveXMin; height = _moveYMax - _moveYMin; for (; height > 0; height--) { memcpy(dst, src, width); dst += screen->pitch; src += srcWidth; } _moveXMin = 0xFFFF; _moveYMin = 0xFFFF; _moveXMax = 0; _moveYMax = 0; } if (_window6Flag == 2) { _window6Flag = 0; byte *src = (byte *)_window6BackScn->pixels; byte *dst = (byte *)screen->pixels + 51 * screen->pitch; for (int i = 0; i < 80; i++) { memcpy(dst, src, _window6BackScn->w); dst += screen->pitch; src += _window6BackScn->pitch; } } } _system->unlockScreen(); if (getGameType() == GType_FF && _scrollFlag) { scrollScreen(); } if (_fastFadeInFlag) { fastFadeIn(); } }
Common::Error SagaEngine::run() { setTotalPlayTime(0); // Assign default values to the config manager, in case settings are missing ConfMan.registerDefault("talkspeed", "255"); ConfMan.registerDefault("subtitles", "true"); _musicVolume = ConfMan.getInt("music_volume"); _subtitlesEnabled = ConfMan.getBool("subtitles"); _readingSpeed = getTalkspeed(); _copyProtection = ConfMan.getBool("copy_protection"); _musicWasPlaying = false; _isIHNMDemo = Common::File::exists("music.res"); _hasITESceneSubstitutes = Common::File::exists("boarhall.bbm"); if (_readingSpeed > 3) _readingSpeed = 0; switch (getGameId()) { case GID_ITE: _resource = new Resource_RSC(this); break; #ifdef ENABLE_IHNM case GID_IHNM: _resource = new Resource_RES(this); break; #endif #ifdef ENABLE_SAGA2 case GID_DINO: case GID_FTA2: _resource = new Resource_HRS(this); break; #endif } // Detect game and open resource files if (!initGame()) { GUIErrorMessage("Error loading game resources."); return Common::kUnknownError; } // Initialize engine modules // TODO: implement differences for SAGA2 _sndRes = new SndRes(this); _events = new Events(this); if (!isSaga2()) { _font = new Font(this); _sprite = new Sprite(this); _script = new SAGA1Script(this); } else { _script = new SAGA2Script(this); } _anim = new Anim(this); _interface = new Interface(this); // requires script module _scene = new Scene(this); _actor = new Actor(this); _palanim = new PalAnim(this); if (getGameId() == GID_ITE) { _isoMap = new IsoMap(this); _puzzle = new Puzzle(this); } // System initialization _previousTicks = _system->getMillis(); // Initialize graphics _gfx = new Gfx(this, _system, getDisplayInfo().width, getDisplayInfo().height); // Graphics driver should be initialized before console _console = new Console(this); // Graphics should be initialized before music _music = new Music(this, _mixer); _render = new Render(this, _system); if (!_render->initialized()) { return Common::kUnknownError; } // Initialize system specific sound _sound = new Sound(this, _mixer); if (!isSaga2()) { _interface->converseClear(); _script->setVerb(_script->getVerbType(kVerbWalkTo)); } _music->setVolume(_musicVolume, 1); if (!isSaga2()) { _gfx->initPalette(); } if (_voiceFilesExist) { if (getGameId() == GID_IHNM) { if (!ConfMan.hasKey("voices")) { _voicesEnabled = true; ConfMan.setBool("voices", true); } else { _voicesEnabled = ConfMan.getBool("voices"); } } else { _voicesEnabled = true; } } syncSoundSettings(); int msec = 0; _previousTicks = _system->getMillis(); if (ConfMan.hasKey("start_scene")) { _scene->changeScene(ConfMan.getInt("start_scene"), 0, kTransitionNoFade); } else if (ConfMan.hasKey("boot_param")) { if (getGameId() == GID_ITE) _interface->addToInventory(_actor->objIndexToId(0)); // Magic hat _scene->changeScene(ConfMan.getInt("boot_param"), 0, kTransitionNoFade); } else if (ConfMan.hasKey("save_slot")) { // Init the current chapter to 8 (character selection) for IHNM if (getGameId() == GID_IHNM) _scene->changeScene(-2, 0, kTransitionFade, 8); // First scene sets up palette _scene->changeScene(getStartSceneNumber(), 0, kTransitionNoFade); _events->handleEvents(0); // Process immediate events if (getGameId() == GID_ITE) _interface->setMode(kPanelMain); else _interface->setMode(kPanelChapterSelection); char *fileName = calcSaveFileName(ConfMan.getInt("save_slot")); load(fileName); syncSoundSettings(); } else { _framesEsc = 0; _scene->startScene(); } uint32 currentTicks; while (!shouldQuit()) { _console->onFrame(); if (_render->getFlags() & RF_RENDERPAUSE) { // Freeze time while paused _previousTicks = _system->getMillis(); } else { currentTicks = _system->getMillis(); // Timer has rolled over after 49 days if (currentTicks < _previousTicks) msec = 0; else { msec = currentTicks - _previousTicks; _previousTicks = currentTicks; } if (msec > MAX_TIME_DELTA) { msec = MAX_TIME_DELTA; } // Since Puzzle and forced text are actorless, we do them here if ((getGameId() == GID_ITE && _puzzle->isActive()) || _actor->isForcedTextShown()) { _actor->handleSpeech(msec); } else if (!_scene->isInIntro()) { if (_interface->getMode() == kPanelMain || _interface->getMode() == kPanelConverse || _interface->getMode() == kPanelCutaway || _interface->getMode() == kPanelNull || _interface->getMode() == kPanelChapterSelection) _actor->direct(msec); } _events->handleEvents(msec); _script->executeThreads(msec); } // Per frame processing _render->drawScene(); _system->delayMillis(10); } return Common::kNoError; }