diff options
Diffstat (limited to 'engines/wintermute/base')
30 files changed, 524 insertions, 66 deletions
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..24779b9793 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"; @@ -351,6 +361,12 @@ bool BaseGame::initConfManSettings() { _debugShowFPS = false; } + if (ConfMan.hasKey("bilinear_filtering")) { + _bilinearFiltering = ConfMan.getBool("bilinear_filtering"); + } else { + _bilinearFiltering = false; + } + if (ConfMan.hasKey("disable_smartcache")) { _smartCache = ConfMan.getBool("disable_smartcache"); } else { @@ -398,7 +414,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..46484cc5ca 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 { @@ -97,7 +101,7 @@ public: virtual bool displayDebugInfo(); void setShowFPS(bool enabled) { _debugShowFPS = enabled; } - + bool getBilinearFiltering() { return _bilinearFiltering; } bool getSuspendedRendering() const { return _suspendedRendering; } TTextEncoding _textEncoding; @@ -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; @@ -271,6 +279,7 @@ protected: VideoTheoraPlayer *_theoraPlayer; private: bool _debugShowFPS; + bool _bilinearFiltering; void *_debugLogFile; void DEBUG_DebugDisable(); void DEBUG_DebugEnable(const char *filename = nullptr); 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 30c502665b..0684b3f591 100644 --- a/engines/wintermute/base/file/base_disk_file.cpp +++ b/engines/wintermute/base/file/base_disk_file.cpp @@ -115,13 +115,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/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp index afe884300a..78d445ac8c 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp +++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp @@ -27,6 +27,7 @@ */ +#include "engines/wintermute/base/base_game.h" #include "engines/wintermute/base/gfx/osystem/render_ticket.h" #include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h" #include "graphics/transform_tools.h" @@ -59,7 +60,12 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s // TransformTools.) if (_transform._angle != Graphics::kDefaultAngle) { Graphics::TransparentSurface src(*_surface, false); - Graphics::Surface *temp = src.rotoscale(transform); + Graphics::Surface *temp; + if (owner->_gameRef->getBilinearFiltering()) { + temp = src.rotoscale<Graphics::FILTER_BILINEAR>(transform); + } else { + temp = src.rotoscale<Graphics::FILTER_NEAREST>(transform); + } _surface->free(); delete _surface; _surface = temp; @@ -67,7 +73,12 @@ RenderTicket::RenderTicket(BaseSurfaceOSystem *owner, const Graphics::Surface *s dstRect->height() != srcRect->height()) && _transform._numTimesX * _transform._numTimesY == 1) { Graphics::TransparentSurface src(*_surface, false); - Graphics::Surface *temp = src.scale(dstRect->width(), dstRect->height()); + Graphics::Surface *temp; + if (owner->_gameRef->getBilinearFiltering()) { + temp = src.scale<Graphics::FILTER_BILINEAR>(dstRect->width(), dstRect->height()); + } else { + temp = src.scale<Graphics::FILTER_NEAREST>(dstRect->width(), dstRect->height()); + } _surface->free(); delete _surface; _surface = temp; 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 f1e0c3b1f9..f95a21de33 100644 --- a/engines/wintermute/base/sound/base_sound_manager.cpp +++ b/engines/wintermute/base/sound/base_sound_manager.cpp @@ -97,18 +97,22 @@ BaseSoundBuffer *BaseSoundMgr::addSound(const Common::String &filename, Audio::M return nullptr; } + if (filename.empty()) { + // At least one game, Bickadoodle, calls playSound with an empty filename, see #6594 + BaseEngine::LOG(0, "addSound called with empty filename"); + } + 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; } } |