ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

grim.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #define FORBIDDEN_SYMBOL_EXCEPTION_fprintf
00024 #define FORBIDDEN_SYMBOL_EXCEPTION_fgetc
00025 #define FORBIDDEN_SYMBOL_EXCEPTION_stderr
00026 #define FORBIDDEN_SYMBOL_EXCEPTION_stdin
00027 
00028 #include "common/archive.h"
00029 #include "common/debug-channels.h"
00030 #include "common/file.h"
00031 #include "common/foreach.h"
00032 #include "common/fs.h"
00033 #include "common/config-manager.h"
00034 #include "common/translation.h"
00035 
00036 #include "graphics/pixelbuffer.h"
00037 #include "graphics/renderer.h"
00038 
00039 #ifdef USE_OPENGL
00040 #include "graphics/opengl/context.h"
00041 #endif
00042 
00043 #include "gui/error.h"
00044 #include "gui/gui-manager.h"
00045 #include "gui/message.h"
00046 
00047 #include "image/png.h"
00048 
00049 #include "engines/engine.h"
00050 
00051 #include "engines/grim/md5check.h"
00052 #include "engines/grim/md5checkdialog.h"
00053 #include "engines/grim/debug.h"
00054 #include "engines/grim/grim.h"
00055 #include "engines/grim/lua.h"
00056 #include "engines/grim/lua_v1.h"
00057 #include "engines/grim/emi/poolsound.h"
00058 #include "engines/grim/emi/layer.h"
00059 #include "engines/grim/actor.h"
00060 #include "engines/grim/movie/movie.h"
00061 #include "engines/grim/savegame.h"
00062 #include "engines/grim/registry.h"
00063 #include "engines/grim/resource.h"
00064 #include "engines/grim/localize.h"
00065 #include "engines/grim/gfx_base.h"
00066 #include "engines/grim/bitmap.h"
00067 #include "engines/grim/font.h"
00068 #include "engines/grim/primitives.h"
00069 #include "engines/grim/objectstate.h"
00070 #include "engines/grim/set.h"
00071 #include "engines/grim/sound.h"
00072 #include "engines/grim/stuffit.h"
00073 #include "engines/grim/debugger.h"
00074 
00075 #include "engines/grim/imuse/imuse.h"
00076 #include "engines/grim/emi/sound/emisound.h"
00077 
00078 #include "engines/grim/lua/lua.h"
00079 
00080 namespace Grim {
00081 
00082 GrimEngine *g_grim = nullptr;
00083 GfxBase *g_driver = nullptr;
00084 int g_imuseState = -1;
00085 
00086 GrimEngine::GrimEngine(OSystem *syst, uint32 gameFlags, GrimGameType gameType, Common::Platform platform, Common::Language language) :
00087         Engine(syst), _currSet(nullptr), _selectedActor(nullptr), _pauseStartTime(0) {
00088     g_grim = this;
00089 
00090     setDebugger(new Debugger());
00091     _gameType = gameType;
00092     _gameFlags = gameFlags;
00093     _gamePlatform = platform;
00094     _gameLanguage = language;
00095 
00096     if (getGameType() == GType_GRIM)
00097         g_registry = new Registry();
00098     else
00099         g_registry = nullptr;
00100 
00101     g_resourceloader = nullptr;
00102     g_localizer = nullptr;
00103     g_movie = nullptr;
00104     g_imuse = nullptr;
00105 
00106     //Set default settings
00107     ConfMan.registerDefault("use_arb_shaders", true);
00108 
00109     _showFps = ConfMan.getBool("show_fps");
00110 
00111     _softRenderer = true;
00112 
00113     _mixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, 192);
00114     _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
00115     _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
00116     _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
00117 
00118     _currSet = nullptr;
00119     _selectedActor = nullptr;
00120     _controlsEnabled = new bool[KEYCODE_EXTRA_LAST];
00121     _controlsState = new bool[KEYCODE_EXTRA_LAST];
00122     for (int i = 0; i < KEYCODE_EXTRA_LAST; i++) {
00123         _controlsEnabled[i] = false;
00124         _controlsState[i] = false;
00125     }
00126     _joyAxisPosition = new float[NUM_JOY_AXES];
00127     for (int i = 0; i < NUM_JOY_AXES; i++) {
00128         _joyAxisPosition[i] = 0;
00129     }
00130     _speechMode = TextAndVoice;
00131     _textSpeed = 7;
00132     _mode = _previousMode = NormalMode;
00133     _flipEnable = true;
00134     int speed = ConfMan.getInt("engine_speed");
00135     if (speed == 0) {
00136         _speedLimitMs = 0;
00137     } else if (speed < 0 || speed > 100) {
00138         _speedLimitMs = 1000 / 60;
00139         ConfMan.setInt("engine_speed", 1000 / _speedLimitMs);
00140     } else {
00141         _speedLimitMs = 1000 / speed;
00142     }
00143     _listFilesIter = nullptr;
00144     _savedState = nullptr;
00145     _fps[0] = 0;
00146     _iris = new Iris();
00147     _buildActiveActorsList = false;
00148 
00149     Color c(0, 0, 0);
00150 
00151     _printLineDefaults.setX(0);
00152     _printLineDefaults.setY(100);
00153     _printLineDefaults.setWidth(0);
00154     _printLineDefaults.setHeight(0);
00155     _printLineDefaults.setFGColor(c);
00156     _printLineDefaults.setFont(nullptr);
00157     _printLineDefaults.setJustify(TextObject::LJUSTIFY);
00158 
00159     _sayLineDefaults.setX(0);
00160     _sayLineDefaults.setY(100);
00161     _sayLineDefaults.setWidth(0);
00162     _sayLineDefaults.setHeight(0);
00163     _sayLineDefaults.setFGColor(c);
00164     _sayLineDefaults.setFont(nullptr);
00165     _sayLineDefaults.setJustify(TextObject::CENTER);
00166 
00167     _blastTextDefaults.setX(0);
00168     _blastTextDefaults.setY(200);
00169     _blastTextDefaults.setWidth(0);
00170     _blastTextDefaults.setHeight(0);
00171     _blastTextDefaults.setFGColor(c);
00172     _blastTextDefaults.setFont(nullptr);
00173     _blastTextDefaults.setJustify(TextObject::LJUSTIFY);
00174 
00175     const Common::FSNode gameDataDir(ConfMan.get("path"));
00176     SearchMan.addSubDirectoryMatching(gameDataDir, "movies"); // Add 'movies' subdirectory for the demo
00177     SearchMan.addSubDirectoryMatching(gameDataDir, "credits");
00178     SearchMan.addSubDirectoryMatching(gameDataDir, "widescreen");
00179 
00180     Debug::registerDebugChannels();
00181 }
00182 
00183 GrimEngine::~GrimEngine() {
00184     delete[] _controlsEnabled;
00185     delete[] _controlsState;
00186     delete[] _joyAxisPosition;
00187 
00188     clearPools();
00189 
00190     delete LuaBase::instance();
00191     if (g_registry) {
00192         g_registry->save();
00193         delete g_registry;
00194         g_registry = nullptr;
00195     }
00196     delete g_movie;
00197     g_movie = nullptr;
00198     delete g_imuse;
00199     g_imuse = nullptr;
00200     delete g_emiSound;
00201     g_emiSound = nullptr;
00202     delete g_sound;
00203     g_sound = nullptr;
00204     delete g_localizer;
00205     g_localizer = nullptr;
00206     delete g_resourceloader;
00207     g_resourceloader = nullptr;
00208     delete g_driver;
00209     g_driver = nullptr;
00210     delete _iris;
00211 
00212     ConfMan.flushToDisk();
00213     DebugMan.clearAllDebugChannels();
00214 
00215     g_grim = nullptr;
00216 }
00217 
00218 void GrimEngine::clearPools() {
00219     Set::getPool().deleteObjects();
00220     Actor::getPool().deleteObjects();
00221     PrimitiveObject::getPool().deleteObjects();
00222     TextObject::getPool().deleteObjects();
00223     Bitmap::getPool().deleteObjects();
00224     Font::getPool().deleteObjects();
00225     ObjectState::getPool().deleteObjects();
00226 
00227     _currSet = nullptr;
00228 }
00229 
00230 LuaBase *GrimEngine::createLua() {
00231     return new Lua_V1();
00232 }
00233 
00234 GfxBase *GrimEngine::createRenderer(int screenW, int screenH, bool fullscreen) {
00235     Common::String rendererConfig = ConfMan.get("renderer");
00236     Graphics::RendererType desiredRendererType = Graphics::parseRendererTypeCode(rendererConfig);
00237     Graphics::RendererType matchingRendererType = Graphics::getBestMatchingAvailableRendererType(desiredRendererType);
00238 
00239     _softRenderer = matchingRendererType == Graphics::kRendererTypeTinyGL;
00240     _system->setupScreen(screenW, screenH, fullscreen, !_softRenderer);
00241 
00242 #if defined(USE_OPENGL)
00243     // Check the OpenGL context actually supports shaders
00244     if (matchingRendererType == Graphics::kRendererTypeOpenGLShaders && !OpenGLContext.shadersSupported) {
00245         matchingRendererType = Graphics::kRendererTypeOpenGL;
00246     }
00247 #endif
00248 
00249     if (matchingRendererType != desiredRendererType && desiredRendererType != Graphics::kRendererTypeDefault) {
00250         // Display a warning if unable to use the desired renderer
00251         warning("Unable to create a '%s' renderer", rendererConfig.c_str());
00252     }
00253 
00254     GfxBase *renderer = nullptr;
00255 #if defined(USE_GLES2) || defined(USE_OPENGL_SHADERS)
00256     if (matchingRendererType == Graphics::kRendererTypeOpenGLShaders) {
00257         renderer = CreateGfxOpenGLShader();
00258     }
00259 #endif
00260 #if defined(USE_OPENGL) && !defined(USE_GLES2)
00261     if (matchingRendererType == Graphics::kRendererTypeOpenGL) {
00262         renderer = CreateGfxOpenGL();
00263     }
00264 #endif
00265     if (matchingRendererType == Graphics::kRendererTypeTinyGL) {
00266         renderer = CreateGfxTinyGL();
00267     }
00268 
00269     if (!renderer) {
00270         error("Unable to create a '%s' renderer", rendererConfig.c_str());
00271     }
00272 
00273     renderer->setupScreen(screenW, screenH, fullscreen);
00274     renderer->loadEmergFont();
00275     return renderer;
00276 }
00277 
00278 const char *GrimEngine::getUpdateFilename() {
00279     if (!(getGameFlags() & ADGF_DEMO))
00280         return "gfupd101.exe";
00281     else
00282         return nullptr;
00283 }
00284 
00285 Common::Error GrimEngine::run() {
00286     // Try to see if we have the EMI Mac installer present
00287     // Currently, this requires the data fork to be standalone
00288     if (getGameType() == GType_MONKEY4) {
00289         if (SearchMan.hasFile("Monkey Island 4 Installer")) {
00290             StuffItArchive *archive = new StuffItArchive();
00291 
00292             if (archive->open("Monkey Island 4 Installer"))
00293                 SearchMan.add("Monkey Island 4 Installer", archive, 0, true);
00294             else
00295                 delete archive;
00296         }
00297         if (SearchMan.hasFile("EFMI Installer")) {
00298             StuffItArchive *archive = new StuffItArchive();
00299 
00300             if (archive->open("EFMI Installer"))
00301                 SearchMan.add("EFMI Installer", archive, 0, true);
00302             else
00303                 delete archive;
00304 
00305         }
00306     }
00307 
00308     ConfMan.registerDefault("check_gamedata", true);
00309     if (ConfMan.getBool("check_gamedata")) {
00310         MD5CheckDialog d;
00311         if (!d.runModal()) {
00312             Common::String confirmString = Common::String::format(_(
00313                 "ResidualVM found some problems with your game data files.\n"
00314                 "Running ResidualVM nevertheless may cause game bugs or even crashes.\n"
00315                 "Do you still want to run %s?"),
00316             GType_MONKEY4 == getGameType() ? _("Escape From Monkey Island") : _("Grim Fandango")
00317              );
00318             GUI::MessageDialog msg(confirmString, _("Yes"), _("No"));
00319             if (!msg.runModal()) {
00320                 return Common::kUserCanceled;
00321             }
00322         }
00323 
00324         ConfMan.setBool("check_gamedata", false);
00325         ConfMan.flushToDisk();
00326     }
00327 
00328     g_resourceloader = new ResourceLoader();
00329     bool demo = getGameFlags() & ADGF_DEMO;
00330     if (getGameType() == GType_GRIM)
00331         g_movie = CreateSmushPlayer(demo);
00332     else if (getGameType() == GType_MONKEY4) {
00333         if (_gamePlatform == Common::kPlatformPS2)
00334             g_movie = CreateMpegPlayer();
00335         else
00336             g_movie = CreateBinkPlayer(demo);
00337     }
00338     if (getGameType() == GType_GRIM) {
00339         g_imuse = new Imuse(20, demo);
00340         g_emiSound = nullptr;
00341     } else if (getGameType() == GType_MONKEY4) {
00342         g_emiSound = new EMISound(20);
00343         g_imuse = nullptr;
00344     }
00345     g_sound = new SoundPlayer();
00346 
00347     bool fullscreen = ConfMan.getBool("fullscreen");
00348     g_driver = createRenderer(640, 480, fullscreen);
00349 
00350     if (getGameType() == GType_MONKEY4 && SearchMan.hasFile("AMWI.m4b")) {
00351         // Play EMI Mac Aspyr logo
00352         playAspyrLogo();
00353     }
00354 
00355     Bitmap *splash_bm = nullptr;
00356     if (!(_gameFlags & ADGF_DEMO) && getGameType() == GType_GRIM)
00357         splash_bm = Bitmap::create("splash.bm");
00358     else if ((_gameFlags & ADGF_DEMO) && getGameType() == GType_MONKEY4)
00359         splash_bm = Bitmap::create("splash.til");
00360     else if (getGamePlatform() == Common::kPlatformPS2 && getGameType() == GType_MONKEY4)
00361         splash_bm = Bitmap::create("load.tga");
00362 
00363     g_driver->clearScreen();
00364 
00365     if (splash_bm != nullptr)
00366         splash_bm->draw();
00367 
00368     // This flipBuffer() may make the OpenGL renderer show garbage instead of the splash,
00369     // while the TinyGL renderer needs it.
00370     if (_softRenderer)
00371         g_driver->flipBuffer();
00372 
00373     LuaBase *lua = createLua();
00374 
00375     lua->registerOpcodes();
00376     lua->registerLua();
00377 
00378     // One version of the demo doesn't set the demo flag in scripts.
00379     if (getGameType() == GType_GRIM && _gameFlags & ADGF_DEMO) {
00380         lua->forceDemo();
00381     }
00382 
00383     //Initialize Localizer first. In system-script are already localizeable Strings
00384     g_localizer = new Localizer();
00385     lua->loadSystemScript();
00386     lua->boot();
00387 
00388     _savegameLoadRequest = false;
00389     _savegameSaveRequest = false;
00390 
00391     // Load game from specified slot, if any
00392     if (ConfMan.hasKey("save_slot")) {
00393         loadGameState(ConfMan.getInt("save_slot"));
00394     }
00395 
00396     g_grim->setMode(NormalMode);
00397     delete splash_bm;
00398     g_grim->mainLoop();
00399 
00400     return Common::kNoError;
00401 }
00402 
00403 void GrimEngine::playAspyrLogo() {
00404     // A trimmed down version of the code found in mainloop
00405     // for the purpose of playing the Aspyr-logo. 
00406     // The reason for this, is that the logo needs a different
00407     // codec than all the other videos (which are Bink).
00408     // Code is provided to keep within the fps-limit, as well as to
00409     // allow for pressing ESC to skip the movie.
00410     MoviePlayer *defaultPlayer = g_movie;
00411     g_movie = CreateQuickTimePlayer();
00412     g_movie->play("AMWI.m4b", false, 0, 0);
00413     setMode(SmushMode);
00414     while (g_movie->isPlaying()) {
00415         _doFlip = true;
00416         uint32 startTime = g_system->getMillis();
00417 
00418         updateDisplayScene();
00419         if (_doFlip) {
00420             doFlip();
00421         }
00422         // Process events to allow the user to skip the logo.
00423         Common::Event event;
00424         while (g_system->getEventManager()->pollEvent(event)) {
00425             // Ignore everything but ESC when movies are playing
00426             Common::EventType type = event.type;
00427             if (type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) {
00428                 g_movie->stop();
00429                 break;
00430             }
00431         }
00432 
00433         uint32 endTime = g_system->getMillis();
00434         if (startTime > endTime)
00435             continue;
00436         uint32 diffTime = endTime - startTime;
00437         if (_speedLimitMs == 0)
00438             continue;
00439         if (diffTime < _speedLimitMs) {
00440             uint32 delayTime = _speedLimitMs - diffTime;
00441             g_system->delayMillis(delayTime);
00442         }
00443     }
00444     delete g_movie;
00445     setMode(NormalMode);
00446     g_movie = defaultPlayer;
00447 }
00448 
00449 Common::Error GrimEngine::loadGameState(int slot) {
00450     assert(slot >= 0);
00451     if (getGameType() == GType_MONKEY4) {
00452         if (getGamePlatform() == Common::kPlatformPS2) {
00453             _savegameFileName = Common::String::format("efmi%03d.ps2", slot);
00454         } else {
00455             _savegameFileName = Common::String::format("efmi%03d.gsv", slot);
00456         }
00457     } else {
00458         _savegameFileName = Common::String::format("grim%02d.gsv", slot);
00459     }
00460     _savegameLoadRequest = true;
00461     return Common::kNoError;
00462 }
00463 
00464 void GrimEngine::handlePause() {
00465     if (!LuaBase::instance()->callback("pauseHandler")) {
00466         error("handlePause: invalid handler");
00467     }
00468 }
00469 
00470 void GrimEngine::handleExit() {
00471     if (!LuaBase::instance()->callback("exitHandler")) {
00472         error("handleExit: invalid handler");
00473     }
00474 }
00475 
00476 void GrimEngine::handleUserPaint() {
00477     if (!LuaBase::instance()->callback("userPaintHandler")) {
00478         error("handleUserPaint: invalid handler");
00479     }
00480 }
00481 
00482 void GrimEngine::cameraChangeHandle(int prev, int next) {
00483     LuaObjects objects;
00484     objects.add(prev);
00485     objects.add(next);
00486     LuaBase::instance()->callback("camChangeHandler", objects);
00487 }
00488 
00489 void GrimEngine::cameraPostChangeHandle(int num) {
00490     LuaObjects objects;
00491     objects.add(num);
00492     LuaBase::instance()->callback("postCamChangeHandler", objects);
00493 }
00494 
00495 void GrimEngine::savegameCallback() {
00496     if (!LuaBase::instance()->callback("saveGameCallback")) {
00497         error("GrimEngine::savegameCallback: invalid handler");
00498     }
00499 }
00500 
00501 void GrimEngine::handleDebugLoadResource() {
00502     void *resource = nullptr;
00503     int c, i = 0;
00504     char buf[513];
00505 
00506     // Tool for debugging the loading of a particular resource without
00507     // having to actually make it all the way to it in the game
00508     fprintf(stderr, "Enter resource to load (extension specifies type): ");
00509     while (i < 512 && (c = fgetc(stdin)) != EOF && c != '\n')
00510         buf[i++] = c;
00511 
00512     buf[i] = '\0';
00513     if (strstr(buf, ".key"))
00514         resource = (void *)g_resourceloader->loadKeyframe(buf);
00515     else if (strstr(buf, ".zbm") || strstr(buf, ".bm"))
00516         resource = (void *)Bitmap::create(buf);
00517     else if (strstr(buf, ".cmp"))
00518         resource = (void *)g_resourceloader->loadColormap(buf);
00519     else if (strstr(buf, ".cos"))
00520         resource = (void *)g_resourceloader->loadCostume(buf, nullptr, nullptr);
00521     else if (strstr(buf, ".lip"))
00522         resource = (void *)g_resourceloader->loadLipSync(buf);
00523     else if (strstr(buf, ".snm"))
00524         resource = (void *)g_movie->play(buf, false, 0, 0);
00525     else if (strstr(buf, ".wav") || strstr(buf, ".imu")) {
00526         if (g_imuse)
00527             g_imuse->startSfx(buf);
00528         resource = (void *)1;
00529     } else if (strstr(buf, ".mat")) {
00530         CMap *cmap = g_resourceloader->loadColormap("item.cmp");
00531         warning("Default colormap applied to resources loaded in this fashion");
00532         // Default to repeating the texture as in GRIM
00533         resource = (void *)g_resourceloader->loadMaterial(buf, cmap, false);
00534     } else {
00535         warning("Resource type not understood");
00536     }
00537     if (!resource)
00538         warning("Requested resouce (%s) not found", buf);
00539 }
00540 
00541 void GrimEngine::drawTextObjects() {
00542     foreach (TextObject *t, TextObject::getPool()) {
00543         t->draw();
00544     }
00545 }
00546 
00547 void GrimEngine::playIrisAnimation(Iris::Direction dir, int x, int y, int time) {
00548     _iris->play(dir, x, y, time);
00549 }
00550 
00551 void GrimEngine::luaUpdate() {
00552     if (_savegameLoadRequest || _savegameSaveRequest || _changeHardwareState)
00553         return;
00554 
00555     // Update timing information
00556     unsigned newStart = g_system->getMillis();
00557     if (newStart < _frameStart) {
00558         _frameStart = newStart;
00559         return;
00560     }
00561     _frameTime = newStart - _frameStart;
00562     _frameStart = newStart;
00563 
00564     if (_mode == PauseMode || _shortFrame) {
00565         _frameTime = 0;
00566     }
00567 
00568     LuaBase::instance()->update(_frameTime, _movieTime);
00569 
00570     if (_currSet && (_mode == NormalMode || _mode == SmushMode)) {
00571         // call updateTalk() before calling update(), since it may modify costumes state, and
00572         // the costumes are updated in update().
00573         for (Common::List<Actor *>::iterator i = _talkingActors.begin(); i != _talkingActors.end(); ++i) {
00574             Actor *a = *i;
00575             if (!a->updateTalk(_frameTime)) {
00576                 i = _talkingActors.reverse_erase(i);
00577             }
00578         }
00579 
00580         // Update the actors. Do it here so that we are sure to react asap to any change
00581         // in the actors state caused by lua.
00582         buildActiveActorsList();
00583         foreach (Actor *a, _activeActors) {
00584             // Note that the actor need not be visible to update chores, for example:
00585             // when Manny has just brought Meche back he is offscreen several times
00586             // when he needs to perform certain chores
00587             a->update(_frameTime);
00588         }
00589 
00590         _iris->update(_frameTime);
00591 
00592         foreach (TextObject *t, TextObject::getPool()) {
00593             t->update();
00594         }
00595     }
00596 }
00597 
00598 void GrimEngine::updateDisplayScene() {
00599     _doFlip = true;
00600 
00601     if (_mode == SmushMode) {
00602         if (g_movie->isPlaying()) {
00603             _movieTime = g_movie->getMovieTime();
00604             if (g_movie->isUpdateNeeded()) {
00605                 g_driver->prepareMovieFrame(g_movie->getDstSurface());
00606                 g_movie->clearUpdateNeeded();
00607             }
00608             int frame = g_movie->getFrame();
00609             if (frame >= 0) {
00610                 if (frame != _prevSmushFrame) {
00611                     _prevSmushFrame = g_movie->getFrame();
00612                     g_driver->drawMovieFrame(g_movie->getX(), g_movie->getY());
00613                     if (_showFps)
00614                         g_driver->drawEmergString(550, 25, _fps, Color(255, 255, 255));
00615                 } else
00616                     _doFlip = false;
00617             } else
00618                 g_driver->releaseMovieFrame();
00619         }
00620         // Draw Primitives
00621         _iris->draw();
00622 
00623         g_movie->drawMovieSubtitle();
00624 
00625     } else if (_mode == NormalMode || _mode == OverworldMode) {
00626         updateNormalMode();
00627     } else if (_mode == DrawMode) {
00628         updateDrawMode();
00629     }
00630 }
00631 
00632 void GrimEngine::updateNormalMode() {
00633     if (!_currSet || !_flipEnable)
00634         return;
00635 
00636     g_driver->clearScreen();
00637 
00638     drawNormalMode();
00639 
00640     _iris->draw();
00641     drawTextObjects();
00642 }
00643 
00644 void GrimEngine::updateDrawMode() {
00645     _doFlip = false;
00646     _prevSmushFrame = 0;
00647     _movieTime = 0;
00648 }
00649 
00650 void GrimEngine::drawNormalMode() {
00651     _prevSmushFrame = 0;
00652     _movieTime = 0;
00653 
00654     _currSet->drawBackground();
00655 
00656     // Draw underlying scene components
00657     // Background objects are drawn underneath everything except the background
00658     // There are a bunch of these, especially in the tube-switcher room
00659     _currSet->drawBitmaps(ObjectState::OBJSTATE_BACKGROUND);
00660 
00661     // State objects are drawn on top of other things, such as the flag
00662     // on Manny's message tube
00663     _currSet->drawBitmaps(ObjectState::OBJSTATE_STATE);
00664 
00665     // Play SMUSH Animations
00666     // This should occur on top of all underlying scene objects,
00667     // a good example is the tube switcher room where some state objects
00668     // need to render underneath the animation or you can't see what's going on
00669     // This should not occur on top of everything though or Manny gets covered
00670     // up when he's next to Glottis's service room
00671     if (g_movie->isPlaying() && _movieSetup == _currSet->getCurrSetup()->_name) {
00672         _movieTime = g_movie->getMovieTime();
00673         if (g_movie->isUpdateNeeded()) {
00674             g_driver->prepareMovieFrame(g_movie->getDstSurface());
00675             g_movie->clearUpdateNeeded();
00676         }
00677         if (g_movie->getFrame() >= 0)
00678             g_driver->drawMovieFrame(g_movie->getX(), g_movie->getY());
00679         else
00680             g_driver->releaseMovieFrame();
00681     }
00682 
00683     // Underlay objects must be drawn on top of movies
00684     // Otherwise the lighthouse door will always be open as the underlay for
00685     // the closed door will be overdrawn by a movie used as background image.
00686     _currSet->drawBitmaps(ObjectState::OBJSTATE_UNDERLAY);
00687 
00688     // Draw Primitives
00689     foreach (PrimitiveObject *p, PrimitiveObject::getPool()) {
00690         p->draw();
00691     }
00692 
00693     _currSet->setupCamera();
00694 
00695     g_driver->set3DMode();
00696 
00697     if (_setupChanged) {
00698         cameraPostChangeHandle(_currSet->getSetup());
00699         _setupChanged = false;
00700         setSideTextures(_currSet->getCurrSetup()->_name.c_str());
00701     }
00702 
00703     // Draw actors
00704     buildActiveActorsList();
00705     foreach (Actor *a, _activeActors) {
00706         if (a->isVisible())
00707             a->draw();
00708     }
00709 
00710     flagRefreshShadowMask(false);
00711 
00712     // Draw overlying scene components
00713     // The overlay objects should be drawn on top of everything else,
00714     // including 3D objects such as Manny and the message tube
00715     _currSet->drawBitmaps(ObjectState::OBJSTATE_OVERLAY);
00716 }
00717 
00718 void GrimEngine::doFlip() {
00719     _frameCounter++;
00720     if (!_doFlip) {
00721         return;
00722     }
00723 
00724     if (_showFps && _mode != DrawMode)
00725         g_driver->drawEmergString(550, 25, _fps, Color(255, 255, 255));
00726 
00727     if (_flipEnable)
00728         g_driver->flipBuffer();
00729 
00730     if (_showFps && _mode != DrawMode) {
00731         unsigned int currentTime = g_system->getMillis();
00732         unsigned int delta = currentTime - _lastFrameTime;
00733         if (delta > 500) {
00734             snprintf(_fps, sizeof(_fps), "%7.2f", (double)(_frameCounter * 1000) / (double)delta);
00735             _frameCounter = 0;
00736             _lastFrameTime = currentTime;
00737         }
00738     }
00739 }
00740 
00741 void GrimEngine::mainLoop() {
00742     _movieTime = 0;
00743     _frameTime = 0;
00744     _frameStart = g_system->getMillis();
00745     _frameCounter = 0;
00746     _lastFrameTime = 0;
00747     _prevSmushFrame = 0;
00748     _refreshShadowMask = false;
00749     _shortFrame = false;
00750     bool resetShortFrame = false;
00751     _changeHardwareState = false;
00752     _changeFullscreenState = false;
00753     _setupChanged = true;
00754 
00755     for (;;) {
00756         uint32 startTime = g_system->getMillis();
00757         if (_shortFrame) {
00758             if (resetShortFrame) {
00759                 _shortFrame = false;
00760             }
00761             resetShortFrame = !resetShortFrame;
00762         }
00763 
00764         if (shouldQuit())
00765             return;
00766 
00767         if (_savegameLoadRequest) {
00768             savegameRestore();
00769         }
00770         if (_savegameSaveRequest) {
00771             savegameSave();
00772         }
00773 
00774         // If the backend can keep the OpenGL context when switching to fullscreen,
00775         // just toggle the fullscreen feature (SDL2 path).
00776         if (_changeFullscreenState &&
00777                 _system->hasFeature(OSystem::kFeatureFullscreenToggleKeepsContext)) {
00778             bool fullscreen = _system->getFeatureState(OSystem::kFeatureFullscreenMode);
00779             _system->setFeatureState(OSystem::kFeatureFullscreenMode, !fullscreen);
00780             _changeFullscreenState = false;
00781         }
00782 
00783         // If the backend destroys the OpenGL context or the user switched to a different
00784         // renderer, the GFX driver needs to be recreated (SDL1 path).
00785         if (_changeHardwareState || _changeFullscreenState) {
00786             _changeHardwareState = false;
00787 
00788             bool fullscreen = _system->getFeatureState(OSystem::kFeatureFullscreenMode);
00789             if (_changeFullscreenState) {
00790                 fullscreen = !fullscreen;
00791             }
00792 
00793             uint screenWidth = g_driver->getScreenWidth();
00794             uint screenHeight = g_driver->getScreenHeight();
00795 
00796             EngineMode mode = getMode();
00797 
00798             _savegameFileName = "";
00799             savegameSave();
00800             clearPools();
00801 
00802             delete g_driver;
00803             g_driver = createRenderer(screenWidth, screenHeight, fullscreen);
00804             savegameRestore();
00805 
00806             if (mode == DrawMode) {
00807                 setMode(GrimEngine::NormalMode);
00808                 updateDisplayScene();
00809                 g_driver->storeDisplay();
00810                 g_driver->dimScreen();
00811             }
00812             setMode(mode);
00813             _changeFullscreenState = false;
00814         }
00815 
00816         g_sound->flushTracks();
00817         if (g_imuse) {
00818             g_imuse->refreshScripts();
00819         }
00820 
00821         // Process events
00822         Common::Event event;
00823         while (g_system->getEventManager()->pollEvent(event)) {
00824             // Handle any buttons, keys and joystick operations
00825             Common::EventType type = event.type;
00826             if (type == Common::EVENT_KEYDOWN || type == Common::EVENT_KEYUP) {
00827                 if (type == Common::EVENT_KEYDOWN) {
00828                     // Ignore everything but ESC when movies are playing
00829                     // This matches the retail and demo versions of EMI
00830                     // This also allows the PS2 version to skip movies
00831                     if (_mode == SmushMode && g_grim->getGameType() == GType_MONKEY4) {
00832                         if (event.kbd.keycode == Common::KEYCODE_ESCAPE) {
00833                             g_movie->stop();
00834                             break;
00835                         }
00836                         continue;
00837                     }
00838 
00839                     if (_mode != DrawMode && _mode != SmushMode && (event.kbd.ascii == 'q')) {
00840                         handleExit();
00841                         break;
00842                     } else if (_mode != DrawMode && (event.kbd.keycode == Common::KEYCODE_PAUSE)) {
00843                         handlePause();
00844                         break;
00845                     } else {
00846                         handleChars(type, event.kbd);
00847                     }
00848                 }
00849 
00850                 handleControls(type, event.kbd);
00851 
00852                 if (getGameType() != GType_MONKEY4) {
00853                     // Allow lua to react to the event.
00854                     // Without this lua_update switching the entries in the menu is slow because
00855                     // if the button is not kept pressed the KEYUP will arrive just after the KEYDOWN
00856                     // and it will break the lua scripts that checks for the state of the button
00857                     // with GetControlState()
00858                     //
00859                     // This call seems to be only necessary to handle Grim's menu correctly.
00860                     // In EMI it would have the side-effect that luaUpdate() is sometimes called
00861                     // in the same millisecond which causes getPerSecond() to return 0 for
00862                     // any given rate which is not compatible with e.g. actor walking.
00863 
00864                     // We do not want the scripts to update while a movie is playing in the PS2-version.
00865                     if (!(getGamePlatform() == Common::kPlatformPS2 && _mode == SmushMode)) {
00866                         luaUpdate();
00867                     }
00868                 }
00869             }
00870             if (type == Common::EVENT_JOYAXIS_MOTION)
00871                 handleJoyAxis(event.joystick.axis, event.joystick.position);
00872             if (type == Common::EVENT_JOYBUTTON_DOWN || type == Common::EVENT_JOYBUTTON_UP)
00873                 handleJoyButton(type, event.joystick.button);
00874             if (type == Common::EVENT_SCREEN_CHANGED) {
00875                 handleUserPaint();
00876             }
00877         }
00878 
00879         if (_mode != PauseMode) {
00880             // Draw the display scene before doing the luaUpdate.
00881             // This give a large performance boost as OpenGL stores commands
00882             // in a queue on the gpu to be rendered later. When doFlip is
00883             // called the cpu must wait for the gpu to finish its queue.
00884             // Now, it will queue all the OpenGL commands and draw them on the
00885             // GPU while the CPU is busy updating the game world.
00886             updateDisplayScene();
00887         }
00888 
00889         if (_mode != PauseMode) {
00890             doFlip();
00891         }
00892 
00893         // We do not want the scripts to update while a movie is playing in the PS2-version.
00894         if (!(getGamePlatform() == Common::kPlatformPS2 && _mode == SmushMode)) {
00895             luaUpdate();
00896         }
00897 
00898         if (g_imuseState != -1) {
00899             g_sound->setMusicState(g_imuseState);
00900             g_imuseState = -1;
00901         }
00902 
00903         uint32 endTime = g_system->getMillis();
00904         if (startTime > endTime)
00905             continue;
00906         uint32 diffTime = endTime - startTime;
00907         if (_speedLimitMs == 0)
00908             continue;
00909         if (diffTime < _speedLimitMs) {
00910             uint32 delayTime = _speedLimitMs - diffTime;
00911             g_system->delayMillis(delayTime);
00912         }
00913     }
00914 }
00915 
00916 void GrimEngine::changeHardwareState() {
00917     _changeHardwareState = true;
00918 }
00919 
00920 void GrimEngine::saveGame(const Common::String &file) {
00921     _savegameFileName = file;
00922     _savegameSaveRequest = true;
00923 }
00924 
00925 void GrimEngine::loadGame(const Common::String &file) {
00926     _savegameFileName = file;
00927     _savegameLoadRequest = true;
00928 }
00929 
00930 void GrimEngine::savegameRestore() {
00931     debug("GrimEngine::savegameRestore() started.");
00932     _savegameLoadRequest = false;
00933     Common::String filename;
00934     if (_savegameFileName.size() == 0) {
00935         filename = "grim.sav";
00936     } else {
00937         filename = _savegameFileName;
00938     }
00939     _savedState = SaveGame::openForLoading(filename);
00940     if (!_savedState || !_savedState->isCompatible())
00941         return;
00942     if (g_imuse) {
00943         g_imuse->stopAllSounds();
00944         g_imuse->resetState();
00945     }
00946     g_movie->stop();
00947     if (g_imuse)
00948         g_imuse->pause(true);
00949     g_movie->pause(true);
00950     if (g_registry)
00951         g_registry->save();
00952 
00953     _selectedActor = nullptr;
00954     delete _currSet;
00955     _currSet = nullptr;
00956 
00957     Bitmap::getPool().restoreObjects(_savedState);
00958     Debug::debug(Debug::Engine, "Bitmaps restored successfully.");
00959 
00960     Font::getPool().restoreObjects(_savedState);
00961     Debug::debug(Debug::Engine, "Fonts restored successfully.");
00962 
00963     ObjectState::getPool().restoreObjects(_savedState);
00964     Debug::debug(Debug::Engine, "ObjectStates restored successfully.");
00965 
00966     Set::getPool().restoreObjects(_savedState);
00967     Debug::debug(Debug::Engine, "Sets restored successfully.");
00968 
00969     TextObject::getPool().restoreObjects(_savedState);
00970     Debug::debug(Debug::Engine, "TextObjects restored successfully.");
00971 
00972     PrimitiveObject::getPool().restoreObjects(_savedState);
00973     Debug::debug(Debug::Engine, "PrimitiveObjects restored successfully.");
00974 
00975     Actor::getPool().restoreObjects(_savedState);
00976     Debug::debug(Debug::Engine, "Actors restored successfully.");
00977 
00978     if (getGameType() == GType_MONKEY4) {
00979         PoolSound::getPool().restoreObjects(_savedState);
00980         Debug::debug(Debug::Engine, "Pool sounds saved successfully.");
00981 
00982         Layer::getPool().restoreObjects(_savedState);
00983         Debug::debug(Debug::Engine, "Layers restored successfully.");
00984     }
00985 
00986     restoreGRIM();
00987     Debug::debug(Debug::Engine, "Engine restored successfully.");
00988 
00989     g_driver->restoreState(_savedState);
00990     Debug::debug(Debug::Engine, "Renderer restored successfully.");
00991 
00992     g_sound->restoreState(_savedState);
00993     Debug::debug(Debug::Engine, "iMuse restored successfully.");
00994 
00995     g_movie->restoreState(_savedState);
00996     Debug::debug(Debug::Engine, "Movie restored successfully.");
00997 
00998     _iris->restoreState(_savedState);
00999     Debug::debug(Debug::Engine, "Iris restored successfully.");
01000 
01001     lua_Restore(_savedState);
01002     Debug::debug(Debug::Engine, "Lua restored successfully.");
01003 
01004     delete _savedState;
01005 
01006     //Re-read the values, since we may have been in some state that changed them when loading the savegame,
01007     //e.g. running a cutscene, which sets the sfx volume to 0.
01008     _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
01009     _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
01010     _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
01011 
01012     LuaBase::instance()->postRestoreHandle();
01013     if (g_imuse)
01014         g_imuse->pause(false);
01015     g_movie->pause(false);
01016     debug("GrimEngine::savegameRestore() finished.");
01017 
01018     _shortFrame = true;
01019     clearEventQueue();
01020     invalidateActiveActorsList();
01021     buildActiveActorsList();
01022 
01023     _currSet->setupCamera();
01024     g_driver->set3DMode();
01025 }
01026 
01027 void GrimEngine::restoreGRIM() {
01028     _savedState->beginSection('GRIM');
01029 
01030     _mode = (EngineMode)_savedState->readLEUint32();
01031     _previousMode = (EngineMode)_savedState->readLEUint32();
01032 
01033     // Actor stuff
01034     int32 id = _savedState->readLESint32();
01035     if (id != 0) {
01036         _selectedActor = Actor::getPool().getObject(id);
01037     }
01038 
01039     //TextObject stuff
01040     _sayLineDefaults.setFGColor(_savedState->readColor());
01041     _sayLineDefaults.setFont(Font::getPool().getObject(_savedState->readLESint32()));
01042     _sayLineDefaults.setHeight(_savedState->readLESint32());
01043     _sayLineDefaults.setJustify(_savedState->readLESint32());
01044     _sayLineDefaults.setWidth(_savedState->readLESint32());
01045     _sayLineDefaults.setX(_savedState->readLESint32());
01046     _sayLineDefaults.setY(_savedState->readLESint32());
01047     _sayLineDefaults.setDuration(_savedState->readLESint32());
01048     if (_savedState->saveMinorVersion() > 5) {
01049         _movieSubtitle = TextObject::getPool().getObject(_savedState->readLESint32());
01050     }
01051 
01052     // Set stuff
01053     _currSet = Set::getPool().getObject(_savedState->readLESint32());
01054     if (_savedState->saveMinorVersion() > 4) {
01055         _movieSetup = _savedState->readString();
01056     } else {
01057         _movieSetup = _currSet->getCurrSetup()->_name;
01058     }
01059 
01060     _savedState->endSection();
01061 }
01062 
01063 void GrimEngine::storeSaveGameImage(SaveGame *state) {
01064     const Graphics::PixelFormat image_format = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
01065     int width = 250, height = 188;
01066     Bitmap *screenshot;
01067 
01068     debug("GrimEngine::StoreSaveGameImage() started.");
01069 
01070     screenshot = g_driver->getScreenshot(width, height, true);
01071     state->beginSection('SIMG');
01072     if (screenshot) {
01073         int size = screenshot->getWidth() * screenshot->getHeight();
01074         screenshot->setActiveImage(0);
01075         screenshot->getBitmapData()->convertToColorFormat(image_format);
01076         uint16 *data = (uint16 *)screenshot->getData().getRawBuffer();
01077         for (int l = 0; l < size; l++) {
01078             state->writeLEUint16(data[l]);
01079         }
01080     } else {
01081         error("Unable to store screenshot");
01082     }
01083     state->endSection();
01084     delete screenshot;
01085     debug("GrimEngine::StoreSaveGameImage() finished.");
01086 }
01087 
01088 void GrimEngine::savegameSave() {
01089     debug("GrimEngine::savegameSave() started.");
01090     _savegameSaveRequest = false;
01091     Common::String filename;
01092     if (_savegameFileName.size() == 0) {
01093         filename = "grim.sav";
01094     } else {
01095         filename = _savegameFileName;
01096     }
01097     if (getGameType() == GType_MONKEY4 && filename.contains('/')) {
01098         filename = Common::lastPathComponent(filename, '/');
01099     }
01100     _savedState = SaveGame::openForSaving(filename);
01101     if (!_savedState) {
01102         //TODO: Translate this!
01103         GUI::displayErrorDialog("Error: the game could not be saved.");
01104         return;
01105     }
01106 
01107     storeSaveGameImage(_savedState);
01108 
01109     if (g_imuse)
01110         g_imuse->pause(true);
01111     g_movie->pause(true);
01112 
01113     savegameCallback();
01114 
01115     Bitmap::getPool().saveObjects(_savedState);
01116     Debug::debug(Debug::Engine, "Bitmaps saved successfully.");
01117 
01118     Font::getPool().saveObjects(_savedState);
01119     Debug::debug(Debug::Engine, "Fonts saved successfully.");
01120 
01121     ObjectState::getPool().saveObjects(_savedState);
01122     Debug::debug(Debug::Engine, "ObjectStates saved successfully.");
01123 
01124     Set::getPool().saveObjects(_savedState);
01125     Debug::debug(Debug::Engine, "Sets saved successfully.");
01126 
01127     TextObject::getPool().saveObjects(_savedState);
01128     Debug::debug(Debug::Engine, "TextObjects saved successfully.");
01129 
01130     PrimitiveObject::getPool().saveObjects(_savedState);
01131     Debug::debug(Debug::Engine, "PrimitiveObjects saved successfully.");
01132 
01133     Actor::getPool().saveObjects(_savedState);
01134     Debug::debug(Debug::Engine, "Actors saved successfully.");
01135 
01136     if (getGameType() == GType_MONKEY4) {
01137         PoolSound::getPool().saveObjects(_savedState);
01138         Debug::debug(Debug::Engine, "Pool sounds saved successfully.");
01139 
01140         Layer::getPool().saveObjects(_savedState);
01141         Debug::debug(Debug::Engine, "Layers saved successfully.");
01142     }
01143 
01144     saveGRIM();
01145     Debug::debug(Debug::Engine, "Engine saved successfully.");
01146 
01147     g_driver->saveState(_savedState);
01148     Debug::debug(Debug::Engine, "Renderer saved successfully.");
01149 
01150     g_sound->saveState(_savedState);
01151     Debug::debug(Debug::Engine, "iMuse saved successfully.");
01152 
01153     g_movie->saveState(_savedState);
01154     Debug::debug(Debug::Engine, "Movie saved successfully.");
01155 
01156     _iris->saveState(_savedState);
01157     Debug::debug(Debug::Engine, "Iris saved successfully.");
01158 
01159     lua_Save(_savedState);
01160 
01161     delete _savedState;
01162 
01163     if (g_imuse)
01164         g_imuse->pause(false);
01165     g_movie->pause(false);
01166     debug("GrimEngine::savegameSave() finished.");
01167 
01168     _shortFrame = true;
01169     clearEventQueue();
01170 }
01171 
01172 void GrimEngine::saveGRIM() {
01173     _savedState->beginSection('GRIM');
01174 
01175     _savedState->writeLEUint32((uint32)_mode);
01176     _savedState->writeLEUint32((uint32)_previousMode);
01177 
01178     //Actor stuff
01179     if (_selectedActor) {
01180         _savedState->writeLESint32(_selectedActor->getId());
01181     } else {
01182         _savedState->writeLESint32(0);
01183     }
01184 
01185     //TextObject stuff
01186     _savedState->writeColor(_sayLineDefaults.getFGColor());
01187     _savedState->writeLESint32(_sayLineDefaults.getFont()->getId());
01188     _savedState->writeLESint32(_sayLineDefaults.getHeight());
01189     _savedState->writeLESint32(_sayLineDefaults.getJustify());
01190     _savedState->writeLESint32(_sayLineDefaults.getWidth());
01191     _savedState->writeLESint32(_sayLineDefaults.getX());
01192     _savedState->writeLESint32(_sayLineDefaults.getY());
01193     _savedState->writeLESint32(_sayLineDefaults.getDuration());
01194     _savedState->writeLESint32(_movieSubtitle ? _movieSubtitle->getId() : 0);
01195 
01196     //Set stuff
01197     _savedState->writeLESint32(_currSet->getId());
01198     _savedState->writeString(_movieSetup);
01199 
01200     _savedState->endSection();
01201 }
01202 
01203 Set *GrimEngine::findSet(const Common::String &name) {
01204     // Find scene object
01205     foreach (Set *s, Set::getPool()) {
01206         if (s->getName() == name)
01207             return s;
01208     }
01209     return nullptr;
01210 }
01211 
01212 void GrimEngine::setSetLock(const char *name, bool lockStatus) {
01213     Set *scene = findSet(name);
01214 
01215     if (!scene) {
01216         Debug::warning(Debug::Engine, "Set object '%s' not found in list", name);
01217         return;
01218     }
01219     // Change the locking status
01220     scene->_locked = lockStatus;
01221 }
01222 
01223 Set *GrimEngine::loadSet(const Common::String &name) {
01224     Set *s = findSet(name);
01225 
01226     if (!s) {
01227         Common::String filename(name);
01228         // EMI-scripts refer to their .setb files as .set
01229         if (g_grim->getGameType() == GType_MONKEY4) {
01230             filename += "b";
01231         }
01232         Common::SeekableReadStream *stream;
01233         stream = g_resourceloader->openNewStreamFile(filename.c_str());
01234         if (!stream)
01235             error("Could not find scene file %s", name.c_str());
01236 
01237         s = new Set(name, stream);
01238         delete stream;
01239     }
01240 
01241     return s;
01242 }
01243 
01244 void GrimEngine::setSet(const char *name) {
01245     setSet(loadSet(name));
01246 }
01247 
01248 void GrimEngine::setSet(Set *scene) {
01249     if (scene == _currSet)
01250         return;
01251 
01252     if (getGameType() == GType_MONKEY4) {
01253         foreach (PoolSound *s, PoolSound::getPool()) {
01254             s->stop();
01255         }
01256     }
01257     // Stop the actors. This fixes bug #289 (https://github.com/residualvm/residualvm/issues/289)
01258     // and it makes sense too, since when changing set the directions
01259     // and coords change too.
01260     foreach (Actor *a, Actor::getPool()) {
01261         a->stopWalking();
01262     }
01263 
01264     Set *lastSet = _currSet;
01265     _currSet = scene;
01266     _currSet->setSoundParameters(20, 127);
01267     // should delete the old scene after setting the new one
01268     if (lastSet && !lastSet->_locked) {
01269         delete lastSet;
01270     }
01271     _shortFrame = true;
01272     _setupChanged = true;
01273     invalidateActiveActorsList();
01274 }
01275 
01276 void GrimEngine::makeCurrentSetup(int num) {
01277     int prevSetup = g_grim->getCurrSet()->getSetup();
01278     if (prevSetup != num) {
01279         getCurrSet()->setSetup(num);
01280         getCurrSet()->setSoundParameters(20, 127);
01281         cameraChangeHandle(prevSetup, num);
01282         // here should be set sound position
01283 
01284         _setupChanged = true;
01285     }
01286 }
01287 
01288 void GrimEngine::setTextSpeed(int speed) {
01289     if (speed < 1)
01290         _textSpeed = 1;
01291     if (speed > 10)
01292         _textSpeed = 10;
01293     _textSpeed = speed;
01294 }
01295 
01296 float GrimEngine::getControlAxis(int num) {
01297     int idx = num - KEYCODE_AXIS_JOY1_X;
01298     if (idx >= 0 && idx < NUM_JOY_AXES) {
01299         return _joyAxisPosition[idx];
01300     }
01301     return 0;
01302 }
01303 
01304 bool GrimEngine::getControlState(int num) {
01305     return _controlsState[num];
01306 }
01307 
01308 float GrimEngine::getPerSecond(float rate) const {
01309     return rate * _frameTime / 1000;
01310 }
01311 
01312 void GrimEngine::invalidateActiveActorsList() {
01313     _buildActiveActorsList = true;
01314 }
01315 
01316 void GrimEngine::immediatelyRemoveActor(Actor *actor) {
01317     _activeActors.remove(actor);
01318     _talkingActors.remove(actor);
01319 }
01320 
01321 void GrimEngine::buildActiveActorsList() {
01322     if (!_buildActiveActorsList) {
01323         return;
01324     }
01325 
01326     _activeActors.clear();
01327     foreach (Actor *a, Actor::getPool()) {
01328         if (((_mode == NormalMode || _mode == DrawMode) && a->isDrawableInSet(_currSet->getName())) ||
01329             a->isInOverworld()) {
01330             _activeActors.push_back(a);
01331         }
01332     }
01333     _buildActiveActorsList = false;
01334 }
01335 
01336 void GrimEngine::addTalkingActor(Actor *a) {
01337     _talkingActors.push_back(a);
01338 }
01339 
01340 bool GrimEngine::areActorsTalking() const {
01341     //This takes into account that there may be actors which are still talking, but in the background.
01342     bool talking = false;
01343     foreach (Actor *a, _talkingActors) {
01344         if (a->isTalkingForeground()) {
01345             talking = true;
01346             break;
01347         }
01348     }
01349     return talking;
01350 }
01351 
01352 void GrimEngine::setMovieSubtitle(TextObject *to) {
01353     if (_movieSubtitle != to) {
01354         delete _movieSubtitle;
01355         _movieSubtitle = to;
01356     }
01357 }
01358 
01359 void GrimEngine::drawMovieSubtitle() {
01360     if (_movieSubtitle)
01361         _movieSubtitle->draw();
01362 }
01363 
01364 void GrimEngine::setMovieSetup() {
01365     _movieSetup = _currSet->getCurrSetup()->_name;
01366 }
01367 
01368 void GrimEngine::setMode(EngineMode mode) {
01369     _mode = mode;
01370     invalidateActiveActorsList();
01371 }
01372 
01373 void GrimEngine::clearEventQueue() {
01374     Common::Event event;
01375     while (g_system->getEventManager()->pollEvent(event)) {
01376     }
01377 
01378     for (int i = 0; i < KEYCODE_EXTRA_LAST; ++i) {
01379         _controlsState[i] = false;
01380     }
01381 }
01382 
01383 bool GrimEngine::hasFeature(EngineFeature f) const {
01384     return
01385         (f == kSupportsRTL) ||
01386         (f == kSupportsLoadingDuringRuntime) ||
01387         (f == kSupportsJoystick);
01388 }
01389 
01390 void GrimEngine::pauseEngineIntern(bool pause) {
01391     if (g_imuse)
01392         g_imuse->pause(pause);
01393     if (g_movie)
01394         g_movie->pause(pause);
01395 
01396     if (pause) {
01397         _pauseStartTime = _system->getMillis();
01398     } else {
01399         _frameStart += _system->getMillis() - _pauseStartTime;
01400     }
01401 }
01402 
01403 
01404 Graphics::Surface *loadPNG(const Common::String &filename) {
01405     Image::PNGDecoder d;
01406     Common::SeekableReadStream *s = SearchMan.createReadStreamForMember(filename);
01407     if (!s)
01408         return nullptr;
01409     d.loadStream(*s);
01410     delete s;
01411 
01412     Graphics::Surface *srf = d.getSurface()->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
01413     return srf;
01414 }
01415 
01416 void GrimEngine::setSideTextures(const Common::String &setup) {
01417     if (! g_system->hasFeature(OSystem::kFeatureSideTextures))
01418             return;
01419     Graphics::Surface *t1 = loadPNG(Common::String::format("%s_left.png", setup.c_str()));
01420     Graphics::Surface *t2 = loadPNG(Common::String::format("%s_right.png", setup.c_str()));
01421     g_system->suggestSideTextures(t1, t2);
01422     if (t1)
01423         t1->free();
01424     if (t2)
01425         t2->free();
01426     delete t1;
01427     delete t2;
01428 }
01429 
01430 
01431 void GrimEngine::debugLua(const Common::String &str) {
01432     lua_dostring(str.c_str());
01433 }
01434 
01435 } // end of namespace Grim


Generated on Sat May 30 2020 05:00:46 for ResidualVM by doxygen 1.7.1
curved edge   curved edge