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


Generated on Sat May 18 2019 05:01:04 for ResidualVM by doxygen 1.7.1
curved edge   curved edge