You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
830 lines
28 KiB
C++
830 lines
28 KiB
C++
#include "cellstore.hpp"
|
|
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
|
|
#include <components/esm/cellstate.hpp>
|
|
#include <components/esm/cellid.hpp>
|
|
#include <components/esm/esmwriter.hpp>
|
|
#include <components/esm/objectstate.hpp>
|
|
#include <components/esm/containerstate.hpp>
|
|
#include <components/esm/npcstate.hpp>
|
|
#include <components/esm/creaturestate.hpp>
|
|
#include <components/esm/fogstate.hpp>
|
|
#include <components/esm/creaturelevliststate.hpp>
|
|
#include <components/esm/doorstate.hpp>
|
|
|
|
#include "../mwbase/environment.hpp"
|
|
#include "../mwbase/world.hpp"
|
|
|
|
#include "../mwmechanics/creaturestats.hpp"
|
|
|
|
#include "ptr.hpp"
|
|
#include "esmstore.hpp"
|
|
#include "class.hpp"
|
|
#include "containerstore.hpp"
|
|
|
|
namespace
|
|
{
|
|
template<typename T>
|
|
MWWorld::Ptr searchInContainerList (MWWorld::CellRefList<T>& containerList, const std::string& id)
|
|
{
|
|
for (typename MWWorld::CellRefList<T>::List::iterator iter (containerList.mList.begin());
|
|
iter!=containerList.mList.end(); ++iter)
|
|
{
|
|
MWWorld::Ptr container (&*iter, 0);
|
|
|
|
MWWorld::Ptr ptr =
|
|
container.getClass().getContainerStore (container).search (id);
|
|
|
|
if (!ptr.isEmpty())
|
|
return ptr;
|
|
}
|
|
|
|
return MWWorld::Ptr();
|
|
}
|
|
|
|
template<typename T>
|
|
MWWorld::Ptr searchViaActorId (MWWorld::CellRefList<T>& actorList, int actorId,
|
|
MWWorld::CellStore *cell)
|
|
{
|
|
for (typename MWWorld::CellRefList<T>::List::iterator iter (actorList.mList.begin());
|
|
iter!=actorList.mList.end(); ++iter)
|
|
{
|
|
MWWorld::Ptr actor (&*iter, cell);
|
|
|
|
if (actor.getClass().getCreatureStats (actor).matchesActorId (actorId) && actor.getRefData().getCount() > 0)
|
|
return actor;
|
|
}
|
|
|
|
return MWWorld::Ptr();
|
|
}
|
|
|
|
template<typename RecordType, typename T>
|
|
void writeReferenceCollection (ESM::ESMWriter& writer,
|
|
const MWWorld::CellRefList<T>& collection)
|
|
{
|
|
if (!collection.mList.empty())
|
|
{
|
|
// references
|
|
for (typename MWWorld::CellRefList<T>::List::const_iterator
|
|
iter (collection.mList.begin());
|
|
iter!=collection.mList.end(); ++iter)
|
|
{
|
|
if (!iter->mData.hasChanged() && !iter->mRef.hasChanged() && iter->mRef.hasContentFile())
|
|
{
|
|
// Reference that came from a content file and has not been changed -> ignore
|
|
continue;
|
|
}
|
|
if (iter->mData.getCount()==0 && !iter->mRef.hasContentFile())
|
|
{
|
|
// Deleted reference that did not come from a content file -> ignore
|
|
continue;
|
|
}
|
|
|
|
RecordType state;
|
|
iter->save (state);
|
|
|
|
// recordId currently unused
|
|
writer.writeHNT ("OBJE", collection.mList.front().mBase->sRecordId);
|
|
|
|
state.save (writer);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename RecordType, typename T>
|
|
void readReferenceCollection (ESM::ESMReader& reader,
|
|
MWWorld::CellRefList<T>& collection, const ESM::CellRef& cref, const std::map<int, int>& contentFileMap)
|
|
{
|
|
const MWWorld::ESMStore& esmStore = MWBase::Environment::get().getWorld()->getStore();
|
|
|
|
RecordType state;
|
|
state.mRef = cref;
|
|
state.load(reader);
|
|
|
|
// If the reference came from a content file, make sure this content file is loaded
|
|
if (state.mRef.mRefNum.hasContentFile())
|
|
{
|
|
std::map<int, int>::const_iterator iter =
|
|
contentFileMap.find (state.mRef.mRefNum.mContentFile);
|
|
|
|
if (iter==contentFileMap.end())
|
|
return; // content file has been removed -> skip
|
|
|
|
state.mRef.mRefNum.mContentFile = iter->second;
|
|
}
|
|
|
|
if (!MWWorld::LiveCellRef<T>::checkState (state))
|
|
return; // not valid anymore with current content files -> skip
|
|
|
|
const T *record = esmStore.get<T>().search (state.mRef.mRefID);
|
|
|
|
if (!record)
|
|
return;
|
|
|
|
if (state.mRef.mRefNum.hasContentFile())
|
|
{
|
|
for (typename MWWorld::CellRefList<T>::List::iterator iter (collection.mList.begin());
|
|
iter!=collection.mList.end(); ++iter)
|
|
if (iter->mRef.getRefNum()==state.mRef.mRefNum)
|
|
{
|
|
// overwrite existing reference
|
|
iter->load (state);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// new reference
|
|
MWWorld::LiveCellRef<T> ref (record);
|
|
ref.load (state);
|
|
collection.mList.push_back (ref);
|
|
}
|
|
}
|
|
|
|
namespace MWWorld
|
|
{
|
|
|
|
template <typename X>
|
|
void CellRefList<X>::load(ESM::CellRef &ref, bool deleted, const MWWorld::ESMStore &esmStore)
|
|
{
|
|
const MWWorld::Store<X> &store = esmStore.get<X>();
|
|
|
|
if (const X *ptr = store.search (ref.mRefID))
|
|
{
|
|
typename std::list<LiveRef>::iterator iter =
|
|
std::find(mList.begin(), mList.end(), ref.mRefNum);
|
|
|
|
LiveRef liveCellRef (ref, ptr);
|
|
|
|
if (deleted)
|
|
liveCellRef.mData.setDeleted(true);
|
|
|
|
if (iter != mList.end())
|
|
*iter = liveCellRef;
|
|
else
|
|
mList.push_back (liveCellRef);
|
|
}
|
|
else
|
|
{
|
|
std::cerr
|
|
<< "Error: could not resolve cell reference " << ref.mRefID
|
|
<< " (dropping reference)" << std::endl;
|
|
}
|
|
}
|
|
|
|
template<typename X> bool operator==(const LiveCellRef<X>& ref, int pRefnum)
|
|
{
|
|
return (ref.mRef.mRefnum == pRefnum);
|
|
}
|
|
|
|
CellStore::CellStore (const ESM::Cell *cell)
|
|
: mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0)
|
|
{
|
|
mWaterLevel = cell->mWater;
|
|
}
|
|
|
|
const ESM::Cell *CellStore::getCell() const
|
|
{
|
|
return mCell;
|
|
}
|
|
|
|
CellStore::State CellStore::getState() const
|
|
{
|
|
return mState;
|
|
}
|
|
|
|
bool CellStore::hasState() const
|
|
{
|
|
return mHasState;
|
|
}
|
|
|
|
bool CellStore::hasId (const std::string& id) const
|
|
{
|
|
if (mState==State_Unloaded)
|
|
return false;
|
|
|
|
if (mState==State_Preloaded)
|
|
return std::binary_search (mIds.begin(), mIds.end(), id);
|
|
|
|
/// \todo address const-issues
|
|
return const_cast<CellStore *> (this)->search (id).isEmpty();
|
|
}
|
|
|
|
Ptr CellStore::search (const std::string& id)
|
|
{
|
|
bool oldState = mHasState;
|
|
|
|
mHasState = true;
|
|
|
|
if (LiveCellRef<ESM::Activator> *ref = mActivators.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Potion> *ref = mPotions.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Apparatus> *ref = mAppas.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Armor> *ref = mArmors.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Book> *ref = mBooks.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Clothing> *ref = mClothes.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Container> *ref = mContainers.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Creature> *ref = mCreatures.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Door> *ref = mDoors.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Ingredient> *ref = mIngreds.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::CreatureLevList> *ref = mCreatureLists.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::ItemLevList> *ref = mItemLists.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Light> *ref = mLights.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Lockpick> *ref = mLockpicks.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Miscellaneous> *ref = mMiscItems.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::NPC> *ref = mNpcs.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Probe> *ref = mProbes.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Repair> *ref = mRepairs.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Static> *ref = mStatics.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Weapon> *ref = mWeapons.find (id))
|
|
return Ptr (ref, this);
|
|
|
|
mHasState = oldState;
|
|
|
|
return Ptr();
|
|
}
|
|
|
|
Ptr CellStore::searchViaHandle (const std::string& handle)
|
|
{
|
|
bool oldState = mHasState;
|
|
|
|
mHasState = true;
|
|
|
|
if (LiveCellRef<ESM::Activator> *ref = mActivators.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Potion> *ref = mPotions.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Apparatus> *ref = mAppas.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Armor> *ref = mArmors.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Book> *ref = mBooks.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Clothing> *ref = mClothes.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Container> *ref = mContainers.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Creature> *ref = mCreatures.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Door> *ref = mDoors.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Ingredient> *ref = mIngreds.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::CreatureLevList> *ref = mCreatureLists.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::ItemLevList> *ref = mItemLists.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Light> *ref = mLights.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Lockpick> *ref = mLockpicks.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Miscellaneous> *ref = mMiscItems.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::NPC> *ref = mNpcs.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Probe> *ref = mProbes.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Repair> *ref = mRepairs.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Static> *ref = mStatics.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
if (LiveCellRef<ESM::Weapon> *ref = mWeapons.searchViaHandle (handle))
|
|
return Ptr (ref, this);
|
|
|
|
mHasState = oldState;
|
|
|
|
return Ptr();
|
|
}
|
|
|
|
Ptr CellStore::searchViaActorId (int id)
|
|
{
|
|
if (Ptr ptr = ::searchViaActorId (mNpcs, id, this))
|
|
return ptr;
|
|
|
|
if (Ptr ptr = ::searchViaActorId (mCreatures, id, this))
|
|
return ptr;
|
|
|
|
return Ptr();
|
|
}
|
|
|
|
float CellStore::getWaterLevel() const
|
|
{
|
|
return mWaterLevel;
|
|
}
|
|
|
|
void CellStore::setWaterLevel (float level)
|
|
{
|
|
mWaterLevel = level;
|
|
mHasState = true;
|
|
}
|
|
|
|
int CellStore::count() const
|
|
{
|
|
return
|
|
mActivators.mList.size()
|
|
+ mPotions.mList.size()
|
|
+ mAppas.mList.size()
|
|
+ mArmors.mList.size()
|
|
+ mBooks.mList.size()
|
|
+ mClothes.mList.size()
|
|
+ mContainers.mList.size()
|
|
+ mDoors.mList.size()
|
|
+ mIngreds.mList.size()
|
|
+ mCreatureLists.mList.size()
|
|
+ mItemLists.mList.size()
|
|
+ mLights.mList.size()
|
|
+ mLockpicks.mList.size()
|
|
+ mMiscItems.mList.size()
|
|
+ mProbes.mList.size()
|
|
+ mRepairs.mList.size()
|
|
+ mStatics.mList.size()
|
|
+ mWeapons.mList.size()
|
|
+ mCreatures.mList.size()
|
|
+ mNpcs.mList.size();
|
|
}
|
|
|
|
void CellStore::load (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
|
|
{
|
|
if (mState!=State_Loaded)
|
|
{
|
|
if (mState==State_Preloaded)
|
|
mIds.clear();
|
|
|
|
loadRefs (store, esm);
|
|
|
|
mState = State_Loaded;
|
|
|
|
// TODO: the pathgrid graph only needs to be loaded for active cells, so move this somewhere else.
|
|
// In a simple test, loading the graph for all cells in MW + expansions took 200 ms
|
|
mPathgridGraph.load(this);
|
|
}
|
|
}
|
|
|
|
void CellStore::preload (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
|
|
{
|
|
if (mState==State_Unloaded)
|
|
{
|
|
listRefs (store, esm);
|
|
|
|
mState = State_Preloaded;
|
|
}
|
|
}
|
|
|
|
void CellStore::listRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
|
|
{
|
|
assert (mCell);
|
|
|
|
if (mCell->mContextList.empty())
|
|
return; // this is a dynamically generated cell -> skipping.
|
|
|
|
// Load references from all plugins that do something with this cell.
|
|
for (size_t i = 0; i < mCell->mContextList.size(); i++)
|
|
{
|
|
// Reopen the ESM reader and seek to the right position.
|
|
int index = mCell->mContextList.at(i).index;
|
|
mCell->restore (esm[index], i);
|
|
|
|
ESM::CellRef ref;
|
|
|
|
// Get each reference in turn
|
|
bool deleted = false;
|
|
while (mCell->getNextRef (esm[index], ref, deleted))
|
|
{
|
|
if (deleted)
|
|
continue;
|
|
|
|
// Don't list reference if it was moved to a different cell.
|
|
ESM::MovedCellRefTracker::const_iterator iter =
|
|
std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefNum);
|
|
if (iter != mCell->mMovedRefs.end()) {
|
|
continue;
|
|
}
|
|
|
|
mIds.push_back (Misc::StringUtils::lowerCase (ref.mRefID));
|
|
}
|
|
}
|
|
|
|
// List moved references, from separately tracked list.
|
|
for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it)
|
|
{
|
|
const ESM::CellRef &ref = *it;
|
|
|
|
mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID));
|
|
}
|
|
|
|
std::sort (mIds.begin(), mIds.end());
|
|
}
|
|
|
|
void CellStore::loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
|
|
{
|
|
assert (mCell);
|
|
|
|
if (mCell->mContextList.empty())
|
|
return; // this is a dynamically generated cell -> skipping.
|
|
|
|
// Load references from all plugins that do something with this cell.
|
|
for (size_t i = 0; i < mCell->mContextList.size(); i++)
|
|
{
|
|
// Reopen the ESM reader and seek to the right position.
|
|
int index = mCell->mContextList.at(i).index;
|
|
mCell->restore (esm[index], i);
|
|
|
|
ESM::CellRef ref;
|
|
ref.mRefNum.mContentFile = ESM::RefNum::RefNum_NoContentFile;
|
|
|
|
// Get each reference in turn
|
|
bool deleted = false;
|
|
while(mCell->getNextRef(esm[index], ref, deleted))
|
|
{
|
|
// Don't load reference if it was moved to a different cell.
|
|
ESM::MovedCellRefTracker::const_iterator iter =
|
|
std::find(mCell->mMovedRefs.begin(), mCell->mMovedRefs.end(), ref.mRefNum);
|
|
if (iter != mCell->mMovedRefs.end()) {
|
|
continue;
|
|
}
|
|
|
|
loadRef (ref, deleted, store);
|
|
}
|
|
}
|
|
|
|
// Load moved references, from separately tracked list.
|
|
for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it)
|
|
{
|
|
ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it);
|
|
|
|
loadRef (ref, false, store);
|
|
}
|
|
}
|
|
|
|
bool CellStore::isExterior() const
|
|
{
|
|
return mCell->isExterior();
|
|
}
|
|
|
|
Ptr CellStore::searchInContainer (const std::string& id)
|
|
{
|
|
bool oldState = mHasState;
|
|
|
|
mHasState = true;
|
|
|
|
if (Ptr ptr = searchInContainerList (mContainers, id))
|
|
return ptr;
|
|
|
|
if (Ptr ptr = searchInContainerList (mCreatures, id))
|
|
return ptr;
|
|
|
|
if (Ptr ptr = searchInContainerList (mNpcs, id))
|
|
return ptr;
|
|
|
|
mHasState = oldState;
|
|
|
|
return Ptr();
|
|
}
|
|
|
|
void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store)
|
|
{
|
|
Misc::StringUtils::toLower (ref.mRefID);
|
|
|
|
switch (store.find (ref.mRefID))
|
|
{
|
|
case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break;
|
|
case ESM::REC_ALCH: mPotions.load(ref, deleted, store); break;
|
|
case ESM::REC_APPA: mAppas.load(ref, deleted, store); break;
|
|
case ESM::REC_ARMO: mArmors.load(ref, deleted, store); break;
|
|
case ESM::REC_BOOK: mBooks.load(ref, deleted, store); break;
|
|
case ESM::REC_CLOT: mClothes.load(ref, deleted, store); break;
|
|
case ESM::REC_CONT: mContainers.load(ref, deleted, store); break;
|
|
case ESM::REC_CREA: mCreatures.load(ref, deleted, store); break;
|
|
case ESM::REC_DOOR: mDoors.load(ref, deleted, store); break;
|
|
case ESM::REC_INGR: mIngreds.load(ref, deleted, store); break;
|
|
case ESM::REC_LEVC: mCreatureLists.load(ref, deleted, store); break;
|
|
case ESM::REC_LEVI: mItemLists.load(ref, deleted, store); break;
|
|
case ESM::REC_LIGH: mLights.load(ref, deleted, store); break;
|
|
case ESM::REC_LOCK: mLockpicks.load(ref, deleted, store); break;
|
|
case ESM::REC_MISC: mMiscItems.load(ref, deleted, store); break;
|
|
case ESM::REC_NPC_: mNpcs.load(ref, deleted, store); break;
|
|
case ESM::REC_PROB: mProbes.load(ref, deleted, store); break;
|
|
case ESM::REC_REPA: mRepairs.load(ref, deleted, store); break;
|
|
case ESM::REC_STAT: mStatics.load(ref, deleted, store); break;
|
|
case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break;
|
|
|
|
case 0: std::cerr << "Cell reference " + ref.mRefID + " not found!\n"; break;
|
|
|
|
default:
|
|
std::cerr
|
|
<< "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
|
|
}
|
|
}
|
|
|
|
void CellStore::loadState (const ESM::CellState& state)
|
|
{
|
|
mHasState = true;
|
|
|
|
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater)
|
|
mWaterLevel = state.mWaterLevel;
|
|
|
|
mWaterLevel = state.mWaterLevel;
|
|
mLastRespawn = MWWorld::TimeStamp(state.mLastRespawn);
|
|
}
|
|
|
|
void CellStore::saveState (ESM::CellState& state) const
|
|
{
|
|
state.mId = mCell->getCellId();
|
|
|
|
if (mCell->mData.mFlags & ESM::Cell::Interior && mCell->mData.mFlags & ESM::Cell::HasWater)
|
|
state.mWaterLevel = mWaterLevel;
|
|
|
|
state.mWaterLevel = mWaterLevel;
|
|
state.mHasFogOfWar = (mFogState.get() ? 1 : 0);
|
|
state.mLastRespawn = mLastRespawn.toEsm();
|
|
}
|
|
|
|
void CellStore::writeFog(ESM::ESMWriter &writer) const
|
|
{
|
|
if (mFogState.get())
|
|
{
|
|
mFogState->save(writer, mCell->mData.mFlags & ESM::Cell::Interior);
|
|
}
|
|
}
|
|
|
|
void CellStore::readFog(ESM::ESMReader &reader)
|
|
{
|
|
mFogState.reset(new ESM::FogState());
|
|
mFogState->load(reader);
|
|
}
|
|
|
|
void CellStore::writeReferences (ESM::ESMWriter& writer) const
|
|
{
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mActivators);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mPotions);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mAppas);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mArmors);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mBooks);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mClothes);
|
|
writeReferenceCollection<ESM::ContainerState> (writer, mContainers);
|
|
writeReferenceCollection<ESM::CreatureState> (writer, mCreatures);
|
|
writeReferenceCollection<ESM::DoorState> (writer, mDoors);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mIngreds);
|
|
writeReferenceCollection<ESM::CreatureLevListState> (writer, mCreatureLists);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mItemLists);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mLights);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mLockpicks);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mMiscItems);
|
|
writeReferenceCollection<ESM::NpcState> (writer, mNpcs);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mProbes);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mRepairs);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mStatics);
|
|
writeReferenceCollection<ESM::ObjectState> (writer, mWeapons);
|
|
}
|
|
|
|
void CellStore::readReferences (ESM::ESMReader& reader,
|
|
const std::map<int, int>& contentFileMap)
|
|
{
|
|
mHasState = true;
|
|
|
|
while (reader.isNextSub ("OBJE"))
|
|
{
|
|
unsigned int unused;
|
|
reader.getHT (unused);
|
|
|
|
// load the RefID first so we know what type of object it is
|
|
ESM::CellRef cref;
|
|
cref.loadId(reader, true);
|
|
|
|
int type = MWBase::Environment::get().getWorld()->getStore().find(cref.mRefID);
|
|
if (type == 0)
|
|
{
|
|
std::cerr << "Dropping reference to '" << cref.mRefID << "' (object no longer exists)" << std::endl;
|
|
reader.skipHSubUntil("OBJE");
|
|
continue;
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case ESM::REC_ACTI:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mActivators, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_ALCH:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mPotions, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_APPA:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mAppas, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_ARMO:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mArmors, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_BOOK:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mBooks, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_CLOT:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mClothes, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_CONT:
|
|
|
|
readReferenceCollection<ESM::ContainerState> (reader, mContainers, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_CREA:
|
|
|
|
readReferenceCollection<ESM::CreatureState> (reader, mCreatures, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_DOOR:
|
|
|
|
readReferenceCollection<ESM::DoorState> (reader, mDoors, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_INGR:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mIngreds, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_LEVC:
|
|
|
|
readReferenceCollection<ESM::CreatureLevListState> (reader, mCreatureLists, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_LEVI:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mItemLists, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_LIGH:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mLights, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_LOCK:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mLockpicks, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_MISC:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mMiscItems, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_NPC_:
|
|
|
|
readReferenceCollection<ESM::NpcState> (reader, mNpcs, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_PROB:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mProbes, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_REPA:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mRepairs, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_STAT:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mStatics, cref, contentFileMap);
|
|
break;
|
|
|
|
case ESM::REC_WEAP:
|
|
|
|
readReferenceCollection<ESM::ObjectState> (reader, mWeapons, cref, contentFileMap);
|
|
break;
|
|
|
|
default:
|
|
|
|
throw std::runtime_error ("unknown type in cell reference section");
|
|
}
|
|
}
|
|
}
|
|
|
|
bool operator== (const CellStore& left, const CellStore& right)
|
|
{
|
|
return left.getCell()->getCellId()==right.getCell()->getCellId();
|
|
}
|
|
|
|
bool operator!= (const CellStore& left, const CellStore& right)
|
|
{
|
|
return !(left==right);
|
|
}
|
|
|
|
bool CellStore::isPointConnected(const int start, const int end) const
|
|
{
|
|
return mPathgridGraph.isPointConnected(start, end);
|
|
}
|
|
|
|
std::list<ESM::Pathgrid::Point> CellStore::aStarSearch(const int start, const int end) const
|
|
{
|
|
return mPathgridGraph.aStarSearch(start, end);
|
|
}
|
|
|
|
void CellStore::setFog(ESM::FogState *fog)
|
|
{
|
|
mFogState.reset(fog);
|
|
}
|
|
|
|
ESM::FogState* CellStore::getFog() const
|
|
{
|
|
return mFogState.get();
|
|
}
|
|
|
|
void CellStore::respawn()
|
|
{
|
|
if (mState == State_Loaded)
|
|
{
|
|
static int iMonthsToRespawn = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find("iMonthsToRespawn")->getInt();
|
|
if (MWBase::Environment::get().getWorld()->getTimeStamp() - mLastRespawn > 24*30*iMonthsToRespawn)
|
|
{
|
|
mLastRespawn = MWBase::Environment::get().getWorld()->getTimeStamp();
|
|
for (CellRefList<ESM::Container>::List::iterator it (mContainers.mList.begin()); it!=mContainers.mList.end(); ++it)
|
|
{
|
|
Ptr ptr (&*it, this);
|
|
ptr.getClass().respawn(ptr);
|
|
}
|
|
for (CellRefList<ESM::Creature>::List::iterator it (mCreatures.mList.begin()); it!=mCreatures.mList.end(); ++it)
|
|
{
|
|
Ptr ptr (&*it, this);
|
|
ptr.getClass().respawn(ptr);
|
|
}
|
|
for (CellRefList<ESM::NPC>::List::iterator it (mNpcs.mList.begin()); it!=mNpcs.mList.end(); ++it)
|
|
{
|
|
Ptr ptr (&*it, this);
|
|
ptr.getClass().respawn(ptr);
|
|
}
|
|
for (CellRefList<ESM::CreatureLevList>::List::iterator it (mCreatureLists.mList.begin()); it!=mCreatureLists.mList.end(); ++it)
|
|
{
|
|
Ptr ptr (&*it, this);
|
|
ptr.getClass().respawn(ptr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|