#ifndef GAME_MWWORLD_CELLSTORE_H #define GAME_MWWORLD_CELLSTORE_H #include <algorithm> #include <stdexcept> #include <string> #include <typeinfo> #include <map> #include <boost/shared_ptr.hpp> #include "livecellref.hpp" #include "cellreflist.hpp" #include <components/esm/loadacti.hpp> #include <components/esm/loadalch.hpp> #include <components/esm/loadappa.hpp> #include <components/esm/loadarmo.hpp> #include <components/esm/loadbook.hpp> #include <components/esm/loadclot.hpp> #include <components/esm/loadcont.hpp> #include <components/esm/loadcrea.hpp> #include <components/esm/loaddoor.hpp> #include <components/esm/loadingr.hpp> #include <components/esm/loadlevlist.hpp> #include <components/esm/loadligh.hpp> #include <components/esm/loadlock.hpp> #include <components/esm/loadprob.hpp> #include <components/esm/loadrepa.hpp> #include <components/esm/loadstat.hpp> #include <components/esm/loadweap.hpp> #include <components/esm/loadnpc.hpp> #include <components/esm/loadmisc.hpp> #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<ESM::FogState> mFogState; const ESM::Cell *mCell; State mState; bool mHasState; std::vector<std::string> mIds; float mWaterLevel; MWWorld::TimeStamp mLastRespawn; // List of refs owned by this cell CellRefList<ESM::Activator> mActivators; CellRefList<ESM::Potion> mPotions; CellRefList<ESM::Apparatus> mAppas; CellRefList<ESM::Armor> mArmors; CellRefList<ESM::Book> mBooks; CellRefList<ESM::Clothing> mClothes; CellRefList<ESM::Container> mContainers; CellRefList<ESM::Creature> mCreatures; CellRefList<ESM::Door> mDoors; CellRefList<ESM::Ingredient> mIngreds; CellRefList<ESM::CreatureLevList> mCreatureLists; CellRefList<ESM::ItemLevList> mItemLists; CellRefList<ESM::Light> mLights; CellRefList<ESM::Lockpick> mLockpicks; CellRefList<ESM::Miscellaneous> mMiscItems; CellRefList<ESM::NPC> mNpcs; CellRefList<ESM::Probe> mProbes; CellRefList<ESM::Repair> mRepairs; CellRefList<ESM::Static> mStatics; CellRefList<ESM::Weapon> mWeapons; typedef std::map<LiveCellRefBase*, MWWorld::CellStore*> MovedRefTracker; // References owned by a different cell that have been moved here. // <reference, cell the reference originally came from> MovedRefTracker mMovedHere; // References owned by this cell that have been moved to another cell. // <reference, cell the reference was moved to> MovedRefTracker mMovedToAnotherCell; // Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell std::vector<LiveCellRefBase*> mMergedRefs; /// Moves object from the given cell to this cell. void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from); /// Repopulate mMergedRefs. void updateMergedRefs(); public: /// Moves object from this cell to the given cell. /// @note automatically updates given cell by calling cellToMoveTo->moveFrom(...) void 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 <typename T> LiveCellRefBase* insert(const LiveCellRef<T>* ref); 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 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::ESMReader> &esm); ///< Load references from content file. void preload (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &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<class Functor> 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<class Functor> bool forEachContainer (Functor& functor) { mHasState = true; return forEachImp (functor, mContainers) && forEachImp (functor, mCreatures) && forEachImp (functor, mNpcs); } /// \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<int, int>& 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<ESM::Pathgrid::Point> aStarSearch(const int start, const int end) const; private: template<class Functor, class List> 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::ESMReader> &esm); void loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &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 LiveCellRefBase* CellStore::insert<ESM::Activator>(const LiveCellRef<ESM::Activator>* ref) { mHasState = true; return &mActivators.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Potion>(const LiveCellRef<ESM::Potion>* ref) { mHasState = true; return &mPotions.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Apparatus>(const LiveCellRef<ESM::Apparatus>* ref) { mHasState = true; return &mAppas.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Armor>(const LiveCellRef<ESM::Armor>* ref) { mHasState = true; return &mArmors.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Book>(const LiveCellRef<ESM::Book>* ref) { mHasState = true; return &mBooks.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Clothing>(const LiveCellRef<ESM::Clothing>* ref) { mHasState = true; return &mClothes.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Container>(const LiveCellRef<ESM::Container>* ref) { mHasState = true; return &mContainers.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Creature>(const LiveCellRef<ESM::Creature>* ref) { mHasState = true; return &mCreatures.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Door>(const LiveCellRef<ESM::Door>* ref) { mHasState = true; return &mDoors.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Ingredient>(const LiveCellRef<ESM::Ingredient>* ref) { mHasState = true; return &mIngreds.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::CreatureLevList>(const LiveCellRef<ESM::CreatureLevList>* ref) { mHasState = true; return &mCreatureLists.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::ItemLevList>(const LiveCellRef<ESM::ItemLevList>* ref) { mHasState = true; return &mItemLists.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Light>(const LiveCellRef<ESM::Light>* ref) { mHasState = true; return &mLights.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Lockpick>(const LiveCellRef<ESM::Lockpick>* ref) { mHasState = true; return &mLockpicks.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Miscellaneous>(const LiveCellRef<ESM::Miscellaneous>* ref) { mHasState = true; return &mMiscItems.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::NPC>(const LiveCellRef<ESM::NPC>* ref) { mHasState = true; return &mNpcs.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Probe>(const LiveCellRef<ESM::Probe>* ref) { mHasState = true; return &mProbes.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Repair>(const LiveCellRef<ESM::Repair>* ref) { mHasState = true; return &mRepairs.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Static>(const LiveCellRef<ESM::Static>* ref) { mHasState = true; return &mStatics.insert(*ref); } template<> inline LiveCellRefBase* CellStore::insert<ESM::Weapon>(const LiveCellRef<ESM::Weapon>* ref) { mHasState = true; return &mWeapons.insert(*ref); } bool operator== (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right); } #endif