void MADSEngine::initialize() { // Set up debug channels DebugMan.addDebugChannel(kDebugPath, "Path", "Pathfinding debug level"); DebugMan.addDebugChannel(kDebugScripts, "scripts", "Game scripts"); DebugMan.addDebugChannel(kDebugGraphics, "graphics", "Graphics handling"); // Initial sub-system engine references MSurface::setVm(this); MSprite::setVm(this); Resources::init(this); Conversation::init(this); _debugger = new Debugger(this); _dialogs = Dialogs::init(this); _events = new EventsManager(this); _palette = new Palette(this); Font::init(this); _font = new Font(); _screen.init(); _sound = new SoundManager(this, _mixer); _audio = new AudioPlayer(_mixer, getGameID()); _game = Game::init(this); switch (getGameID()) { case GType_RexNebular: _gameConv = nullptr; break; default: _gameConv = new GameConversation(this); } loadOptions(); _screen.empty(); }
MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { const GameSettings *g; const char *gameid = ConfMan.get("gameid").c_str(); for (g = madeSettings; g->gameid; ++g) if (!scumm_stricmp(g->gameid, gameid)) _gameId = g->id; _rnd = new Common::RandomSource(); syst->getEventManager()->registerRandomSource(*_rnd, "made"); int cd_num = ConfMan.getInt("cdrom"); if (cd_num >= 0) _system->openCD(cd_num); _pmvPlayer = new PmvPlayer(this, _mixer); _res = new ResourceReader(); _screen = new Screen(this); if (getGameID() == GID_LGOP2 || getGameID() == GID_MANHOLE || getGameID() == GID_RODNEY) { _dat = new GameDatabaseV2(this); } else if (getGameID() == GID_RTZ) { _dat = new GameDatabaseV3(this); } else { error("Unknown GameID"); } _script = new ScriptInterpreter(this); int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); //bool adlib = (midiDriver == MD_ADLIB); MidiDriver *driver = MidiDriver::createMidi(midiDriver); if (native_mt32) driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); _music = new MusicPlayer(driver); _music->setNativeMT32(native_mt32); //_music->setAdlib(adlib); // Set default sound frequency switch (getGameID()) { case GID_RODNEY: _soundRate = 11025; break; case GID_MANHOLE: _soundRate = 11025; break; case GID_LGOP2: _soundRate = 8000; break; case GID_RTZ: // Return to Zork sets it itself via a script funtion break; } syncSoundSettings(); }
void AgiEngine::setupOpcodes() { if (getVersion() >= 0x2000) { for (int i = 0; i < ARRAYSIZE(insV2Test); ++i) _agiCondCommands[i] = insV2Test[i].func; for (int i = 0; i < ARRAYSIZE(insV2); ++i) _agiCommands[i] = insV2[i].func; logicNamesTest = insV2Test; logicNamesCmd = insV2; // Alter opcode parameters for specific games // TODO: This could be either turned into a game feature, or a version // specific check, instead of a game version check // The Apple IIGS versions of MH1 and Goldrush both have a parameter for // show.mouse and hide.mouse. Fixes bugs #3577754 and #3426946. if ((getGameID() == GID_MH1 || getGameID() == GID_GOLDRUSH) && getPlatform() == Common::kPlatformApple2GS) { logicNamesCmd[176].args = "n"; // hide.mouse logicNamesCmd[178].args = "n"; // show.mouse } } else { for (int i = 0; i < ARRAYSIZE(insV1Test); ++i) _agiCondCommands[i] = insV1Test[i].func; for (int i = 0; i < ARRAYSIZE(insV1); ++i) _agiCommands[i] = insV1[i].func; logicNamesTest = insV1Test; logicNamesCmd = insV1; } }
Common::Error MadeEngine::run() { _music = new MusicPlayer(getGameID() == GID_RTZ); syncSoundSettings(); // Initialize backend initGraphics(320, 200, false); resetAllTimers(); if (getGameID() == GID_RTZ) { if (getFeatures() & GF_DEMO) { _dat->open("demo.dat"); _res->open("demo.prj"); } else if (getFeatures() & GF_CD) { _dat->open("rtzcd.dat"); _res->open("rtzcd.prj"); } else if (getFeatures() & GF_CD_COMPRESSED) { _dat->openFromRed("rtzcd.red", "rtzcd.dat"); _res->open("rtzcd.prj"); } else if (getFeatures() & GF_FLOPPY) { _dat->open("rtz.dat"); _res->open("rtz.prj"); } else { error("Unknown RTZ game features"); } } else if (getGameID() == GID_MANHOLE) { _dat->open("manhole.dat"); if (getVersion() == 2) { _res->open("manhole.prj"); } else { _res->openResourceBlocks(); } } else if (getGameID() == GID_LGOP2) { _dat->open("lgop2.dat"); _res->open("lgop2.prj"); } else if (getGameID() == GID_RODNEY) { _dat->open("rodneys.dat"); _res->open("rodneys.prj"); } else { error ("Unknown MADE game"); } if ((getFeatures() & GF_CD) || (getFeatures() & GF_CD_COMPRESSED)) checkCD(); _autoStopSound = false; _eventNum = _eventKey = _eventMouseX = _eventMouseY = 0; #ifdef DUMP_SCRIPTS _script->dumpAllScripts(); #else _screen->setDefaultMouseCursor(); _script->runScript(_dat->getMainCodeObjectIndex()); #endif return Common::kNoError; }
void SherlockEngine::loadConfig() { // Load sound settings syncSoundSettings(); ConfMan.registerDefault("font", getGameID() == GType_SerratedScalpel ? 1 : 4); _screen->setFont(ConfMan.getInt("font")); if (getGameID() == GType_SerratedScalpel) _screen->_fadeStyle = ConfMan.getBool("fade_style"); _ui->_helpStyle = ConfMan.getBool("help_style"); _ui->_slideWindows = ConfMan.getBool("window_style"); _people->_portraitsOn = ConfMan.getBool("portraits_on"); }
MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { const GameSettings *g; const char *gameid = ConfMan.get("gameid").c_str(); for (g = madeSettings; g->gameid; ++g) if (!scumm_stricmp(g->gameid, gameid)) _gameId = g->id; _rnd = new Common::RandomSource("made"); _console = new MadeConsole(this); int cd_num = ConfMan.getInt("cdrom"); if (cd_num >= 0) _system->getAudioCDManager()->openCD(cd_num); _pmvPlayer = new PmvPlayer(this, _mixer); _res = new ResourceReader(); _screen = new Screen(this); if (getGameID() == GID_LGOP2 || getGameID() == GID_MANHOLE || getGameID() == GID_RODNEY) { _dat = new GameDatabaseV2(this); } else if (getGameID() == GID_RTZ) { _dat = new GameDatabaseV3(this); } else { error("Unknown GameID"); } _script = new ScriptInterpreter(this); _music = nullptr; // Set default sound frequency switch (getGameID()) { case GID_RODNEY: _soundRate = 11025; break; case GID_MANHOLE: _soundRate = 11025; break; case GID_LGOP2: _soundRate = 8000; break; case GID_RTZ: // Return to Zork sets it itself via a script funtion break; } }
void MADSEngine::loadOptions() { if (ConfMan.hasKey("EasyMouse")) _easyMouse = ConfMan.getBool("EasyMouse"); if (ConfMan.hasKey("mute") && ConfMan.getBool("mute")) { _soundFlag = false; _musicFlag = false; } else { _soundFlag = !ConfMan.hasKey("sfx_mute") || !ConfMan.getBool("sfx_mute"); _musicFlag = !ConfMan.hasGameDomain("music_mute") || !ConfMan.getBool("music_mute"); } if (ConfMan.hasKey("ScreenFade")) _screenFade = (ScreenFade)ConfMan.getInt("ScreenFade"); //if (ConfMan.hasKey("GraphicsDithering")) // _dithering = ConfMan.getBool("GraphicsDithering"); if (getGameID() == GType_RexNebular) { if (ConfMan.hasKey("InvObjectsAnimated")) _invObjectsAnimated = ConfMan.getBool("InvObjectsAnimated"); if (ConfMan.hasKey("TextWindowStill")) _textWindowStill = !ConfMan.getBool("TextWindowAnimated"); if (ConfMan.hasKey("NaughtyMode")) _game->setNaughtyMode(ConfMan.getBool("NaughtyMode")); } // Note: MADS is weird in that sfx and music are handled by the same driver, // and the game scripts themselves check for music being enabled before playing // a "music" sound. Which means we can independantly mute music in ScummVM, but // otherwise all sound, music and sfx, is controlled by the SFX volume slider. int soundVolume = MIN(255, ConfMan.getInt("sfx_volume")); _sound->setVolume(soundVolume); }
void cmdDrawPic(AgiGame *state, uint8 *p) { debugC(6, kDebugLevelScripts, "=== draw pic %d ===", _v[p0]); state->_vm->_sprites->eraseBoth(); state->_vm->_picture->decodePicture(_v[p0], true); state->_vm->_sprites->blitBoth(); state->_vm->_sprites->commitBoth(); state->pictureShown = 0; debugC(6, kDebugLevelScripts, "--- end of draw pic %d ---", _v[p0]); // WORKAROUND for a script bug which exists in SQ1, logic scripts // 20 and 110. Flag 103 is not reset correctly, which leads to erroneous // behavior from view 46 (the spider droid). View 46 is supposed to // follow ego and explode when it comes in contact with him. However, as // flag 103 is not reset correctly, when the player goes down the path // and back up, the spider is always at the base of the path (since it // can't go up) and kills the player when he goes down at ground level // (although the spider droid sprite itself seems to be correctly positioned). // With this workaround, when the player goes back to picture 20 (1 screen // above the ground), flag 103 is reset, thereby fixing this issue. Note // that this is a script bug and occurs in the original interpreter as well. // Fixes bug #1658514: AGI: SQ1 (2.2 DOS ENG) bizzare exploding roger if (getGameID() == GID_SQ1 && _v[p0] == 20) setflag(103, false); // Simulate slowww computer. Many effects rely on this state->_vm->pause(kPausePicture); }
GameDef createGameDef(const Game *g) { return ((getGameID(g->game) & 0xF) << 12) | ((getPlatformID(g->platform) & 0xF) << 8) | ((getSpecialID(g->special) & 0xF) << 4) | ((getLanguageID(g->lang) & 0xF) << 0); return 0; }
int AgiEngine::setupV3Game(int ver) { int ec = errOK; debug(0, "Setting up for version 0x%04X", ver); // 'unknown176' takes 1 arg for 3.002.086, not 0 args. // 'unknown173' also takes 1 arg for 3.002.068, not 0 args. // Is this actually used anywhere? -- dsymonds if (ver == 0x3086) { // logicNamesCmd[0xb0].numArgs = 1; // logicNamesCmd[0xad].numArgs = 1; logicNamesCmd[0xb0].args = "n"; logicNamesCmd[0xad].args = "n"; } // FIXME: Apply this fix to other games also that use 2 arguments for command 182. // 'adj.ego.move.to.x.y' (i.e. command 182) takes 2 arguments for at least the // Amiga Gold Rush! (v2.05 1989-03-09) using Amiga AGI 2.316. Amiga's Gold Rush // has been set to use AGI 3.149 in ScummVM so that's why this initialization is // here and not in setupV2Game. if (getGameID() == GID_GOLDRUSH && getPlatform() == Common::kPlatformAmiga) // logicNamesCmd[182].numArgs = 2; logicNamesCmd[182].args = "vv"; return ec; }
uint32 getFilename(int game, int plat, int spec, int lang, const ExtractFilename *fDesc) { // GAME, PLATFORM, SPECIAL, ID, LANG return ((getGameID(game) & 0xF) << 24) | ((getPlatformID(plat) & 0xF) << 20) | ((getSpecialID(spec) & 0xF) << 16) | ((fDesc->id & 0xFFF) << 4) | ((getLanguageID(fDesc->langSpecific ? lang : UNK_LANG) & 0xF) << 0); }
void PreAgiEngine::clearTextArea() { int start = IDI_MAX_ROW_PIC; if (getGameID() == GID_TROLL) start = 21; for (int row = start; row < 200 / 8; row++) { clearRow(row); } }
uint32 getFilename(const ExtractInformation *info, const int id) { const ExtractFilename *fDesc = getFilenameDesc(id); if (!fDesc) return 0; // GAME, PLATFORM, SPECIAL, ID, LANG return ((getGameID(info->game) & 0xF) << 24) | ((getPlatformID(info->platform) & 0xF) << 20) | ((getSpecialID(info->special) & 0xF) << 16) | ((id & 0xFFF) << 4) | ((getLanguageID(fDesc->langSpecific ? info->lang : UNK_LANG) & 0xF) << 0); }
void cmdDistance(AgiGame *state, uint8 *p) { int16 x1, y1, x2, y2, d; VtEntry *v0 = &state->viewTable[p0]; VtEntry *v1 = &state->viewTable[p1]; if (v0->flags & fDrawn && v1->flags & fDrawn) { x1 = v0->xPos + v0->xSize / 2; y1 = v0->yPos; x2 = v1->xPos + v1->xSize / 2; y2 = v1->yPos; d = ABS(x1 - x2) + ABS(y1 - y2); if (d > 0xfe) d = 0xfe; } else { d = 0xff; } // WORKAROUND: Fixes King's Quest IV's script bug #1660424 (KQ4: Zombie bug). // In the graveyard (Rooms 16 and 18) at night if you had the Obsidian Scarab (Item 4) // and you were very close to a spot where a zombie was going to rise up from the // ground you could reproduce the bug. Just standing there and letting the zombie // try to rise up the Obsidian Scarab would repel the zombie immediately and that // would make the script bug so that the zombie would still come up but it just // wouldn't chase Rosella around anymore. If it had worked correctly the zombie // wouldn't have come up at all or it would have come up and gone back down // immediately. The latter approach is the one implemented here. if (getGameID() == GID_KQ4 && (_v[vCurRoom] == 16 || _v[vCurRoom] == 18) && p2 >= 221 && p2 <= 223) { // Rooms 16 and 18 are graveyards where three zombies come up at night. They use logics 16 and 18. // Variables 221-223 are used to save the distance between each zombie and Rosella. // Variables 155, 156 and 162 are used to save the state of each zombie in room 16. // Variables 155, 156 and 158 are used to save the state of each zombie in room 18. // Rosella gets turned to a zombie only if any of the zombies is under 10 units away // from her and she doesn't have the Obsidian Scarab (Item 4). Likewise Rosella makes // a zombie go back into the ground if the zombie comes under 15 units away from her // and she has the Obsidian Scarab. To ensure a zombie always first rises up before // checking for either of the aforementioned conditions (Rosella getting turned to // a zombie or the zombie getting turned away by the scarab) we make it appear the // zombie is far away from Rosella if the zombie is not already up and chasing her. enum zombieStates {ZOMBIE_SET_TO_RISE_UP, ZOMBIE_RISING_UP, ZOMBIE_CHASING_EGO}; uint8 zombieStateVarNumList[] = {155, 156, (_v[vCurRoom] == 16) ? 162 : 158}; uint8 zombieNum = p2 - 221; // Zombie's number (In range 0-2) uint8 zombieStateVarNum = zombieStateVarNumList[zombieNum]; // Number of the variable containing zombie's state uint8 zombieState = _v[zombieStateVarNum]; // Zombie's state // If zombie is not chasing Rosella then set its distance from Rosella to the maximum if (zombieState != ZOMBIE_CHASING_EGO) d = 0xff; } _v[p2] = (unsigned char)d; }
void cmdNewRoom(AgiGame *state, uint8 *p) { state->_vm->newRoom(p0); // WORKAROUND: Works around intro skipping bug (#1737343) in Gold Rush. // Intro was skipped because the enter-keypress finalizing the entering // of the copy protection string (Copy protection is in logic.128) was // left over to the intro scene (Starts with room 73 i.e. logic.073). // The intro scene checks for any keys pressed and if it finds any it // jumps to the game's start (Room 1 i.e. logic.001). We clear the // keyboard buffer when the intro sequence's first room (Room 73) is // loaded so that no keys from the copy protection scene can be left // over to cause the intro to skip to the game's start. if (getGameID() == GID_GOLDRUSH && p0 == 73) state->keypress = 0; }
void XeenEngine::play() { _interface->setup(); _screen->loadBackground("back.raw"); _screen->loadPalette("mm4.pal"); if (getGameID() == GType_DarkSide && !_map->_loadCcNum) { _map->_loadCcNum = 1; _party->_mazeId = 29; _party->_mazeDirection = DIR_NORTH; _party->_mazePosition.x = 25; _party->_mazePosition.y = 21; } _map->clearMaze(); if (_loadSaveSlot >= 0) { _saves->newGame(); _saves->loadGameState(_loadSaveSlot); _loadSaveSlot = -1; } else { _map->load(_party->_mazeId); } _interface->startup(); if (_mode == MODE_STARTUP) { // _screen->fadeOut(); } (*_windows)[0].update(); _interface->mainIconsPrint(); (*_windows)[0].update(); _events->setCursor(0); _combat->_moveMonsters = true; if (_mode == MODE_STARTUP) { _mode = MODE_INTERACTIVE; _screen->fadeIn(); } _combat->_moveMonsters = true; gameLoop(); if (_party->_dead) death(); _mode = MODE_STARTUP; _gameMode = GMODE_MENU; }
void MADSEngine::saveOptions() { ConfMan.setBool("EasyMouse", _easyMouse); ConfMan.setInt("ScreenFade", (int)_screenFade); //ConfMan.setBool("GraphicsDithering", _dithering); ConfMan.setBool("mute", !_soundFlag && !_musicFlag); ConfMan.setBool("sfx_mute", !_soundFlag && _musicFlag); ConfMan.setBool("music_mute", _soundFlag && !_musicFlag); if (getGameID() == GType_RexNebular) { ConfMan.setBool("InvObjectsAnimated", _invObjectsAnimated); ConfMan.setBool("TextWindowAnimated", !_textWindowStill); ConfMan.setBool("NaughtyMode", _game->getNaughtyMode()); } ConfMan.flushToDisk(); }
Common::Error DirectorEngine::run() { debug("Starting v%d Director game", getVersion()); _currentPalette = nullptr; _macBinary = nullptr; _soundManager = nullptr; _wm = new Graphics::MacWindowManager; _lingo = new Lingo(this); _soundManager = new DirectorSound(); if (getGameID() == GID_TEST) { _mainArchive = nullptr; _currentScore = nullptr; _lingo->runTests(); return Common::kNoError; } //FIXME //_mainArchive = new RIFFArchive(); //_mainArchive->openFile("bookshelf_example.mmm"); //testFont(); if (getPlatform() == Common::kPlatformWindows) _sharedCastFile = "SHARDCST.MMM"; else _sharedCastFile = "Shared Cast*"; loadSharedCastsFrom(_sharedCastFile); loadMainArchive(); _currentScore = new Score(this, _mainArchive); debug(0, "Score name %s", _currentScore->getMacName().c_str()); _currentScore->loadArchive(); _currentScore->startLoop(); return Common::kNoError; }
void PreAgiEngine::initialize() { initRenderMode(); _gfx = new GfxMgr(this); _picture = new PictureMgr(this, _gfx); if (getGameID() == GID_MICKEY) { _fontData = fontData_Mickey; } else { _fontData = fontData_IBM; } _gfx->initMachine(); _game.gameFlags = 0; _game.colorFg = 15; _game.colorBg = 0; _defaultColor = 0xF; _game.name[0] = '\0'; _game.sbufOrig = (uint8 *)calloc(_WIDTH, _HEIGHT * 2); // Allocate space for two AGI screens vertically _game.sbuf16c = _game.sbufOrig + SBUF16_OFFSET; // Make sbuf16c point to the 16 color (+control line & priority info) AGI screen _game.sbuf = _game.sbuf16c; // Make sbuf point to the 16 color (+control line & priority info) AGI screen by default _game.lineMinPrint = 0; // hardcoded _gfx->initVideo(); _speakerStream = new Audio::PCSpeaker(); _mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, _speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); debugC(2, kDebugLevelMain, "Detect game"); // clear all resources and events for (int i = 0; i < MAX_DIRS; i++) { memset(&_game.pictures[i], 0, sizeof(struct AgiPicture)); memset(&_game.sounds[i], 0, sizeof(class AgiSound *)); // _game.sounds contains pointers now memset(&_game.dirPic[i], 0, sizeof(struct AgiDir)); memset(&_game.dirSound[i], 0, sizeof(struct AgiDir)); } }
Common::Error DirectorEngine::run() { debug("Starting v%d Director game", getVersion()); _sharedCasts = nullptr; _sharedSound = nullptr; _sharedBMP = nullptr; _sharedSTXT = nullptr; _sharedDIB = nullptr; _movies = nullptr; _currentPalette = nullptr; _macBinary = nullptr; _soundManager = nullptr; _lingo = new Lingo(this); _soundManager = new DirectorSound(); if (getGameID() == GID_TEST) { _mainArchive = nullptr; _currentScore = nullptr; _lingo->runTests(); return Common::kNoError; } //FIXME _mainArchive = new RIFFArchive(); _mainArchive->openFile("bookshelf_example.mmm"); _currentScore = new Score(this); debug(0, "Score name %s", _currentScore->getMacName().c_str()); _currentScore->loadArchive(); _currentScore->startLoop(); if (getPlatform() == Common::kPlatformWindows) loadEXE(); else loadMac(); return Common::kNoError; }
uint16 AgiEngine::artificialDelay_SearchTable(AgiArtificialDelayTriggerType triggerType, int16 orgNr, int16 newNr) { if (getPlatform() != Common::kPlatformApple2GS) { return 0; } const AgiArtificialDelayEntry *delayEntry = artificialDelayTable; while (delayEntry->triggerType != ARTIFICIALDELAYTYPE_END) { if (triggerType == delayEntry->triggerType) { if ((orgNr == delayEntry->orgNr) && (newNr == delayEntry->newNr)) { if ((getGameID() == delayEntry->gameId) && (getPlatform() == delayEntry->platform)) { warning("artificial delay forced"); return delayEntry->millisecondsDelay; } } } delayEntry++; } return 0; }
Common::Error PreAgiEngine::go() { setflag(fSoundOn, true); // enable sound // // FIXME (Fingolfin asks): Why are Mickey, Winnie and Troll standalone classes // instead of being subclasses of PreAgiEngine ? // // run preagi engine main loop switch (getGameID()) { case GID_MICKEY: { Mickey *mickey = new Mickey(this); mickey->init(); mickey->run(); delete mickey; } break; case GID_WINNIE: { Winnie *winnie = new Winnie(this); winnie->init(); winnie->run(); delete winnie; } break; case GID_TROLL: { Troll *troll = new Troll(this); troll->init(); troll->run(); delete troll; } break; default: error("Unknown preagi engine"); break; } return Common::kNoError; }
void cmdSetPriority(AgiGame *state, uint8 *p) { vt.flags |= fFixedPriority; vt.priority = p1; // WORKAROUND: this fixes bug #1712585 in KQ4 (dwarf sprite priority) // For this scene, ego (Rosella) hasn't got a fixed priority till script 54 // explicitly sets priority 8 for her, so that she can walk back to the table // without being drawn over the other dwarfs // It seems that in this scene, ego's priority is set to 8, but the priority of // the last dwarf with the soup bowls (view 152) is also set to 8, which causes // the dwarf to be drawn behind ego // With this workaround, when the game scripts set the priority of view 152 // (seventh dwarf with soup bowls), ego's priority is set to 7 // The game script itself sets priotity 8 for ego before she starts walking, // and then releases the fixed priority set on ego after ego is seated // Therefore, this workaround only affects that specific part of this scene // Ego is set to object 19 by script 54 if (getGameID() == GID_KQ4 && vt.currentView == 152) { state->viewTable[19].flags |= fFixedPriority; state->viewTable[19].priority = 7; } }
void XeenEngine::play() { // TODO: Init variables _quitMode = 0; _interface->setup(); _screen->loadBackground("back.raw"); _screen->loadPalette("mm4.pal"); if (getGameID() != GType_WorldOfXeen && !_map->_loadDarkSide) { _map->_loadDarkSide = true; _party->_mazeId = 29; _party->_mazeDirection = DIR_NORTH; _party->_mazePosition.x = 25; _party->_mazePosition.y = 21; } _map->load(_party->_mazeId); _interface->startup(); if (_mode == MODE_0) { // _screen->fadeOut(); } _screen->_windows[0].update(); _interface->mainIconsPrint(); _screen->_windows[0].update(); _events->setCursor(0); _combat->_moveMonsters = true; if (_mode == MODE_0) { _mode = MODE_1; _screen->fadeIn(); } _combat->_moveMonsters = true; gameLoop(); }
int AgiEngine::agiLoadResource(int r, int n) { int i; i = _loader->loadResource(r, n); // WORKAROUND: Patches broken picture 147 in a corrupted Amiga version of Gold Rush! (v2.05 1989-03-09). // The picture can be seen in room 147 after dropping through the outhouse's hole in room 146. if (i == errOK && getGameID() == GID_GOLDRUSH && r == rPICTURE && n == 147 && _game.dirPic[n].len == 1982) { uint8 *pic = _game.pictures[n].rdata; Common::MemoryReadStream picStream(pic, _game.dirPic[n].len); Common::String md5str = Common::computeStreamMD5AsString(picStream, _game.dirPic[n].len); if (md5str == "1c685eb048656cedcee4eb6eca2cecea") { pic[0x042] = 0x4B; // 0x49 -> 0x4B pic[0x043] = 0x66; // 0x26 -> 0x66 pic[0x204] = 0x68; // 0x28 -> 0x68 pic[0x6C0] = 0x2D; // 0x25 -> 0x2D pic[0x6F0] = 0xF0; // 0x70 -> 0xF0 pic[0x734] = 0x6F; // 0x2F -> 0x6F } } return i; }
void MADSEngine::initialize() { // Initial sub-system engine references MSurface::setVm(this); MSprite::setVm(this); Resources::init(this); Conversation::init(this); _debugger = new Debugger(this); _dialogs = Dialogs::init(this); _events = new EventsManager(this); _palette = new Palette(this); Font::init(this); _font = new Font(); _screen = new Screen(); _sound = new SoundManager(this, _mixer); _audio = new AudioPlayer(_mixer, getGameID()); _game = Game::init(this); _gameConv = new GameConversations(this); loadOptions(); _screen->clear(); }
bool AgiEngine::handleController(uint16 key) { ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY]; if (key == 0) // nothing pressed return false; // This previously skipped processing, when ESC was pressed and called menu directly. // This original approach was bad, because games check different flags before actually allowing the // user to enter the menu. We checked a few common flags, like for example the availability of the prompt. // But this stopped the user being able to enter the menu, when the original interpreter actually allowed it. // We now instead implement this feature using another way for those platforms. if (key == AGI_KEY_ESCAPE) { // Escape pressed, user probably wants to trigger the menu // For PC, just passing ASCII code for ESC will normally trigger a controller // and the scripts will then trigger the menu switch (getPlatform()) { case Common::kPlatformAmiga: case Common::kPlatformApple2GS: case Common::kPlatformAtariST: // For these platforms, the button ESC normally triggered "pause" // But users could at the same time trigger the menu by clicking on the status line // We check, if menu is currently available and supposed to be accessible. // If yes, we do a delayed trigger now, otherwise we continue processing the key just like normal. // // This is probably the solution with the highest compatibility. // Several games also look for special keys see AGI_MENU_TRIGGER_* // And then there's also Mixed Up Mother Goose, which actually hooks the ESC key for the regular menu // // We risk in here of course, that we let the user access the menu, when it shouldn't be possible. // I'm not 100% sure if those other interpreters really only check VM_FLAG_MENUS_ACCESSIBLE // Needs further investigation. if (getFlag(VM_FLAG_MENUS_ACCESSIBLE) && _menu->isAvailable()) { // menu is supposed to be accessible and is also available _menu->delayedExecuteViaKeyboard(); return true; } default: break; } // Otherwise go on and look for the ESC controller } // AGI 3.149 games, The Black Cauldron and King's Quest 4 need KEY_ESCAPE to use menus // Games with the GF_ESCPAUSE flag need KEY_ESCAPE to pause the game // (key == KEY_ESCAPE && getVersion() != 0x3149 && getGameID() != GID_BC && getGameID() != GID_KQ4 && !(getFeatures() & GF_ESCPAUSE)) ) // return false; if ((getGameID() == GID_MH1 || getGameID() == GID_MH2) && (key == AGI_KEY_ENTER) && (!_text->promptIsEnabled())) { key = 0x20; // Set Enter key to Space in Manhunter when prompt is disabled } debugC(3, kDebugLevelInput, "key = %04x", key); for (uint16 curMapping = 0; curMapping < MAX_CONTROLLER_KEYMAPPINGS; curMapping++) { if (_game.controllerKeyMapping[curMapping].keycode == key) { debugC(3, kDebugLevelInput, "event %d: key press", _game.controllerKeyMapping[curMapping].controllerSlot); _game.controllerOccured[_game.controllerKeyMapping[curMapping].controllerSlot] = true; return true; } } int16 newDirection = 0; switch (key) { case AGI_KEY_UP: newDirection = 1; break; case AGI_KEY_DOWN: newDirection = 5; break; case AGI_KEY_LEFT: newDirection = 7; break; case AGI_KEY_RIGHT: newDirection = 3; break; case AGI_KEY_UP_RIGHT: newDirection = 2; break; case AGI_KEY_DOWN_RIGHT: newDirection = 4; break; case AGI_KEY_UP_LEFT: newDirection = 8; break; case AGI_KEY_DOWN_LEFT: newDirection = 6; break; default: break; } if (_game.playerControl) { if (!(getFeatures() & GF_AGIMOUSE)) { // Handle mouse button events if (!_game.mouseHidden) { if (key == AGI_MOUSE_BUTTON_LEFT) { if (getGameID() == GID_PQ1 && getVar(VM_VAR_CURRENT_ROOM) == 116) { // WORKAROUND: Special handling for mouse clicks in the newspaper // screen of PQ1. Fixes bug #3018770. newDirection = 3; // fake a right arrow key (next page) } else { // Click-to-walk mouse interface //v->flags |= fAdjEgoXY; // setting fAdjEgoXY here will at least break "climbing the log" in SQ2 // in case you walked to the log by using the mouse, so don't!!! int16 egoDestinationX = _mouse.pos.x; int16 egoDestinationY = _mouse.pos.y; _gfx->translateDisplayPosToGameScreen(egoDestinationX, egoDestinationY); screenObjEgo->motionType = kMotionEgo; if (egoDestinationX < (screenObjEgo->xSize / 2)) { screenObjEgo->move_x = -1; } else { screenObjEgo->move_x = egoDestinationX - (screenObjEgo->xSize / 2); } screenObjEgo->move_y = egoDestinationY; screenObjEgo->move_stepSize = screenObjEgo->stepSize; return true; } } } } } if (newDirection || key == AGI_KEY_STATIONARY) { // TODO: not sure, what original AGI did with AdjEgoXY screenObjEgo->flags &= ~fAdjEgoXY; if (screenObjEgo->direction == newDirection) { setVar(VM_VAR_EGO_DIRECTION, 0); } else { setVar(VM_VAR_EGO_DIRECTION, newDirection); } if (_game.playerControl) { screenObjEgo->motionType = kMotionNormal; } return true; } return false; }
GameDef createGameDef(const ExtractInformation *eI) { return ((getGameID(eI->game) & 0xF) << 12) | ((getPlatformID(eI->platform) & 0xF) << 8) | ((getSpecialID(eI->special) & 0xF) << 4) | ((getLanguageID(eI->lang) & 0xF) << 0); }
Common::Error TinselEngine::run() { // Initialize backend if (getGameID() == GID_DW2) { #ifndef DW2_EXACT_SIZE initGraphics(640, 480, true); #else initGraphics(640, 432, true); #endif _screenSurface.create(640, 432, 1); } else { initGraphics(320, 200, false); _screenSurface.create(320, 200, 1); } g_system->getEventManager()->registerRandomSource(_random, "tinsel"); _console = new Console(); _scheduler = new Scheduler(); InitSysVars(); // init memory manager MemoryInit(); // load user configuration ReadConfig(); #if 1 // FIXME: The following is taken from RestartGame(). // It may have to be adjusted a bit CountOut = 1; RebootCursor(); RebootDeadTags(); RebootMovers(); resetUserEventTime(); RebootTimers(); RebootScalingReels(); DelayedScene.scene = HookScene.scene = 0; #endif // Load in text strings ChangeLanguage(g_language); // Init palette and object managers, scheduler, keyboard and mouse RestartDrivers(); // load in graphics info SetupHandleTable(); // Actors, globals and inventory icons LoadBasicChunks(); // Continuous game processes CreateConstProcesses(); // allow game to run in the background //RestartBackgroundProcess(); // FIXME: is this still needed? //dumpMusic(); // dumps all of the game's music in external XMIDI files // Load game from specified slot, if any // // TODO: We might want to think about properly taking care of possible // errors when loading the save state. if (ConfMan.hasKey("save_slot")) { if (loadGameState(ConfMan.getInt("save_slot")) == Common::kNoError) loadingFromGMM = true; } // Foreground loop uint32 timerVal = 0; while (!shouldQuit()) { assert(_console); if (_console->isAttached()) _console->onFrame(); // Check for time to do next game cycle if ((g_system->getMillis() > timerVal + GAME_FRAME_DELAY)) { timerVal = g_system->getMillis(); AudioCD.updateCD(); NextGameCycle(); } if (bRestart) { RestartGame(); bRestart = false; bHasRestarted = true; // Set restarted flag } // Save/Restore scene file transfers ProcessSRQueue(); // Handle any playing movie FettleBMV(); #ifdef DEBUG if (bFast) continue; // run flat-out #endif // Loop processing events while there are any pending while (pollEvent()) ; DoCdChange(); if (MoviePlaying() && NextMovieTime()) g_system->delayMillis(MAX<int>(NextMovieTime() - g_system->getMillis() + MovieAudioLag(), 0)); else g_system->delayMillis(10); } // Write configuration WriteConfig(); return Common::kNoError; }
void PreAgiEngine::drawStr(int row, int col, int attr, const char *buffer) { int code; if (attr == kColorDefault) attr = _defaultColor; for (int iChar = 0; iChar < (int)strlen(buffer); iChar++) { code = buffer[iChar]; switch (code) { case '\n': case 0x8D: if (++row == 200 / 8) return; col = 0; break; case '|': // swap attribute nibbles break; default: _gfx->putTextCharacter(1, col * 8 , row * 8, static_cast<char>(code), attr & 0x0f, (attr & 0xf0) / 0x10, false, getGameID() == GID_MICKEY ? mickey_fontdata : ibm_fontdata); if (++col == 320 / 8) { col = 0; if (++row == 200 / 8) return; } } } }