mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-04 01:46:42 +00:00
bb813719b5
The engine ID identifies which engine should be used to launch the target. Also remove the 'single ID' system. Different games from engines that used that system now have different game IDs. Also-By: Matthew Hoops <clone2727@gmail.com>
678 lines
21 KiB
C++
678 lines
21 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "gui/EventRecorder.h"
|
|
|
|
#ifdef ENABLE_EVENTRECORDER
|
|
|
|
namespace Common {
|
|
DECLARE_SINGLETON(GUI::EventRecorder);
|
|
}
|
|
|
|
#include "common/debug-channels.h"
|
|
#include "backends/timer/sdl/sdl-timer.h"
|
|
#include "backends/mixer/sdl/sdl-mixer.h"
|
|
#include "common/config-manager.h"
|
|
#include "common/md5.h"
|
|
#include "gui/gui-manager.h"
|
|
#include "gui/widget.h"
|
|
#include "gui/onscreendialog.h"
|
|
#include "common/random.h"
|
|
#include "common/savefile.h"
|
|
#include "common/textconsole.h"
|
|
#include "graphics/thumbnail.h"
|
|
#include "graphics/surface.h"
|
|
#include "graphics/scaler.h"
|
|
|
|
namespace GUI {
|
|
|
|
|
|
const int kMaxRecordsNames = 0x64;
|
|
const int kDefaultScreenshotPeriod = 60000;
|
|
|
|
uint32 readTime(Common::ReadStream *inFile) {
|
|
uint32 d = inFile->readByte();
|
|
if (d == 0xff) {
|
|
d = inFile->readUint32LE();
|
|
}
|
|
|
|
return d;
|
|
}
|
|
|
|
void writeTime(Common::WriteStream *outFile, uint32 d) {
|
|
//Simple RLE compression
|
|
if (d >= 0xff) {
|
|
outFile->writeByte(0xff);
|
|
outFile->writeUint32LE(d);
|
|
} else {
|
|
outFile->writeByte(d);
|
|
}
|
|
}
|
|
|
|
EventRecorder::EventRecorder() {
|
|
_timerManager = NULL;
|
|
_recordMode = kPassthrough;
|
|
_fakeMixerManager = NULL;
|
|
_initialized = false;
|
|
_needRedraw = false;
|
|
_fastPlayback = false;
|
|
|
|
_fakeTimer = 0;
|
|
_savedState = false;
|
|
_needcontinueGame = false;
|
|
_temporarySlot = 0;
|
|
_realSaveManager = 0;
|
|
_realMixerManager = 0;
|
|
_controlPanel = 0;
|
|
_lastMillis = 0;
|
|
_lastScreenshotTime = 0;
|
|
_screenshotPeriod = 0;
|
|
_playbackFile = 0;
|
|
|
|
DebugMan.addDebugChannel(kDebugLevelEventRec, "EventRec", "Event recorder debug level");
|
|
}
|
|
|
|
EventRecorder::~EventRecorder() {
|
|
if (_timerManager != NULL) {
|
|
delete _timerManager;
|
|
}
|
|
}
|
|
|
|
void EventRecorder::deinit() {
|
|
if (!_initialized) {
|
|
return;
|
|
}
|
|
setFileHeader();
|
|
_needRedraw = false;
|
|
_initialized = false;
|
|
_recordMode = kPassthrough;
|
|
delete _fakeMixerManager;
|
|
_fakeMixerManager = NULL;
|
|
_controlPanel->close();
|
|
delete _controlPanel;
|
|
debugC(1, kDebugLevelEventRec, "playback:action=stopplayback");
|
|
g_system->getEventManager()->getEventDispatcher()->unregisterSource(this);
|
|
_recordMode = kPassthrough;
|
|
_playbackFile->close();
|
|
delete _playbackFile;
|
|
switchMixer();
|
|
switchTimerManagers();
|
|
DebugMan.disableDebugChannel("EventRec");
|
|
}
|
|
|
|
void EventRecorder::processMillis(uint32 &millis, bool skipRecord) {
|
|
if (!_initialized) {
|
|
return;
|
|
}
|
|
if (skipRecord) {
|
|
millis = _fakeTimer;
|
|
return;
|
|
}
|
|
if (_recordMode == kRecorderPlaybackPause) {
|
|
millis = _fakeTimer;
|
|
}
|
|
uint32 millisDelay;
|
|
Common::RecorderEvent timerEvent;
|
|
switch (_recordMode) {
|
|
case kRecorderRecord:
|
|
updateSubsystems();
|
|
millisDelay = millis - _lastMillis;
|
|
_lastMillis = millis;
|
|
_fakeTimer += millisDelay;
|
|
_controlPanel->setReplayedTime(_fakeTimer);
|
|
timerEvent.recordedtype = Common::kRecorderEventTypeTimer;
|
|
timerEvent.time = _fakeTimer;
|
|
_playbackFile->writeEvent(timerEvent);
|
|
takeScreenshot();
|
|
_timerManager->handler();
|
|
break;
|
|
case kRecorderPlayback:
|
|
updateSubsystems();
|
|
if (_nextEvent.recordedtype == Common::kRecorderEventTypeTimer) {
|
|
_fakeTimer = _nextEvent.time;
|
|
_nextEvent = _playbackFile->getNextEvent();
|
|
_timerManager->handler();
|
|
} else {
|
|
if (_nextEvent.type == Common::EVENT_RTL) {
|
|
error("playback:action=stopplayback");
|
|
} else {
|
|
uint32 seconds = _fakeTimer / 1000;
|
|
Common::String screenTime = Common::String::format("%.2d:%.2d:%.2d", seconds / 3600 % 24, seconds / 60 % 60, seconds % 60);
|
|
error("playback:action=error reason=\"synchronization error\" time = %s", screenTime.c_str());
|
|
}
|
|
}
|
|
millis = _fakeTimer;
|
|
_controlPanel->setReplayedTime(_fakeTimer);
|
|
break;
|
|
case kRecorderPlaybackPause:
|
|
millis = _fakeTimer;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool EventRecorder::processDelayMillis() {
|
|
return _fastPlayback;
|
|
}
|
|
|
|
void EventRecorder::checkForKeyCode(const Common::Event &event) {
|
|
if ((event.type == Common::EVENT_KEYDOWN) && (event.kbd.flags & Common::KBD_CTRL) && (event.kbd.keycode == Common::KEYCODE_p) && (!event.kbdRepeat)) {
|
|
togglePause();
|
|
}
|
|
}
|
|
|
|
bool EventRecorder::pollEvent(Common::Event &ev) {
|
|
if ((_recordMode != kRecorderPlayback) || !_initialized)
|
|
return false;
|
|
|
|
if ((_nextEvent.recordedtype == Common::kRecorderEventTypeTimer) || (_nextEvent.type == Common::EVENT_INVALID)) {
|
|
return false;
|
|
}
|
|
|
|
switch (_nextEvent.type) {
|
|
case Common::EVENT_MOUSEMOVE:
|
|
case Common::EVENT_LBUTTONDOWN:
|
|
case Common::EVENT_LBUTTONUP:
|
|
case Common::EVENT_RBUTTONDOWN:
|
|
case Common::EVENT_RBUTTONUP:
|
|
case Common::EVENT_WHEELUP:
|
|
case Common::EVENT_WHEELDOWN:
|
|
g_system->warpMouse(_nextEvent.mouse.x, _nextEvent.mouse.y);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
ev = _nextEvent;
|
|
_nextEvent = _playbackFile->getNextEvent();
|
|
return true;
|
|
}
|
|
|
|
void EventRecorder::switchFastMode() {
|
|
if (_recordMode == kRecorderPlaybackPause) {
|
|
_fastPlayback = !_fastPlayback;
|
|
}
|
|
}
|
|
|
|
void EventRecorder::togglePause() {
|
|
RecordMode oldState;
|
|
switch (_recordMode) {
|
|
case kRecorderPlayback:
|
|
case kRecorderRecord:
|
|
oldState = _recordMode;
|
|
_recordMode = kRecorderPlaybackPause;
|
|
_controlPanel->runModal();
|
|
_recordMode = oldState;
|
|
_initialized = true;
|
|
break;
|
|
case kRecorderPlaybackPause:
|
|
_controlPanel->close();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EventRecorder::RegisterEventSource() {
|
|
g_system->getEventManager()->getEventDispatcher()->registerMapper(this, false);
|
|
}
|
|
|
|
uint32 EventRecorder::getRandomSeed(const Common::String &name) {
|
|
uint32 result = g_system->getMillis();
|
|
if (_recordMode == kRecorderRecord) {
|
|
_playbackFile->getHeader().randomSourceRecords[name] = result;
|
|
} else if (_recordMode == kRecorderPlayback) {
|
|
result = _playbackFile->getHeader().randomSourceRecords[name];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Common::String EventRecorder::generateRecordFileName(const Common::String &target) {
|
|
Common::String pattern(target+".r??");
|
|
Common::StringArray files = g_system->getSavefileManager()->listSavefiles(pattern);
|
|
for (int i = 0; i < kMaxRecordsNames; ++i) {
|
|
Common::String recordName = Common::String::format("%s.r%02d", target.c_str(), i);
|
|
if (find(files.begin(), files.end(), recordName) != files.end()) {
|
|
continue;
|
|
}
|
|
return recordName;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|
|
void EventRecorder::init(Common::String recordFileName, RecordMode mode) {
|
|
_fakeMixerManager = new NullSdlMixerManager();
|
|
_fakeMixerManager->init();
|
|
_fakeMixerManager->suspendAudio();
|
|
_fakeTimer = 0;
|
|
_lastMillis = g_system->getMillis();
|
|
_playbackFile = new Common::PlaybackFile();
|
|
_lastScreenshotTime = 0;
|
|
_recordMode = mode;
|
|
_needcontinueGame = false;
|
|
if (ConfMan.hasKey("disable_display")) {
|
|
DebugMan.enableDebugChannel("EventRec");
|
|
gDebugLevel = 1;
|
|
}
|
|
if (_recordMode == kRecorderPlayback) {
|
|
debugC(1, kDebugLevelEventRec, "playback:action=\"Load file\" filename=%s", recordFileName.c_str());
|
|
}
|
|
g_system->getEventManager()->getEventDispatcher()->registerSource(this, false);
|
|
_screenshotPeriod = ConfMan.getInt("screenshot_period");
|
|
if (_screenshotPeriod == 0) {
|
|
_screenshotPeriod = kDefaultScreenshotPeriod;
|
|
}
|
|
if (!openRecordFile(recordFileName)) {
|
|
deinit();
|
|
error("playback:action=error reason=\"Record file loading error\"");
|
|
return;
|
|
}
|
|
if (_recordMode != kPassthrough) {
|
|
_controlPanel = new GUI::OnScreenDialog(_recordMode == kRecorderRecord);
|
|
}
|
|
if (_recordMode == kRecorderPlayback) {
|
|
applyPlaybackSettings();
|
|
_nextEvent = _playbackFile->getNextEvent();
|
|
}
|
|
if (_recordMode == kRecorderRecord) {
|
|
getConfig();
|
|
}
|
|
|
|
switchMixer();
|
|
switchTimerManagers();
|
|
_needRedraw = true;
|
|
_initialized = true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Opens or creates file depend of recording mode.
|
|
*
|
|
*@param id of recording or playing back game
|
|
*@return true in case of success, false in case of error
|
|
*
|
|
*/
|
|
bool EventRecorder::openRecordFile(const Common::String &fileName) {
|
|
bool result;
|
|
switch (_recordMode) {
|
|
case kRecorderRecord:
|
|
return _playbackFile->openWrite(fileName);
|
|
case kRecorderPlayback:
|
|
_recordMode = kPassthrough;
|
|
result = _playbackFile->openRead(fileName);
|
|
_recordMode = kRecorderPlayback;
|
|
return result;
|
|
default:
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool EventRecorder::checkGameHash(const ADGameDescription *gameDesc) {
|
|
if (_playbackFile->getHeader().hashRecords.size() == 0) {
|
|
warning("Engine doesn't contain description table");
|
|
return false;
|
|
}
|
|
for (const ADGameFileDescription *fileDesc = gameDesc->filesDescriptions; fileDesc->fileName; fileDesc++) {
|
|
if (_playbackFile->getHeader().hashRecords.find(fileDesc->fileName) == _playbackFile->getHeader().hashRecords.end()) {
|
|
warning("MD5 hash for file %s not found in record file", fileDesc->fileName);
|
|
debugC(1, kDebugLevelEventRec, "playback:action=\"Check game hash\" filename=%s filehash=%s storedhash=\"\" result=different", fileDesc->fileName, fileDesc->md5);
|
|
return false;
|
|
}
|
|
if (_playbackFile->getHeader().hashRecords[fileDesc->fileName] != fileDesc->md5) {
|
|
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);
|
|
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());
|
|
return false;
|
|
}
|
|
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());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void EventRecorder::registerMixerManager(SdlMixerManager *mixerManager) {
|
|
_realMixerManager = mixerManager;
|
|
}
|
|
|
|
void EventRecorder::switchMixer() {
|
|
if (_recordMode == kPassthrough) {
|
|
_realMixerManager->resumeAudio();
|
|
} else {
|
|
_realMixerManager->suspendAudio();
|
|
_fakeMixerManager->resumeAudio();
|
|
}
|
|
}
|
|
|
|
SdlMixerManager *EventRecorder::getMixerManager() {
|
|
if (_recordMode == kPassthrough) {
|
|
return _realMixerManager;
|
|
} else {
|
|
return _fakeMixerManager;
|
|
}
|
|
}
|
|
|
|
void EventRecorder::getConfigFromDomain(const Common::ConfigManager::Domain *domain) {
|
|
for (Common::ConfigManager::Domain::const_iterator entry = domain->begin(); entry!= domain->end(); ++entry) {
|
|
_playbackFile->getHeader().settingsRecords[entry->_key] = entry->_value;
|
|
}
|
|
}
|
|
|
|
void EventRecorder::getConfig() {
|
|
getConfigFromDomain(ConfMan.getDomain(ConfMan.kApplicationDomain));
|
|
getConfigFromDomain(ConfMan.getActiveDomain());
|
|
_playbackFile->getHeader().settingsRecords["save_slot"] = ConfMan.get("save_slot");
|
|
}
|
|
|
|
|
|
void EventRecorder::applyPlaybackSettings() {
|
|
for (Common::StringMap::const_iterator i = _playbackFile->getHeader().settingsRecords.begin(); i != _playbackFile->getHeader().settingsRecords.end(); ++i) {
|
|
Common::String currentValue = ConfMan.get(i->_key);
|
|
if (currentValue != i->_value) {
|
|
ConfMan.set(i->_key, i->_value, ConfMan.kTransientDomain);
|
|
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());
|
|
} else {
|
|
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());
|
|
}
|
|
}
|
|
removeDifferentEntriesInDomain(ConfMan.getDomain(ConfMan.kApplicationDomain));
|
|
removeDifferentEntriesInDomain(ConfMan.getActiveDomain());
|
|
}
|
|
|
|
void EventRecorder::removeDifferentEntriesInDomain(Common::ConfigManager::Domain *domain) {
|
|
for (Common::ConfigManager::Domain::const_iterator entry = domain->begin(); entry!= domain->end(); ++entry) {
|
|
if (_playbackFile->getHeader().settingsRecords.find(entry->_key) == _playbackFile->getHeader().settingsRecords.end()) {
|
|
debugC(1, kDebugLevelEventRec, "playback:action=\"Apply settings\" checksettings:key=%s storedvalue=%s currentvalue="" result=different", entry->_key.c_str(), entry->_value.c_str());
|
|
domain->erase(entry->_key);
|
|
}
|
|
}
|
|
}
|
|
|
|
DefaultTimerManager *EventRecorder::getTimerManager() {
|
|
return _timerManager;
|
|
}
|
|
|
|
void EventRecorder::registerTimerManager(DefaultTimerManager *timerManager) {
|
|
_timerManager = timerManager;
|
|
}
|
|
|
|
void EventRecorder::switchTimerManagers() {
|
|
delete _timerManager;
|
|
if (_recordMode == kPassthrough) {
|
|
_timerManager = new SdlTimerManager();
|
|
} else {
|
|
_timerManager = new DefaultTimerManager();
|
|
}
|
|
}
|
|
|
|
void EventRecorder::updateSubsystems() {
|
|
if (_recordMode == kPassthrough) {
|
|
return;
|
|
}
|
|
RecordMode oldRecordMode = _recordMode;
|
|
_recordMode = kPassthrough;
|
|
_fakeMixerManager->update();
|
|
_recordMode = oldRecordMode;
|
|
}
|
|
|
|
Common::List<Common::Event> EventRecorder::mapEvent(const Common::Event &ev, Common::EventSource *source) {
|
|
if ((!_initialized) && (_recordMode != kRecorderPlaybackPause)) {
|
|
return DefaultEventMapper::mapEvent(ev, source);
|
|
}
|
|
|
|
checkForKeyCode(ev);
|
|
Common::Event evt = ev;
|
|
evt.mouse.x = evt.mouse.x * (g_system->getOverlayWidth() / g_system->getWidth());
|
|
evt.mouse.y = evt.mouse.y * (g_system->getOverlayHeight() / g_system->getHeight());
|
|
switch (_recordMode) {
|
|
case kRecorderPlayback:
|
|
if (ev.kbdRepeat != true) {
|
|
return Common::List<Common::Event>();
|
|
}
|
|
return Common::DefaultEventMapper::mapEvent(ev, source);
|
|
break;
|
|
case kRecorderRecord:
|
|
g_gui.processEvent(evt, _controlPanel);
|
|
if (((evt.type == Common::EVENT_LBUTTONDOWN) || (evt.type == Common::EVENT_LBUTTONUP) || (evt.type == Common::EVENT_MOUSEMOVE)) && _controlPanel->isMouseOver()) {
|
|
return Common::List<Common::Event>();
|
|
} else {
|
|
Common::RecorderEvent e(ev);
|
|
e.recordedtype = Common::kRecorderEventTypeNormal;
|
|
e.time = _fakeTimer;
|
|
_playbackFile->writeEvent(e);
|
|
return DefaultEventMapper::mapEvent(ev, source);
|
|
}
|
|
break;
|
|
case kRecorderPlaybackPause: {
|
|
Common::Event dialogEvent;
|
|
if (_controlPanel->isEditDlgVisible()) {
|
|
dialogEvent = ev;
|
|
} else {
|
|
dialogEvent = evt;
|
|
}
|
|
g_gui.processEvent(dialogEvent, _controlPanel->getActiveDlg());
|
|
if (((dialogEvent.type == Common::EVENT_LBUTTONDOWN) || (dialogEvent.type == Common::EVENT_LBUTTONUP) || (dialogEvent.type == Common::EVENT_MOUSEMOVE)) && _controlPanel->isMouseOver()) {
|
|
return Common::List<Common::Event>();
|
|
}
|
|
return Common::DefaultEventMapper::mapEvent(dialogEvent, source);
|
|
}
|
|
break;
|
|
default:
|
|
return Common::DefaultEventMapper::mapEvent(ev, source);
|
|
}
|
|
|
|
return Common::DefaultEventMapper::mapEvent(ev, source);
|
|
}
|
|
|
|
void EventRecorder::setGameMd5(const ADGameDescription *gameDesc) {
|
|
for (const ADGameFileDescription *fileDesc = gameDesc->filesDescriptions; fileDesc->fileName; fileDesc++) {
|
|
if (fileDesc->md5 != NULL) {
|
|
_playbackFile->getHeader().hashRecords[fileDesc->fileName] = fileDesc->md5;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EventRecorder::processGameDescription(const ADGameDescription *desc) {
|
|
if (_recordMode == kRecorderRecord) {
|
|
setGameMd5(desc);
|
|
}
|
|
if ((_recordMode == kRecorderPlayback) && !checkGameHash(desc)) {
|
|
deinit();
|
|
error("playback:action=error reason=\"\"");
|
|
}
|
|
}
|
|
|
|
void EventRecorder::deleteRecord(const Common::String& fileName) {
|
|
g_system->getSavefileManager()->removeSavefile(fileName);
|
|
}
|
|
|
|
void EventRecorder::takeScreenshot() {
|
|
if ((_fakeTimer - _lastScreenshotTime) > _screenshotPeriod) {
|
|
Graphics::Surface screen;
|
|
uint8 md5[16];
|
|
if (grabScreenAndComputeMD5(screen, md5)) {
|
|
_lastScreenshotTime = _fakeTimer;
|
|
_playbackFile->saveScreenShot(screen, md5);
|
|
screen.free();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool EventRecorder::grabScreenAndComputeMD5(Graphics::Surface &screen, uint8 md5[16]) {
|
|
if (!createScreenShot(screen)) {
|
|
warning("Can't save screenshot");
|
|
return false;
|
|
}
|
|
Common::MemoryReadStream bitmapStream((const byte*)screen.getPixels(), screen.w * screen.h * screen.format.bytesPerPixel);
|
|
computeStreamMD5(bitmapStream, md5);
|
|
return true;
|
|
}
|
|
|
|
Common::SeekableReadStream *EventRecorder::processSaveStream(const Common::String &fileName) {
|
|
Common::InSaveFile *saveFile;
|
|
switch (_recordMode) {
|
|
case kRecorderPlayback:
|
|
debugC(1, kDebugLevelEventRec, "playback:action=\"Process save file\" filename=%s len=%d", fileName.c_str(), _playbackFile->getHeader().saveFiles[fileName].size);
|
|
return new Common::MemoryReadStream(_playbackFile->getHeader().saveFiles[fileName].buffer, _playbackFile->getHeader().saveFiles[fileName].size);
|
|
case kRecorderRecord:
|
|
saveFile = _realSaveManager->openForLoading(fileName);
|
|
if (saveFile != NULL) {
|
|
_playbackFile->addSaveFile(fileName, saveFile);
|
|
saveFile->seek(0);
|
|
}
|
|
return saveFile;
|
|
default:
|
|
return NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Common::SaveFileManager *EventRecorder::getSaveManager(Common::SaveFileManager *realSaveManager) {
|
|
_realSaveManager = realSaveManager;
|
|
if (_recordMode != kPassthrough) {
|
|
return &_fakeSaveManager;
|
|
} else {
|
|
return realSaveManager;
|
|
}
|
|
}
|
|
|
|
void EventRecorder::preDrawOverlayGui() {
|
|
if ((_initialized) || (_needRedraw)) {
|
|
RecordMode oldMode = _recordMode;
|
|
_recordMode = kPassthrough;
|
|
g_system->showOverlay();
|
|
g_gui.theme()->clearAll();
|
|
g_gui.theme()->drawToBackbuffer();
|
|
_controlPanel->drawDialog(kDrawLayerBackground);
|
|
g_gui.theme()->drawToScreen();
|
|
g_gui.theme()->copyBackBufferToScreen();
|
|
_controlPanel->drawDialog(kDrawLayerForeground);
|
|
g_gui.theme()->updateScreen();
|
|
_recordMode = oldMode;
|
|
}
|
|
}
|
|
|
|
void EventRecorder::postDrawOverlayGui() {
|
|
if ((_initialized) || (_needRedraw)) {
|
|
RecordMode oldMode = _recordMode;
|
|
_recordMode = kPassthrough;
|
|
g_system->hideOverlay();
|
|
_recordMode = oldMode;
|
|
}
|
|
}
|
|
|
|
Common::StringArray EventRecorder::listSaveFiles(const Common::String &pattern) {
|
|
if (_recordMode == kRecorderPlayback) {
|
|
Common::StringArray result;
|
|
for (Common::HashMap<Common::String, Common::PlaybackFile::SaveFileBuffer>::iterator i = _playbackFile->getHeader().saveFiles.begin(); i != _playbackFile->getHeader().saveFiles.end(); ++i) {
|
|
if (i->_key.matchString(pattern, false, true)) {
|
|
result.push_back(i->_key);
|
|
}
|
|
}
|
|
return result;
|
|
} else {
|
|
return _realSaveManager->listSavefiles(pattern);
|
|
}
|
|
}
|
|
|
|
void EventRecorder::setFileHeader() {
|
|
if (_recordMode != kRecorderRecord) {
|
|
return;
|
|
}
|
|
TimeDate t;
|
|
PlainGameDescriptor desc = EngineMan.findTarget(ConfMan.getActiveDomainName());
|
|
g_system->getTimeAndDate(t);
|
|
if (_author.empty()) {
|
|
setAuthor("Unknown Author");
|
|
}
|
|
if (_name.empty()) {
|
|
g_eventRec.setName(Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description);
|
|
}
|
|
_playbackFile->getHeader().author = _author;
|
|
_playbackFile->getHeader().notes = _desc;
|
|
_playbackFile->getHeader().name = _name;
|
|
}
|
|
|
|
SDL_Surface *EventRecorder::getSurface(int width, int height) {
|
|
// Create a RGB565 surface of the requested dimensions.
|
|
return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 16, 0xF800, 0x07E0, 0x001F, 0x0000);
|
|
}
|
|
|
|
bool EventRecorder::switchMode() {
|
|
const Plugin *plugin = EngineMan.findPlugin(ConfMan.get("engineid"));
|
|
bool metaInfoSupport = plugin->get<MetaEngine>().hasFeature(MetaEngine::kSavesSupportMetaInfo);
|
|
bool featuresSupport = metaInfoSupport &&
|
|
g_engine->canSaveGameStateCurrently() &&
|
|
plugin->get<MetaEngine>().hasFeature(MetaEngine::kSupportsListSaves) &&
|
|
plugin->get<MetaEngine>().hasFeature(MetaEngine::kSupportsDeleteSave);
|
|
if (!featuresSupport) {
|
|
return false;
|
|
}
|
|
|
|
const Common::String target = ConfMan.getActiveDomainName();
|
|
SaveStateList saveList = plugin->get<MetaEngine>().listSaves(target.c_str());
|
|
|
|
int emptySlot = 1;
|
|
for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x) {
|
|
int saveSlot = x->getSaveSlot();
|
|
if (saveSlot == 0) {
|
|
continue;
|
|
}
|
|
if (emptySlot != saveSlot) {
|
|
break;
|
|
}
|
|
emptySlot++;
|
|
}
|
|
Common::String saveName;
|
|
if (emptySlot >= 0) {
|
|
saveName = Common::String::format("Save %d", emptySlot + 1);
|
|
Common::Error status = g_engine->saveGameState(emptySlot, saveName);
|
|
if (status.getCode() == Common::kNoError) {
|
|
Common::Event eventRTL;
|
|
eventRTL.type = Common::EVENT_RTL;
|
|
g_system->getEventManager()->pushEvent(eventRTL);
|
|
}
|
|
}
|
|
ConfMan.set("record_mode", "", Common::ConfigManager::kTransientDomain);
|
|
ConfMan.setInt("save_slot", emptySlot, Common::ConfigManager::kTransientDomain);
|
|
_needcontinueGame = true;
|
|
return true;
|
|
}
|
|
|
|
bool EventRecorder::checkForContinueGame() {
|
|
bool result = _needcontinueGame;
|
|
_needcontinueGame = false;
|
|
return result;
|
|
}
|
|
|
|
void EventRecorder::deleteTemporarySave() {
|
|
if (_temporarySlot == -1) return;
|
|
const Plugin *plugin = EngineMan.findPlugin(ConfMan.get("engineid"));
|
|
const Common::String target = ConfMan.getActiveDomainName();
|
|
plugin->get<MetaEngine>().removeSaveState(target.c_str(), _temporarySlot);
|
|
_temporarySlot = -1;
|
|
}
|
|
|
|
} // End of namespace GUI
|
|
|
|
#endif // ENABLE_EVENTRECORDER
|