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

EventRecorder.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM 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 
00024 #include "gui/EventRecorder.h"
00025 
00026 #ifdef ENABLE_EVENTRECORDER
00027 
00028 namespace Common {
00029 DECLARE_SINGLETON(GUI::EventRecorder);
00030 }
00031 
00032 #include "common/debug-channels.h"
00033 #include "backends/timer/sdl/sdl-timer.h"
00034 #include "backends/mixer/sdl/sdl-mixer.h"
00035 #include "common/config-manager.h"
00036 #include "common/md5.h"
00037 #include "gui/gui-manager.h"
00038 #include "gui/widget.h"
00039 #include "gui/onscreendialog.h"
00040 #include "common/random.h"
00041 #include "common/savefile.h"
00042 #include "common/textconsole.h"
00043 #include "graphics/thumbnail.h"
00044 #include "graphics/surface.h"
00045 #include "graphics/scaler.h"
00046 
00047 namespace GUI {
00048 
00049 
00050 const int kMaxRecordsNames = 0x64;
00051 const int kDefaultScreenshotPeriod = 60000;
00052 
00053 uint32 readTime(Common::ReadStream *inFile) {
00054     uint32 d = inFile->readByte();
00055     if (d == 0xff) {
00056         d = inFile->readUint32LE();
00057     }
00058 
00059     return d;
00060 }
00061 
00062 void writeTime(Common::WriteStream *outFile, uint32 d) {
00063         //Simple RLE compression
00064     if (d >= 0xff) {
00065         outFile->writeByte(0xff);
00066         outFile->writeUint32LE(d);
00067     } else {
00068         outFile->writeByte(d);
00069     }
00070 }
00071 
00072 EventRecorder::EventRecorder() {
00073     _timerManager = NULL;
00074     _recordMode = kPassthrough;
00075     _fakeMixerManager = NULL;
00076     _initialized = false;
00077     _needRedraw = false;
00078     _fastPlayback = false;
00079 
00080     _fakeTimer = 0;
00081     _savedState = false;
00082     _needcontinueGame = false;
00083     _temporarySlot = 0;
00084     _realSaveManager = 0;
00085     _realMixerManager = 0;
00086     _controlPanel = 0;
00087     _lastMillis = 0;
00088     _lastScreenshotTime = 0;
00089     _screenshotPeriod = 0;
00090     _playbackFile = 0;
00091 
00092     DebugMan.addDebugChannel(kDebugLevelEventRec, "EventRec", "Event recorder debug level");
00093 }
00094 
00095 EventRecorder::~EventRecorder() {
00096     if (_timerManager != NULL) {
00097         delete _timerManager;
00098     }
00099 }
00100 
00101 void EventRecorder::deinit() {
00102     if (!_initialized) {
00103         return;
00104     }
00105     setFileHeader();
00106     _needRedraw = false;
00107     _initialized = false;
00108     _recordMode = kPassthrough;
00109     delete _fakeMixerManager;
00110     _fakeMixerManager = NULL;
00111     _controlPanel->close();
00112     delete _controlPanel;
00113     debugC(1, kDebugLevelEventRec, "playback:action=stopplayback");
00114     g_system->getEventManager()->getEventDispatcher()->unregisterSource(this);
00115     _recordMode = kPassthrough;
00116     _playbackFile->close();
00117     delete _playbackFile;
00118     switchMixer();
00119     switchTimerManagers();
00120     DebugMan.disableDebugChannel("EventRec");
00121 }
00122 
00123 void EventRecorder::processMillis(uint32 &millis, bool skipRecord) {
00124     if (!_initialized) {
00125         return;
00126     }
00127     if (skipRecord) {
00128         millis = _fakeTimer;
00129         return;
00130     }
00131     if (_recordMode == kRecorderPlaybackPause) {
00132         millis = _fakeTimer;
00133     }
00134     uint32 millisDelay;
00135     Common::RecorderEvent timerEvent;
00136     switch (_recordMode) {
00137     case kRecorderRecord:
00138         updateSubsystems();
00139         millisDelay = millis - _lastMillis;
00140         _lastMillis = millis;
00141         _fakeTimer += millisDelay;
00142         _controlPanel->setReplayedTime(_fakeTimer);
00143         timerEvent.recordedtype = Common::kRecorderEventTypeTimer;
00144         timerEvent.time = _fakeTimer;
00145         _playbackFile->writeEvent(timerEvent);
00146         takeScreenshot();
00147         _timerManager->handler();
00148         break;
00149     case kRecorderPlayback:
00150         updateSubsystems();
00151         if (_nextEvent.recordedtype == Common::kRecorderEventTypeTimer) {
00152             _fakeTimer = _nextEvent.time;
00153             _nextEvent = _playbackFile->getNextEvent();
00154             _timerManager->handler();
00155         } else {
00156             if (_nextEvent.type == Common::EVENT_RTL) {
00157                 error("playback:action=stopplayback");
00158             } else {
00159                 uint32 seconds = _fakeTimer / 1000;
00160                 Common::String screenTime = Common::String::format("%.2d:%.2d:%.2d", seconds / 3600 % 24, seconds / 60 % 60, seconds % 60);
00161                 error("playback:action=error reason=\"synchronization error\" time = %s", screenTime.c_str());
00162             }
00163         }
00164         millis = _fakeTimer;
00165         _controlPanel->setReplayedTime(_fakeTimer);
00166         break;
00167     case kRecorderPlaybackPause:
00168         millis = _fakeTimer;
00169         break;
00170     default:
00171         break;
00172     }
00173 }
00174 
00175 bool EventRecorder::processDelayMillis() {
00176     return _fastPlayback;
00177 }
00178 
00179 void EventRecorder::checkForKeyCode(const Common::Event &event) {
00180     if ((event.type == Common::EVENT_KEYDOWN) && (event.kbd.flags & Common::KBD_CTRL) && (event.kbd.keycode == Common::KEYCODE_p) && (!event.kbdRepeat)) {
00181         togglePause();
00182     }
00183 }
00184 
00185 bool EventRecorder::pollEvent(Common::Event &ev) {
00186     if ((_recordMode != kRecorderPlayback) || !_initialized)
00187         return false;
00188 
00189     if ((_nextEvent.recordedtype == Common::kRecorderEventTypeTimer) || (_nextEvent.type ==  Common::EVENT_INVALID)) {
00190         return false;
00191     }
00192 
00193     switch (_nextEvent.type) {
00194     case Common::EVENT_MOUSEMOVE:
00195     case Common::EVENT_LBUTTONDOWN:
00196     case Common::EVENT_LBUTTONUP:
00197     case Common::EVENT_RBUTTONDOWN:
00198     case Common::EVENT_RBUTTONUP:
00199     case Common::EVENT_WHEELUP:
00200     case Common::EVENT_WHEELDOWN:
00201         g_system->warpMouse(_nextEvent.mouse.x, _nextEvent.mouse.y);
00202         break;
00203     default:
00204         break;
00205     }
00206     ev = _nextEvent;
00207     _nextEvent = _playbackFile->getNextEvent();
00208     return true;
00209 }
00210 
00211 void EventRecorder::switchFastMode() {
00212     if (_recordMode == kRecorderPlaybackPause) {
00213         _fastPlayback = !_fastPlayback;
00214     }
00215 }
00216 
00217 void EventRecorder::togglePause() {
00218     RecordMode oldState;
00219     switch (_recordMode) {
00220     case kRecorderPlayback:
00221     case kRecorderRecord:
00222         oldState = _recordMode;
00223         _recordMode = kRecorderPlaybackPause;
00224         _controlPanel->runModal();
00225         _recordMode = oldState;
00226         _initialized = true;
00227         break;
00228     case kRecorderPlaybackPause:
00229         _controlPanel->close();
00230         break;
00231     default:
00232         break;
00233     }
00234 }
00235 
00236 void EventRecorder::RegisterEventSource() {
00237     g_system->getEventManager()->getEventDispatcher()->registerMapper(this, false);
00238 }
00239 
00240 uint32 EventRecorder::getRandomSeed(const Common::String &name) {
00241     uint32 result = g_system->getMillis();
00242     if (_recordMode == kRecorderRecord) {
00243         _playbackFile->getHeader().randomSourceRecords[name] = result;
00244     } else if (_recordMode == kRecorderPlayback) {
00245         result = _playbackFile->getHeader().randomSourceRecords[name];
00246     }
00247     return result;
00248 }
00249 
00250 Common::String EventRecorder::generateRecordFileName(const Common::String &target) {
00251     Common::String pattern(target+".r??");
00252     Common::StringArray files = g_system->getSavefileManager()->listSavefiles(pattern);
00253     for (int i = 0; i < kMaxRecordsNames; ++i) {
00254         Common::String recordName = Common::String::format("%s.r%02d", target.c_str(), i);
00255         if (find(files.begin(), files.end(), recordName) != files.end()) {
00256             continue;
00257         }
00258         return recordName;
00259     }
00260     return "";
00261 }
00262 
00263 
00264 void EventRecorder::init(Common::String recordFileName, RecordMode mode) {
00265     _fakeMixerManager = new NullSdlMixerManager();
00266     _fakeMixerManager->init();
00267     _fakeMixerManager->suspendAudio();
00268     _fakeTimer = 0;
00269     _lastMillis = g_system->getMillis();
00270     _playbackFile = new Common::PlaybackFile();
00271     _lastScreenshotTime = 0;
00272     _recordMode = mode;
00273     _needcontinueGame = false;
00274     if (ConfMan.hasKey("disable_display")) {
00275         DebugMan.enableDebugChannel("EventRec");
00276         gDebugLevel = 1;
00277     }
00278     if (_recordMode == kRecorderPlayback) {
00279         debugC(1, kDebugLevelEventRec, "playback:action=\"Load file\" filename=%s", recordFileName.c_str());
00280     }
00281     g_system->getEventManager()->getEventDispatcher()->registerSource(this, false);
00282     _screenshotPeriod = ConfMan.getInt("screenshot_period");
00283     if (_screenshotPeriod == 0) {
00284         _screenshotPeriod = kDefaultScreenshotPeriod;
00285     }
00286     if (!openRecordFile(recordFileName)) {
00287         deinit();
00288         error("playback:action=error reason=\"Record file loading error\"");
00289         return;
00290     }
00291     if (_recordMode != kPassthrough) {
00292         _controlPanel = new GUI::OnScreenDialog(_recordMode == kRecorderRecord);
00293     }
00294     if (_recordMode == kRecorderPlayback) {
00295         applyPlaybackSettings();
00296         _nextEvent = _playbackFile->getNextEvent();
00297     }
00298     if (_recordMode == kRecorderRecord) {
00299         getConfig();
00300     }
00301 
00302     switchMixer();
00303     switchTimerManagers();
00304     _needRedraw = true;
00305     _initialized = true;
00306 }
00307 
00308 
00316 bool EventRecorder::openRecordFile(const Common::String &fileName) {
00317     bool result;
00318     switch (_recordMode) {
00319     case kRecorderRecord:
00320         return _playbackFile->openWrite(fileName);
00321     case kRecorderPlayback:
00322         _recordMode = kPassthrough;
00323         result = _playbackFile->openRead(fileName);
00324         _recordMode = kRecorderPlayback;
00325         return result;
00326     default:
00327         return false;
00328     }
00329     return true;
00330 }
00331 
00332 bool EventRecorder::checkGameHash(const ADGameDescription *gameDesc) {
00333     if (_playbackFile->getHeader().hashRecords.size() == 0) {
00334         warning("Engine doesn't contain description table");
00335         return false;
00336     }
00337     for (const ADGameFileDescription *fileDesc = gameDesc->filesDescriptions; fileDesc->fileName; fileDesc++) {
00338         if (_playbackFile->getHeader().hashRecords.find(fileDesc->fileName) == _playbackFile->getHeader().hashRecords.end()) {
00339             warning("MD5 hash for file %s not found in record file", fileDesc->fileName);
00340             debugC(1, kDebugLevelEventRec, "playback:action=\"Check game hash\" filename=%s filehash=%s storedhash=\"\" result=different", fileDesc->fileName, fileDesc->md5);
00341             return false;
00342         }
00343         if (_playbackFile->getHeader().hashRecords[fileDesc->fileName] != fileDesc->md5) {
00344             warning("Incorrect version of game file %s. Stored MD5 is %s. MD5 of loaded game is %s", fileDesc->fileName, _playbackFile->getHeader().hashRecords[fileDesc->fileName].c_str(), fileDesc->md5);
00345             debugC(1, kDebugLevelEventRec, "playback:action=\"Check game hash\" filename=%s filehash=%s storedhash=%s result=different", fileDesc->fileName, fileDesc->md5, _playbackFile->getHeader().hashRecords[fileDesc->fileName].c_str());
00346             return false;
00347         }
00348         debugC(1, kDebugLevelEventRec, "playback:action=\"Check game hash\" filename=%s filehash=%s storedhash=%s result=equal", fileDesc->fileName, fileDesc->md5, _playbackFile->getHeader().hashRecords[fileDesc->fileName].c_str());
00349     }
00350     return true;
00351 }
00352 
00353 void EventRecorder::registerMixerManager(SdlMixerManager *mixerManager) {
00354     _realMixerManager = mixerManager;
00355 }
00356 
00357 void EventRecorder::switchMixer() {
00358     if (_recordMode == kPassthrough) {
00359         _realMixerManager->resumeAudio();
00360     } else {
00361         _realMixerManager->suspendAudio();
00362         _fakeMixerManager->resumeAudio();
00363     }
00364 }
00365 
00366 SdlMixerManager *EventRecorder::getMixerManager() {
00367     if (_recordMode == kPassthrough) {
00368         return _realMixerManager;
00369     } else {
00370         return _fakeMixerManager;
00371     }
00372 }
00373 
00374 void EventRecorder::getConfigFromDomain(const Common::ConfigManager::Domain *domain) {
00375     for (Common::ConfigManager::Domain::const_iterator entry = domain->begin(); entry!= domain->end(); ++entry) {
00376         _playbackFile->getHeader().settingsRecords[entry->_key] = entry->_value;
00377     }
00378 }
00379 
00380 void EventRecorder::getConfig() {
00381     getConfigFromDomain(ConfMan.getDomain(ConfMan.kApplicationDomain));
00382     getConfigFromDomain(ConfMan.getActiveDomain());
00383     _playbackFile->getHeader().settingsRecords["save_slot"] = ConfMan.get("save_slot");
00384 }
00385 
00386 
00387 void EventRecorder::applyPlaybackSettings() {
00388     for (Common::StringMap::const_iterator i = _playbackFile->getHeader().settingsRecords.begin(); i != _playbackFile->getHeader().settingsRecords.end(); ++i) {
00389         Common::String currentValue = ConfMan.get(i->_key);
00390         if (currentValue != i->_value) {
00391             ConfMan.set(i->_key, i->_value, ConfMan.kTransientDomain);
00392             debugC(1, kDebugLevelEventRec, "playback:action=\"Apply settings\" key=%s storedvalue=%s currentvalue=%s result=different", i->_key.c_str(), i->_value.c_str(), currentValue.c_str());
00393         } else {
00394             debugC(1, kDebugLevelEventRec, "playback:action=\"Apply settings\" key=%s storedvalue=%s currentvalue=%s result=equal", i->_key.c_str(), i->_value.c_str(), currentValue.c_str());
00395         }
00396     }
00397     removeDifferentEntriesInDomain(ConfMan.getDomain(ConfMan.kApplicationDomain));
00398     removeDifferentEntriesInDomain(ConfMan.getActiveDomain());
00399 }
00400 
00401 void EventRecorder::removeDifferentEntriesInDomain(Common::ConfigManager::Domain *domain) {
00402     for (Common::ConfigManager::Domain::const_iterator entry = domain->begin(); entry!= domain->end(); ++entry) {
00403         if (_playbackFile->getHeader().settingsRecords.find(entry->_key) == _playbackFile->getHeader().settingsRecords.end()) {
00404             debugC(1, kDebugLevelEventRec, "playback:action=\"Apply settings\" checksettings:key=%s storedvalue=%s currentvalue="" result=different", entry->_key.c_str(), entry->_value.c_str());
00405             domain->erase(entry->_key);
00406         }
00407     }
00408 }
00409 
00410 DefaultTimerManager *EventRecorder::getTimerManager() {
00411     return _timerManager;
00412 }
00413 
00414 void EventRecorder::registerTimerManager(DefaultTimerManager *timerManager) {
00415     _timerManager = timerManager;
00416 }
00417 
00418 void EventRecorder::switchTimerManagers() {
00419     delete _timerManager;
00420     if (_recordMode == kPassthrough) {
00421         _timerManager = new SdlTimerManager();
00422     } else {
00423         _timerManager = new DefaultTimerManager();
00424     }
00425 }
00426 
00427 void EventRecorder::updateSubsystems() {
00428     if (_recordMode == kPassthrough) {
00429         return;
00430     }
00431     RecordMode oldRecordMode = _recordMode;
00432     _recordMode = kPassthrough;
00433     _fakeMixerManager->update();
00434     _recordMode = oldRecordMode;
00435 }
00436 
00437 Common::List<Common::Event> EventRecorder::mapEvent(const Common::Event &ev, Common::EventSource *source) {
00438     if ((!_initialized) && (_recordMode != kRecorderPlaybackPause)) {
00439         return DefaultEventMapper::mapEvent(ev, source);
00440     }
00441 
00442     checkForKeyCode(ev);
00443     Common::Event evt = ev;
00444     evt.mouse.x = evt.mouse.x * (g_system->getOverlayWidth() / g_system->getWidth());
00445     evt.mouse.y = evt.mouse.y * (g_system->getOverlayHeight() / g_system->getHeight());
00446     switch (_recordMode) {
00447     case kRecorderPlayback:
00448         if (ev.kbdRepeat != true) {
00449             return Common::List<Common::Event>();
00450         }
00451         return Common::DefaultEventMapper::mapEvent(ev, source);
00452         break;
00453     case kRecorderRecord:
00454         g_gui.processEvent(evt, _controlPanel);
00455         if (((evt.type == Common::EVENT_LBUTTONDOWN) || (evt.type == Common::EVENT_LBUTTONUP) || (evt.type == Common::EVENT_MOUSEMOVE)) && _controlPanel->isMouseOver()) {
00456             return Common::List<Common::Event>();
00457         } else {
00458             Common::RecorderEvent e;
00459             memcpy(&e, &ev, sizeof(ev));
00460             e.recordedtype = Common::kRecorderEventTypeNormal;
00461             e.time = _fakeTimer;
00462             _playbackFile->writeEvent(e);
00463             return DefaultEventMapper::mapEvent(ev, source);
00464         }
00465         break;
00466     case kRecorderPlaybackPause: {
00467         Common::Event dialogEvent;
00468         if (_controlPanel->isEditDlgVisible()) {
00469             dialogEvent = ev;
00470         } else {
00471             dialogEvent = evt;
00472         }
00473         g_gui.processEvent(dialogEvent, _controlPanel->getActiveDlg());
00474         if (((dialogEvent.type == Common::EVENT_LBUTTONDOWN) || (dialogEvent.type == Common::EVENT_LBUTTONUP) || (dialogEvent.type == Common::EVENT_MOUSEMOVE)) && _controlPanel->isMouseOver()) {
00475             return Common::List<Common::Event>();
00476         }
00477         return Common::DefaultEventMapper::mapEvent(dialogEvent, source);
00478     }
00479         break;
00480     default:
00481         return Common::DefaultEventMapper::mapEvent(ev, source);
00482     }
00483 
00484     return Common::DefaultEventMapper::mapEvent(ev, source);
00485 }
00486 
00487 void EventRecorder::setGameMd5(const ADGameDescription *gameDesc) {
00488     for (const ADGameFileDescription *fileDesc = gameDesc->filesDescriptions; fileDesc->fileName; fileDesc++) {
00489         if (fileDesc->md5 != NULL) {
00490             _playbackFile->getHeader().hashRecords[fileDesc->fileName] = fileDesc->md5;
00491         }
00492     }
00493 }
00494 
00495 void EventRecorder::processGameDescription(const ADGameDescription *desc) {
00496     if (_recordMode == kRecorderRecord) {
00497         setGameMd5(desc);
00498     }
00499     if ((_recordMode == kRecorderPlayback) && !checkGameHash(desc)) {
00500         deinit();
00501         error("playback:action=error reason=\"\"");
00502     }
00503 }
00504 
00505 void EventRecorder::deleteRecord(const Common::String& fileName) {
00506     g_system->getSavefileManager()->removeSavefile(fileName);
00507 }
00508 
00509 void EventRecorder::takeScreenshot() {
00510     if ((_fakeTimer - _lastScreenshotTime) > _screenshotPeriod) {
00511         Graphics::Surface screen;
00512         uint8 md5[16];
00513         if (grabScreenAndComputeMD5(screen, md5)) {
00514             _lastScreenshotTime = _fakeTimer;
00515             _playbackFile->saveScreenShot(screen, md5);
00516             screen.free();
00517         }
00518     }
00519 }
00520 
00521 bool EventRecorder::grabScreenAndComputeMD5(Graphics::Surface &screen, uint8 md5[16]) {
00522     if (!createScreenShot(screen)) {
00523         warning("Can't save screenshot");
00524         return false;
00525     }
00526     Common::MemoryReadStream bitmapStream((const byte*)screen.getPixels(), screen.w * screen.h * screen.format.bytesPerPixel);
00527     computeStreamMD5(bitmapStream, md5);
00528     return true;
00529 }
00530 
00531 Common::SeekableReadStream *EventRecorder::processSaveStream(const Common::String &fileName) {
00532     Common::InSaveFile *saveFile;
00533     switch (_recordMode) {
00534     case kRecorderPlayback:
00535         debugC(1, kDebugLevelEventRec, "playback:action=\"Process save file\" filename=%s len=%d", fileName.c_str(), _playbackFile->getHeader().saveFiles[fileName].size);
00536         return new Common::MemoryReadStream(_playbackFile->getHeader().saveFiles[fileName].buffer, _playbackFile->getHeader().saveFiles[fileName].size);
00537     case kRecorderRecord:
00538         saveFile = _realSaveManager->openForLoading(fileName);
00539         if (saveFile != NULL) {
00540             _playbackFile->addSaveFile(fileName, saveFile);
00541             saveFile->seek(0);
00542         }
00543         return saveFile;
00544     default:
00545         return NULL;
00546         break;
00547     }
00548 }
00549 
00550 Common::SaveFileManager *EventRecorder::getSaveManager(Common::SaveFileManager *realSaveManager) {
00551     _realSaveManager = realSaveManager;
00552     if (_recordMode != kPassthrough) {
00553         return &_fakeSaveManager;
00554     } else {
00555         return realSaveManager;
00556     }
00557 }
00558 
00559 void EventRecorder::preDrawOverlayGui() {
00560     if ((_initialized) || (_needRedraw)) {
00561         RecordMode oldMode = _recordMode;
00562         _recordMode = kPassthrough;
00563         g_system->showOverlay();
00564         g_gui.theme()->clearAll();
00565         g_gui.theme()->drawToBackbuffer();
00566         _controlPanel->drawDialog(kDrawLayerBackground);
00567         g_gui.theme()->drawToScreen();
00568         g_gui.theme()->copyBackBufferToScreen();
00569         _controlPanel->drawDialog(kDrawLayerForeground);
00570         g_gui.theme()->updateScreen();
00571         _recordMode = oldMode;
00572     }
00573 }
00574 
00575 void EventRecorder::postDrawOverlayGui() {
00576     if ((_initialized) || (_needRedraw)) {
00577         RecordMode oldMode = _recordMode;
00578         _recordMode = kPassthrough;
00579         g_system->hideOverlay();
00580         _recordMode = oldMode;
00581     }
00582 }
00583 
00584 Common::StringArray EventRecorder::listSaveFiles(const Common::String &pattern) {
00585     if (_recordMode == kRecorderPlayback) {
00586         Common::StringArray result;
00587         for (Common::HashMap<Common::String, Common::PlaybackFile::SaveFileBuffer>::iterator  i = _playbackFile->getHeader().saveFiles.begin(); i != _playbackFile->getHeader().saveFiles.end(); ++i) {
00588             if (i->_key.matchString(pattern, false, true)) {
00589                 result.push_back(i->_key);
00590             }
00591         }
00592         return result;
00593     } else {
00594         return _realSaveManager->listSavefiles(pattern);
00595     }
00596 }
00597 
00598 void EventRecorder::setFileHeader() {
00599     if (_recordMode != kRecorderRecord) {
00600         return;
00601     }
00602     TimeDate t;
00603     PlainGameDescriptor desc = EngineMan.findGame(ConfMan.getActiveDomainName());
00604     g_system->getTimeAndDate(t);
00605     if (_author.empty()) {
00606         setAuthor("Unknown Author");
00607     }
00608     if (_name.empty()) {
00609         g_eventRec.setName(Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description);
00610     }
00611     _playbackFile->getHeader().author = _author;
00612     _playbackFile->getHeader().notes = _desc;
00613     _playbackFile->getHeader().name = _name;
00614 }
00615 
00616 SDL_Surface *EventRecorder::getSurface(int width, int height) {
00617     // Create a RGB565 surface of the requested dimensions.
00618     return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 16, 0xF800, 0x07E0, 0x001F, 0x0000);
00619 }
00620 
00621 bool EventRecorder::switchMode() {
00622     const Common::String gameId = ConfMan.get("gameid");
00623     const Plugin *plugin = nullptr;
00624     EngineMan.findGame(gameId, &plugin);
00625     bool metaInfoSupport = plugin->get<MetaEngine>().hasFeature(MetaEngine::kSavesSupportMetaInfo);
00626     bool featuresSupport = metaInfoSupport &&
00627                           g_engine->canSaveGameStateCurrently() &&
00628                           plugin->get<MetaEngine>().hasFeature(MetaEngine::kSupportsListSaves) &&
00629                           plugin->get<MetaEngine>().hasFeature(MetaEngine::kSupportsDeleteSave);
00630     if (!featuresSupport) {
00631         return false;
00632     }
00633 
00634     int emptySlot = 1;
00635     SaveStateList saveList = plugin->get<MetaEngine>().listSaves(gameId.c_str());
00636     for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x) {
00637         int saveSlot = x->getSaveSlot();
00638         if (saveSlot == 0) {
00639             continue;
00640         }
00641         if (emptySlot != saveSlot) {
00642             break;
00643         }
00644         emptySlot++;
00645     }
00646     Common::String saveName;
00647     if (emptySlot >= 0) {
00648         saveName = Common::String::format("Save %d", emptySlot + 1);
00649         Common::Error status = g_engine->saveGameState(emptySlot, saveName);
00650         if (status.getCode() == Common::kNoError) {
00651             Common::Event eventRTL;
00652             eventRTL.type = Common::EVENT_RTL;
00653             g_system->getEventManager()->pushEvent(eventRTL);
00654         }
00655     }
00656     ConfMan.set("record_mode", "", Common::ConfigManager::kTransientDomain);
00657     ConfMan.setInt("save_slot", emptySlot, Common::ConfigManager::kTransientDomain);
00658     _needcontinueGame = true;
00659     return true;
00660 }
00661 
00662 bool EventRecorder::checkForContinueGame() {
00663     bool result = _needcontinueGame;
00664     _needcontinueGame = false;
00665     return result;
00666 }
00667 
00668 void EventRecorder::deleteTemporarySave() {
00669     if (_temporarySlot == -1) return;
00670     const Common::String gameId = ConfMan.get("gameid");
00671     const Plugin *plugin = 0;
00672     EngineMan.findGame(gameId, &plugin);
00673      plugin->get<MetaEngine>().removeSaveState(gameId.c_str(), _temporarySlot);
00674     _temporarySlot = -1;
00675 }
00676 
00677 } // End of namespace GUI
00678 
00679 #endif // ENABLE_EVENTRECORDER


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