#ifndef GAME_MWWORLD_CELLSTORE_H #define GAME_MWWORLD_CELLSTORE_H #include #include #include #include #include #include #include "livecellref.hpp" #include "cellreflist.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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: const MWWorld::ESMStore& mStore; std::vector& mReader; // 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; // List of refs owned by this cell 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; typedef std::map MovedRefTracker; // References owned by a different cell that have been moved here. // MovedRefTracker mMovedHere; // References owned by this cell that have been moved to another cell. // MovedRefTracker mMovedToAnotherCell; // Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell std::vector mMergedRefs; /// Moves object from the given cell to this cell. void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from); /// Repopulate mMergedRefs. void updateMergedRefs(); template LiveCellRefBase* insertBase(CellRefList& list, const LiveCellRef* ref) { mHasState = true; LiveCellRefBase* ret = &list.insert(*ref); updateMergedRefs(); return ret; } // helper function for forEachInternal template bool forEachImp (Visitor& visitor, List& list) { for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end(); ++iter) { if (iter->mData.isDeletedByContentFile()) continue; if (!visitor (MWWorld::Ptr(&*iter, this))) return false; } return true; } // listing only objects owned by this cell. Internal use only, you probably want to use forEach() so that moved objects are accounted for. template bool forEachInternal (Visitor& visitor) { return forEachImp (visitor, mActivators) && forEachImp (visitor, mPotions) && forEachImp (visitor, mAppas) && forEachImp (visitor, mArmors) && forEachImp (visitor, mBooks) && forEachImp (visitor, mClothes) && forEachImp (visitor, mContainers) && forEachImp (visitor, mDoors) && forEachImp (visitor, mIngreds) && forEachImp (visitor, mItemLists) && forEachImp (visitor, mLights) && forEachImp (visitor, mLockpicks) && forEachImp (visitor, mMiscItems) && forEachImp (visitor, mProbes) && forEachImp (visitor, mRepairs) && forEachImp (visitor, mStatics) && forEachImp (visitor, mWeapons) && forEachImp (visitor, mCreatures) && forEachImp (visitor, mNpcs) && forEachImp (visitor, mCreatureLists); } public: /// Moves object from this cell to the given cell. /// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...) /// @note throws exception if cellToMoveTo == this /// @return updated MWWorld::Ptr with the new CellStore pointer set. MWWorld::Ptr moveTo(const MWWorld::Ptr& object, MWWorld::CellStore* cellToMoveTo); /// Make a copy of the given object and insert it into this cell. /// @note If you get a linker error here, this means the given type can not be inserted into a cell. /// The supported types are defined at the bottom of this file. template LiveCellRefBase* insert(const LiveCellRef* ref); /// @param readerList The readers to use for loading of the cell on-demand. CellStore (const ESM::Cell *cell_, const MWWorld::ESMStore& store, std::vector& readerList); 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. /// @note Will not account for moved references which may exist in Loaded state. Use search() instead if the cell is loaded. Ptr search (const std::string& id); ///< Will return an empty Ptr if cell is not loaded. Does not check references in /// containers. 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 (); ///< Load references from content file. void preload (); ///< Build ID list from content file. /// Call visitor (ref) for each reference. visitor must return a bool. Returning /// false will abort the iteration. /// \attention This function also lists deleted (count 0) objects! /// \return Iteration completed? template bool forEach (Visitor& visitor) { if (mState != State_Loaded) return false; mHasState = true; for (unsigned int i=0; imData.isDeletedByContentFile()) continue; if (!visitor(MWWorld::Ptr(mMergedRefs[i], this))) return false; } return true; } /// \todo add const version of forEach 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. bool isPointConnected(const int start, const int end) const; std::list aStarSearch(const int start, const int end) const; private: /// Run through references and store IDs void listRefs(); void loadRefs(); void loadRef (ESM::CellRef& ref, bool deleted); ///< 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 LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mActivators, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mPotions, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mAppas, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mArmors, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mBooks, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mClothes, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mContainers, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mCreatures, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mDoors, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mIngreds, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mCreatureLists, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mItemLists, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mLights, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mLockpicks, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mMiscItems, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mNpcs, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mProbes, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mRepairs, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mStatics, ref); } template<> inline LiveCellRefBase* CellStore::insert(const LiveCellRef* ref) { return insertBase(mWeapons, ref); } bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } #endif