diff options
Diffstat (limited to 'engines/wintermute')
75 files changed, 2868 insertions, 189 deletions
diff --git a/engines/wintermute/ad/ad_entity.cpp b/engines/wintermute/ad/ad_entity.cpp index 1bbadeb7f7..0909d7ef91 100644 --- a/engines/wintermute/ad/ad_entity.cpp +++ b/engines/wintermute/ad/ad_entity.cpp @@ -1134,4 +1134,7 @@ bool AdEntity::setSprite(const char *filename) { } } +Common::String AdEntity::debuggerToString() const { + return Common::String::format("%p: Entity \"%s\"; (X,Y): (%d, %d), rotate(%d): %f deg, scale(%d): (%f, %f)%%", (const void *)this, getName(), _posX, _posY, _rotatable, _rotate, _zoomable, _scaleX, _scaleY); +} } // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_entity.h b/engines/wintermute/ad/ad_entity.h index 7e1525b7c1..678608af36 100644 --- a/engines/wintermute/ad/ad_entity.h +++ b/engines/wintermute/ad/ad_entity.h @@ -60,6 +60,7 @@ public: virtual bool scSetProperty(const char *name, ScValue *value) override; virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; virtual const char *scToString() override; + Common::String debuggerToString() const override; private: int32 _walkToX; int32 _walkToY; diff --git a/engines/wintermute/ad/ad_game.cpp b/engines/wintermute/ad/ad_game.cpp index df0328ce5e..088184b0f6 100644 --- a/engines/wintermute/ad/ad_game.cpp +++ b/engines/wintermute/ad/ad_game.cpp @@ -2280,4 +2280,7 @@ bool AdGame::onScriptShutdown(ScScript *script) { return STATUS_OK; } +Common::String AdGame::debuggerToString() const { + return Common::String::format("%p: Game \"%s\"", (const void *)this, getName()); +} } // End of namespace Wintermute diff --git a/engines/wintermute/ad/ad_game.h b/engines/wintermute/ad/ad_game.h index ebb37e9a07..0e5abc9b3b 100644 --- a/engines/wintermute/ad/ad_game.h +++ b/engines/wintermute/ad/ad_game.h @@ -130,6 +130,7 @@ public: virtual bool scSetProperty(const char *name, ScValue *value) override; virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; bool validMouse(); + Common::String debuggerToString() const override; private: virtual bool externalCall(ScScript *script, ScStack *stack, ScStack *thisStack, char *name) override; diff --git a/engines/wintermute/ad/ad_scene.cpp b/engines/wintermute/ad/ad_scene.cpp index 02a6aeb801..b57faef69b 100644 --- a/engines/wintermute/ad/ad_scene.cpp +++ b/engines/wintermute/ad/ad_scene.cpp @@ -2998,4 +2998,9 @@ bool AdScene::getRegionObjects(AdRegion *region, BaseArray<AdObject *> &objects, return STATUS_OK; } + +Common::String AdScene::debuggerToString() const { + return Common::String::format("%p: Scene \"%s\", paralax: %d, autoscroll: %d", (const void *)this, getName(), _paralaxScrolling, _autoScroll); +} } // End of namespace Wintermute + diff --git a/engines/wintermute/ad/ad_scene.h b/engines/wintermute/ad/ad_scene.h index 1ca52bdda9..71567d2475 100644 --- a/engines/wintermute/ad/ad_scene.h +++ b/engines/wintermute/ad/ad_scene.h @@ -160,7 +160,7 @@ public: virtual bool scSetProperty(const char *name, ScValue *value) override; virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; virtual const char *scToString() override; - + virtual Common::String debuggerToString() const override; private: bool persistState(bool saving = true); diff --git a/engines/wintermute/base/base_engine.cpp b/engines/wintermute/base/base_engine.cpp index 2166a3e070..4ce334aceb 100644 --- a/engines/wintermute/base/base_engine.cpp +++ b/engines/wintermute/base/base_engine.cpp @@ -84,7 +84,7 @@ void BaseEngine::LOG(bool res, const char *fmt, ...) { va_end(va); if (instance()._gameRef) { - instance()._gameRef->LOG("%s", buff); + instance()._gameRef->LOG(res, "%s", buff); } else { debugCN(kWintermuteDebugLog, "%02d:%02d:%02d: %s\n", hours, mins, secs, buff); } diff --git a/engines/wintermute/base/base_engine.h b/engines/wintermute/base/base_engine.h index 0f4a6b0775..cbf5d92d00 100644 --- a/engines/wintermute/base/base_engine.h +++ b/engines/wintermute/base/base_engine.h @@ -74,7 +74,7 @@ public: static const Timer *getTimer(); static const Timer *getLiveTimer(); static void LOG(bool res, const char *fmt, ...); - const char *getGameTargetName() const { return _targetName.c_str(); } + Common::String getGameTargetName() const { return _targetName; } Common::String getGameId() const { return _gameId; } Common::Language getLanguage() const { return _language; } WMETargetExecutable getTargetExecutable() const { diff --git a/engines/wintermute/base/base_frame.cpp b/engines/wintermute/base/base_frame.cpp index 471185f2d2..910ab64a76 100644 --- a/engines/wintermute/base/base_frame.cpp +++ b/engines/wintermute/base/base_frame.cpp @@ -764,4 +764,7 @@ const char *BaseFrame::scToString() { return "[frame]"; } +Common::String BaseFrame::debuggerToString() const { + return Common::String::format("%p: Frame \"%s\": #subframes %d ", (const void *)this, getName(), _subframes.size()); +} } // End of namespace Wintermute diff --git a/engines/wintermute/base/base_frame.h b/engines/wintermute/base/base_frame.h index ff9e67a166..8d261c9e71 100644 --- a/engines/wintermute/base/base_frame.h +++ b/engines/wintermute/base/base_frame.h @@ -65,6 +65,8 @@ public: virtual bool scSetProperty(const char *name, ScValue *value) override; virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; virtual const char *scToString() override; + virtual Common::String debuggerToString() const override; + private: bool _keyframe; bool _editorExpanded; diff --git a/engines/wintermute/base/base_game.cpp b/engines/wintermute/base/base_game.cpp index 668053bb3a..ef3cc2d84f 100644 --- a/engines/wintermute/base/base_game.cpp +++ b/engines/wintermute/base/base_game.cpp @@ -70,6 +70,11 @@ #include "common/keyboard.h" #include "common/system.h" #include "common/file.h" +#include "graphics/scaler.h" + +#if EXTENDED_DEBUGGER_ENABLED +#include "engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h" +#endif namespace Wintermute { @@ -167,7 +172,12 @@ BaseGame::BaseGame(const Common::String &targetName) : BaseObject(this), _target _forceNonStreamedSounds = false; - _thumbnailWidth = _thumbnailHeight = 0; + // These are NOT the actual engine defaults (they are 0, 0), + // but we have a use for thumbnails even for games that don't + // use them in-game, hence we set a default that is suitably + // sized for the GMM (expecting 4:3 ratio) + _thumbnailWidth = kThumbnailWidth; + _thumbnailHeight = kThumbnailHeight2; _localSaveDir = "saves"; @@ -398,7 +408,11 @@ bool BaseGame::initialize1() { break; } +#if EXTENDED_DEBUGGER_ENABLED + _scEngine = new DebuggableScEngine(this); +#else _scEngine = new ScEngine(this); +#endif if (_scEngine == nullptr) { break; } diff --git a/engines/wintermute/base/base_game.h b/engines/wintermute/base/base_game.h index e535cc9618..6aacc1feab 100644 --- a/engines/wintermute/base/base_game.h +++ b/engines/wintermute/base/base_game.h @@ -34,7 +34,11 @@ #include "engines/wintermute/persistent.h" #include "engines/wintermute/coll_templ.h" #include "engines/wintermute/math/rect32.h" +#include "engines/wintermute/debugger.h" #include "common/events.h" +#if EXTENDED_DEBUGGER_ENABLED +#include "engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h" +#endif namespace Wintermute { @@ -148,7 +152,11 @@ public: BaseRenderer *_renderer; BaseSoundMgr *_soundMgr; +#if EXTENDED_DEBUGGER_ENABLED + DebuggableScEngine *_scEngine; +#else ScEngine *_scEngine; +#endif BaseScriptable *_mathClass; BaseSurfaceStorage *_surfaceStorage; BaseFontStorage *_fontStorage; diff --git a/engines/wintermute/base/base_persistence_manager.cpp b/engines/wintermute/base/base_persistence_manager.cpp index bb5e0c4091..5a694e7ce2 100644 --- a/engines/wintermute/base/base_persistence_manager.cpp +++ b/engines/wintermute/base/base_persistence_manager.cpp @@ -56,7 +56,7 @@ namespace Wintermute { #define SAVE_MAGIC_3 0x12564154 ////////////////////////////////////////////////////////////////////////// -BasePersistenceManager::BasePersistenceManager(const char *savePrefix, bool deleteSingleton) { +BasePersistenceManager::BasePersistenceManager(const Common::String &savePrefix, bool deleteSingleton) { _saving = false; _offset = 0; _saveStream = nullptr; @@ -91,7 +91,7 @@ BasePersistenceManager::BasePersistenceManager(const char *savePrefix, bool dele _thumbnailDataSize = 0; _thumbnailData = nullptr; - if (savePrefix) { + if (savePrefix != "") { _savePrefix = savePrefix; } else if (_gameRef) { _savePrefix = _gameRef->getGameTargetName(); @@ -183,7 +183,7 @@ void BasePersistenceManager::getSaveStateDesc(int slot, SaveStateDescriptor &des } } - desc.setSaveDate(_savedTimestamp.tm_year, _savedTimestamp.tm_mon, _savedTimestamp.tm_mday); + desc.setSaveDate(_savedTimestamp.tm_year + 1900, _savedTimestamp.tm_mon + 1, _savedTimestamp.tm_mday); desc.setSaveTime(_savedTimestamp.tm_hour, _savedTimestamp.tm_min); desc.setPlayTime(0); } @@ -215,8 +215,8 @@ bool BasePersistenceManager::getSaveExists(int slot) { } ////////////////////////////////////////////////////////////////////////// -bool BasePersistenceManager::initSave(const char *desc) { - if (!desc) { +bool BasePersistenceManager::initSave(const Common::String &desc) { + if (desc == "") { return STATUS_FAILED; } @@ -297,11 +297,11 @@ bool BasePersistenceManager::initSave(const char *desc) { uint32 dataOffset = _offset + sizeof(uint32) + // data offset - sizeof(uint32) + strlen(desc) + 1 + // description + sizeof(uint32) + strlen(desc.c_str()) + 1 + // description sizeof(uint32); // timestamp putDWORD(dataOffset); - putString(desc); + putString(desc.c_str()); g_system->getTimeAndDate(_savedTimestamp); putTimeDate(_savedTimestamp); diff --git a/engines/wintermute/base/base_persistence_manager.h b/engines/wintermute/base/base_persistence_manager.h index 373d1580de..760b45c907 100644 --- a/engines/wintermute/base/base_persistence_manager.h +++ b/engines/wintermute/base/base_persistence_manager.h @@ -63,7 +63,7 @@ public: uint32 getMaxUsedSlot(); bool getSaveExists(int slot); bool initLoad(const Common::String &filename); - bool initSave(const char *desc); + bool initSave(const Common::String &desc); bool getBytes(byte *buffer, uint32 size); bool putBytes(byte *buffer, uint32 size); uint32 _offset; @@ -86,7 +86,7 @@ public: bool transferCharPtr(const char *name, char **val); bool transferString(const char *name, Common::String *val); bool transferVector2(const char *name, Vector2 *val); - BasePersistenceManager(const char *savePrefix = nullptr, bool deleteSingleton = false); + BasePersistenceManager(const Common::String &savePrefix = "", bool deleteSingleton = false); virtual ~BasePersistenceManager(); bool checkVersion(byte verMajor, byte verMinor, byte verBuild); diff --git a/engines/wintermute/base/base_region.cpp b/engines/wintermute/base/base_region.cpp index 9a31f5cd66..02ab365eff 100644 --- a/engines/wintermute/base/base_region.cpp +++ b/engines/wintermute/base/base_region.cpp @@ -532,4 +532,7 @@ bool BaseRegion::mimic(BaseRegion *region, float scale, int x, int y) { return createRegion() ? STATUS_OK : STATUS_FAILED; } +Common::String BaseRegion::debuggerToString() const { + return Common::String::format("%p: Region \"%s\": Rect (top, right, bottom, left): (%d, %d, %d, %d), active: %d ", (const void *)this, getName(), _rect.top, _rect.right, _rect.bottom, _rect.left, _active); +} } // End of namespace Wintermute diff --git a/engines/wintermute/base/base_region.h b/engines/wintermute/base/base_region.h index fc3389c501..4cb5dd85d6 100644 --- a/engines/wintermute/base/base_region.h +++ b/engines/wintermute/base/base_region.h @@ -59,6 +59,8 @@ public: virtual bool scSetProperty(const char *name, ScValue *value) override; virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; virtual const char *scToString() override; + virtual Common::String debuggerToString() const override; + private: float _lastMimicScale; int32 _lastMimicX; diff --git a/engines/wintermute/base/base_script_holder.cpp b/engines/wintermute/base/base_script_holder.cpp index 5b1c961479..fd9dd6a2a5 100644 --- a/engines/wintermute/base/base_script_holder.cpp +++ b/engines/wintermute/base/base_script_holder.cpp @@ -42,7 +42,7 @@ IMPLEMENT_PERSISTENT(BaseScriptHolder, false) ////////////////////////////////////////////////////////////////////// BaseScriptHolder::BaseScriptHolder(BaseGame *inGame) : BaseScriptable(inGame) { setName("<unnamed>"); - + _ready = false; _freezable = true; _filename = nullptr; } @@ -312,7 +312,11 @@ bool BaseScriptHolder::addScript(const char *filename) { if (!scr) { if (_gameRef->_editorForceScripts) { // editor hack +#if EXTENDED_DEBUGGER_ENABLED + scr = new DebuggableScript(_gameRef, _gameRef->_scEngine); +#else scr = new ScScript(_gameRef, _gameRef->_scEngine); +#endif scr->_filename = new char[strlen(filename) + 1]; strcpy(scr->_filename, filename); scr->_state = SCRIPT_ERROR; @@ -462,8 +466,15 @@ void BaseScriptHolder::makeFreezable(bool freezable) { ScScript *BaseScriptHolder::invokeMethodThread(const char *methodName) { for (int i = _scripts.size() - 1; i >= 0; i--) { if (_scripts[i]->canHandleMethod(methodName)) { - +#if EXTENDED_DEBUGGER_ENABLED + DebuggableScEngine* debuggableEngine; + debuggableEngine = dynamic_cast<DebuggableScEngine*>(_scripts[i]->_engine); + // TODO: Not pretty + assert(debuggableEngine); + ScScript *thread = new DebuggableScript(_gameRef, debuggableEngine); +#else ScScript *thread = new ScScript(_gameRef, _scripts[i]->_engine); +#endif if (thread) { bool ret = thread->createMethodThread(_scripts[i], methodName); if (DID_SUCCEED(ret)) { diff --git a/engines/wintermute/base/base_scriptable.cpp b/engines/wintermute/base/base_scriptable.cpp index c65d30d941..01f6f9e02f 100644 --- a/engines/wintermute/base/base_scriptable.cpp +++ b/engines/wintermute/base/base_scriptable.cpp @@ -188,4 +188,9 @@ ScScript *BaseScriptable::invokeMethodThread(const char *methodName) { return nullptr; } +Common::String BaseScriptable::debuggerToString() const { + return Common::String::format("%p: BaseScriptable %s", (const void *)this, getName()); +} + + } // End of namespace Wintermute diff --git a/engines/wintermute/base/base_scriptable.h b/engines/wintermute/base/base_scriptable.h index b32668d6c8..7b4f269871 100644 --- a/engines/wintermute/base/base_scriptable.h +++ b/engines/wintermute/base/base_scriptable.h @@ -63,6 +63,7 @@ public: virtual void scSetBool(bool val); virtual int scCompare(BaseScriptable *val); virtual void scDebuggerDesc(char *buf, int bufSize); + virtual Common::String debuggerToString() const; int32 _refCount; ScValue *_scValue; ScValue *_scProp; diff --git a/engines/wintermute/base/base_sprite.cpp b/engines/wintermute/base/base_sprite.cpp index 09e138a1fd..f282004a59 100644 --- a/engines/wintermute/base/base_sprite.cpp +++ b/engines/wintermute/base/base_sprite.cpp @@ -826,4 +826,7 @@ bool BaseSprite::killAllSounds() { return STATUS_OK; } +Common::String BaseSprite::debuggerToString() const { + return Common::String::format("%p: Sprite \"%s\"", (const void *)this, getName()); +} } // End of namespace Wintermute diff --git a/engines/wintermute/base/base_sprite.h b/engines/wintermute/base/base_sprite.h index ec71512ec9..2313b7b3dc 100644 --- a/engines/wintermute/base/base_sprite.h +++ b/engines/wintermute/base/base_sprite.h @@ -69,6 +69,7 @@ public: virtual bool scSetProperty(const char *name, ScValue *value) override; virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) override; virtual const char *scToString() override; + Common::String debuggerToString() const override; private: BaseObject *_owner; bool _canBreak; diff --git a/engines/wintermute/base/base_sub_frame.cpp b/engines/wintermute/base/base_sub_frame.cpp index 6d0c48ff17..8068e61168 100644 --- a/engines/wintermute/base/base_sub_frame.cpp +++ b/engines/wintermute/base/base_sub_frame.cpp @@ -673,4 +673,8 @@ bool BaseSubFrame::setSurfaceSimple() { } } +Common::String BaseSubFrame::debuggerToString() const { + return Common::String::format("%p: BaseSubFrame \"%s\" - Mirror:(%d, %d), Hotspot:(%d, %d), ", (const void *)this, getName(), _mirrorX, _mirrorY, _hotspotX, _hotspotY); +} + } // End of namespace Wintermute diff --git a/engines/wintermute/base/base_sub_frame.h b/engines/wintermute/base/base_sub_frame.h index f156c332d6..0fd38f9548 100644 --- a/engines/wintermute/base/base_sub_frame.h +++ b/engines/wintermute/base/base_sub_frame.h @@ -86,6 +86,7 @@ public: virtual bool scSetProperty(const char *name, ScValue *value); virtual bool scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name); virtual const char *scToString(); + Common::String debuggerToString() const override; }; diff --git a/engines/wintermute/base/base_viewport.cpp b/engines/wintermute/base/base_viewport.cpp index bf3700a14e..aed0355eb9 100644 --- a/engines/wintermute/base/base_viewport.cpp +++ b/engines/wintermute/base/base_viewport.cpp @@ -96,4 +96,7 @@ int BaseViewport::getHeight() const { return _rect.bottom - _rect.top; } +Common::String BaseViewport::debuggerToString() const { + return Common::String::format("%p: BaseViewport: (top, right, bottom, left): (%d, %d, %d, %d)", (const void *)this, _rect.top, _rect.right, _rect.bottom, _rect.left); +} } // End of namespace Wintermute diff --git a/engines/wintermute/base/base_viewport.h b/engines/wintermute/base/base_viewport.h index eae756f9c6..c2e8727ad8 100644 --- a/engines/wintermute/base/base_viewport.h +++ b/engines/wintermute/base/base_viewport.h @@ -48,6 +48,7 @@ public: BaseObject *_mainObject; BaseViewport(BaseGame *inGame = nullptr); virtual ~BaseViewport(); + virtual Common::String debuggerToString() const; private: Rect32 _rect; }; diff --git a/engines/wintermute/base/file/base_disk_file.cpp b/engines/wintermute/base/file/base_disk_file.cpp index 82a9e24dfb..d0c51616f4 100644 --- a/engines/wintermute/base/file/base_disk_file.cpp +++ b/engines/wintermute/base/file/base_disk_file.cpp @@ -113,13 +113,28 @@ Common::SeekableReadStream *openDiskFile(const Common::String &filename) { Common::String fixedFilename = filename; correctSlashes(fixedFilename); - // Absolute path: TODO: Add specific fallbacks here. + // HACK: There are a few games around which mistakenly refer to absolute paths in the scripts. + // The original interpreter on Windows usually simply ignores them when it can't find them. + // We try to turn the known ones into relative paths. if (fixedFilename.contains(':')) { - if (fixedFilename.hasPrefix("c:/windows/fonts/")) { // East Side Story refers to "c:\windows\fonts\framd.ttf" - fixedFilename = filename.c_str() + 14; - } else if (fixedFilename.hasPrefix("c:/carol6/svn/data/")) { // Carol Reed 6: Black Circle refers to "c:\carol6\svn\data\sprites\system\help.png" - fixedFilename = fixedFilename.c_str() + 19; - } else { + const char* const knownPrefixes[] = { // Known absolute paths + "c:/windows/fonts/", // East Side Story refers to "c:\windows\fonts\framd.ttf" + "c:/carol6/svn/data/", // Carol Reed 6: Black Circle refers to "c:\carol6\svn\data\sprites\system\help.png" + "f:/dokument/spel 5/demo/data/" // Carol Reed 5 (non-demo) refers to "f:\dokument\spel 5\demo\data\scenes\credits\op_cred_00\op_cred_00.jpg" + }; + + bool matched = false; + + for (uint i = 0; i < ARRAYSIZE(knownPrefixes); i++) { + if (fixedFilename.hasPrefix(knownPrefixes[i])) { + fixedFilename = fixedFilename.c_str() + strlen(knownPrefixes[i]); + matched = true; + } + } + + if (!matched) { + // fixedFilename is unchanged and thus still broken, none of the above workarounds worked. + // We can only bail out error("openDiskFile::Absolute path or invalid filename used in %s", filename.c_str()); } } diff --git a/engines/wintermute/base/scriptables/debuggable/debuggable_script.cpp b/engines/wintermute/base/scriptables/debuggable/debuggable_script.cpp new file mode 100644 index 0000000000..5a2291894f --- /dev/null +++ b/engines/wintermute/base/scriptables/debuggable/debuggable_script.cpp @@ -0,0 +1,148 @@ +/* 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 "common/tokenizer.h" +#include "debuggable_script.h" +#include "engines/wintermute/base/scriptables/script_stack.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h" +#include "engines/wintermute/debugger/breakpoint.h" +#include "engines/wintermute/debugger/script_monitor.h" +#include "engines/wintermute/debugger/watch_instance.h" + +namespace Wintermute { + +DebuggableScript::DebuggableScript(BaseGame *inGame, DebuggableScEngine *engine) : ScScript(inGame, engine), _engine(engine), _stepDepth(kDefaultStepDepth) { + _engine->_watches.subscribe(this); + for (uint i = 0; i < _engine->_watches.size(); i++) { + _watchInstances.push_back(new WatchInstance(_engine->_watches[i], this)); + } +} + +DebuggableScript::~DebuggableScript() { + for (uint i = 0; i < _watchInstances.size(); i++) { + delete _watchInstances[i]; + } + _engine->_watches.unsubscribe(this); +} +void DebuggableScript::preInstHook(uint32 inst) {} + +void DebuggableScript::postInstHook(uint32 inst) { + if (inst == II_DBG_LINE) { + for (uint j = 0; j < _engine->_breakpoints.size(); j++) { + _engine->_breakpoints[j]->evaluate(this); + } + + if (_callStack->_sP <= _stepDepth) { + _engine->_monitor->notifyStep(this); + } + } + + for (uint i = 0; i < _watchInstances.size(); i++) { + this->_watchInstances[i]->evaluate(); + } + +} + +void DebuggableScript::setStepDepth(int depth) { + _stepDepth = depth; +} + +void DebuggableScript::step() { + setStepDepth(_callStack->_sP); + // TODO double check +} + +void DebuggableScript::stepContinue() { + setStepDepth(kDefaultStepDepth); +} + +void DebuggableScript::stepFinish() { + setStepDepth(_callStack->_sP - 1); +} + +ScValue *DebuggableScript::resolveName(const Common::String &name) { + + Common::String trimmed = name; + trimmed.trim(); + Common::StringTokenizer st = Common::StringTokenizer(trimmed.c_str(), "."); + Common::String nextToken; + + nextToken = st.nextToken(); + + + char cstr[256]; // TODO not pretty + Common::strlcpy(cstr, nextToken.c_str(), nextToken.size() + 1); + cstr[255] = '\0'; // We 0-terminate it just in case it's > 256 chars. + + ScValue *value = getVar(cstr); + ScValue *res = new ScValue(_gameRef); + + if (value == nullptr) { + return res; + } + + nextToken = st.nextToken(); + + while (nextToken.size() > 0 && (value->isObject() || value->isNative())) { + value = value->getProp(nextToken.c_str()); + nextToken = st.nextToken(); + if (value == nullptr) { + return res; + } + } + + res->copy(value); + + return res; +} + +uint DebuggableScript::dbgGetLine() const { + return _currentLine; +} + +Common::String DebuggableScript::dbgGetFilename() const { + return _filename; +} + +void DebuggableScript::updateWatches() { + // We drop obsolete watches + for (uint i = 0; i < _watchInstances.size(); i++) { + Watch *findMe = _watchInstances[i]->_watch; + if (Common::find(_engine->_watches.begin(), _engine->_watches.end(), findMe) == _engine->_watches.end()) { + // Not found on engine-wide list, must have been removed from watches. Must remove it from local list. + delete _watchInstances[i]; + _watchInstances.remove_at(i); + } + } + + // We add any new watches + for (uint i = 0; i < _engine->_watches.size(); i++) { + Watch *findMe = _engine->_watches[i]; + if (Common::find(_engine->_watches.begin(), _engine->_watches.end(), findMe) == _engine->_watches.end()) { + // Not found on local list, must be a new one. + _watchInstances.push_back(new WatchInstance(_engine->_watches[i], this)); + } + } +} +} // End of namespace Wintermute + diff --git a/engines/wintermute/base/scriptables/debuggable/debuggable_script.h b/engines/wintermute/base/scriptables/debuggable/debuggable_script.h new file mode 100644 index 0000000000..b32a5ca4af --- /dev/null +++ b/engines/wintermute/base/scriptables/debuggable/debuggable_script.h @@ -0,0 +1,67 @@ +/* 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. + * + */ + +#ifndef DEBUGGABLE_SCRIPT_H_ +#define DEBUGGABLE_SCRIPT_H_ +#include "engines/wintermute/base/scriptables/script.h" + +namespace Wintermute { +class ScriptMonitor; +class Watch; +class WatchInstance; +class DebuggableScEngine; + +class DebuggableScript : public ScScript { + static const int kDefaultStepDepth = -2; + int32 _stepDepth; + DebuggableScEngine *_engine; + BaseArray<WatchInstance *> _watchInstances; + virtual void preInstHook(uint32 inst) override; + virtual void postInstHook(uint32 inst) override; + void setStepDepth(int depth); +public: + DebuggableScript(BaseGame *inGame, DebuggableScEngine *engine); + virtual ~DebuggableScript(); + ScValue *resolveName(const Common::String &name); + /** + * Return argument to last II_DBG_LINE encountered + */ + virtual uint dbgGetLine() const; + virtual Common::String dbgGetFilename() const; + /** + * Execute one more instruction + */ + void step(); + /** + * Continue execution + */ + void stepContinue(); + /** + * Continue execution until the activation record on top of the stack is popped + */ + void stepFinish(); + void updateWatches(); +}; + +} // End of namespace Wintermute + +#endif /* DEBUGGABLE_SCRIPT_H_ */ diff --git a/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.cpp b/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.cpp new file mode 100644 index 0000000000..28a00cd4ae --- /dev/null +++ b/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.cpp @@ -0,0 +1,35 @@ +/* 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 "debuggable_script_engine.h" +#include "debuggable_script.h" +#include "engines/wintermute/debugger/watch_instance.h" + +namespace Wintermute { + +DebuggableScEngine::DebuggableScEngine(BaseGame *inGame) : ScEngine(inGame), _monitor(nullptr) {} + +void DebuggableScEngine::attachMonitor(ScriptMonitor *monitor) { + _monitor = monitor; +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h b/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h new file mode 100644 index 0000000000..a4d9d2bfe7 --- /dev/null +++ b/engines/wintermute/base/scriptables/debuggable/debuggable_script_engine.h @@ -0,0 +1,110 @@ +/* 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. + * + */ + +#ifndef DEBUGGABLE_SCRIPT_ENGINE_H_ +#define DEBUGGABLE_SCRIPT_ENGINE_H_ +#include "engines/wintermute/base/scriptables/script_engine.h" +#include "engines/wintermute/coll_templ.h" +#include "common/algorithm.h" +#include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h" + +namespace Wintermute { + +class Breakpoint; +class Watch; +class DebuggableScript; +class DebuggableScEngine; +class ScriptMonitor; + +class PublisherWArray : private Common::Array<Watch *> { + Common::Array<DebuggableScript *> _subscribers; + void notifySubscribers() { + for (uint i = 0; i < _subscribers.size(); i++) { + _subscribers[i]->updateWatches(); + } + } +public: + void subscribe(DebuggableScript *script) { + if (Common::find(_subscribers.begin(), _subscribers.end(), script) == _subscribers.end()) { + // If not already contained + _subscribers.push_back(script); + } + } + + void unsubscribe(DebuggableScript *script) { + int location = -1; + for (uint i = 0; i < _subscribers.size() && location == -1; i++) { + if (_subscribers[i] == script) { + location = i; + } + } + if (location >= 0) { + _subscribers.remove_at(location); + } else { + // TODO: If this happens... it's funny. Some script out there forgot to subscribe. + } + } + + void push_back(Watch *newElement) { + Common::Array<Watch *>::push_back(newElement); + notifySubscribers(); + } + + size_type size() { + return Common::Array<Watch *>::size(); + } + + iterator begin() { + return Common::Array<Watch *>::begin(); + } + + iterator end() { + return Common::Array<Watch *>::end(); + } + + Watch *&operator[](size_type idx) { + return Common::Array<Watch *>::operator[](idx); + } + Watch *remove_at(size_type idx) { + Watch *res = Common::Array<Watch *>::remove_at(idx); + notifySubscribers(); + return res; + } +}; + +class DebuggableScEngine : public ScEngine { + Common::Array<Breakpoint *> _breakpoints; + PublisherWArray _watches; + ScriptMonitor *_monitor; +public: + DebuggableScEngine(BaseGame *inGame); + void attachMonitor(ScriptMonitor *); + + friend class DebuggerController; + friend class DebuggableScript; + friend class ScScript; + friend class WatchableScriptArray; +}; + +} // End of namespace Wintermute + +#endif /* DEBUGGABLE_SCRIPT_ENGINE_H_ */ diff --git a/engines/wintermute/base/scriptables/script.cpp b/engines/wintermute/base/scriptables/script.cpp index 44fd117e61..c13310255d 100644 --- a/engines/wintermute/base/scriptables/script.cpp +++ b/engines/wintermute/base/scriptables/script.cpp @@ -32,7 +32,9 @@ #include "engines/wintermute/base/scriptables/script_engine.h" #include "engines/wintermute/base/scriptables/script_stack.h" #include "common/memstream.h" - +#if EXTENDED_DEBUGGER_ENABLED +#include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h" +#endif namespace Wintermute { IMPLEMENT_PERSISTENT(ScScript, false) @@ -522,6 +524,9 @@ bool ScScript::executeInstruction() { ScValue *op2; uint32 inst = getDWORD(); + + preInstHook(inst); + switch (inst) { case II_DEF_VAR: @@ -1092,6 +1097,7 @@ bool ScScript::executeInstruction() { ret = STATUS_FAILED; } // switch(instruction) + postInstHook(inst); //delete op; return ret; @@ -1314,8 +1320,15 @@ ScScript *ScScript::invokeEventHandler(const Common::String &eventName, bool unb if (!pos) { return nullptr; } - +#if EXTENDED_DEBUGGER_ENABLED + // TODO: Not pretty + DebuggableScEngine* debuggableEngine; + debuggableEngine = dynamic_cast<DebuggableScEngine*>(_engine); + assert(debuggableEngine); + ScScript *thread = new DebuggableScript(_gameRef, debuggableEngine); +#else ScScript *thread = new ScScript(_gameRef, _engine); +#endif if (thread) { bool ret = thread->createThread(this, pos, eventName); if (DID_SUCCEED(ret)) { @@ -1434,18 +1447,6 @@ bool ScScript::finishThreads() { return STATUS_OK; } - -////////////////////////////////////////////////////////////////////////// -// IWmeDebugScript interface implementation -int ScScript::dbgGetLine() { - return _currentLine; -} - -////////////////////////////////////////////////////////////////////////// -const char *ScScript::dbgGetFilename() { - return _filename; -} - ////////////////////////////////////////////////////////////////////////// void ScScript::afterLoad() { if (_buffer == nullptr) { @@ -1466,4 +1467,8 @@ void ScScript::afterLoad() { } } +void ScScript::preInstHook(uint32 inst) {} + +void ScScript::postInstHook(uint32 inst) {} + } // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script.h b/engines/wintermute/base/scriptables/script.h index 1edeae5b55..c1d1cce4ee 100644 --- a/engines/wintermute/base/scriptables/script.h +++ b/engines/wintermute/base/scriptables/script.h @@ -33,12 +33,15 @@ #include "engines/wintermute/base/base.h" #include "engines/wintermute/base/scriptables/dcscript.h" // Added by ClassView #include "engines/wintermute/coll_templ.h" +#include "engines/wintermute/persistent.h" namespace Wintermute { class BaseScriptHolder; class BaseObject; class ScEngine; class ScStack; +class ScValue; + class ScScript : public BaseClass { public: BaseArray<int> _breakpoints; @@ -50,7 +53,7 @@ public: bool copyParameters(ScStack *stack); void afterLoad(); -private: +protected: ScValue *_operand; ScValue *_reg1; public: @@ -125,7 +128,7 @@ public: ScValue *_globals; ScEngine *_engine; int32 _currentLine; - bool executeInstruction(); + virtual bool executeInstruction(); char *getString(); uint32 getDWORD(); double getFloat(); @@ -162,11 +165,8 @@ private: bool initScript(); bool initTables(); - -// IWmeDebugScript interface implementation -public: - virtual int dbgGetLine(); - virtual const char *dbgGetFilename(); + virtual void preInstHook(uint32 inst); + virtual void postInstHook(uint32 inst); }; } // End of namespace Wintermute diff --git a/engines/wintermute/base/scriptables/script_engine.cpp b/engines/wintermute/base/scriptables/script_engine.cpp index cdf55a304c..8d957c6951 100644 --- a/engines/wintermute/base/scriptables/script_engine.cpp +++ b/engines/wintermute/base/scriptables/script_engine.cpp @@ -144,7 +144,15 @@ ScScript *ScEngine::runScript(const char *filename, BaseScriptHolder *owner) { } // add new script +#if EXTENDED_DEBUGGER_ENABLED + DebuggableScEngine* debuggableEngine; + debuggableEngine = dynamic_cast<DebuggableScEngine*>(this); + // TODO: Not pretty + assert(debuggableEngine); + ScScript *script = new DebuggableScript(_gameRef, debuggableEngine); +#else ScScript *script = new ScScript(_gameRef, this); +#endif bool ret = script->create(filename, compBuffer, compSize, owner); if (DID_FAIL(ret)) { _gameRef->LOG(ret, "Error running script '%s'...", filename); diff --git a/engines/wintermute/base/scriptables/script_engine.h b/engines/wintermute/base/scriptables/script_engine.h index bdb139e1f8..8b7e4acd19 100644 --- a/engines/wintermute/base/scriptables/script_engine.h +++ b/engines/wintermute/base/scriptables/script_engine.h @@ -66,20 +66,6 @@ public: Common::String _filename; }; - class CScBreakpoint { - public: - CScBreakpoint(const char *filename) { - _filename = filename; - } - - ~CScBreakpoint() { - _lines.clear(); - } - - Common::String _filename; - BaseArray<int> _lines; - }; - public: bool clearGlobals(bool includingNatives = false); bool tickUnbreakable(); diff --git a/engines/wintermute/base/sound/base_sound_manager.cpp b/engines/wintermute/base/sound/base_sound_manager.cpp index 3b91f1490f..f95a21de33 100644 --- a/engines/wintermute/base/sound/base_sound_manager.cpp +++ b/engines/wintermute/base/sound/base_sound_manager.cpp @@ -105,15 +105,14 @@ BaseSoundBuffer *BaseSoundMgr::addSound(const Common::String &filename, Audio::M BaseSoundBuffer *sound; Common::String useFilename = filename; + useFilename.toLowercase(); // try to switch WAV to OGG file (if available) - AnsiString ext = PathUtil::getExtension(filename); - if (StringUtil::compareNoCase(ext, "wav")) { - AnsiString path = PathUtil::getDirectoryName(filename); - AnsiString name = PathUtil::getFileNameWithoutExtension(filename); - - AnsiString newFile = PathUtil::combine(path, name + "ogg"); - if (BaseFileManager::getEngineInstance()->hasFile(newFile)) { - useFilename = newFile; + if (useFilename.hasSuffix(".wav")) { + Common::String oggFilename = useFilename; + oggFilename.erase(oggFilename.size() - 4); + oggFilename = oggFilename + ".ogg"; + if (BaseFileManager::getEngineInstance()->hasFile(oggFilename)) { + useFilename = oggFilename; } } diff --git a/engines/wintermute/configure.engine b/engines/wintermute/configure.engine index bdaf49de3f..55385776de 100644 --- a/engines/wintermute/configure.engine +++ b/engines/wintermute/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine wintermute "Wintermute" yes "" "" "jpeg png zlib vorbis 16bit" +add_engine wintermute "Wintermute" yes "" "" "jpeg png zlib vorbis 16bit highres" diff --git a/engines/wintermute/debugger.cpp b/engines/wintermute/debugger.cpp index 5b617d9db9..c643c33246 100644 --- a/engines/wintermute/debugger.cpp +++ b/engines/wintermute/debugger.cpp @@ -21,29 +21,289 @@ */ #include "engines/wintermute/debugger.h" -#include "engines/wintermute/wintermute.h" #include "engines/wintermute/base/base_engine.h" #include "engines/wintermute/base/base_file_manager.h" -#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/debugger/debugger_controller.h" +#include "engines/wintermute/wintermute.h" + +#define CONTROLLER _engineRef->_dbgController namespace Wintermute { Console::Console(WintermuteEngine *vm) : GUI::Debugger(), _engineRef(vm) { registerCmd("show_fps", WRAP_METHOD(Console, Cmd_ShowFps)); registerCmd("dump_file", WRAP_METHOD(Console, Cmd_DumpFile)); + registerCmd("show_fps", WRAP_METHOD(Console, Cmd_ShowFps)); + registerCmd("dump_file", WRAP_METHOD(Console, Cmd_DumpFile)); + registerCmd("help", WRAP_METHOD(Console, Cmd_Help)); + // Actual (script) debugger commands + registerCmd(STEP_CMD, WRAP_METHOD(Console, Cmd_Step)); + registerCmd(CONTINUE_CMD, WRAP_METHOD(Console, Cmd_Continue)); + registerCmd(FINISH_CMD, WRAP_METHOD(Console, Cmd_Finish)); + registerCmd(WATCH_CMD, WRAP_METHOD(Console, Cmd_Watch)); + registerCmd(BREAK_CMD, WRAP_METHOD(Console, Cmd_AddBreakpoint)); + registerCmd(LIST_CMD, WRAP_METHOD(Console, Cmd_List)); + registerCmd(REMOVE_BREAKPOINT_CMD, WRAP_METHOD(Console, Cmd_RemoveBreakpoint)); + registerCmd(DISABLE_BREAKPOINT_CMD, WRAP_METHOD(Console, Cmd_DisableBreakpoint)); + registerCmd(ENABLE_BREAKPOINT_CMD, WRAP_METHOD(Console, Cmd_EnableBreakpoint)); + registerCmd(REMOVE_WATCH_CMD, WRAP_METHOD(Console, Cmd_RemoveWatch)); + registerCmd(DISABLE_WATCH_CMD, WRAP_METHOD(Console, Cmd_DisableWatch)); + registerCmd(ENABLE_WATCH_CMD, WRAP_METHOD(Console, Cmd_EnableWatch)); + registerCmd(PRINT_CMD, WRAP_METHOD(Console, Cmd_Print)); + registerCmd(SET_CMD, WRAP_METHOD(Console, Cmd_Set)); + registerCmd(INFO_CMD, WRAP_METHOD(Console, Cmd_Info)); + registerCmd(SET_PATH_CMD, WRAP_METHOD(Console, Cmd_SourcePath)); + registerCmd(TOP_CMD, WRAP_METHOD(Console, Cmd_Top)); } Console::~Console(void) { +} + +bool Console::Cmd_Help(int argc, const char **argv) { + if (argc == 1) { + // Debugger::Cmd_Help(argc, argv); + debugPrintf("\nType help somecommand to get specific help.\n"); + } else { + printUsage(argv[1]); + } + return true; +} +void Console::printUsage(const Common::String &command) { + // TODO: This is horrible and would probably benefit from a map or something. + if (command.equals(BREAK_CMD)) { + debugPrintf("Usage: %s <file path> <line> to break at line <line> of file <file path>\n", command.c_str()); + } else if (command.equals(REMOVE_BREAKPOINT_CMD)) { + debugPrintf("Usage: %s <id> to remove breakpoint #id\n", command.c_str()); + } else if (command.equals(ENABLE_BREAKPOINT_CMD)) { + debugPrintf("Usage: %s <id> to enable breakpoint #id\n", command.c_str()); + } else if (command.equals(DISABLE_BREAKPOINT_CMD)) { + debugPrintf("Usage: %s <id> to disable breakpoint #id\n", command.c_str()); + } else if (command.equals(REMOVE_WATCH_CMD)) { + debugPrintf("Usage: %s <id> to remove watchpoint #id\n", command.c_str()); + } else if (command.equals(ENABLE_WATCH_CMD)) { + debugPrintf("Usage: %s <id> to enable watchpoint #id\n", command.c_str()); + } else if (command.equals(DISABLE_WATCH_CMD)) { + debugPrintf("Usage: %s <id> to disable watchpoint #id\n", command.c_str()); + } else if (command.equals(INFO_CMD)) { + debugPrintf("Usage: %s [watch|breakpoints]\n", command.c_str()); + } else if (command.equals(WATCH_CMD)) { + debugPrintf("Usage: %s <file path> <name> to watch for <name> in file <file path>\n", command.c_str()); + } else if (command.equals(STEP_CMD)) { + debugPrintf("Usage: %s to step\n", command.c_str()); + } else if (command.equals(CONTINUE_CMD)) { + debugPrintf("Usage: %s to continue\n", command.c_str()); + } else if (command.equals(FINISH_CMD)) { + debugPrintf("Usage: %s to finish\n", command.c_str()); + } else if (command.equals(PRINT_CMD)) { + debugPrintf("Usage: %s <name> to print value of <name>\n", command.c_str()); + } else if (command.equals(SET_CMD)) { + debugPrintf("Usage: %s <name> = <value> to set <name> to <value>\n", command.c_str()); + } else { + debugPrintf("No help about this command, sorry."); + } +} + +bool Console::Cmd_AddBreakpoint(int argc, const char **argv) { + if (argc == 3) { + Wintermute::Error error = CONTROLLER->addBreakpoint(argv[1], atoi(argv[2])); + printError(argv[0], error); + } else { + printUsage(argv[0]); + } + return true; +} + +bool Console::Cmd_RemoveBreakpoint(int argc, const char **argv) { + if (argc == 2) { + Error error = CONTROLLER->removeBreakpoint(atoi(argv[1])); + printError(argv[0], error); + } else { + printUsage(argv[0]); + } + return true; +} + +bool Console::Cmd_EnableBreakpoint(int argc, const char **argv) { + if (argc == 2) { + Error error = CONTROLLER->enableBreakpoint(atoi(argv[1])); + printError(argv[0], error); + } else { + printUsage(argv[0]); + } + return true; +} + +bool Console::Cmd_DisableBreakpoint(int argc, const char **argv) { + if (argc == 2) { + Error error = CONTROLLER->disableBreakpoint(atoi(argv[1])); + debugPrintf("%s: %s\n", argv[0], error.getErrorDisplayStr().c_str()); + } else { + printUsage(argv[0]); + } + return true; +} + +bool Console::Cmd_RemoveWatch(int argc, const char **argv) { + if (argc == 2) { + Error error = CONTROLLER->removeWatchpoint(atoi(argv[1])); + printError(argv[0], error); + } else { + printUsage(argv[0]); + } + + return true; +} + +bool Console::Cmd_EnableWatch(int argc, const char **argv) { + if (argc == 2) { + Error error = CONTROLLER->enableWatchpoint(atoi(argv[1])); + printError(argv[0], error); + } else { + printUsage(argv[0]); + } + return true; +} + +bool Console::Cmd_DisableWatch(int argc, const char **argv) { + if (argc == 2) { + Error error = CONTROLLER->disableWatchpoint(atoi(argv[1])); + printError(argv[0], error); + } else { + printUsage(argv[0]); + } + return true; +} + +bool Console::Cmd_Watch(int argc, const char **argv) { + if (argc == 3) { + Error error = CONTROLLER->addWatch(argv[1], argv[2]); + printError(argv[0], error); + } else { + printUsage(argv[0]); + } + return true; +} + +bool Console::Cmd_Info(int argc, const char **argv) { + if (argc == 2 && !strncmp(argv[1], "breakpoints", 10)) { + Common::Array<BreakpointInfo> breakpoints = CONTROLLER->getBreakpoints(); + for (uint i = 0; i < breakpoints.size(); i++) { + debugPrintf("%d %s:%d x%d, enabled: %d \n", i, breakpoints[i]._filename.c_str(), breakpoints[i]._line, breakpoints[i]._hits, breakpoints[i]._enabled); + } + return 1; + } else if (argc == 2 && !strncmp(argv[1], WATCH_CMD, 5)) { + Common::Array<WatchInfo>watchlist = CONTROLLER->getWatchlist(); + for (uint i = 0; i < watchlist.size(); i++) { + debugPrintf("%d %s:%s x%d \n", i, watchlist[i]._filename.c_str(), watchlist[i]._symbol.c_str(), watchlist[i]._hits); + } + return 1; + } else { + printUsage(argv[0]); + return 1; + } +} + +bool Console::Cmd_Step(int argc, const char **argv) { + if (argc == 1) { + Error error = CONTROLLER->step(); + if (error.getErrorLevel() == SUCCESS) { + return false; + } else { + printError(argv[0], error); + return true; + } + } else { + printUsage(argv[0]); + return true; + } +} + +bool Console::Cmd_Continue(int argc, const char **argv) { + if (argc == 1) { + Error error = CONTROLLER->stepContinue(); + if (error.getErrorLevel() == SUCCESS) { + return false; + } else { + printError(argv[0], error); + return true; + } + } else { + printUsage(argv[0]); + return true; + } +} + +bool Console::Cmd_Finish(int argc, const char **argv) { + if (argc == 1) { + Error error = CONTROLLER->stepFinish(); + printError(argv[0], error); + if (error.getErrorLevel() == SUCCESS) { + return false; + } else { + printError(argv[0], error); + return true; + } + } else { + printUsage(argv[0]); + return true; + } +} + +bool Console::Cmd_List(int argc, const char **argv) { + Error error = printSource(); + if (error.getErrorLevel() != SUCCESS) { + printError(argv[0], error); + } + return true; +} + +bool Console::Cmd_Print(int argc, const char **argv) { + if (argc == 2) { + Error error = Error(SUCCESS, OK, 0); + Common::String temp = CONTROLLER->readValue(argv[1], &error); + if (error.getErrorLevel() == SUCCESS) { + debugPrintf("%s = %s \n", argv[1], temp.c_str()); + return true; + } else { + printError(argv[0], error); + return true; + } + } else { + printUsage(argv[0]); + return true; + } +} + + +bool Console::Cmd_Set(int argc, const char **argv) { + if (argc == 4 && !strncmp("=", argv[2], 1)) { + ScValue *val = nullptr; + Error error = CONTROLLER->setValue(argv[1], argv[3], val); + if (error.getErrorLevel() == SUCCESS) { + assert(val); + debugPrintf("%s = %s\n", argv[1], val->getString()); + } else { + printError(argv[0], error); + } + } else { + printUsage(argv[0]); + } + return true; } bool Console::Cmd_ShowFps(int argc, const char **argv) { - if (argc > 1) { + if (argc == 2) { if (Common::String(argv[1]) == "true") { - _engineRef->_game->setShowFPS(true); + CONTROLLER->showFps(true); } else if (Common::String(argv[1]) == "false") { - _engineRef->_game->setShowFPS(false); + CONTROLLER->showFps(false); + } else { + debugPrintf("%s: argument 1 must be \"true\" or \"false\"\n", argv[0]); } + } else { + debugPrintf("Usage: %s [true|false]\n", argv[0]); } return true; } @@ -81,4 +341,80 @@ bool Console::Cmd_DumpFile(int argc, const char **argv) { return true; } + +bool Console::Cmd_SourcePath(int argc, const char **argv) { + if (argc != 2) { + debugPrintf("Usage: %s <source path>\n", argv[0]); + return true; + } else { + if (CONTROLLER->setSourcePath(Common::String(argv[1])).getErrorCode() == OK) { + debugPrintf("Source path set to '%s'\n", CONTROLLER->getSourcePath().c_str()); + } else { + debugPrintf("Error setting source path. Note that \"\" is illegal."); + } + return true; + } +} + +void Console::notifyBreakpoint(const char *filename, int line) { + debugPrintf("Breakpoint hit %s: %d\n", filename, line); + printSource(0); + attach(); + onFrame(); +} + +void Console::notifyStep(const char *filename, int line) { + debugPrintf("Step: %s:%d\n", filename, line); + printSource(0); + attach(); + onFrame(); +} + +void Console::notifyWatch(const char *filename, const char *symbol, const char *newValue) { + debugPrintf("Watch: %s:%s <---- %s\n", filename, symbol, newValue); + printSource(0); + attach(); + onFrame(); +} + +Error Console::printSource(int n) { + + Error* error = nullptr; + Listing *listing = CONTROLLER->getListing(error); + Error err(*error); + delete error; + + if (err.getErrorLevel() == SUCCESS || err.getErrorLevel() == WARNING) { + Common::Array<ListingLine> lines = listing->getLines(CONTROLLER->getLastLine(), n/2, n/2); + for (uint i = 0; i < lines.size(); i++) { + if (lines[i].number == CONTROLLER->getLastLine()) { + debugPrintf(" -> "); + } else { + debugPrintf(" "); + } + debugPrintf("%d", lines[i].number); + debugPrintf("%s", lines[i].text.c_str()); + debugPrintf("\n"); + } + } + + delete listing; + return err; +} + +bool Console::Cmd_Top(int argc, const char **argv) { + Common::Array<TopEntry> entries = CONTROLLER->getTop(); + for (uint i = 0; i < entries.size(); i++) { + if (entries[i].current) { + debugPrintf("%d*: %s\n", i, entries[i].filename.c_str()); + } else { + debugPrintf("%d: %s\n", i, entries[i].filename.c_str()); + } + } + return true; +} + +void Console::printError(const Common::String &command, Error error) { + debugPrintf("%s: %s\n", command.c_str(), error.getErrorDisplayStr().c_str()); +} } // End of namespace Wintermute diff --git a/engines/wintermute/debugger.h b/engines/wintermute/debugger.h index 625da0ce41..6b1d2312ba 100644 --- a/engines/wintermute/debugger.h +++ b/engines/wintermute/debugger.h @@ -23,20 +23,134 @@ #ifndef WINTERMUTE_DEBUGGER_H #define WINTERMUTE_DEBUGGER_H +#define EXTENDED_DEBUGGER_ENABLED 1 + #include "gui/debugger.h" -namespace Wintermute { +#if EXTENDED_DEBUGGER_ENABLED +#include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h" +#else +#include "engines/wintermute/base/scriptables/script.h" +#endif + +#define DEFAULT_SOURCE_PADDING 5 + +#define STEP_CMD "step" +#define CONTINUE_CMD "continue" +#define FINISH_CMD "finish" +#define WATCH_CMD "watch" +#define BREAK_CMD "break" +#define LIST_CMD "list" +#define REMOVE_BREAKPOINT_CMD "del" +#define DISABLE_BREAKPOINT_CMD "disable" +#define ENABLE_BREAKPOINT_CMD "enable" +#define REMOVE_WATCH_CMD "delw" +#define DISABLE_WATCH_CMD "disablew" +#define ENABLE_WATCH_CMD "enablew" +#define INFO_CMD "info" +#define SET_CMD "set" +#define PRINT_CMD "print" +#define SET_PATH_CMD "set_path" +#define TOP_CMD "top" + +namespace Wintermute { class WintermuteEngine; +class Adapter; +class DebuggerController; +class Error; + class Console : public GUI::Debugger { public: Console(WintermuteEngine *vm); virtual ~Console(); - + /* + * Debug commands + */ + bool Cmd_Help(int argc, const char **argv); bool Cmd_ShowFps(int argc, const char **argv); bool Cmd_DumpFile(int argc, const char **argv); + +#if EXTENDED_DEBUGGER_ENABLED + /** + * Step - break again on next line + */ + bool Cmd_Step(int argc, const char **argv); + /** + * Continue execution + */ + bool Cmd_Continue(int argc, const char **argv); + /** + * Only break again when the current function is finished + * (activation record is popped) + */ + bool Cmd_Finish(int argc, const char **argv); + bool Cmd_Print(int argc, const char **argv); + bool Cmd_Set(int argc, const char **argv); + // Breakpoints + bool Cmd_AddBreakpoint(int argc, const char **argv); + bool Cmd_RemoveBreakpoint(int argc, const char **argv); + bool Cmd_EnableBreakpoint(int argc, const char **argv); + bool Cmd_DisableBreakpoint(int argc, const char **argv); + /** + * Add a watch. + * + * It monitors the value of some variable x against its + * last known state and it breaks if it has changed since. + * + */ + bool Cmd_Watch(int argc, const char **argv); + bool Cmd_RemoveWatch(int argc, const char **argv); + bool Cmd_EnableWatch(int argc, const char **argv); + bool Cmd_DisableWatch(int argc, const char **argv); + /** + * Print info re:watch and breakpoints. + * This differs from e.g. gdb in that we have separate lists. + */ + bool Cmd_Info(int argc, const char **argv); + /** + * Print source + */ + bool Cmd_List(int argc, const char **argv); + /** + * Set (DOS-style) source path for debugging. + * This is where you will (optionally) put your sources + * to enable printing of sources as you step through the + * scripts. + * + * Please note that we have no checksum or anything + * to make sure your source files are up to date. + * + * YOU HAVE to make sure of that. + * + * You have been warned! :) + */ + bool Cmd_SourcePath(int argc, const char **argv); + + /** + * Top + */ + bool Cmd_Top(int argc, const char **argv); + + Error printSource(int n = DEFAULT_SOURCE_PADDING); + + /** + * Hooks for the controller to open the console + */ + void notifyBreakpoint(const char *filename, int line); + void notifyStep(const char *filename, int line); + /** + * To be called by the adapter when a watched variable + * is changed. + * Opens a console and prints info and listing if available. + */ + void notifyWatch(const char *filename, const char *symbol, const char *newValue); +#endif + private: - WintermuteEngine *_engineRef; + const WintermuteEngine *_engineRef; + void printError(const Common::String &command, Error error); + void printUsage(const Common::String &command); }; } diff --git a/engines/wintermute/debugger/breakpoint.cpp b/engines/wintermute/debugger/breakpoint.cpp new file mode 100644 index 0000000000..7f2a02b0ea --- /dev/null +++ b/engines/wintermute/debugger/breakpoint.cpp @@ -0,0 +1,68 @@ +/* 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 "breakpoint.h" +#include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h" +#include "script_monitor.h" + +namespace Wintermute { + +Breakpoint::Breakpoint(const Common::String &filename, uint line, ScriptMonitor *monitor) : + _filename(filename), _line(line), _monitor(monitor), _enabled(0), _hits(0) {} + +void Breakpoint::hit(DebuggableScript *script) { + _hits++; + _monitor->onBreakpoint(this, script); +} + +Common::String Breakpoint::getFilename() const { + return _filename; +} +int Breakpoint::getLine() const { + return _line; +} +int Breakpoint::getHits() const { + return _hits; +} +bool Breakpoint::isEnabled() const { + return _enabled; +} +void Breakpoint::enable() { + _enabled = true; +} +void Breakpoint::disable() { + _enabled = false; +} + +void Breakpoint::evaluate(DebuggableScript *script) { + if (isEnabled() && + getLine() == script->_currentLine && + !getFilename().compareTo(script->_filename)) { + hit(script); + } +} + +Breakpoint::~Breakpoint() { + // Nothing to take care of in here +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/debugger/breakpoint.h b/engines/wintermute/debugger/breakpoint.h new file mode 100644 index 0000000000..3757791ba3 --- /dev/null +++ b/engines/wintermute/debugger/breakpoint.h @@ -0,0 +1,58 @@ +/* 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. + * + */ + +#ifndef BREAKPOINT_H_ +#define BREAKPOINT_H_ +#include "common/str.h" + +namespace Wintermute { + +class ScriptMonitor; +class DebuggableScript; + +class Breakpoint { + const Common::String _filename; + const uint _line; + uint _hits; + bool _enabled; + ScriptMonitor *_monitor; + void hit(DebuggableScript *script); +public: + Breakpoint(const Common::String &filename, uint line, ScriptMonitor *monitor); + /** + * This should be called inside the interpreter; the breakpoint is evaluated + * in the context of script, and, if it is enabled and filename & line match, + * the attached ScriptMonitor is notified. + */ + void evaluate(DebuggableScript* script); + Common::String getFilename() const; + int getLine() const; + int getHits() const; + bool isEnabled() const; + void enable(); + void disable(); + virtual ~Breakpoint(); +}; + +} // End of namespace Wintermute + +#endif /* BREAKPOINT_H_ */ diff --git a/engines/wintermute/debugger/debugger_controller.cpp b/engines/wintermute/debugger/debugger_controller.cpp new file mode 100644 index 0000000000..38f862365d --- /dev/null +++ b/engines/wintermute/debugger/debugger_controller.cpp @@ -0,0 +1,325 @@ +/* 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 "common/algorithm.h" +#include "common/str.h" +#include "common/tokenizer.h" +#include "engines/wintermute/debugger.h" +#include "engines/wintermute/base/base_file_manager.h" +#include "engines/wintermute/base/base_engine.h" +#include "engines/wintermute/base/base_game.h" +#include "engines/wintermute/base/scriptables/script.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/script_stack.h" +#include "engines/wintermute/debugger/breakpoint.h" +#include "engines/wintermute/debugger/debugger_controller.h" +#include "engines/wintermute/debugger/watch.h" +#include "engines/wintermute/debugger/listing_providers/blank_listing_provider.h" +#include "engines/wintermute/debugger/listing_providers/cached_source_listing_provider.h" +#include "engines/wintermute/debugger/listing_providers/source_listing.h" +#define SCENGINE _engine->_game->_scEngine +#define DEBUGGER _engine->_debugger + +namespace Wintermute { + +DebuggerController::~DebuggerController() { + delete _sourceListingProvider; +} + +DebuggerController::DebuggerController(WintermuteEngine *vm) : _engine(vm) { + _sourceListingProvider = new CachedSourceListingProvider(); + clear(); +} + +bool DebuggerController::bytecodeExists(const Common::String &filename) { + uint32 compSize; + byte *compBuffer = SCENGINE->getCompiledScript(filename.c_str(), &compSize); + if (!compBuffer) { + return false; + } else { + return true; + } +} + +Error DebuggerController::addBreakpoint(const char *filename, int line) { + assert(SCENGINE); + if (bytecodeExists(filename)) { + SCENGINE->_breakpoints.push_back(new Breakpoint(filename, line, this)); + return Error(SUCCESS, OK); + } else { + return Error(ERROR, NO_SUCH_BYTECODE); + } +} + +Error DebuggerController::removeBreakpoint(uint id) { + assert(SCENGINE); + if (SCENGINE->_breakpoints.size() > id) { + SCENGINE->_breakpoints.remove_at(id); + return Error(SUCCESS, OK); + } else { + return Error(ERROR, NO_SUCH_BREAKPOINT, id); + } +} + +Error DebuggerController::disableBreakpoint(uint id) { + assert(SCENGINE); + if (SCENGINE->_breakpoints.size() > id) { + SCENGINE->_breakpoints[id]->disable(); + return Error(SUCCESS, OK); + } else { + return Error(ERROR, NO_SUCH_BREAKPOINT, id); + } +} + +Error DebuggerController::enableBreakpoint(uint id) { + assert(SCENGINE); + if (SCENGINE->_breakpoints.size() > id) { + SCENGINE->_breakpoints[id]->enable(); + return Error(SUCCESS, OK); + } else { + return Error(ERROR, NO_SUCH_BREAKPOINT, id); + } +} + +Error DebuggerController::removeWatchpoint(uint id) { + assert(SCENGINE); + if (SCENGINE->_watches.size() > id) { + SCENGINE->_watches.remove_at(id); + return Error(SUCCESS, OK); + } else { + return Error(ERROR, NO_SUCH_BREAKPOINT, id); + } +} + + +Error DebuggerController::disableWatchpoint(uint id) { + assert(SCENGINE); + if (SCENGINE->_watches.size() > id) { + SCENGINE->_watches[id]->disable(); + return Error(SUCCESS, OK); + } else { + return Error(ERROR, NO_SUCH_BREAKPOINT, id); + } +} + +Error DebuggerController::enableWatchpoint(uint id) { + assert(SCENGINE); + if (SCENGINE->_watches.size() > id) { + SCENGINE->_watches[id]->enable(); + return Error(SUCCESS, OK); + } else { + return Error(ERROR, NO_SUCH_BREAKPOINT, id); + } + +} + +Error DebuggerController::addWatch(const char *filename, const char *symbol) { + assert(SCENGINE); + if (!bytecodeExists(filename)) { + return Error(ERROR, NO_SUCH_BYTECODE, filename); + } + SCENGINE->_watches.push_back(new Watch(filename, symbol, this)); + return Error(SUCCESS, OK, "Watchpoint added"); +} + +void DebuggerController::onBreakpoint(const Breakpoint *breakpoint, DebuggableScript *script) { + _lastScript = script; + _lastLine = script->_currentLine; + DEBUGGER->notifyBreakpoint(script->dbgGetFilename().c_str(), script->_currentLine); +} + +void DebuggerController::notifyStep(DebuggableScript *script) { + _lastScript = script; + _lastLine = script->_currentLine; + DEBUGGER->notifyStep(script->dbgGetFilename().c_str(), script->_currentLine); +} + +void DebuggerController::onWatch(const Watch *watch, DebuggableScript *script) { + _lastScript = script; // If script has changed do we still care? + _lastLine = script->_currentLine; + Common::String symbol = watch->getSymbol(); + DEBUGGER->notifyWatch(script->dbgGetFilename().c_str(), symbol.c_str(), script->resolveName(symbol)->getString()); +} + +Error DebuggerController::step() { + if (!_lastScript) { + return Error(ERROR, NOT_ALLOWED); + } + _lastScript->step(); + clear(); + return Error(SUCCESS, OK); +} + +Error DebuggerController::stepContinue() { + if (!_lastScript) { + return Error(ERROR, NOT_ALLOWED); + } + _lastScript->stepContinue(); + return Error(SUCCESS, OK); +} + +Error DebuggerController::stepFinish() { + if (!_lastScript) { + return Error(ERROR, NOT_ALLOWED); + } + _lastScript->stepFinish(); + clear(); + return Error(SUCCESS, OK); +} + +void DebuggerController::clear() { + _lastScript = nullptr; + _lastLine = -1; +} + +Common::String DebuggerController::readValue(const Common::String &name, Error *error) { + if (!_lastScript) { + delete error; + error = new Error(ERROR, NOT_ALLOWED); + return Common::String(); + } + char cstr[256]; // TODO not pretty + Common::strlcpy(cstr, name.c_str(), name.size() + 1); + cstr[255] = '\0'; // We 0-terminate it just in case it's longer than 255. + return _lastScript->resolveName(cstr)->getString(); +} + +Error DebuggerController::setValue(const Common::String &name, const Common::String &value, ScValue *&var) { + if (!_lastScript) { + return Error(ERROR, NOT_ALLOWED); + } + + Common::String trimmed = value; + trimmed.trim(); + char cstr[256]; + Common::strlcpy(cstr, name.c_str(), name.size() + 1); // TODO not pretty + + var = _lastScript->getVar(cstr); + if (var->_type == VAL_INT) { + char *endptr; + int res = strtol(trimmed.c_str(), &endptr, 10); // TODO: Hex too? + if (endptr == trimmed.c_str()) { + return Error(ERROR, PARSE_ERROR); + } else if (endptr == trimmed.c_str() + trimmed.size()) { + // We've parsed all of it, have we? + var->setInt(res); + } else { + assert(false); + return Error(ERROR, PARSE_ERROR); + // Something funny happened here. + } + } else if (var->_type == VAL_FLOAT) { + char *endptr; + float res = (float)strtod(trimmed.c_str(), &endptr); + if (endptr == trimmed.c_str()) { + return Error(ERROR, PARSE_ERROR); + } else if (endptr == trimmed.c_str() + trimmed.size()) { + // We've parsed all of it, have we? + var->setFloat(res); + } else { + return Error(ERROR, PARSE_ERROR); + assert(false); + // Something funny happened here. + } + } else if (var->_type == VAL_BOOL) { + Common::String str = Common::String(trimmed); + bool valAsBool; + if (Common::parseBool(trimmed, valAsBool)) { + var->setBool(valAsBool); + } else { + return Error(ERROR, PARSE_ERROR); + } + } else if (var->_type == VAL_STRING) { + var->setString(trimmed); + } else { + return Error(ERROR, NOT_YET_IMPLEMENTED); + } + return Error(SUCCESS, OK); +} + +void DebuggerController::showFps(bool show) { + _engine->_game->setShowFPS(show); +} + +Common::Array<BreakpointInfo> DebuggerController::getBreakpoints() const { + assert(SCENGINE); + Common::Array<BreakpointInfo> breakpoints; + for (uint i = 0; i < SCENGINE->_breakpoints.size(); i++) { + BreakpointInfo bpInfo; + bpInfo._filename = SCENGINE->_breakpoints[i]->getFilename(); + bpInfo._line = SCENGINE->_breakpoints[i]->getLine(); + bpInfo._hits = SCENGINE->_breakpoints[i]->getHits(); + bpInfo._enabled = SCENGINE->_breakpoints[i]->isEnabled(); + breakpoints.push_back(bpInfo); + } + return breakpoints; +} + +Common::Array<WatchInfo> DebuggerController::getWatchlist() const { + Common::Array<WatchInfo> watchlist; + for (uint i = 0; i < SCENGINE->_watches.size(); i++) { + WatchInfo watchInfo; + watchInfo._filename = SCENGINE->_watches[i]->getFilename(); + watchInfo._symbol = SCENGINE->_watches[i]->getSymbol(); + watchlist.push_back(watchInfo); + } + return watchlist; +} + +uint32 DebuggerController::getLastLine() const { + return _lastLine; +} + +Common::String DebuggerController::getSourcePath() const { + return _sourceListingProvider->getPath(); +} + +Error DebuggerController::setSourcePath(const Common::String &sourcePath) { + ErrorCode err = _sourceListingProvider->setPath(sourcePath); + return Error((err == OK ? SUCCESS : ERROR), err); +} + +Listing* DebuggerController::getListing(Error* &error) { + delete (error); + if (_lastScript == nullptr) { + error = new Error(ERROR, NOT_ALLOWED); + return nullptr; + } + ErrorCode err; + Listing* res = _sourceListingProvider->getListing(SCENGINE->_currentScript->_filename, err); + error = new Error(err == OK ? SUCCESS : ERROR, err); + return res; +} + +Common::Array<TopEntry> DebuggerController::getTop() const { + Common::Array<TopEntry> res; + assert(SCENGINE); + for (uint i = 0; i < SCENGINE->_scripts.size(); i++) { + TopEntry entry; + entry.filename = SCENGINE->_scripts[i]->_filename; + entry.current = (SCENGINE->_scripts[i] == SCENGINE->_currentScript); + res.push_back(entry); + } + return res; +} + +} // end of namespace Wintermute diff --git a/engines/wintermute/debugger/debugger_controller.h b/engines/wintermute/debugger/debugger_controller.h new file mode 100644 index 0000000000..fd207868dc --- /dev/null +++ b/engines/wintermute/debugger/debugger_controller.h @@ -0,0 +1,119 @@ +/* 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. + * + */ + +#ifndef WINTERMUTE_DEBUGGER_ADAPTER_H +#define WINTERMUTE_DEBUGGER_ADAPTER_H + +#include "common/str.h" +#include "engines/wintermute/coll_templ.h" +#include "engines/wintermute/wintermute.h" +#include "engines/wintermute/debugger/listing_providers/source_listing_provider.h" +#include "script_monitor.h" +#include "error.h" +#include "listing.h" +namespace Wintermute { + +class ScScript; +class DebuggableScript; +class ScValue; + +struct BreakpointInfo { + Common::String _filename; + int _line; + int _hits; + bool _enabled; +}; + +struct WatchInfo { + Common::String _filename; + Common::String _symbol; + int _hits; + bool _enabled; +}; + +struct TopEntry { + bool current; + Common::String filename; + int watches; + int breakpointInfo; +}; + +class DebuggerController : public ScriptMonitor { + SourceListingProvider *_sourceListingProvider; + const WintermuteEngine *_engine; + DebuggableScript *_lastScript; + uint32 _lastDepth; + uint32 _lastLine; + void clear(); + bool bytecodeExists(const Common::String &filename); +public: + DebuggerController(WintermuteEngine *vm); + ~DebuggerController(); + Common::Array<TopEntry> getTop() const; + /** + * Get the last line # we've stopped at + */ + uint32 getLastLine() const; + Error addBreakpoint(const char *filename, int line); + Error removeBreakpoint(uint id); + Error disableBreakpoint(uint id); + Error enableBreakpoint(uint id); + Error addWatch(const char *filename, const char *symbol); + Error removeWatchpoint(uint id); + Error disableWatchpoint(uint id); + Error enableWatchpoint(uint id); + Common::Array<BreakpointInfo> getBreakpoints() const; + Common::Array<WatchInfo> getWatchlist() const; + /** + * @brief step one instruction + */ + Error step(); + /** + * @brief continue execution and don't step until next breakpoint + */ + Error stepContinue(); + /** + * @brief continue execution and don't step until the current activation record is popped + */ + Error stepFinish(); + /** + * @brief read value for a variable accessible from within the current scope. + */ + Common::String readValue(const Common::String &name, Error *error); + /** + * @brief set value for a variable accessible from within the current scope. + */ + Error setValue(const Common::String &name, const Common::String &value, ScValue*&var); + Error setSourcePath(const Common::String &sourcePath); + Common::String getSourcePath() const; + Listing *getListing(Error* &err); + void showFps(bool show); + /** + * Inherited from ScriptMonitor + */ + void onBreakpoint(const Breakpoint *breakpoint, DebuggableScript *script); + void onWatch(const Watch *watch, DebuggableScript *script); + void notifyStep(DebuggableScript *script) override; +}; +} + +#endif // WINTERMUTE_DEBUGGER_H diff --git a/engines/wintermute/debugger/error.cpp b/engines/wintermute/debugger/error.cpp new file mode 100644 index 0000000000..dd6e41c7bc --- /dev/null +++ b/engines/wintermute/debugger/error.cpp @@ -0,0 +1,137 @@ +/* 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 "error.h" +#include "engines/wintermute/debugger.h" + +namespace Wintermute { + +Error::Error(ErrorLevel errorLevel, + ErrorCode errorCode, + Common::String errorExtraString, + int errorExtraInt) : + _errorLevel(errorLevel), + _errorCode(errorCode), + _errorExtraInt(errorExtraInt), + _errorExtraString(errorExtraString){} + +Error::Error(ErrorLevel errorLevel, + ErrorCode errorCode, + int errorExtraInt) : + _errorLevel(errorLevel), + _errorCode(errorCode), + _errorExtraInt(errorExtraInt), + _errorExtraString(""){} + +Error::Error(ErrorLevel errorLevel, + ErrorCode errorCode) : + _errorLevel(errorLevel), + _errorCode(errorCode), + _errorExtraInt(0), + _errorExtraString(""){} + +Error::Error(ErrorLevel errorLevel, + ErrorCode errorCode, + Common::String errorExtraString) : + _errorLevel(errorLevel), + _errorCode(errorCode), + _errorExtraInt(0), + _errorExtraString(errorExtraString){} + +ErrorLevel Error::getErrorLevel() const { + return _errorLevel; +} + +ErrorCode Error::getErrorCode() const { + return _errorCode; +} + +Common::String Error::getErrorLevelStr() const { + switch (this->_errorLevel) { + case SUCCESS: + return "SUCCESS"; + break; + case NOTICE: + return "NOTICE"; + break; + case WARNING: + return "WARNING"; + break; + case ERROR: + return "ERROR"; + break; + } + return "SUCCESS"; +} + +Common::String Error::getErrorDisplayStr() const { + + Common::String errorStr; + + switch (this->_errorLevel) { + case SUCCESS: + errorStr += "OK!"; + break; + case WARNING: + errorStr += "WARNING: "; + break; + case ERROR: + errorStr += "ERROR: "; + break; + case NOTICE: + errorStr += "NOTICE: "; + break; + default: + // Um... + break; + } + + switch (this->_errorCode) { + case OK: + break; + case NOT_ALLOWED: + errorStr += "Could not execute requested operation. This is allowed only after a break."; + break; + case NO_SUCH_SOURCE: + errorStr += Common::String::format("Can't find source for %s. Double check you source path.", this->_errorExtraString.c_str()); + break; + case NO_SUCH_BYTECODE: + errorStr += Common::String::format("No such script: %s. Can't find bytecode; double check the script path.", this->_errorExtraString.c_str()); + break; + case SOURCE_PATH_NOT_SET: + errorStr += Common::String("Source path not set. Source won't be displayed. Try 'help " + Common::String(SET_PATH_CMD) + "'."); + break; + case NO_SUCH_BREAKPOINT: + errorStr += Common::String::format("No such breakpoint %d.", this->_errorExtraInt); + break; + case WRONG_TYPE: + errorStr += Common::String::format("Incompatible type: %s.", this->_errorExtraString.c_str()); + break; + default: + errorStr += Common::String::format("Unknown condition %d", this->_errorCode); + break; + } + + return errorStr; +} + +} // End namespace Wintermute diff --git a/engines/wintermute/debugger/error.h b/engines/wintermute/debugger/error.h new file mode 100644 index 0000000000..4e5b973445 --- /dev/null +++ b/engines/wintermute/debugger/error.h @@ -0,0 +1,73 @@ +/* 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. + * + */ + +#ifndef ERROR_H_ +#define ERROR_H_ + +#include "common/str.h" + +namespace Wintermute { + +enum ErrorLevel { + SUCCESS, + NOTICE, + WARNING, + ERROR +}; + +enum ErrorCode { + OK, + NO_SUCH_SOURCE, + COULD_NOT_OPEN, + NO_SUCH_LINE, + NOT_ALLOWED, + NO_SUCH_BYTECODE, + DUPLICATE_BREAKPOINT, + NO_SUCH_BREAKPOINT, + WRONG_TYPE, + PARSE_ERROR, + NOT_YET_IMPLEMENTED, + SOURCE_PATH_NOT_SET, + ILLEGAL_PATH, + UNKNOWN_ERROR +}; + + +class Error { + const ErrorLevel _errorLevel; + const ErrorCode _errorCode; + const int _errorExtraInt; + const Common::String _errorExtraString; +public: + Error(ErrorLevel, ErrorCode); + Error(ErrorLevel, ErrorCode, int errorExtraInt); + Error(ErrorLevel, ErrorCode, Common::String errorExtraString); + Error(ErrorLevel, ErrorCode, Common::String errorExtraString, int errorExtraInt); + ErrorLevel getErrorLevel() const; + ErrorCode getErrorCode() const; + Common::String getErrorLevelStr() const; + Common::String getErrorDisplayStr() const; +}; + +} // End of namespace Wintermute + +#endif /* ERROR_H_ */ diff --git a/engines/wintermute/debugger/listing.cpp b/engines/wintermute/debugger/listing.cpp new file mode 100644 index 0000000000..b8707fb842 --- /dev/null +++ b/engines/wintermute/debugger/listing.cpp @@ -0,0 +1,46 @@ +/* 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 "listing.h" +#include "common/array.h" + +namespace Wintermute { + +Common::Array<ListingLine> Listing::getLines(uint begin, uint end) { + assert(begin <= end); + Common::Array<ListingLine> ret; + for (uint i = begin; i <= end; i++) { + ListingLine listingline; + listingline.number = i; + listingline.text = getLine(i); + ret.push_back(listingline); + } + return ret; +} + +Common::Array<ListingLine> Listing::getLines(uint centre, uint before, uint after) { + uint begin = MAX(centre - before, (uint)1); // Line numbers start from 1 + uint end = MIN(centre + after, (uint)(getLength() - 1)); // Line numbers start from 1 + return getLines(begin, end); +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/debugger/listing.h b/engines/wintermute/debugger/listing.h new file mode 100644 index 0000000000..2ef21b702d --- /dev/null +++ b/engines/wintermute/debugger/listing.h @@ -0,0 +1,64 @@ +/* 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. + * + */ + +#ifndef LISTING_H_ +#define LISTING_H_ + +#include "common/array.h" + + +namespace Common { + +class String; + +} + +namespace Wintermute { + +struct ListingLine { + uint number; + Common::String text; +}; + +class Listing { +public: + virtual ~Listing() {}; + /** + * @brief get the listing length (in lines) + */ + virtual uint getLength() const = 0; + /** + * @brief return a specific line from a listing + * @param n line number + */ + virtual Common::String getLine(uint n) = 0; + /** + * @brief shorthand to get a lump of lines instead of calling getLine a number of times + * Generally you won't need to redefine these + */ + virtual Common::Array<ListingLine> getLines(uint centre, uint before, uint after); + virtual Common::Array<ListingLine> getLines(uint beginning, uint end); +}; + +} // End of namespace Wintermute + +#endif /* LISTING_H_ */ diff --git a/engines/wintermute/debugger/listing_provider.h b/engines/wintermute/debugger/listing_provider.h new file mode 100644 index 0000000000..b5ea23e49b --- /dev/null +++ b/engines/wintermute/debugger/listing_provider.h @@ -0,0 +1,42 @@ +/* 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. + * + */ + +#ifndef LISTING_PROVIDER_H_ +#define LISTING_PROVIDER_H_ + +#include "listing.h" +#include "engines/wintermute/debugger/error.h" + +namespace Wintermute { + +class ListingProvider { +public: + virtual ~ListingProvider() {}; + /** + * Get a listing. When implementing this, the result should be safe to delete for the caller. + */ + virtual Listing *getListing(const Common::String &filename, ErrorCode &error) = 0; +}; + +} // End of namespace Wintermute + +#endif /* LISTING_PROVIDER_H_ */ diff --git a/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.cpp b/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.cpp new file mode 100644 index 0000000000..30d29ee23e --- /dev/null +++ b/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.cpp @@ -0,0 +1,92 @@ +/* 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 "basic_source_listing_provider.h" +#include "engines/wintermute/base/base_file_manager.h" + +namespace Wintermute { +BasicSourceListingProvider::BasicSourceListingProvider() : _fsDirectory(nullptr) { +} + +BasicSourceListingProvider::~BasicSourceListingProvider() { +} + +SourceListing *BasicSourceListingProvider::getListing(const Common::String &filename, ErrorCode &_err) { + _err = OK; + if (!_fsDirectory) { + _err = SOURCE_PATH_NOT_SET; + return nullptr; + }; + + Common::String unixFilename; + + for (uint i = 0; i < filename.size(); i++) { + if (filename[i] == '\\') { + unixFilename.insertChar('/', unixFilename.size()); + } else { + unixFilename.insertChar(filename[i], unixFilename.size()); + } + } + + Common::SeekableReadStream *file = _fsDirectory->createReadStreamForMember(unixFilename); + Common::Array<Common::String> strings; + + if (!file) { + _err = NO_SUCH_SOURCE; + } else { + if (file->err()) { + _err = UNKNOWN_ERROR; + } + while (!file->eos()) { + strings.push_back(file->readLine()); + if (file->err()) { + _err = UNKNOWN_ERROR; + } + } + } + + if (_err == OK) { + return new SourceListing(strings); + } else { + return nullptr; + } +} + +ErrorCode BasicSourceListingProvider::setPath(const Common::String &path) { + if (path == "") + return ILLEGAL_PATH; + delete _fsDirectory; + Common::FSNode node(path); + if (node.exists() && node.isDirectory()) { + _fsDirectory = new Common::FSDirectory(node, 64); + return OK; + } else { + return COULD_NOT_OPEN; + } +} + +Common::String BasicSourceListingProvider::getPath() const { + if (!_fsDirectory) return ""; + return _fsDirectory->getFSNode().getPath(); +} + +} diff --git a/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.h b/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.h new file mode 100644 index 0000000000..e242205578 --- /dev/null +++ b/engines/wintermute/debugger/listing_providers/basic_source_listing_provider.h @@ -0,0 +1,44 @@ +/* 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. + * + */ + +#ifndef BASIC_SOURCE_LISTING_PROVIDER_H_ +#define BASIC_SOURCE_LISTING_PROVIDER_H_ + +#include "engines/wintermute/debugger/listing_provider.h" +#include "source_listing_provider.h" +#include "source_listing.h" +#include "common/fs.h" + +namespace Wintermute { + +class BasicSourceListingProvider : public SourceListingProvider { + Common::FSDirectory *_fsDirectory; +public: + BasicSourceListingProvider(); + virtual ~BasicSourceListingProvider(); + SourceListing *getListing(const Common::String &filename, ErrorCode &err); + ErrorCode setPath(const Common::String &path); + Common::String getPath() const; +}; + +} +#endif /* BASIC_SOURCE_LISTING_PROVIDER_H_ */ diff --git a/engines/wintermute/debugger/listing_providers/blank_listing.cpp b/engines/wintermute/debugger/listing_providers/blank_listing.cpp new file mode 100644 index 0000000000..928c91dc7f --- /dev/null +++ b/engines/wintermute/debugger/listing_providers/blank_listing.cpp @@ -0,0 +1,38 @@ +/* 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 "blank_listing.h" +#include "limits.h" + +namespace Wintermute { + +BlankListing::BlankListing(const Common::String filename) : _filename(filename) {} + +uint BlankListing::getLength() const { return UINT_MAX; } + +Common::String BlankListing::getLine(uint n) { + return "<no source for " + _filename + " ~~~ line: " + Common::String::format("%d", n) + ">"; +} +BlankListing::~BlankListing() {} + +} + diff --git a/engines/wintermute/debugger/listing_providers/blank_listing.h b/engines/wintermute/debugger/listing_providers/blank_listing.h new file mode 100644 index 0000000000..8c5ea19aa7 --- /dev/null +++ b/engines/wintermute/debugger/listing_providers/blank_listing.h @@ -0,0 +1,39 @@ +/* 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. + * + */ + +#ifndef BLANK_LISTING_H_ +#define BLANK_LISTING_H_ +#include "engines/wintermute/debugger/listing.h" + +namespace Wintermute { +class BlankListing : public Listing { + const Common::String _filename; +public: + BlankListing(const Common::String filename); + virtual ~BlankListing(); + virtual uint getLength() const; + virtual Common::String getLine(uint n); +}; + +} // End of namespace Wintermute + +#endif diff --git a/engines/wintermute/debugger/listing_providers/blank_listing_provider.cpp b/engines/wintermute/debugger/listing_providers/blank_listing_provider.cpp new file mode 100644 index 0000000000..58e9e7e156 --- /dev/null +++ b/engines/wintermute/debugger/listing_providers/blank_listing_provider.cpp @@ -0,0 +1,35 @@ +/* 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 "blank_listing_provider.h" +#include "blank_listing.h" +namespace Wintermute { +BlankListingProvider::BlankListingProvider() {} + +BlankListingProvider::~BlankListingProvider() {} + +Listing *BlankListingProvider::getListing(const Common::String &filename, ErrorCode &error) { + Listing *l = new BlankListing(filename); + error = OK; + return l; // Delete this sometime please. +} +} // End of namespace Wintermute diff --git a/engines/wintermute/debugger/listing_providers/blank_listing_provider.h b/engines/wintermute/debugger/listing_providers/blank_listing_provider.h new file mode 100644 index 0000000000..e583455c92 --- /dev/null +++ b/engines/wintermute/debugger/listing_providers/blank_listing_provider.h @@ -0,0 +1,38 @@ +/* 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. + * + */ + +#ifndef BLANK_LISTING_PROVIDER_H_ +#define BLANK_LISTING_PROVIDER_H_ + +#include "engines/wintermute/debugger/listing.h" +#include "engines/wintermute/debugger/listing_provider.h" +#include "engines/wintermute/debugger/error.h" + +namespace Wintermute { +class BlankListingProvider : public ListingProvider { +public: + BlankListingProvider(); + ~BlankListingProvider(); + Listing *getListing(const Common::String &filename, ErrorCode &error); +}; +} // End of namespace Wintermute +#endif diff --git a/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.cpp b/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.cpp new file mode 100644 index 0000000000..20fe708380 --- /dev/null +++ b/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.cpp @@ -0,0 +1,80 @@ +/* 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 "cached_source_listing_provider.h" +#include "basic_source_listing_provider.h" +#include "blank_listing_provider.h" +#include "source_listing.h" + +namespace Wintermute { + +CachedSourceListingProvider::CachedSourceListingProvider() { + _sourceListingProvider = new BasicSourceListingProvider(); + _fallbackListingProvider = new BlankListingProvider(); +} + +CachedSourceListingProvider::~CachedSourceListingProvider() { + delete _sourceListingProvider; + delete _fallbackListingProvider; + for (Common::HashMap<Common::String, SourceListing*>::iterator it = _cached.begin(); + it != _cached.end(); it++) { + delete (it->_value); + } +} + +Listing *CachedSourceListingProvider::getListing(const Common::String &filename, Wintermute::ErrorCode &error) { + if (_cached.contains(filename)) { + error = OK; + SourceListing *copy = new SourceListing(*_cached.getVal(filename)); + return copy; + } else { + ErrorCode inner; + SourceListing *res = _sourceListingProvider->getListing(filename, inner); + if (inner == OK) { + SourceListing *copy = new SourceListing(*res); + _cached.setVal(filename, copy); // The cached copy is deleted on destruction + return res; + } else { + delete res; + return _fallbackListingProvider->getListing(filename, error); + } + } +} + +void CachedSourceListingProvider::invalidateCache() { + for (Common::HashMap<Common::String, SourceListing*>::iterator it = _cached.begin(); + it != _cached.end(); it++) { + delete (it->_value); + } + _cached.clear(); +} + +ErrorCode CachedSourceListingProvider::setPath(const Common::String &path) { + invalidateCache(); + return _sourceListingProvider->setPath(path); +} + +Common::String CachedSourceListingProvider::getPath() const { + return _sourceListingProvider->getPath(); +} + +} // End of namespace Wintermute diff --git a/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.h b/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.h new file mode 100644 index 0000000000..6e4925f2b4 --- /dev/null +++ b/engines/wintermute/debugger/listing_providers/cached_source_listing_provider.h @@ -0,0 +1,52 @@ +/* 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. + * + */ + +#ifndef CACHED_LISTING_PROVIDER_H_ +#define CACHED_LISTING_PROVIDER_H_ + +#include "common/hashmap.h" +#include "common/hash-str.h" +#include "engines/wintermute/debugger/error.h" +#include "source_listing_provider.h" + +namespace Wintermute { + +class BasicSourceListingProvider; +class BlankListingProvider; +class Listing; + +class CachedSourceListingProvider : public SourceListingProvider { + BasicSourceListingProvider *_sourceListingProvider; + BlankListingProvider *_fallbackListingProvider; + Common::HashMap<Common::String, SourceListing *> _cached; + void invalidateCache(); +public: + CachedSourceListingProvider(); + virtual ~CachedSourceListingProvider(); + ErrorCode setPath(const Common::String &path); + Common::String getPath() const; + Listing *getListing(const Common::String &filename, ErrorCode &err); +}; + +} // End of namespace Wintermute + +#endif /* CACHED_LISTING_PROVIDER_H_ */ diff --git a/engines/wintermute/debugger/listing_providers/source_listing.cpp b/engines/wintermute/debugger/listing_providers/source_listing.cpp new file mode 100644 index 0000000000..ff81e20f02 --- /dev/null +++ b/engines/wintermute/debugger/listing_providers/source_listing.cpp @@ -0,0 +1,57 @@ +/* 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 "source_listing.h" + +namespace Wintermute { + +SourceListing::SourceListing(const Common::Array<Common::String> &strings) : _strings(strings) {} + +SourceListing::~SourceListing() {} + +uint SourceListing::getLength() const { + return _strings.size(); +} + +Common::String SourceListing::getLine(uint n) { + uint index = n - 1; // Line numbers start from 1, arrays from 0 + /* + * Clients should not ask for a line number that + * is not in the source file. + * 0 is undefined, n - 1 is undefined. + * It is easy for the client to check that n > 0 + * and n < getLength(), so it should just not happen. + * We return '^', after vim, to misbehaving clients. + */ + if (n == 0) { + return Common::String("^"); + } + if (index < getLength()) { + return _strings[index]; + } else { + return Common::String("^"); + } +} + +} // End of namespace Wintermute + + diff --git a/engines/wintermute/debugger/listing_providers/source_listing.h b/engines/wintermute/debugger/listing_providers/source_listing.h new file mode 100644 index 0000000000..bf08578218 --- /dev/null +++ b/engines/wintermute/debugger/listing_providers/source_listing.h @@ -0,0 +1,37 @@ +/* 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. + * + */ + +#ifndef SOURCE_LISTING_H_ +#define SOURCE_LISTING_H_ +#include "engines/wintermute/debugger/listing.h" + +namespace Wintermute { +class SourceListing : public Listing { + const Common::Array<Common::String> _strings; +public: + SourceListing(const Common::Array<Common::String> &strings); + virtual ~SourceListing(); + virtual uint getLength() const; + virtual Common::String getLine(uint n); +}; +} +#endif /* DUMMY_LISTING_H_ */ diff --git a/engines/wintermute/debugger/listing_providers/source_listing_provider.h b/engines/wintermute/debugger/listing_providers/source_listing_provider.h new file mode 100644 index 0000000000..18f05e56ed --- /dev/null +++ b/engines/wintermute/debugger/listing_providers/source_listing_provider.h @@ -0,0 +1,49 @@ +/* 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. + * + */ + +#ifndef SOURCE_LISTING_PROVIDER_H_ +#define SOURCE_LISTING_PROVIDER_H_ + +#include "engines/wintermute/debugger/error.h" +#include "engines/wintermute/debugger/listing_provider.h" +#include "common/str.h" + +namespace Wintermute { + +class SourceListing; +class Listing; + +class SourceListingProvider : ListingProvider { +public: + virtual ~SourceListingProvider() {}; + /** + * Get a listing. When implementing this, the result should be safe to delete for the caller. + */ + virtual Listing *getListing(const Common::String &filename, ErrorCode &err) = 0; + virtual ErrorCode setPath(const Common::String &path) = 0; + virtual Common::String getPath() const = 0; + +}; + +} // End of namespace Wintermute + +#endif /* SOURCE_LISTING_PROVIDER_H_ */ diff --git a/engines/wintermute/debugger/script_monitor.cpp b/engines/wintermute/debugger/script_monitor.cpp new file mode 100644 index 0000000000..2e9370c923 --- /dev/null +++ b/engines/wintermute/debugger/script_monitor.cpp @@ -0,0 +1,26 @@ +/* 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 "script_monitor.h" + +namespace Wintermute { +} diff --git a/engines/wintermute/debugger/script_monitor.h b/engines/wintermute/debugger/script_monitor.h new file mode 100644 index 0000000000..e9559e2ade --- /dev/null +++ b/engines/wintermute/debugger/script_monitor.h @@ -0,0 +1,43 @@ +/* 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. + * + */ + +#ifndef SCRIPTMONITOR_H_ +#define SCRIPTMONITOR_H_ + +namespace Wintermute { + +class DebuggableScript; +class Breakpoint; +class Watch; + +class ScriptMonitor { +public: + + virtual ~ScriptMonitor() {}; + virtual void notifyStep(DebuggableScript* script) = 0; + virtual void onBreakpoint(const Breakpoint* breakpoint, DebuggableScript* script) = 0; + virtual void onWatch(const Watch* watch, DebuggableScript* script) = 0; +}; + +} // End of namespace Wintermute + +#endif /* SCRIPTMONITOR_H_ */ diff --git a/engines/wintermute/debugger/watch.cpp b/engines/wintermute/debugger/watch.cpp new file mode 100644 index 0000000000..410756fdc8 --- /dev/null +++ b/engines/wintermute/debugger/watch.cpp @@ -0,0 +1,42 @@ +/* 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 "watch.h" +#include "watch_instance.h" +#include "script_monitor.h" + +namespace Wintermute { + +Watch::Watch(const Common::String &filename, const Common::String &symbol, ScriptMonitor* monitor) : _enabled(false), _filename(filename), _symbol(symbol), _monitor(monitor) {} + +Watch::~Watch() { /* Nothing to take care of in here */ } + +void Watch::trigger(WatchInstance* instance) { + _monitor->onWatch(this, instance->_script); +} + +Common::String Watch::getFilename() const { return _filename; } +Common::String Watch::getSymbol() const { return _symbol; } +bool Watch::isEnabled() const { return _enabled; } +void Watch::enable() { _enabled = true; } +void Watch::disable() { _enabled = false; } +} diff --git a/engines/wintermute/debugger/watch.h b/engines/wintermute/debugger/watch.h new file mode 100644 index 0000000000..cbffe43b41 --- /dev/null +++ b/engines/wintermute/debugger/watch.h @@ -0,0 +1,51 @@ +/* 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. + * + */ + +#ifndef WATCH_H_ +#define WATCH_H_ + +#include "common/str.h" + +namespace Wintermute { + +class ScValue; +class ScScript; +class WatchInstance; +class ScriptMonitor; + +class Watch { + const Common::String _filename; + const Common::String _symbol; + int _enabled; + ScriptMonitor *_monitor; +public: + Watch(const Common::String &filename, const Common::String &symbol, ScriptMonitor*); + Common::String getFilename() const; + Common::String getSymbol() const; + bool isEnabled() const; + void enable(); + void disable(); + void trigger(WatchInstance*); + virtual ~Watch(); +}; +} +#endif /* WATCH_H_ */ diff --git a/engines/wintermute/debugger/watch_instance.cpp b/engines/wintermute/debugger/watch_instance.cpp new file mode 100644 index 0000000000..2d31221ad4 --- /dev/null +++ b/engines/wintermute/debugger/watch_instance.cpp @@ -0,0 +1,53 @@ +/* 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 "watch_instance.h" +#include "engines/wintermute/base/scriptables/script_value.h" +#include "engines/wintermute/base/scriptables/debuggable/debuggable_script.h" +#include "engines/wintermute/debugger/watch.h" + +namespace Wintermute { + +WatchInstance::WatchInstance(Watch* watch, DebuggableScript* script) : _watch(watch), _script(script), _lastValue(nullptr) {} +WatchInstance::~WatchInstance() { delete _lastValue; } + +void WatchInstance::evaluate() { + if (_watch->isEnabled()) { + if (!_watch->getFilename().compareTo(_script->_filename)) { + + if(_lastValue == nullptr) { + _lastValue = new ScValue(_script->_gameRef); + // ^^ This here is NULL by default + } + ScValue* currentValue = _script->resolveName(_watch->getSymbol()); + if(ScValue::compare( + currentValue, + _lastValue + )) { + _lastValue->copy(currentValue); + _watch->trigger(this); + } + delete currentValue; + } + } +} +} // End of namespace Wintermute diff --git a/engines/wintermute/debugger/watch_instance.h b/engines/wintermute/debugger/watch_instance.h new file mode 100644 index 0000000000..84fb62968d --- /dev/null +++ b/engines/wintermute/debugger/watch_instance.h @@ -0,0 +1,44 @@ +/* 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. + * + */ + +#ifndef WATCH_INSTANCE_H_ +#define WATCH_INSTANCE_H_ + +namespace Wintermute { +class Watch; +class ScValue; +class DebuggableScript; + +class WatchInstance { + Watch* _watch; + ScValue *_lastValue; + DebuggableScript* _script; +public: + WatchInstance (Watch* watch, DebuggableScript* script); + ~WatchInstance(); + void evaluate(); +friend class DebuggableScript; +friend class Watch; +}; +} // End of namespace Wintermute + +#endif /* WATCH_INSTANCE_H_ */ diff --git a/engines/wintermute/detection.cpp b/engines/wintermute/detection.cpp index aca682ae99..4e8eab505f 100644 --- a/engines/wintermute/detection.cpp +++ b/engines/wintermute/detection.cpp @@ -75,8 +75,8 @@ static const char *directoryGlobs[] = { class WintermuteMetaEngine : public AdvancedMetaEngine { public: WintermuteMetaEngine() : AdvancedMetaEngine(Wintermute::gameDescriptions, sizeof(WMEGameDescription), Wintermute::wintermuteGames, gameGuiOptions) { - _singleid = "wintermute"; - _guioptions = GUIO2(GUIO_NOMIDI, GAMEOPTION_SHOW_FPS); + _singleId = "wintermute"; + _guiOptions = GUIO2(GUIO_NOMIDI, GAMEOPTION_SHOW_FPS); _maxScanDepth = 2; _directoryGlobs = directoryGlobs; } @@ -85,7 +85,7 @@ public: } virtual const char *getOriginalCopyright() const { - return "Copyright (c) 2011 Jan Nedoma"; + return "Copyright (C) 2011 Jan Nedoma"; } virtual const ADGameDescription *fallbackDetect(const FileMap &allFiles, const Common::FSList &fslist) const { @@ -94,8 +94,8 @@ public: s_fallbackDesc.language = Common::UNK_LANG; s_fallbackDesc.flags = ADGF_UNSTABLE; s_fallbackDesc.platform = Common::kPlatformWindows; // default to Windows - s_fallbackDesc.gameid = "wintermute"; - s_fallbackDesc.guioptions = GUIO0(); + s_fallbackDesc.gameId = "wintermute"; + s_fallbackDesc.guiOptions = GUIO0(); if (allFiles.contains("data.dcp")) { Common::String name, caption; @@ -109,7 +109,7 @@ public: // Prefix to avoid collisions with actually known games name = "wmeunk-" + name; Common::strlcpy(s_fallbackGameIdBuf, name.c_str(), sizeof(s_fallbackGameIdBuf) - 1); - s_fallbackDesc.gameid = s_fallbackGameIdBuf; + s_fallbackDesc.gameId = s_fallbackGameIdBuf; if (caption != name) { caption += " (unknown version) "; char *offset = s_fallbackGameIdBuf + name.size() + 1; diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h index 25a01766e4..68985d8d0c 100644 --- a/engines/wintermute/detection_tables.h +++ b/engines/wintermute/detection_tables.h @@ -138,111 +138,118 @@ static const PlainGameDescriptor wintermuteGames[] = { static const WMEGameDescription gameDescriptions[] = { // Five Lethal Demons - WME_WINENTRY("5ld", "", + WME_WINENTRY("5ld", "", WME_ENTRY1s("data.dcp", "1037a77cbd001e0644898addc022322c", 15407750), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Five Magical Amulets (Czech) - WME_WINENTRY("5ma", "", + WME_WINENTRY("5ma", "", WME_ENTRY2s("czech.dcp", "7b2515a8ceb955c72bc14f0f1fca869e", 184, "data.dcp", "0134e92bcd5fd2837df3971087e96067", 163316498), Common::CZ_CZE, ADGF_UNSTABLE, WME_1_7_0), // Five Magical Amulets (English) WME_WINENTRY("5ma", "", WME_ENTRY2s("english.dcp", "2f97bca09260ba23b645da9f0855ce7f", 893681, "data.dcp", "0134e92bcd5fd2837df3971087e96067", 163316498), Common::EN_ANY, ADGF_UNSTABLE, WME_1_7_0), + // Five Magical Amulets (German) + WME_WINENTRY("5ma", "", + WME_ENTRY2s("german.dcp", "bfa74aae81672803d0d0748ac0a532b7", 885150, + "data.dcp", "0134e92bcd5fd2837df3971087e96067", 163316498), Common::DE_DEU, ADGF_UNSTABLE, WME_1_7_0), // Five Magical Amulets (Polish) WME_WINENTRY("5ma", "", WME_ENTRY2s("polish.dcp", "bb877d48795471a17f25b0b5109100d1", 1132197, "data.dcp", "0134e92bcd5fd2837df3971087e96067", 163316498), Common::PL_POL, ADGF_UNSTABLE, WME_1_7_0), // Actual Destination - WME_WINENTRY("actualdest", "", + WME_WINENTRY("actualdest", "", WME_ENTRY1s("data.dcp", "6926f44b26f21ceb1d840eaab9aeb510", 9081740), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Boredom of Agustin Cordes - WME_WINENTRY("agustin", "", + WME_WINENTRY("agustin", "", WME_ENTRY1s("data.dcp", "abb79c16c9b92e9b06525a4c7c3f5861", 2461949), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Beyond the Threshold - WME_WINENTRY("bthreshold", "", + WME_WINENTRY("bthreshold", "", WME_ENTRY1s("data.dcp", "d49bf9ccb2e74507447c82d6ad3e2bc4", 12773712), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Bickadoodle - WME_WINENTRY("bickadoodle", "", + WME_WINENTRY("bickadoodle", "", WME_ENTRY1s("data.dcp", "84db4d1594cac95e25614985775d10a8", 35303844), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Bickadoodle (Ver 1.1) - WME_WINENTRY("bickadoodle", "Version 1.1", + WME_WINENTRY("bickadoodle", "Version 1.1", WME_ENTRY1s("data.dcp", "8bb52ac9a9ee129c5059e8e808b669d7", 35337760), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Bickadoodle (Ver 1.2) WME_WINENTRY("bickadoodle", "Version 1.2", WME_ENTRY1s("data.dcp", "1796a48f3ed72dd785ce93334ab883cc", 35337760), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Bickadoodle (download from http://aethericgames.com/games/bickadoodle/download-bickadoodle/) - WME_WINENTRY("bickadoodle", "", + WME_WINENTRY("bickadoodle", "", WME_ENTRY1s("data.dcp", "1584d83577c32add0fce27fae91141a2", 35337728), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Book of Gron Part One - WME_WINENTRY("bookofgron", "", + WME_WINENTRY("bookofgron", "", WME_ENTRY1s("data.dcp", "e61b2ebee044a82fa0f8ca0fce2c8946", 83129531), Common::RU_RUS, ADGF_UNSTABLE, LATEST_VERSION), // Carol Reed 4 - East Side Story (Demo) - WME_WINENTRY("carolreed4", "Demo", + WME_WINENTRY("carolreed4", "Demo", WME_ENTRY1s("data.dcp", "b3f8b09bb4b05ee3e9d14697525257f9", 59296246), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Carol Reed 4 - East Side Story - WME_WINENTRY("carolreed4", "", - WME_ENTRY1s("data.dcp", "b26377797f060afc2d440d820100c1ce", 529320536), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), + WME_WINENTRY("carolreed4", "", + WME_ENTRY1s("data.dcp", "b26377797f060afc2d440d820100c1ce", 529320536), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Carol Reed 5 - The Colour of Murder - WME_WINENTRY("carolreed5", "", + WME_WINENTRY("carolreed5", "", WME_ENTRY1s("data.dcp", "3fcfca44209545d0e26774156427b494", 603660415), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), + // Carol Reed 5 - The Colour of Murder (1.0 Demo) + WME_WINENTRY("carolreed5", "Demo", + WME_ENTRY1s("data.dcp", "27b3efc018ade5ee8f4adf08b4e3c0dd", 92019500), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Carol Reed 6 - Black Circle - WME_WINENTRY("carolreed6", "", + WME_WINENTRY("carolreed6", "", WME_ENTRY1s("data.dcp", "0e4c532beecf23d85012168753f41189", 456258147), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Carol Reed 7 - Blue Madonna (Demo) - WME_WINENTRY("carolreed7", "Demo", + WME_WINENTRY("carolreed7", "Demo", WME_ENTRY1s("data.dcp", "0372ad0c775266f6355e9e8ae397a2f1", 103719442), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Carol Reed 7 - Blue Madonna - WME_WINENTRY("carolreed7", "", + WME_WINENTRY("carolreed7", "", WME_ENTRY1s("data.dcp", "24e3db3e2fabfc956713796d87a3efb0", 495471147), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Carol Reed 8 - Amber's Blood - WME_WINENTRY("carolreed8", "", + WME_WINENTRY("carolreed8", "", WME_ENTRY1s("data.dcp", "859d16b0d5b9b255e470cbded2c6cedc", 502714557), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Carol Reed 9 - Cold Case Summer - WME_WINENTRY("carolreed9", "", + WME_WINENTRY("carolreed9", "", WME_ENTRY1s("data.dcp", "2b343b48a7aee508d728a546b414a255", 620005266), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Chivalry is Not Dead - WME_WINENTRY("chivalry", "", - WME_ENTRY1s("data.dcp", "ebd0915d9a12df5224be22f53bb23eb6", 7278306), Common::EN_ANY, ADGF_TESTING, LATEST_VERSION), + WME_WINENTRY("chivalry", "", + WME_ENTRY1s("data.dcp", "ebd0915d9a12df5224be22f53bb23eb6", 7278306), Common::EN_ANY, ADGF_NO_FLAGS, LATEST_VERSION), // Chivalry is Not Dead (Version from deirdrakai.com) - WME_WINENTRY("chivalry", "", - WME_ENTRY1s("data.dcp", "ae6d91b9517f4d2851a8ad94c96951c8", 7278302), Common::EN_ANY, ADGF_TESTING, LATEST_VERSION), + WME_WINENTRY("chivalry", "", + WME_ENTRY1s("data.dcp", "ae6d91b9517f4d2851a8ad94c96951c8", 7278302), Common::EN_ANY, ADGF_NO_FLAGS, LATEST_VERSION), // Conspiracao Dumont - WME_WINENTRY("conspiracao", "", + WME_WINENTRY("conspiracao", "", WME_ENTRY1s("ConspiracaoDumont.exe", "106f3f2c8f18bb5ffffeed634ace256c", 32908032), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Corrosion: Cold Winter Waiting - WME_WINENTRY("corrosion", "", - WME_ENTRY1s("data.dcp", "ae885b1a8faa0b27f43c0e8f0df02fc9", 525931618), Common::EN_ANY, ADGF_TESTING, LATEST_VERSION), + WME_WINENTRY("corrosion", "", + WME_ENTRY1s("data.dcp", "ae885b1a8faa0b27f43c0e8f0df02fc9", 525931618), Common::EN_ANY, ADGF_NO_FLAGS, LATEST_VERSION), // Dead City (Czech) // The Czech data are in data.dcp, so in this case we'll have to // just detect the english version twice, to give the user a choice. WME_WINENTRY("deadcity", "", - WME_ENTRY2s("english.dcp", "c591046d6de7e381d76f70e0787b2b1f", 415935, + WME_ENTRY2s("english.dcp", "c591046d6de7e381d76f70e0787b2b1f", 415935, "data.dcp", "7ebfd50d1a22370ed7b079bcaa631d62", 9070205), Common::CZ_CZE, ADGF_UNSTABLE, LATEST_VERSION), // Dead City (English) WME_WINENTRY("deadcity", "", - WME_ENTRY2s("english.dcp", "c591046d6de7e381d76f70e0787b2b1f", 415935, + WME_ENTRY2s("english.dcp", "c591046d6de7e381d76f70e0787b2b1f", 415935, "data.dcp", "7ebfd50d1a22370ed7b079bcaa631d62", 9070205), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Dead City (Italian) WME_WINENTRY("deadcity", "", - WME_ENTRY2s("italian.dcp", "92d8efb94436bec7bd1b7fe0b548192e", 454037, + WME_ENTRY2s("italian.dcp", "92d8efb94436bec7bd1b7fe0b548192e", 454037, "data.dcp", "7ebfd50d1a22370ed7b079bcaa631d62", 9070205), Common::IT_ITA, ADGF_UNSTABLE, LATEST_VERSION), // Dead City (Russian) WME_WINENTRY("deadcity", "", - WME_ENTRY2s("russian.dcp", "a0ae71e9e1185596fffb07ad2c951eb9", 653317, + WME_ENTRY2s("russian.dcp", "a0ae71e9e1185596fffb07ad2c951eb9", 653317, "data.dcp", "7ebfd50d1a22370ed7b079bcaa631d62", 9070205), Common::RU_RUS, ADGF_UNSTABLE, LATEST_VERSION), // Dirty Split (Czech) WME_WINENTRY("dirtysplit", "", - WME_ENTRY2s("czech.dcp", "08a71446467cf8f9444cfea446b46ad6", 127697934, + WME_ENTRY2s("czech.dcp", "08a71446467cf8f9444cfea446b46ad6", 127697934, "data.dcp", "8b4b81b718bf65f30a67fc0b1e329eb5", 88577623), Common::CZ_CZE, ADGF_UNSTABLE, LATEST_VERSION), // Dirty Split (English) - WME_WINENTRY("dirtysplit", "", + WME_WINENTRY("dirtysplit", "", WME_ENTRY1s("data.dcp", "8f3dae199361ece0f59fb20cfff6eed3", 88577621), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Dirty Split (French) WME_WINENTRY("dirtysplit", "", - WME_ENTRY2s("french.dcp", "a0508dedebd0fe478d0158fa4c2a1136", 125534323, + WME_ENTRY2s("french.dcp", "a0508dedebd0fe478d0158fa4c2a1136", 125534323, "data.dcp", "e6d70c7f5d181b761cfcf974adf9186a", 88577623), Common::FR_FRA, ADGF_UNSTABLE, LATEST_VERSION), // Dirty Split (German) - WME_WINENTRY("dirtysplit", "", + WME_WINENTRY("dirtysplit", "", WME_ENTRY1s("data.dcp", "139d8a25579e969f8b37d20e6e3de5f9", 92668291), Common::DE_DEU, ADGF_UNSTABLE, LATEST_VERSION), // Dirty Split (Italian) WME_WINENTRY("dirtysplit", "", @@ -253,36 +260,36 @@ static const WMEGameDescription gameDescriptions[] = { WME_ENTRY2s("spanish.dcp", "b3982c0a5e85b42e1e38240fef004aa4", 164428596, "data.dcp", "63766d6c68b9f00b632ea1736fc8a95c", 88577621), Common::ES_ESP, ADGF_UNSTABLE, LATEST_VERSION), // Des Reves Elastiques Avec Mille Insectes Nommes Georges - WME_WINENTRY("dreaming", "", + WME_WINENTRY("dreaming", "", WME_ENTRY1s("data.dcp", "4af26d97ea063fc1277ce30ae431de90", 8804073), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Dreamscape - WME_WINENTRY("dreamscape", "", + WME_WINENTRY("dreamscape", "", WME_ENTRY1s("data.dcp", "7a5752ed4446c862be9f02d7932acf54", 17034377), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Escape from the Mansion - WME_WINENTRY("escapemansion", "Beta 1", + WME_WINENTRY("escapemansion", "Beta 1", WME_ENTRY1s("data.dcp", "d8e348b2312cc36a929cad75f12e0b3a", 21452380), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Escape from the Mansion - WME_WINENTRY("escapemansion", "Beta 2", + WME_WINENTRY("escapemansion", "Beta 2", WME_ENTRY1s("data.dcp", "ded5fa6c5f2afdaf2cafb53e52cd3dd8", 21455763), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Escape from the Mansion - WME_WINENTRY("escapemansion", "1.3", + WME_WINENTRY("escapemansion", "1.3", WME_ENTRY1s("data.dcp", "1e5d231b56c8a228cd15cb690f50253e", 29261972), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Four - WME_WINENTRY("four", "", + WME_WINENTRY("four", "", WME_ENTRY1s("data.dcp", "ec05cd5e37c9a524053b8859635a4234", 62599855), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Framed - WME_WINENTRY("framed", "", + WME_WINENTRY("framed", "", WME_ENTRY1s("data.dcp", "e7259fb36f2c6f9f28242291e0c3de98", 34690568), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Ghost in the Sheet WME_WINENTRY("ghostsheet", "", WME_ENTRY2s("english.dcp", "e6d0aad2c89996bcabe416105a3d6d3a", 12221017, "data.dcp", "b2f8b05328e4881e15e98e845b63f451", 168003), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Ghost in the Sheet (Demo) - WME_WINENTRY("ghostsheet", "Demo", + WME_WINENTRY("ghostsheet", "Demo", WME_ENTRY1s("data.dcp", "dc1f6595f412ac25a52eaf47dad4ab81", 169083), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Hamlet or the last game without MMORPS features, shaders and product placement - WME_WINENTRY("hamlet", "", - + WME_WINENTRY("hamlet", "", + WME_ENTRY1s("data.dcp", "f624add957a77c9930529fb28cc2450f", 88183022), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Helga Deep In Trouble (English) WME_WINENTRY("helga", "", @@ -293,37 +300,37 @@ static const WMEGameDescription gameDescriptions[] = { WME_ENTRY2s("english.dcp", "b3a93e678f0ef97200f691cd1724643f", 135864, "data.dcp", "45134ed93bc391edf148b79cdcbf2a09", 154266028), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // James Peris: No License Nor Control (English) - WME_WINENTRY("jamesperis", "", + WME_WINENTRY("jamesperis", "", WME_ENTRY1s("data.dcp", "a420961e170cb7d168a0d2bae2fe5218", 225294032), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // James Peris: No License Nor Control (Spanish) - WME_WINENTRY("jamesperis", "", + WME_WINENTRY("jamesperis", "", WME_ENTRY1s("data.dcp", "a420961e170cb7d168a0d2bae2fe5218", 225294032), Common::ES_ESP, ADGF_UNSTABLE, LATEST_VERSION), // James Peris: No License Nor Control (Demo) (English) - WME_WINENTRY("jamesperis", "Demo", + WME_WINENTRY("jamesperis", "Demo", WME_ENTRY1s("data.dcp", "edb9f9c7a08993c1e28f4e477b5f9830", 116113507), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // James Peris: No License Nor Control (Demo) (Spanish) - WME_WINENTRY("jamesperis", "Demo", + WME_WINENTRY("jamesperis", "Demo", WME_ENTRY1s("data.dcp", "edb9f9c7a08993c1e28f4e477b5f9830", 116113507), Common::ES_ESP, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // J.U.L.I.A. (English) - WME_WINENTRY("julia", "", + WME_WINENTRY("julia", "", WME_ENTRY1s("data.dcp", "c2264b4f8fcd132d2913ff5b6076a24f", 10109741), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // J.U.L.I.A. (English, Bundle in a box-version) - WME_WINENTRY("julia", "Version 1.2", + WME_WINENTRY("julia", "Version 1.2", WME_ENTRY1s("data.dcp", "fe90023ccc22f35185b40b910e0d03a2", 10101373), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // J.U.L.I.A. (English) (Demo) - WME_WINENTRY("julia", "Demo", + WME_WINENTRY("julia", "Demo", WME_ENTRY1s("data.dcp", "f0bbc3394555a9811f6050dae428cab6", 7655237), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // J.U.L.I.A. (English) (Greenlight Demo) - WME_WINENTRY("julia", "Greenlight Demo", + WME_WINENTRY("julia", "Greenlight Demo", WME_ENTRY1s("data.dcp", "4befd448d36b0dae9c3ab1aa7cb8b78d", 7271886), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Kulivocko (Czech) - WME_WINENTRY("kulivocko", "", + WME_WINENTRY("kulivocko", "", WME_ENTRY1s("data.dcp", "44306dc470e9b27474043932eccee02f", 155106392), Common::CZ_CZE, ADGF_UNSTABLE, LATEST_VERSION), // Kulivocko (Czech) (Demo) - WME_WINENTRY("kulivocko", "Demo", + WME_WINENTRY("kulivocko", "Demo", WME_ENTRY1s("data.dcp", "63b164bdfadecbb0deb5da691afb8154", 48362234), Common::CZ_CZE, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Life In 3 Minutes - WME_WINENTRY("lifein3minutes", "", + WME_WINENTRY("lifein3minutes", "", WME_ENTRY1s("data.dcp", "c6368950e37a95bf098b02b4eaa5b929", 141787214), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Looky Demo (English) WME_WINENTRY("looky", "Demo", @@ -338,10 +345,10 @@ static const WMEGameDescription gameDescriptions[] = { WME_ENTRY2s("german.dcp", "bf4c2b8c26342342441a6d64934ab832", 107027865, "data.dcp", "50de0beaa5ad621aa9f020df901d1e74", 1342214), Common::DE_DEU, ADGF_UNSTABLE, LATEST_VERSION), // Mirage - WME_WINENTRY("mirage", "", + WME_WINENTRY("mirage", "", WME_ENTRY1s("data.dcp", "d230b0b99c0aa77b9ecd094d8ee5573b", 17844056), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Oknytt - WME_WINENTRY("oknytt", "Version 1.0", + WME_WINENTRY("oknytt", "Version 1.0", WME_ENTRY1s("data.dcp", "6456cf8f429905c83f07509f9da536dd", 109502959), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Oknytt (Version 1.13 English) (These are detected along with d_sounds.dcp to avoid mass-detecting in the languages-subfolder.) WME_WINENTRY("oknytt", "Version 1.13", @@ -360,25 +367,25 @@ static const WMEGameDescription gameDescriptions[] = { WME_ENTRY2s("spanish.dcp", "10c46152cb29581671f3b6b7c229c957", 319406572, "d_sounds.dcp", "7d04dff8ca11174486bd4b7a80fdcabb", 154943401), Common::ES_ESP, ADGF_UNSTABLE, LATEST_VERSION), // Night Train Demo - WME_WINENTRY("nighttrain", "", + WME_WINENTRY("nighttrain", "", WME_ENTRY1s("data.dcp", "5a027ef84b083a730c9a4c85ec1d3a32", 131760816), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Paintaria - WME_WINENTRY("paintaria", "", + WME_WINENTRY("paintaria", "", WME_ENTRY1s("data.dcp", "354c08440c98150ff0d4008dd2865880", 48326040), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Pigeons in the Park - WME_WINENTRY("pigeons", "", + WME_WINENTRY("pigeons", "", WME_ENTRY1s("data.dcp", "9143a5b6ff8206aefe3c4c643add3ec7", 2611100), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Project: Doom - WME_WINENTRY("projectdoom", "", + WME_WINENTRY("projectdoom", "", WME_ENTRY1s("data.dcp", "d5894b65a40706845434b99870bcab92", 99223761), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Project Joe - WME_WINENTRY("projectjoe", "", + WME_WINENTRY("projectjoe", "", WME_ENTRY1s("data.dcp", "ada3c08542901295076b5349e655e73f", 160780037), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Project Lonely Robot - WME_WINENTRY("lonelyrobot", "beta", + WME_WINENTRY("lonelyrobot", "beta", WME_ENTRY1s("data.dcp", "a0cf7ad5bab957416dcda454e9f28ef0", 3420120), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Reversion: The Escape Version 1.0 - WME_WINENTRY("reversion1", "Version 1.0", + WME_WINENTRY("reversion1", "Version 1.0", WME_ENTRY1s("data.dcp", "cd616f98ebfd047e0c540b50b4b70761", 254384531), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Reversion: The Escape Version 1.1 (Chinese) WME_WINENTRY("reversion1", "Version 1.1", @@ -469,7 +476,7 @@ static const WMEGameDescription gameDescriptions[] = { WME_ENTRY2s("xlanguage_en.dcp", "ca357d86618d1ab76a21c913f4403cbd", 8414976, "data.dcp", "f7938cbfdc48f07934550245a3286921", 255672016), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Reversion: The Meeting (Spanish) - WME_WINENTRY("reversion2", "", + WME_WINENTRY("reversion2", "", WME_ENTRY1s("data.dcp", "f7938cbfdc48f07934550245a3286921", 255672016), Common::ES_ESP, ADGF_UNSTABLE, LATEST_VERSION), // Reversion: The Meeting Version 2.0.2412 (Chinese) WME_PLATENTRY("reversion2", "Version 2.0.2412", @@ -482,79 +489,79 @@ static const WMEGameDescription gameDescriptions[] = { "xlanguage_en.dcp", "0598bf752ce93b42bcaf1094df537c7b", 8533057, "Linux.dcp", "21858bd77dc86b03f701fd47900e2f51", 984535), Common::EN_ANY, Common::kPlatformLinux, ADGF_UNSTABLE, LATEST_VERSION), // Rhiannon: Curse of the four Branches - WME_WINENTRY("rhiannon", "", + WME_WINENTRY("rhiannon", "", WME_ENTRY1s("data.dcp", "870f348900b735f1cc79c0608ce32b0e", 1046169851), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Rhiannon: Curse of the four Branches (English PC DVD) - WME_WINENTRY("rhiannon", "DVD", + WME_WINENTRY("rhiannon", "DVD", WME_ENTRY1s("data.dcp", "6736bbc921bb6ce5161b3ad095a97bd4", 1053441028), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // 1 1/2 Ritter: Auf der Suche nach der hinreissenden Herzelinde - WME_WINENTRY("ritter", "", + WME_WINENTRY("ritter", "", WME_ENTRY1s("data.dcp", "5ac416cee605d3a30f4d59687b1cdab2", 364260278), Common::DE_DEU, ADGF_UNSTABLE, LATEST_VERSION), // Satan and Son - WME_WINENTRY("satanandson", "", + WME_WINENTRY("satanandson", "", WME_ENTRY1s("data.dcp", "16a6ba8174b697bbba9299619d1e20c4", 67539054), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Rosemary - WME_WINENTRY("rosemary", "", + WME_WINENTRY("rosemary", "", WME_ENTRY1s("data.dcp", "4f2631138bd4d27587d9043f8aeff3df", 29483643), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Securanote - WME_PLATENTRY("securanote", "", + WME_PLATENTRY("securanote", "", WME_ENTRY1s("data.dcp", "5213d3e59b9e95b7fbd5c56f7de5341a", 2625554), Common::EN_ANY, Common::kPlatformIOS, ADGF_UNSTABLE, LATEST_VERSION), // Shaban - WME_WINENTRY("shaban", "", + WME_WINENTRY("shaban", "", WME_ENTRY1s("data.dcp", "35f702ca9baabc5c620e0be230195c8a", 755388466), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // The Shine of a Star - WME_WINENTRY("shinestar", "", + WME_WINENTRY("shinestar", "", WME_ENTRY1s("data.dcp", "f05abe9e2427a5e4f73648fa09c4ba8e", 94113060), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Sofia's Debt - WME_WINENTRY("sofiasdebt", "", + WME_WINENTRY("sofiasdebt", "", WME_ENTRY1s("SD.exe", "e9515f9ba1a2925bb6733476a826a650", 9915047), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Space Invaders (Demo) - WME_WINENTRY("spaceinvaders", "Demo", + WME_WINENTRY("spaceinvaders", "Demo", WME_ENTRY1s("data.dcp", "3f27adefdf72f2c1601cf555c80a509f", 1308361), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // Space Madness - WME_WINENTRY("spacemadness", "1.0.2", + WME_WINENTRY("spacemadness", "1.0.2", WME_ENTRY1s("data.dcp", "b9b83135dc7a9e1b4b5f50195dbeb630", 39546622), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // The Ancient Mark - Episode 1 - WME_WINENTRY("theancientmark1", "", + WME_WINENTRY("theancientmark1", "", WME_ENTRY1s("data.dcp", "ca04c26f03b2bd307368b306b297ddd7", 364664692), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // The Box - WME_WINENTRY("thebox", "", + WME_WINENTRY("thebox", "", WME_ENTRY1s("data.dcp", "ec5f0c7e8174e307701447b53afe7e2f", 108372483), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // The Kite (Version 1.1) - WME_WINENTRY("thekite", "Version 1.1", + WME_WINENTRY("thekite", "Version 1.1", WME_ENTRY1s("data.dcp", "92d29428f464469bda2d81b03d4d5c3e", 47332296), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // The Kite (Version 1.2.e) - WME_WINENTRY("thekite", "Version 1.2.e", + WME_WINENTRY("thekite", "Version 1.2.e", WME_ENTRY1s("data.dcp", "92451578b1bdd2b32a1db592a4f6d5fc", 47360539), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // The Kite (Version 1.2.i) (Italian) - WME_WINENTRY("thekite", "Version 1.2.i", + WME_WINENTRY("thekite", "Version 1.2.i", WME_ENTRY1s("data.dcp", "d3435b106a1b3b4c1df8ad596d271586", 47509274), Common::IT_ITA, ADGF_UNSTABLE, LATEST_VERSION), // The Kite (Version 1.2.r) (Russian) - WME_WINENTRY("thekite", "Version 1.2.r", + WME_WINENTRY("thekite", "Version 1.2.r", WME_ENTRY1s("data.dcp", "d531e097dd884737469da014ed882cde", 47554582 ), Common::RU_RUS, ADGF_UNSTABLE, LATEST_VERSION), // The Kite (Version 1.3.e) - WME_WINENTRY("thekite", "Version 1.3.e", + WME_WINENTRY("thekite", "Version 1.3.e", WME_ENTRY1s("data.dcp", "9761827b51370263b7623721545d7627", 47382987), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Fairy Tales About Toshechka and Boshechka - WME_WINENTRY("tib", "", + WME_WINENTRY("tib", "", WME_ENTRY1s("data.dcp", "87d296ef3f46570ed18f000d3885db77", 340264526), Common::RU_RUS, ADGF_UNSTABLE, LATEST_VERSION), // The Trader of Stories - WME_WINENTRY("tradestory", "Demo", + WME_WINENTRY("tradestory", "Demo", WME_ENTRY1s("data.dcp", "0a0b51191636cc8ead89b905281c3218", 40401902), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // the white chamber (multi-language) - WME_WINENTRY("twc", "", + WME_WINENTRY("twc", "", WME_ENTRY1s("data.dcp", "0011d01142547c61e51ba24dc42b579e", 186451273), Common::UNK_LANG, ADGF_UNSTABLE, LATEST_VERSION), // Vsevolod Prologue (Demo) - WME_WINENTRY("vsevolod", "Prologue", + WME_WINENTRY("vsevolod", "Prologue", WME_ENTRY1s("data.dcp", "f2dcffd2692dbfcc9371fa1a87970fe7", 388669493), Common::EN_ANY, ADGF_UNSTABLE | ADGF_DEMO, LATEST_VERSION), // War - WME_WINENTRY("war", "", + WME_WINENTRY("war", "", WME_ENTRY1s("data.dcp", "003e317cda6d0137bbd5e5d7f089ee4d", 32591890), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Wilma Tetris - WME_WINENTRY("wtetris", "", + WME_WINENTRY("wtetris", "", WME_ENTRY1s("data.dcp", "946e3a0496e6c12fb344c9ed861ff015", 2780093), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), // Zilm: A Game of Reflex 1.0 - WME_WINENTRY("Zilm", "1.0", + WME_WINENTRY("Zilm", "1.0", WME_ENTRY1s("data.dcp", "098dffaf03d8adbb4cb5633e4733e63c", 351726), Common::EN_ANY, ADGF_UNSTABLE, LATEST_VERSION), { AD_TABLE_END_MARKER, diff --git a/engines/wintermute/module.mk b/engines/wintermute/module.mk index 4c95314a02..2c9c2e0180 100644 --- a/engines/wintermute/module.mk +++ b/engines/wintermute/module.mk @@ -27,6 +27,8 @@ MODULE_OBJS := \ ad/ad_talk_holder.o \ ad/ad_talk_node.o \ ad/ad_waypoint_group.o \ + base/scriptables/debuggable/debuggable_script.o \ + base/scriptables/debuggable/debuggable_script_engine.o \ base/scriptables/script.o \ base/scriptables/script_engine.o \ base/scriptables/script_stack.o \ @@ -88,6 +90,18 @@ MODULE_OBJS := \ base/saveload.o \ base/save_thumb_helper.o \ base/timer.o \ + debugger/breakpoint.o \ + debugger/debugger_controller.o \ + debugger/error.o \ + debugger/listing_providers/blank_listing.o \ + debugger/listing_providers/blank_listing_provider.o \ + debugger/listing_providers/basic_source_listing_provider.o \ + debugger/listing_providers/cached_source_listing_provider.o \ + debugger/listing_providers/source_listing.o \ + debugger/listing.o \ + debugger/script_monitor.o \ + debugger/watch.o \ + debugger/watch_instance.o \ detection.o \ math/math_util.o \ math/matrix4.o \ diff --git a/engines/wintermute/ui/ui_edit.cpp b/engines/wintermute/ui/ui_edit.cpp index ffe8d66b4d..81030e09c3 100644 --- a/engines/wintermute/ui/ui_edit.cpp +++ b/engines/wintermute/ui/ui_edit.cpp @@ -899,7 +899,7 @@ int UIEdit::deleteChars(int start, int end) { ////////////////////////////////////////////////////////////////////////// int UIEdit::insertChars(int pos, const byte *chars, int num) { - if ((int)strlen(_text) + num > _maxLength) { + if ((_maxLength != -1) && (int)strlen(_text) + num > _maxLength) { num -= (strlen(_text) + num - _maxLength); } diff --git a/engines/wintermute/ui/ui_window.cpp b/engines/wintermute/ui/ui_window.cpp index 9f3cdeaaa3..34341d1db2 100644 --- a/engines/wintermute/ui/ui_window.cpp +++ b/engines/wintermute/ui/ui_window.cpp @@ -139,13 +139,12 @@ bool UIWindow::display(int offsetX, int offsetY) { _shieldButton->setListener(this, _shieldButton, 0); _shieldButton->_parent = this; } - if (_shieldButton) { - _shieldButton->_posX = _shieldButton->_posY = 0; - _shieldButton->setWidth(_gameRef->_renderer->getWidth()); - _shieldButton->setHeight(_gameRef->_renderer->getHeight()); - _shieldButton->display(); - } + _shieldButton->_posX = _shieldButton->_posY = 0; + _shieldButton->setWidth(_gameRef->_renderer->getWidth()); + _shieldButton->setHeight(_gameRef->_renderer->getHeight()); + + _shieldButton->display(); } if (!_visible) { diff --git a/engines/wintermute/video/subtitle_card.cpp b/engines/wintermute/video/subtitle_card.cpp index 5d882502fd..4199817f49 100644 --- a/engines/wintermute/video/subtitle_card.cpp +++ b/engines/wintermute/video/subtitle_card.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/wintermute/video/subtitle_card.h b/engines/wintermute/video/subtitle_card.h index 629df77287..86bafe7751 100644 --- a/engines/wintermute/video/subtitle_card.h +++ b/engines/wintermute/video/subtitle_card.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/wintermute/video/video_subtitler.cpp b/engines/wintermute/video/video_subtitler.cpp index 95d938574b..5155f4de72 100644 --- a/engines/wintermute/video/video_subtitler.cpp +++ b/engines/wintermute/video/video_subtitler.cpp @@ -8,12 +8,12 @@ * 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. diff --git a/engines/wintermute/video/video_subtitler.h b/engines/wintermute/video/video_subtitler.h index 94f22909a1..d2b5492e84 100644 --- a/engines/wintermute/video/video_subtitler.h +++ b/engines/wintermute/video/video_subtitler.h @@ -8,12 +8,12 @@ * 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. diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp index e35bb60c3d..05dfb961cb 100644 --- a/engines/wintermute/wintermute.cpp +++ b/engines/wintermute/wintermute.cpp @@ -41,6 +41,7 @@ #include "engines/wintermute/base/base_file_manager.h" #include "engines/wintermute/base/gfx/base_renderer.h" #include "engines/wintermute/base/scriptables/script_engine.h" +#include "engines/wintermute/debugger/debugger_controller.h" namespace Wintermute { @@ -49,6 +50,7 @@ namespace Wintermute { WintermuteEngine::WintermuteEngine() : Engine(g_system) { _game = new AdGame(""); _debugger = nullptr; + _dbgController = nullptr; _trigDebug = false; _gameDescription = nullptr; } @@ -76,6 +78,7 @@ WintermuteEngine::WintermuteEngine(OSystem *syst, const WMEGameDescription *desc _game = nullptr; _debugger = nullptr; + _dbgController = nullptr; _trigDebug = false; } @@ -112,6 +115,7 @@ Common::Error WintermuteEngine::run() { } // Create debugger console. It requires GFX to be initialized + _dbgController = new DebuggerController(this); _debugger = new Console(this); // DebugMan.enableDebugChannel("enginelog"); @@ -133,7 +137,7 @@ Common::Error WintermuteEngine::run() { } int WintermuteEngine::init() { - BaseEngine::createInstance(_targetName, _gameDescription->adDesc.gameid, _gameDescription->adDesc.language, _gameDescription->targetExecutable); + BaseEngine::createInstance(_targetName, _gameDescription->adDesc.gameId, _gameDescription->adDesc.language, _gameDescription->targetExecutable); _game = new AdGame(_targetName); if (!_game) { return 1; @@ -171,7 +175,6 @@ int WintermuteEngine::init() { } _game->initialize3(); - // initialize sound manager (non-fatal if we fail) ret = _game->_soundMgr->initialize(); if (DID_FAIL(ret)) { @@ -200,6 +203,8 @@ int WintermuteEngine::init() { _game->loadGame(slot); } + _game->_scEngine->attachMonitor(_dbgController); + // all set, ready to go return 0; } diff --git a/engines/wintermute/wintermute.h b/engines/wintermute/wintermute.h index f8f5fc7deb..a8f9a18530 100644 --- a/engines/wintermute/wintermute.h +++ b/engines/wintermute/wintermute.h @@ -20,8 +20,8 @@ * */ -#ifndef WINTERMUTE_H -#define WINTERMUTE_H +#ifndef WINTERMUTE_WINTERMUTE_H +#define WINTERMUTE_WINTERMUTE_H #include "engines/engine.h" #include "engines/advancedDetector.h" @@ -33,6 +33,8 @@ namespace Wintermute { class Console; class BaseGame; class SystemClassRegistry; +class DebuggerController; + // our engine debug channels enum { kWintermuteDebugLog = 1 << 0, // The debug-logs from the original engine @@ -49,7 +51,7 @@ public: WintermuteEngine(); ~WintermuteEngine(); - virtual GUI::Debugger *getDebugger() { return _debugger; } + virtual Wintermute::Console *getConsole() { return _debugger; } void trigDebugger() { _trigDebug = true; } virtual Common::Error run(); @@ -66,11 +68,13 @@ private: int init(); void deinit(); int messageLoop(); - GUI::Debugger *_debugger; + Wintermute::Console *_debugger; BaseGame *_game; + Wintermute::DebuggerController *_dbgController; const WMEGameDescription *_gameDescription; friend class Console; + friend class DebuggerController; }; } // End of namespace Wintermute |