#ifndef GAME_MWWORLD_CELLSTORE_H #define GAME_MWWORLD_CELLSTORE_H #include #include #include #include #include #include "livecellref.hpp" #include "cellreflist.hpp" #include #include #include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld #include "timestamp.hpp" namespace ESM { struct CellState; struct FogState; } namespace MWWorld { class Ptr; class ESMStore; /// \brief Mutable state of a cell class CellStore { public: enum State { State_Unloaded, State_Preloaded, State_Loaded }; private: // Even though fog actually belongs to the player and not cells, // it makes sense to store it here since we need it once for each cell. // Note this is NULL until the cell is explored to save some memory boost::shared_ptr mFogState; const ESM::Cell *mCell; State mState; bool mHasState; std::vector mIds; float mWaterLevel; MWWorld::TimeStamp mLastRespawn; CellRefList mActivators; CellRefList mPotions; CellRefList mAppas; CellRefList mArmors; CellRefList mBooks; CellRefList mClothes; CellRefList mContainers; CellRefList mCreatures; CellRefList mDoors; CellRefList mIngreds; CellRefList mCreatureLists; CellRefList mItemLists; CellRefList mLights; CellRefList mLockpicks; CellRefList mMiscItems; CellRefList mNpcs; CellRefList mProbes; CellRefList mRepairs; CellRefList mStatics; CellRefList mWeapons; public: CellStore (const ESM::Cell *cell_); const ESM::Cell *getCell() const; State getState() const; bool hasState() const; ///< Does this cell have state that needs to be stored in a saved game file? bool hasId (const std::string& id) const; ///< May return true for deleted IDs when in preload state. Will return false, if cell is /// unloaded. Ptr search (const std::string& id); ///< Will return an empty Ptr if cell is not loaded. Does not check references in /// containers. Ptr searchViaHandle (const std::string& handle); ///< Will return an empty Ptr if cell is not loaded. Ptr searchViaActorId (int id); ///< Will return an empty Ptr if cell is not loaded. float getWaterLevel() const; void setWaterLevel (float level); void setFog (ESM::FogState* fog); ///< \note Takes ownership of the pointer ESM::FogState* getFog () const; int count() const; ///< Return total number of references, including deleted ones. void load (const MWWorld::ESMStore &store, std::vector &esm); ///< Load references from content file. void preload (const MWWorld::ESMStore &store, std::vector &esm); ///< Build ID list from content file. /// Call functor (ref) for each reference. functor must return a bool. Returning /// false will abort the iteration. /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? /// /// \note Creatures and NPCs are handled last. template bool forEach (Functor& functor) { mHasState = true; return forEachImp (functor, mActivators) && forEachImp (functor, mPotions) && forEachImp (functor, mAppas) && forEachImp (functor, mArmors) && forEachImp (functor, mBooks) && forEachImp (functor, mClothes) && forEachImp (functor, mContainers) && forEachImp (functor, mDoors) && forEachImp (functor, mIngreds) && forEachImp (functor, mItemLists) && forEachImp (functor, mLights) && forEachImp (functor, mLockpicks) && forEachImp (functor, mMiscItems) && forEachImp (functor, mProbes) && forEachImp (functor, mRepairs) && forEachImp (functor, mStatics) && forEachImp (functor, mWeapons) && forEachImp (functor, mCreatures) && forEachImp (functor, mNpcs) && forEachImp (functor, mCreatureLists); } template bool forEachContainer (Functor& functor) { mHasState = true; return forEachImp (functor, mContainers) && forEachImp (functor, mCreatures) && forEachImp (functor, mNpcs); } bool isExterior() const; Ptr searchInContainer (const std::string& id); void loadState (const ESM::CellState& state); void saveState (ESM::CellState& state) const; void writeFog (ESM::ESMWriter& writer) const; void readFog (ESM::ESMReader& reader); void writeReferences (ESM::ESMWriter& writer) const; void readReferences (ESM::ESMReader& reader, const std::map& contentFileMap); void respawn (); ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded. template CellRefList& get() { throw std::runtime_error ("Storage for type " + std::string(typeid(T).name())+ " does not exist in cells"); } template const CellRefList& getReadOnly() { throw std::runtime_error ("Read Only CellRefList access not available for type " + std::string(typeid(T).name()) ); } bool isPointConnected(const int start, const int end) const; std::list aStarSearch(const int start, const int end) const; private: template bool forEachImp (Functor& functor, List& list) { for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) { if (iter->mData.isDeletedByContentFile()) continue; if (!functor (MWWorld::Ptr(&*iter, this))) return false; } return true; } /// Run through references and store IDs void listRefs(const MWWorld::ESMStore &store, std::vector &esm); void loadRefs(const MWWorld::ESMStore &store, std::vector &esm); void loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store); ///< Make case-adjustments to \a ref and insert it into the respective container. /// /// Invalid \a ref objects are silently dropped. MWMechanics::PathgridGraph mPathgridGraph; }; template<> inline CellRefList& CellStore::get() { mHasState = true; return mActivators; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mPotions; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mAppas; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mArmors; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mBooks; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mClothes; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mContainers; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mCreatures; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mDoors; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mIngreds; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mCreatureLists; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mItemLists; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mLights; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mLockpicks; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mMiscItems; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mNpcs; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mProbes; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mRepairs; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mStatics; } template<> inline CellRefList& CellStore::get() { mHasState = true; return mWeapons; } template<> inline const CellRefList& CellStore::getReadOnly() { return mDoors; } bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } #endif