From f49fde3d5de464c546aa41e69172c5063cf600dd Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 6 Dec 2014 21:08:18 +0100 Subject: [PATCH] Add support for undeleting references (Fixes #2193) Deleted references should be accessible via an explicit reference, and can be undeleted using "setdelete 0". Also the Resurrect function implicitely undeletes the given reference. --- apps/openmw/mwbase/world.hpp | 1 + apps/openmw/mwscript/miscextensions.cpp | 4 ++++ apps/openmw/mwscript/statsextensions.cpp | 1 + apps/openmw/mwworld/cellreflist.hpp | 4 ++-- apps/openmw/mwworld/cellstore.hpp | 2 +- apps/openmw/mwworld/refdata.cpp | 5 +++++ apps/openmw/mwworld/refdata.hpp | 2 ++ apps/openmw/mwworld/worldimp.cpp | 19 +++++++++++++++++++ apps/openmw/mwworld/worldimp.hpp | 1 + 9 files changed, 36 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index c1a889913..2dd135f3d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -279,6 +279,7 @@ namespace MWBase ///< Attempt to fix position so that the Ptr is no longer inside collision geometry. virtual void deleteObject (const MWWorld::Ptr& ptr) = 0; + virtual void undeleteObject (const MWWorld::Ptr& ptr) = 0; virtual void moveObject (const MWWorld::Ptr& ptr, float x, float y, float z) = 0; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index aa80213de..ec2048e11 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -571,6 +571,10 @@ namespace MWScript if (parameter == 1) MWBase::Environment::get().getWorld()->deleteObject(ptr); + else if (parameter == 0) + MWBase::Environment::get().getWorld()->undeleteObject(ptr); + else + throw std::runtime_error("SetDelete: unexpected parameter"); } }; diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 63405e5b8..09ab0183c 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -1184,6 +1184,7 @@ namespace MWScript ptr.getClass().getCreatureStats(ptr).resurrect(); else if (ptr.getClass().getCreatureStats(ptr).isDead()) { + MWBase::Environment::get().getWorld()->undeleteObject(ptr); // resets runtime state such as inventory, stats and AI. does not reset position in the world ptr.getRefData().setCustomData(NULL); } diff --git a/apps/openmw/mwworld/cellreflist.hpp b/apps/openmw/mwworld/cellreflist.hpp index 9c3370f08..cf1289654 100644 --- a/apps/openmw/mwworld/cellreflist.hpp +++ b/apps/openmw/mwworld/cellreflist.hpp @@ -27,7 +27,7 @@ namespace MWWorld LiveRef *find (const std::string& name) { for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - if (iter->mData.getCount() > 0 && iter->mRef.getRefId() == name) + if (iter->mRef.getRefId() == name) return &*iter; return 0; @@ -42,7 +42,7 @@ namespace MWWorld LiveCellRef *searchViaHandle (const std::string& handle) { for (typename List::iterator iter (mList.begin()); iter!=mList.end(); ++iter) - if (iter->mData.getCount()>0 && iter->mData.getBaseNode() && + if (iter->mData.getBaseNode() && iter->mData.getHandle()==handle) return &*iter; diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index 05e7b0b2e..eba627b3e 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -196,7 +196,7 @@ namespace MWWorld for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) { - if (iter->mData.isDeleted()) + if (iter->mData.isDeletedByContentFile()) continue; if (!functor (MWWorld::Ptr(&*iter, this))) return false; diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 78fea2b86..c2a5e5f83 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -180,6 +180,11 @@ namespace MWWorld return mDeleted || mCount == 0; } + bool RefData::isDeletedByContentFile() const + { + return mDeleted; + } + MWScript::Locals& RefData::getLocals() { return mLocals; diff --git a/apps/openmw/mwworld/refdata.hpp b/apps/openmw/mwworld/refdata.hpp index 1ed3cd79d..da7986ba0 100644 --- a/apps/openmw/mwworld/refdata.hpp +++ b/apps/openmw/mwworld/refdata.hpp @@ -100,6 +100,8 @@ namespace MWWorld /// Returns true if the object was either deleted by the content file or by gameplay. bool isDeleted() const; + /// Returns true if the object was deleted by a content file. + bool isDeletedByContentFile() const; MWScript::Locals& getLocals(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 7baf1d3e5..d783857f1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1072,6 +1072,25 @@ namespace MWWorld } } + void World::undeleteObject(const Ptr& ptr) + { + if (ptr.getCellRef().getRefNum().mContentFile == -1) + return; + if (ptr.getRefData().isDeleted()) + { + ptr.getRefData().setCount(1); + if (mWorldScene->getActiveCells().find(ptr.getCell()) != mWorldScene->getActiveCells().end() + && ptr.getRefData().isEnabled()) + { + mWorldScene->addObjectToScene(ptr); + std::string script = ptr.getClass().getScript(ptr); + if (!script.empty()) + mLocalScripts.add(script, ptr); + addContainerScripts(ptr, ptr.getCell()); + } + } + } + void World::moveObject(const Ptr &ptr, CellStore* newCell, float x, float y, float z) { ESM::Position pos = ptr.getRefData().getPosition(); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index fef279705..2da6a6e05 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -338,6 +338,7 @@ namespace MWWorld virtual std::pair getHitContact(const MWWorld::Ptr &ptr, float distance); virtual void deleteObject (const Ptr& ptr); + virtual void undeleteObject (const Ptr& ptr); virtual void moveObject (const Ptr& ptr, float x, float y, float z); virtual void moveObject (const Ptr& ptr, CellStore* newCell, float x, float y, float z);