|
|
|
@ -1,11 +1,12 @@
|
|
|
|
|
#ifndef GAME_MWWORLD_CELLSTORE_H
|
|
|
|
|
#define GAME_MWWORLD_CELLSTORE_H
|
|
|
|
|
|
|
|
|
|
#include <deque>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
|
|
#include "livecellref.hpp"
|
|
|
|
|
#include "esmstore.hpp"
|
|
|
|
|
#include "cellreflist.hpp"
|
|
|
|
|
|
|
|
|
|
namespace ESM
|
|
|
|
|
{
|
|
|
|
@ -14,164 +15,301 @@ namespace ESM
|
|
|
|
|
|
|
|
|
|
namespace MWWorld
|
|
|
|
|
{
|
|
|
|
|
class Ptr;
|
|
|
|
|
|
|
|
|
|
/// A list of cell references
|
|
|
|
|
template <typename X>
|
|
|
|
|
struct CellRefList
|
|
|
|
|
{
|
|
|
|
|
typedef LiveCellRef<X> LiveRef;
|
|
|
|
|
typedef std::list<LiveRef> List;
|
|
|
|
|
List mList;
|
|
|
|
|
/// \brief Mutable state of a cell
|
|
|
|
|
class CellStore
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
enum State
|
|
|
|
|
{
|
|
|
|
|
State_Unloaded, State_Preloaded, State_Loaded
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
const ESM::Cell *mCell;
|
|
|
|
|
State mState;
|
|
|
|
|
bool mHasState;
|
|
|
|
|
std::vector<std::string> mIds;
|
|
|
|
|
float mWaterLevel;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
float getWaterLevel() const;
|
|
|
|
|
|
|
|
|
|
void setWaterLevel (float level);
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
/// \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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isExterior() const;
|
|
|
|
|
|
|
|
|
|
Ptr searchInContainer (const std::string& id);
|
|
|
|
|
|
|
|
|
|
void loadState (const ESM::CellState& state);
|
|
|
|
|
|
|
|
|
|
void saveState (ESM::CellState& state) const;
|
|
|
|
|
|
|
|
|
|
void writeReferences (ESM::ESMWriter& writer) const;
|
|
|
|
|
|
|
|
|
|
void readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap);
|
|
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
|
CellRefList<T>& get() {
|
|
|
|
|
throw std::runtime_error ("Storage for this type not exist in cells");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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.getCount())
|
|
|
|
|
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.
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Search for the given reference in the given reclist from
|
|
|
|
|
// ESMStore. Insert the reference into the list if a match is
|
|
|
|
|
// found. If not, throw an exception.
|
|
|
|
|
// Moved to cpp file, as we require a custom compare operator for it,
|
|
|
|
|
// and the build will fail with an ugly three-way cyclic header dependence
|
|
|
|
|
// so we need to pass the instantiation of the method to the lnker, when
|
|
|
|
|
// all methods are known.
|
|
|
|
|
void load(ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore);
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Activator>& CellStore::get<ESM::Activator>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mActivators;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LiveRef *find (const std::string& name)
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Potion>& CellStore::get<ESM::Potion>()
|
|
|
|
|
{
|
|
|
|
|
for (typename std::list<LiveRef>::iterator iter (mList.begin()); iter!=mList.end(); ++iter)
|
|
|
|
|
{
|
|
|
|
|
if (iter->mData.getCount() > 0 && iter->mRef.mRefID == name)
|
|
|
|
|
return &*iter;
|
|
|
|
|
}
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mPotions;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Apparatus>& CellStore::get<ESM::Apparatus>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mAppas;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LiveRef &insert(const LiveRef &item) {
|
|
|
|
|
mList.push_back(item);
|
|
|
|
|
return mList.back();
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Armor>& CellStore::get<ESM::Armor>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mArmors;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// A storage struct for one single cell reference.
|
|
|
|
|
class CellStore
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Book>& CellStore::get<ESM::Book>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mBooks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum State
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Clothing>& CellStore::get<ESM::Clothing>()
|
|
|
|
|
{
|
|
|
|
|
State_Unloaded, State_Preloaded, State_Loaded
|
|
|
|
|
};
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mClothes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Container>& CellStore::get<ESM::Container>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mContainers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CellStore (const ESM::Cell *cell_);
|
|
|
|
|
|
|
|
|
|
const ESM::Cell *mCell;
|
|
|
|
|
State mState;
|
|
|
|
|
std::vector<std::string> mIds;
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Creature>& CellStore::get<ESM::Creature>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mCreatures;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float mWaterLevel;
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Door>& CellStore::get<ESM::Door>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mDoors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Ingredient>& CellStore::get<ESM::Ingredient>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mIngreds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::CreatureLevList>& CellStore::get<ESM::CreatureLevList>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mCreatureLists;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::ItemLevList>& CellStore::get<ESM::ItemLevList>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mItemLists;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Light>& CellStore::get<ESM::Light>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mLights;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Lockpick>& CellStore::get<ESM::Lockpick>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mLockpicks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Miscellaneous>& CellStore::get<ESM::Miscellaneous>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mMiscItems;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::NPC>& CellStore::get<ESM::NPC>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mNpcs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Probe>& CellStore::get<ESM::Probe>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mProbes;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Repair>& CellStore::get<ESM::Repair>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mRepairs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Static>& CellStore::get<ESM::Static>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mStatics;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
inline CellRefList<ESM::Weapon>& CellStore::get<ESM::Weapon>()
|
|
|
|
|
{
|
|
|
|
|
mHasState = true;
|
|
|
|
|
return mWeapons;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Lists for each individual object type
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
void load (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
|
|
|
|
|
|
|
|
|
|
void preload (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
|
|
|
|
|
|
|
|
|
|
/// Call functor (ref) for each reference. functor must return a bool. Returning
|
|
|
|
|
/// false will abort the iteration.
|
|
|
|
|
/// \return Iteration completed?
|
|
|
|
|
template<class Functor>
|
|
|
|
|
bool forEach (Functor& functor)
|
|
|
|
|
{
|
|
|
|
|
return
|
|
|
|
|
forEachImp (functor, mActivators) &&
|
|
|
|
|
forEachImp (functor, mPotions) &&
|
|
|
|
|
forEachImp (functor, mAppas) &&
|
|
|
|
|
forEachImp (functor, mArmors) &&
|
|
|
|
|
forEachImp (functor, mBooks) &&
|
|
|
|
|
forEachImp (functor, mClothes) &&
|
|
|
|
|
forEachImp (functor, mContainers) &&
|
|
|
|
|
forEachImp (functor, mCreatures) &&
|
|
|
|
|
forEachImp (functor, mDoors) &&
|
|
|
|
|
forEachImp (functor, mIngreds) &&
|
|
|
|
|
forEachImp (functor, mCreatureLists) &&
|
|
|
|
|
forEachImp (functor, mItemLists) &&
|
|
|
|
|
forEachImp (functor, mLights) &&
|
|
|
|
|
forEachImp (functor, mLockpicks) &&
|
|
|
|
|
forEachImp (functor, mMiscItems) &&
|
|
|
|
|
forEachImp (functor, mNpcs) &&
|
|
|
|
|
forEachImp (functor, mProbes) &&
|
|
|
|
|
forEachImp (functor, mRepairs) &&
|
|
|
|
|
forEachImp (functor, mStatics) &&
|
|
|
|
|
forEachImp (functor, mWeapons);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator==(const CellStore &cell) {
|
|
|
|
|
return mCell->mName == cell.mCell->mName &&
|
|
|
|
|
mCell->mData.mX == cell.mCell->mData.mX &&
|
|
|
|
|
mCell->mData.mY == cell.mCell->mData.mY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator!=(const CellStore &cell) {
|
|
|
|
|
return !(*this == cell);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isExterior() const {
|
|
|
|
|
return mCell->isExterior();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ptr searchInContainer (const std::string& id);
|
|
|
|
|
|
|
|
|
|
void loadState (const ESM::CellState& state);
|
|
|
|
|
|
|
|
|
|
void saveState (ESM::CellState& state) const;
|
|
|
|
|
|
|
|
|
|
void writeReferences (ESM::ESMWriter& writer) const;
|
|
|
|
|
|
|
|
|
|
void readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap);
|
|
|
|
|
|
|
|
|
|
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.getCount())
|
|
|
|
|
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.
|
|
|
|
|
};
|
|
|
|
|
bool operator== (const CellStore& left, const CellStore& right);
|
|
|
|
|
bool operator!= (const CellStore& left, const CellStore& right);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|