diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index a576912c0..2ce7ce2c7 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -45,6 +45,7 @@ namespace MWWorld class Ptr; class TimeStamp; class ESMStore; + class RefData; } namespace MWBase @@ -138,6 +139,9 @@ namespace MWBase virtual std::string getCurrentCellName() const = 0; + virtual void removeRefScript (MWWorld::RefData *ref) = 0; + //< Remove the script attached to ref from mLocalScripts + virtual MWWorld::Ptr getPtr (const std::string& name, bool activeOnly) = 0; ///< Return a pointer to a liveCellRef with the given name. /// \param activeOnly do non search inactive cells. diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index db4537daf..bca4073b5 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -15,6 +15,8 @@ #include "manualref.hpp" #include "refdata.hpp" #include "class.hpp" +#include "localscripts.hpp" +#include "player.hpp" namespace { @@ -71,6 +73,31 @@ bool MWWorld::ContainerStore::stacks(const Ptr& ptr1, const Ptr& ptr2) } MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& ptr) +{ + MWWorld::ContainerStoreIterator it = addImp(ptr); + MWWorld::Ptr item = *it; + + std::string script = MWWorld::Class::get(item).getScript(item); + if(script != "") + { + CellStore *cell; + + Ptr player = MWBase::Environment::get().getWorld ()->getPlayer().getPlayer(); + // Items in players inventory have cell set to 0, so their scripts will never be removed + if(&(MWWorld::Class::get (player).getContainerStore (player)) == this) + cell = 0; + else + cell = player.getCell(); + + item.mCell = cell; + item.mContainerStore = 0; + MWBase::Environment::get().getWorld()->getLocalScripts().add(script, item); + } + + return it; +} + +MWWorld::ContainerStoreIterator MWWorld::ContainerStore::addImp (const Ptr& ptr) { int type = getType(ptr); @@ -162,7 +189,7 @@ void MWWorld::ContainerStore::fill (const ESM::InventoryList& items, const MWWor } ref.getPtr().getRefData().setCount (std::abs(iter->mCount)); /// \todo implement item restocking (indicated by negative count) - add (ref.getPtr()); + addImp (ref.getPtr()); } flagAsModified(); diff --git a/apps/openmw/mwworld/containerstore.hpp b/apps/openmw/mwworld/containerstore.hpp index 1297fc53c..e4f75d547 100644 --- a/apps/openmw/mwworld/containerstore.hpp +++ b/apps/openmw/mwworld/containerstore.hpp @@ -52,6 +52,7 @@ namespace MWWorld int mStateId; mutable float mCachedWeight; mutable bool mWeightUpToDate; + ContainerStoreIterator addImp (const Ptr& ptr); public: diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp index a821ad486..5ec5ca9b5 100644 --- a/apps/openmw/mwworld/localscripts.cpp +++ b/apps/openmw/mwworld/localscripts.cpp @@ -3,6 +3,10 @@ #include "esmstore.hpp" #include "cellstore.hpp" +#include "class.hpp" +#include "containerstore.hpp" + + namespace { template @@ -19,6 +23,32 @@ namespace } } } + + // Adds scripts for items in containers (containers/npcs/creatures) + template + void listCellScriptsCont (MWWorld::LocalScripts& localScripts, + MWWorld::CellRefList& cellRefList, MWWorld::Ptr::CellStore *cell) + { + for (typename MWWorld::CellRefList::List::iterator iter ( + cellRefList.mList.begin()); + iter!=cellRefList.mList.end(); ++iter) + { + + MWWorld::Ptr containerPtr (&*iter, cell); + + MWWorld::ContainerStore& container = MWWorld::Class::get(containerPtr).getContainerStore(containerPtr); + for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3) + { + std::string script = MWWorld::Class::get(*it3).getScript(*it3); + if(script != "") + { + MWWorld::Ptr item = *it3; + item.mCell = cell; + localScripts.add (script, item); + } + } + } + } } MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {} @@ -78,13 +108,16 @@ void MWWorld::LocalScripts::addCell (Ptr::CellStore *cell) listCellScripts (*this, cell->mBooks, cell); listCellScripts (*this, cell->mClothes, cell); listCellScripts (*this, cell->mContainers, cell); + listCellScriptsCont (*this, cell->mContainers, cell); listCellScripts (*this, cell->mCreatures, cell); + listCellScriptsCont (*this, cell->mCreatures, cell); listCellScripts (*this, cell->mDoors, cell); listCellScripts (*this, cell->mIngreds, cell); listCellScripts (*this, cell->mLights, cell); listCellScripts (*this, cell->mLockpicks, cell); listCellScripts (*this, cell->mMiscItems, cell); listCellScripts (*this, cell->mNpcs, cell); + listCellScriptsCont (*this, cell->mNpcs, cell); listCellScripts (*this, cell->mProbes, cell); listCellScripts (*this, cell->mRepairs, cell); listCellScripts (*this, cell->mWeapons, cell); @@ -101,7 +134,7 @@ void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell) while (iter!=mScripts.end()) { - if (iter->second.getCell()==cell) + if (iter->second.mCell==cell) { if (iter==mIter) ++mIter; @@ -113,6 +146,20 @@ void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell) } } +void MWWorld::LocalScripts::remove (RefData *ref) +{ + for (std::list >::iterator iter = mScripts.begin(); + iter!=mScripts.end(); ++iter) + if (&(iter->second.getRefData()) == ref) + { + if (iter==mIter) + ++mIter; + + mScripts.erase (iter); + break; + } +} + void MWWorld::LocalScripts::remove (const Ptr& ptr) { for (std::list >::iterator iter = mScripts.begin(); diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp index 028dcdeda..840243fff 100644 --- a/apps/openmw/mwworld/localscripts.hpp +++ b/apps/openmw/mwworld/localscripts.hpp @@ -10,6 +10,7 @@ namespace MWWorld { struct ESMStore; class CellStore; + class RefData; /// \brief List of active local scripts class LocalScripts @@ -47,6 +48,8 @@ namespace MWWorld void clearCell (CellStore *cell); ///< Remove all scripts belonging to \a cell. + + void remove (RefData *ref); void remove (const Ptr& ptr); ///< Remove script for given reference (ignored if reference does not have a scirpt listed). diff --git a/apps/openmw/mwworld/ptr.hpp b/apps/openmw/mwworld/ptr.hpp index 594ddef2d..d97ebcc6e 100644 --- a/apps/openmw/mwworld/ptr.hpp +++ b/apps/openmw/mwworld/ptr.hpp @@ -74,7 +74,7 @@ namespace MWWorld bool isInCell() const { - return (mCell != 0); + return (mContainerStore == 0); } void setContainerStore (ContainerStore *store); diff --git a/apps/openmw/mwworld/refdata.cpp b/apps/openmw/mwworld/refdata.cpp index 5630bfd5c..4be287810 100644 --- a/apps/openmw/mwworld/refdata.cpp +++ b/apps/openmw/mwworld/refdata.cpp @@ -6,6 +6,9 @@ #include "customdata.hpp" #include "cellstore.hpp" +#include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" + namespace MWWorld { void RefData::copy (const RefData& refData) @@ -107,6 +110,9 @@ namespace MWWorld void RefData::setCount (int count) { + if(count == 0) + MWBase::Environment::get().getWorld()->removeRefScript(this); + mCount = count; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index f49b4bf9b..24d139b37 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -341,6 +341,11 @@ namespace MWWorld return name; } + void World::removeRefScript (MWWorld::RefData *ref) + { + mLocalScripts.remove (ref); + } + Ptr World::getPtr (const std::string& name, bool activeOnly) { // the player is always in an active cell. @@ -396,23 +401,62 @@ namespace MWWorld return MWWorld::Ptr(); } + void World::addContainerScripts(const Ptr& reference, Ptr::CellStore * cell) + { + if( reference.getTypeName()==typeid (ESM::Container).name() || + reference.getTypeName()==typeid (ESM::NPC).name() || + reference.getTypeName()==typeid (ESM::Creature).name()) + { + MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) + { + std::string script = MWWorld::Class::get(*it).getScript(*it); + if(script != "") + { + MWWorld::Ptr item = *it; + item.mCell = cell; + mLocalScripts.add (script, item); + } + } + } + } + void World::enable (const Ptr& reference) { if (!reference.getRefData().isEnabled()) { reference.getRefData().enable(); - + if(mWorldScene->getActiveCells().find (reference.getCell()) != mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->addObjectToScene (reference); } } + + void World::removeContainerScripts(const Ptr& reference) + { + if( reference.getTypeName()==typeid (ESM::Container).name() || + reference.getTypeName()==typeid (ESM::NPC).name() || + reference.getTypeName()==typeid (ESM::Creature).name()) + { + MWWorld::ContainerStore& container = MWWorld::Class::get(reference).getContainerStore(reference); + for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it) + { + std::string script = MWWorld::Class::get(*it).getScript(*it); + if(script != "") + { + MWWorld::Ptr item = *it; + mLocalScripts.remove (item); + } + } + } + } void World::disable (const Ptr& reference) { if (reference.getRefData().isEnabled()) { reference.getRefData().disable(); - + if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) mWorldScene->removeObjectFromScene (reference); } @@ -635,6 +679,7 @@ namespace MWWorld { mWorldScene->removeObjectFromScene (ptr); mLocalScripts.remove (ptr); + removeContainerScripts (ptr); } } } @@ -648,6 +693,8 @@ namespace MWWorld CellStore *currCell = ptr.getCell(); bool isPlayer = ptr == mPlayer->getPlayer(); bool haveToMove = mWorldScene->isCellActive(*currCell) || isPlayer; + + removeContainerScripts(ptr); if (*currCell != newCell) { @@ -675,6 +722,8 @@ namespace MWWorld MWWorld::Ptr copy = MWWorld::Class::get(ptr).copyToCell(ptr, newCell); + addContainerScripts(copy, &newCell); + mRendering->moveObjectToCell(copy, vec, currCell); if (MWWorld::Class::get(ptr).isActor()) @@ -1283,6 +1332,7 @@ namespace MWWorld if (!script.empty()) { mLocalScripts.add(script, dropped); } + addContainerScripts(dropped, &cell); } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7e89c1d87..fa5b41038 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -105,6 +105,9 @@ namespace MWWorld float getNpcActivationDistance (); float getObjectActivationDistance (); + void removeContainerScripts(const Ptr& reference); + void addContainerScripts(const Ptr& reference, Ptr::CellStore* cell); + public: World (OEngine::Render::OgreRenderer& renderer, @@ -172,6 +175,9 @@ namespace MWWorld virtual std::vector getGlobals () const; virtual std::string getCurrentCellName () const; + + virtual void removeRefScript (MWWorld::RefData *ref); + //< Remove the script attached to ref from mLocalScripts virtual Ptr getPtr (const std::string& name, bool activeOnly); ///< Return a pointer to a liveCellRef with the given name.