Merge pull request #840 from scrawl/movedrefs

Object movement between cells
openmw-38
scrawl 9 years ago
commit bdae572264

@ -62,7 +62,7 @@ add_openmw_dir (mwsound
add_openmw_dir (mwworld add_openmw_dir (mwworld
refdata worldimp scene globals class action nullaction actionteleport refdata worldimp scene globals class action nullaction actionteleport
containerstore actiontalk actiontake manualref player cellfunctors failedaction containerstore actiontalk actiontake manualref player cellvisitors failedaction
cells localscripts customdata inventorystore ptr actionopen actionread cells localscripts customdata inventorystore ptr actionopen actionread
actionequip timestamp actionalchemy cellstore actionapply actioneat actionequip timestamp actionalchemy cellstore actionapply actioneat
store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor

@ -130,6 +130,6 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Activator> *ref = MWWorld::LiveCellRef<ESM::Activator> *ref =
ptr.get<ESM::Activator>(); ptr.get<ESM::Activator>();
return MWWorld::Ptr(&cell.get<ESM::Activator>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
} }

@ -148,7 +148,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Apparatus> *ref = MWWorld::LiveCellRef<ESM::Apparatus> *ref =
ptr.get<ESM::Apparatus>(); ptr.get<ESM::Apparatus>();
return MWWorld::Ptr(&cell.get<ESM::Apparatus>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const bool Apparatus::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -382,7 +382,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Armor> *ref = MWWorld::LiveCellRef<ESM::Armor> *ref =
ptr.get<ESM::Armor>(); ptr.get<ESM::Armor>();
return MWWorld::Ptr(&cell.get<ESM::Armor>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const int Armor::getEnchantmentPoints (const MWWorld::Ptr& ptr) const

@ -187,7 +187,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Book> *ref = MWWorld::LiveCellRef<ESM::Book> *ref =
ptr.get<ESM::Book>(); ptr.get<ESM::Book>();
return MWWorld::Ptr(&cell.get<ESM::Book>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const int Book::getEnchantmentPoints (const MWWorld::Ptr& ptr) const

@ -276,7 +276,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Clothing> *ref = MWWorld::LiveCellRef<ESM::Clothing> *ref =
ptr.get<ESM::Clothing>(); ptr.get<ESM::Clothing>();
return MWWorld::Ptr(&cell.get<ESM::Clothing>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const int Clothing::getEnchantmentPoints (const MWWorld::Ptr& ptr) const

@ -293,7 +293,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Container> *ref = MWWorld::LiveCellRef<ESM::Container> *ref =
ptr.get<ESM::Container>(); ptr.get<ESM::Container>();
return MWWorld::Ptr(&cell.get<ESM::Container>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const void Container::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const

@ -600,7 +600,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Creature> *ref = MWWorld::LiveCellRef<ESM::Creature> *ref =
ptr.get<ESM::Creature>(); ptr.get<ESM::Creature>();
return MWWorld::Ptr(&cell.get<ESM::Creature>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
bool Creature::isBipedal(const MWWorld::Ptr &ptr) const bool Creature::isBipedal(const MWWorld::Ptr &ptr) const

@ -310,7 +310,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Door> *ref = MWWorld::LiveCellRef<ESM::Door> *ref =
ptr.get<ESM::Door>(); ptr.get<ESM::Door>();
return MWWorld::Ptr(&cell.get<ESM::Door>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
void Door::ensureCustomData(const MWWorld::Ptr &ptr) const void Door::ensureCustomData(const MWWorld::Ptr &ptr) const

@ -185,7 +185,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Ingredient> *ref = MWWorld::LiveCellRef<ESM::Ingredient> *ref =
ptr.get<ESM::Ingredient>(); ptr.get<ESM::Ingredient>();
return MWWorld::Ptr(&cell.get<ESM::Ingredient>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const bool Ingredient::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -217,7 +217,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Light> *ref = MWWorld::LiveCellRef<ESM::Light> *ref =
ptr.get<ESM::Light>(); ptr.get<ESM::Light>();
return MWWorld::Ptr(&cell.get<ESM::Light>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const bool Light::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -166,7 +166,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Lockpick> *ref = MWWorld::LiveCellRef<ESM::Lockpick> *ref =
ptr.get<ESM::Lockpick>(); ptr.get<ESM::Lockpick>();
return MWWorld::Ptr(&cell.get<ESM::Lockpick>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const bool Lockpick::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -215,13 +215,14 @@ namespace MWClass
MWWorld::ManualRef newRef(store, base); MWWorld::ManualRef newRef(store, base);
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
newRef.getPtr().get<ESM::Miscellaneous>(); newRef.getPtr().get<ESM::Miscellaneous>();
newPtr = MWWorld::Ptr(&cell.get<ESM::Miscellaneous>().insert(*ref), &cell);
newPtr = MWWorld::Ptr(cell.insert(ref), &cell);
newPtr.getCellRef().setGoldValue(goldAmount); newPtr.getCellRef().setGoldValue(goldAmount);
newPtr.getRefData().setCount(1); newPtr.getRefData().setCount(1);
} else { } else {
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref = MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
ptr.get<ESM::Miscellaneous>(); ptr.get<ESM::Miscellaneous>();
newPtr = MWWorld::Ptr(&cell.get<ESM::Miscellaneous>().insert(*ref), &cell); newPtr = MWWorld::Ptr(cell.insert(ref), &cell);
} }
return newPtr; return newPtr;
} }

@ -1130,7 +1130,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::NPC> *ref = MWWorld::LiveCellRef<ESM::NPC> *ref =
ptr.get<ESM::NPC>(); ptr.get<ESM::NPC>();
return MWWorld::Ptr(&cell.get<ESM::NPC>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const int Npc::getSkill(const MWWorld::Ptr& ptr, int skill) const

@ -178,7 +178,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Potion> *ref = MWWorld::LiveCellRef<ESM::Potion> *ref =
ptr.get<ESM::Potion>(); ptr.get<ESM::Potion>();
return MWWorld::Ptr(&cell.get<ESM::Potion>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const bool Potion::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -165,7 +165,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Probe> *ref = MWWorld::LiveCellRef<ESM::Probe> *ref =
ptr.get<ESM::Probe>(); ptr.get<ESM::Probe>();
return MWWorld::Ptr(&cell.get<ESM::Probe>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const bool Probe::canSell (const MWWorld::Ptr& item, int npcServices) const

@ -160,7 +160,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Repair> *ref = MWWorld::LiveCellRef<ESM::Repair> *ref =
ptr.get<ESM::Repair>(); ptr.get<ESM::Repair>();
return MWWorld::Ptr(&cell.get<ESM::Repair>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
boost::shared_ptr<MWWorld::Action> Repair::use (const MWWorld::Ptr& ptr) const boost::shared_ptr<MWWorld::Action> Repair::use (const MWWorld::Ptr& ptr) const

@ -60,6 +60,6 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Static> *ref = MWWorld::LiveCellRef<ESM::Static> *ref =
ptr.get<ESM::Static>(); ptr.get<ESM::Static>();
return MWWorld::Ptr(&cell.get<ESM::Static>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
} }

@ -417,7 +417,7 @@ namespace MWClass
MWWorld::LiveCellRef<ESM::Weapon> *ref = MWWorld::LiveCellRef<ESM::Weapon> *ref =
ptr.get<ESM::Weapon>(); ptr.get<ESM::Weapon>();
return MWWorld::Ptr(&cell.get<ESM::Weapon>().insert(*ref), &cell); return MWWorld::Ptr(cell.insert(ref), &cell);
} }
int Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const int Weapon::getEnchantmentPoints (const MWWorld::Ptr& ptr) const

@ -44,9 +44,9 @@ namespace MWMechanics
return MWWorld::Ptr(); // check interior cells only return MWWorld::Ptr(); // check interior cells only
// Check all the doors in this cell // Check all the doors in this cell
MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>(); const MWWorld::CellRefList<ESM::Door>& doors = cell->getReadOnlyDoors();
MWWorld::CellRefList<ESM::Door>::List& refList = doors.mList; const MWWorld::CellRefList<ESM::Door>::List& refList = doors.mList;
MWWorld::CellRefList<ESM::Door>::List::iterator it = refList.begin(); MWWorld::CellRefList<ESM::Door>::List::const_iterator it = refList.begin();
osg::Vec3f pos(actor.getRefData().getPosition().asVec3()); osg::Vec3f pos(actor.getRefData().getPosition().asVec3());
/// TODO: How to check whether the actor is facing a door? Below code is for /// TODO: How to check whether the actor is facing a door? Below code is for
@ -59,11 +59,12 @@ namespace MWMechanics
/// opposite of the code in World::activateDoor() ::confused:: /// opposite of the code in World::activateDoor() ::confused::
for (; it != refList.end(); ++it) for (; it != refList.end(); ++it)
{ {
MWWorld::LiveCellRef<ESM::Door>& ref = *it; const MWWorld::LiveCellRef<ESM::Door>& ref = *it;
if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr if((pos - ref.mData.getPosition().asVec3()).length2() < minSqr
&& ref.mData.getPosition().rot[2] == ref.mRef.getPosition().rot[2]) && ref.mData.getPosition().rot[2] == ref.mRef.getPosition().rot[2])
{ {
return MWWorld::Ptr(&ref, actor.getCell()); // found, stop searching // FIXME cast
return MWWorld::Ptr(&const_cast<MWWorld::LiveCellRef<ESM::Door> &>(ref), actor.getCell()); // found, stop searching
} }
} }
return MWWorld::Ptr(); // none found return MWWorld::Ptr(); // none found

@ -300,14 +300,16 @@ namespace MWScript
} }
catch(std::exception&) catch(std::exception&)
{ {
// cell not found, move to exterior instead (vanilla PositionCell compatibility)
const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID); const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID);
int cx,cy; int cx,cy;
MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy); MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy);
store = MWBase::Environment::get().getWorld()->getExterior(cx,cy); store = MWBase::Environment::get().getWorld()->getExterior(cx,cy);
if(!cell) if(!cell)
{ {
runtime.getContext().report ("unknown cell (" + cellID + ")"); std::string error = "PositionCell: unknown interior cell (" + cellID + "), moving to exterior instead";
std::cerr << "unknown cell (" << cellID << ")\n"; runtime.getContext().report (error);
std::cerr << error << std::endl;
} }
} }
if(store) if(store)

@ -1,5 +1,7 @@
#include "cells.hpp" #include "cells.hpp"
#include <iostream>
#include <components/esm/esmreader.hpp> #include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp> #include <components/esm/esmwriter.hpp>
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
@ -23,7 +25,7 @@ MWWorld::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
if (result==mInteriors.end()) if (result==mInteriors.end())
{ {
result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell))).first; result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell, mStore, mReader))).first;
} }
return &result->second; return &result->second;
@ -36,7 +38,7 @@ MWWorld::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
if (result==mExteriors.end()) if (result==mExteriors.end())
{ {
result = mExteriors.insert (std::make_pair ( result = mExteriors.insert (std::make_pair (
std::make_pair (cell->getGridX(), cell->getGridY()), CellStore (cell))).first; std::make_pair (cell->getGridX(), cell->getGridY()), CellStore (cell, mStore, mReader))).first;
} }
@ -70,7 +72,7 @@ MWWorld::Ptr MWWorld::Cells::getPtrAndCache (const std::string& name, CellStore&
void MWWorld::Cells::writeCell (ESM::ESMWriter& writer, CellStore& cell) const void MWWorld::Cells::writeCell (ESM::ESMWriter& writer, CellStore& cell) const
{ {
if (cell.getState()!=CellStore::State_Loaded) if (cell.getState()!=CellStore::State_Loaded)
cell.load (mStore, mReader); cell.load ();
ESM::CellState cellState; ESM::CellState cellState;
@ -114,13 +116,12 @@ MWWorld::CellStore *MWWorld::Cells::getExterior (int x, int y)
} }
result = mExteriors.insert (std::make_pair ( result = mExteriors.insert (std::make_pair (
std::make_pair (x, y), CellStore (cell))).first; std::make_pair (x, y), CellStore (cell, mStore, mReader))).first;
} }
if (result->second.getState()!=CellStore::State_Loaded) if (result->second.getState()!=CellStore::State_Loaded)
{ {
// Multiple plugin support for landscape data is much easier than for references. The last plugin wins. result->second.load ();
result->second.load (mStore, mReader);
} }
return &result->second; return &result->second;
@ -135,12 +136,12 @@ MWWorld::CellStore *MWWorld::Cells::getInterior (const std::string& name)
{ {
const ESM::Cell *cell = mStore.get<ESM::Cell>().find(lowerName); const ESM::Cell *cell = mStore.get<ESM::Cell>().find(lowerName);
result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell))).first; result = mInteriors.insert (std::make_pair (lowerName, CellStore (cell, mStore, mReader))).first;
} }
if (result->second.getState()!=CellStore::State_Loaded) if (result->second.getState()!=CellStore::State_Loaded)
{ {
result->second.load (mStore, mReader); result->second.load ();
} }
return &result->second; return &result->second;
@ -158,13 +159,13 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell,
bool searchInContainers) bool searchInContainers)
{ {
if (cell.getState()==CellStore::State_Unloaded) if (cell.getState()==CellStore::State_Unloaded)
cell.preload (mStore, mReader); cell.preload ();
if (cell.getState()==CellStore::State_Preloaded) if (cell.getState()==CellStore::State_Preloaded)
{ {
if (cell.hasId (name)) if (cell.hasId (name))
{ {
cell.load (mStore, mReader); cell.load ();
} }
else else
return Ptr(); return Ptr();
@ -304,6 +305,29 @@ void MWWorld::Cells::write (ESM::ESMWriter& writer, Loading::Listener& progress)
} }
} }
struct GetCellStoreCallback : public MWWorld::CellStore::GetCellStoreCallback
{
public:
GetCellStoreCallback(MWWorld::Cells& cells)
: mCells(cells)
{
}
MWWorld::Cells& mCells;
virtual MWWorld::CellStore* getCellStore(const ESM::CellId& cellId)
{
try
{
return mCells.getCell(cellId);
}
catch (...)
{
return NULL;
}
}
};
bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type, bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
const std::map<int, int>& contentFileMap) const std::map<int, int>& contentFileMap)
{ {
@ -321,9 +345,9 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
catch (...) catch (...)
{ {
// silently drop cells that don't exist anymore // silently drop cells that don't exist anymore
std::cerr << "Dropping state for cell " << state.mId.mWorldspace << " (cell no longer exists)" << std::endl;
reader.skipRecord(); reader.skipRecord();
return true; return true;
/// \todo log
} }
state.load (reader); state.load (reader);
@ -333,9 +357,11 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
cellStore->readFog(reader); cellStore->readFog(reader);
if (cellStore->getState()!=CellStore::State_Loaded) if (cellStore->getState()!=CellStore::State_Loaded)
cellStore->load (mStore, mReader); cellStore->load ();
GetCellStoreCallback callback(*this);
cellStore->readReferences (reader, contentFileMap); cellStore->readReferences (reader, contentFileMap, &callback);
return true; return true;
} }

@ -47,13 +47,16 @@ namespace
template<typename T> template<typename T>
MWWorld::Ptr searchViaActorId (MWWorld::CellRefList<T>& actorList, int actorId, MWWorld::Ptr searchViaActorId (MWWorld::CellRefList<T>& actorList, int actorId,
MWWorld::CellStore *cell) MWWorld::CellStore *cell, const std::map<MWWorld::LiveCellRefBase*, MWWorld::CellStore*>& toIgnore)
{ {
for (typename MWWorld::CellRefList<T>::List::iterator iter (actorList.mList.begin()); for (typename MWWorld::CellRefList<T>::List::iterator iter (actorList.mList.begin());
iter!=actorList.mList.end(); ++iter) iter!=actorList.mList.end(); ++iter)
{ {
MWWorld::Ptr actor (&*iter, cell); MWWorld::Ptr actor (&*iter, cell);
if (toIgnore.find(&*iter) != toIgnore.end())
continue;
if (actor.getClass().getCreatureStats (actor).matchesActorId (actorId) && actor.getRefData().getCount() > 0) if (actor.getClass().getCreatureStats (actor).matchesActorId (actorId) && actor.getRefData().getCount() > 0)
return actor; return actor;
} }
@ -141,6 +144,28 @@ namespace
ref.load (state); ref.load (state);
collection.mList.push_back (ref); collection.mList.push_back (ref);
} }
struct SearchByRefNumVisitor
{
MWWorld::LiveCellRefBase* mFound;
ESM::RefNum mRefNumToFind;
SearchByRefNumVisitor(const ESM::RefNum& toFind)
: mFound(NULL)
, mRefNumToFind(toFind)
{
}
bool operator()(const MWWorld::Ptr& ptr)
{
if (ptr.getCellRef().getRefNum() == mRefNumToFind)
{
mFound = ptr.getBase();
return false;
}
return true;
}
};
} }
namespace MWWorld namespace MWWorld
@ -179,8 +204,121 @@ namespace MWWorld
return (ref.mRef.mRefnum == pRefnum); return (ref.mRef.mRefnum == pRefnum);
} }
CellStore::CellStore (const ESM::Cell *cell) void CellStore::moveFrom(const Ptr &object, CellStore *from)
: mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0) {
if (mState != State_Loaded)
load();
mHasState = true;
MovedRefTracker::iterator found = mMovedToAnotherCell.find(object.getBase());
if (found != mMovedToAnotherCell.end())
{
// A cell we had previously moved an object to is returning it to us.
assert (found->second == from);
mMovedToAnotherCell.erase(found);
}
else
{
mMovedHere.insert(std::make_pair(object.getBase(), from));
}
updateMergedRefs();
}
MWWorld::Ptr CellStore::moveTo(const Ptr &object, CellStore *cellToMoveTo)
{
if (cellToMoveTo == this)
throw std::runtime_error("moveTo: object is already in this cell");
// We assume that *this is in State_Loaded since we could hardly have reference to a live object otherwise.
if (mState != State_Loaded)
throw std::runtime_error("moveTo: can't move object from a non-loaded cell (how did you get this object anyway?)");
// Ensure that the object actually exists in the cell
SearchByRefNumVisitor searchVisitor(object.getCellRef().getRefNum());
forEach(searchVisitor);
if (!searchVisitor.mFound)
throw std::runtime_error("moveTo: object is not in this cell");
// Objects with no refnum can't be handled correctly in the merging process that happens
// on a save/load, so do a simple copy & delete for these objects.
if (!object.getCellRef().getRefNum().hasContentFile())
{
MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo);
object.getRefData().setCount(0);
object.getRefData().setBaseNode(NULL);
return copied;
}
MovedRefTracker::iterator found = mMovedHere.find(object.getBase());
if (found != mMovedHere.end())
{
// Special case - object didn't originate in this cell
// Move it back to its original cell first
CellStore* originalCell = found->second;
assert (originalCell != this);
originalCell->moveFrom(object, this);
mMovedHere.erase(found);
// Now that object is back to its rightful owner, we can move it
if (cellToMoveTo != originalCell)
{
originalCell->moveTo(object, cellToMoveTo);
}
updateMergedRefs();
return MWWorld::Ptr(object.getBase(), cellToMoveTo);
}
cellToMoveTo->moveFrom(object, this);
mMovedToAnotherCell.insert(std::make_pair(object.getBase(), cellToMoveTo));
updateMergedRefs();
return MWWorld::Ptr(object.getBase(), cellToMoveTo);
}
struct MergeVisitor
{
MergeVisitor(std::vector<LiveCellRefBase*>& mergeTo, const std::map<LiveCellRefBase*, MWWorld::CellStore*>& movedHere,
const std::map<LiveCellRefBase*, MWWorld::CellStore*>& movedToAnotherCell)
: mMergeTo(mergeTo)
, mMovedHere(movedHere)
, mMovedToAnotherCell(movedToAnotherCell)
{
}
bool operator() (const MWWorld::Ptr& ptr)
{
if (mMovedToAnotherCell.find(ptr.getBase()) != mMovedToAnotherCell.end())
return true;
mMergeTo.push_back(ptr.getBase());
return true;
}
void merge()
{
for (std::map<LiveCellRefBase*, MWWorld::CellStore*>::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it)
mMergeTo.push_back(it->first);
}
private:
std::vector<LiveCellRefBase*>& mMergeTo;
const std::map<LiveCellRefBase*, MWWorld::CellStore*>& mMovedHere;
const std::map<LiveCellRefBase*, MWWorld::CellStore*>& mMovedToAnotherCell;
};
void CellStore::updateMergedRefs()
{
mMergedRefs.clear();
MergeVisitor visitor(mMergedRefs, mMovedHere, mMovedToAnotherCell);
forEachInternal(visitor);
visitor.merge();
}
CellStore::CellStore (const ESM::Cell *cell, const MWWorld::ESMStore& esmStore, std::vector<ESM::ESMReader>& readerList)
: mStore(esmStore), mReader(readerList), mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0)
{ {
mWaterLevel = cell->mWater; mWaterLevel = cell->mWater;
} }
@ -212,85 +350,50 @@ namespace MWWorld
return const_cast<CellStore *> (this)->search (id).isEmpty(); return const_cast<CellStore *> (this)->search (id).isEmpty();
} }
struct SearchVisitor
{
MWWorld::Ptr mFound;
std::string mIdToFind;
bool operator()(const MWWorld::Ptr& ptr)
{
if (ptr.getCellRef().getRefId() == mIdToFind)
{
mFound = ptr;
return false;
}
return true;
}
};
Ptr CellStore::search (const std::string& id) Ptr CellStore::search (const std::string& id)
{ {
bool oldState = mHasState; bool oldState = mHasState;
mHasState = true; SearchVisitor searchVisitor;
searchVisitor.mIdToFind = id;
if (LiveCellRef<ESM::Activator> *ref = mActivators.find (id)) forEach(searchVisitor);
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; mHasState = oldState;
return searchVisitor.mFound;
return Ptr();
} }
Ptr CellStore::searchViaActorId (int id) Ptr CellStore::searchViaActorId (int id)
{ {
if (Ptr ptr = ::searchViaActorId (mNpcs, id, this)) if (Ptr ptr = ::searchViaActorId (mNpcs, id, this, mMovedToAnotherCell))
return ptr; return ptr;
if (Ptr ptr = ::searchViaActorId (mCreatures, id, this)) if (Ptr ptr = ::searchViaActorId (mCreatures, id, this, mMovedToAnotherCell))
return ptr; return ptr;
for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it)
{
MWWorld::Ptr actor (it->first, this);
if (!actor.getClass().isActor())
continue;
if (actor.getClass().getCreatureStats (actor).matchesActorId (id) && actor.getRefData().getCount() > 0)
return actor;
}
return Ptr(); return Ptr();
} }
@ -309,37 +412,17 @@ namespace MWWorld
int CellStore::count() const int CellStore::count() const
{ {
return return mMergedRefs.size();
mActivators.mList.size() }
+ mPotions.mList.size()
+ mAppas.mList.size() void CellStore::load ()
+ 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_Loaded)
{ {
if (mState==State_Preloaded) if (mState==State_Preloaded)
mIds.clear(); mIds.clear();
loadRefs (store, esm); loadRefs ();
mState = State_Loaded; mState = State_Loaded;
@ -349,18 +432,20 @@ namespace MWWorld
} }
} }
void CellStore::preload (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm) void CellStore::preload ()
{ {
if (mState==State_Unloaded) if (mState==State_Unloaded)
{ {
listRefs (store, esm); listRefs ();
mState = State_Preloaded; mState = State_Preloaded;
} }
} }
void CellStore::listRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm) void CellStore::listRefs()
{ {
std::vector<ESM::ESMReader>& esm = mReader;
assert (mCell); assert (mCell);
if (mCell->mContextList.empty()) if (mCell->mContextList.empty())
@ -404,8 +489,10 @@ namespace MWWorld
std::sort (mIds.begin(), mIds.end()); std::sort (mIds.begin(), mIds.end());
} }
void CellStore::loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm) void CellStore::loadRefs()
{ {
std::vector<ESM::ESMReader>& esm = mReader;
assert (mCell); assert (mCell);
if (mCell->mContextList.empty()) if (mCell->mContextList.empty())
@ -432,7 +519,7 @@ namespace MWWorld
continue; continue;
} }
loadRef (ref, deleted, store); loadRef (ref, deleted);
} }
} }
@ -441,8 +528,10 @@ namespace MWWorld
{ {
ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it); ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it);
loadRef (ref, false, store); loadRef (ref, false);
} }
updateMergedRefs();
} }
bool CellStore::isExterior() const bool CellStore::isExterior() const
@ -470,10 +559,12 @@ namespace MWWorld
return Ptr(); return Ptr();
} }
void CellStore::loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store) void CellStore::loadRef (ESM::CellRef& ref, bool deleted)
{ {
Misc::StringUtils::lowerCaseInPlace (ref.mRefID); Misc::StringUtils::lowerCaseInPlace (ref.mRefID);
const MWWorld::ESMStore& store = mStore;
switch (store.find (ref.mRefID)) switch (store.find (ref.mRefID))
{ {
case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break; case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break;
@ -564,10 +655,19 @@ namespace MWWorld
writeReferenceCollection<ESM::ObjectState> (writer, mRepairs); writeReferenceCollection<ESM::ObjectState> (writer, mRepairs);
writeReferenceCollection<ESM::ObjectState> (writer, mStatics); writeReferenceCollection<ESM::ObjectState> (writer, mStatics);
writeReferenceCollection<ESM::ObjectState> (writer, mWeapons); writeReferenceCollection<ESM::ObjectState> (writer, mWeapons);
for (MovedRefTracker::const_iterator it = mMovedToAnotherCell.begin(); it != mMovedToAnotherCell.end(); ++it)
{
LiveCellRefBase* base = it->first;
ESM::RefNum refNum = base->mRef.getRefNum();
ESM::CellId movedTo = it->second->getCell()->getCellId();
refNum.save(writer, true, "MVRF");
movedTo.save(writer);
}
} }
void CellStore::readReferences (ESM::ESMReader& reader, void CellStore::readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap, GetCellStoreCallback* callback)
const std::map<int, int>& contentFileMap)
{ {
mHasState = true; mHasState = true;
@ -695,6 +795,48 @@ namespace MWWorld
throw std::runtime_error ("unknown type in cell reference section"); throw std::runtime_error ("unknown type in cell reference section");
} }
} }
while (reader.isNextSub("MVRF"))
{
reader.cacheSubName();
ESM::RefNum refnum;
ESM::CellId movedTo;
refnum.load(reader, true, "MVRF");
movedTo.load(reader);
// Search for the reference. It might no longer exist if its content file was removed.
SearchByRefNumVisitor visitor(refnum);
forEachInternal(visitor);
if (!visitor.mFound)
{
std::cout << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId() << " (moved object no longer exists)" << std::endl;
continue;
}
CellStore* otherCell = callback->getCellStore(movedTo);
if (otherCell == NULL)
{
std::cerr << "Dropping moved ref tag for " << visitor.mFound->mRef.getRefId()
<< " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location." << std::endl;
// Note by dropping tag the object will automatically re-appear in its original cell, though potentially at inapproriate coordinates.
// Restore original coordinates:
visitor.mFound->mData.setPosition(visitor.mFound->mRef.getPosition());
continue;
}
if (otherCell == this)
{
// Should never happen unless someone's tampering with files.
std::cerr << "Found invalid moved ref, ignoring" << std::endl;
continue;
}
moveTo(MWWorld::Ptr(visitor.mFound, this), otherCell);
}
updateMergedRefs();
} }
bool operator== (const CellStore& left, const CellStore& right) bool operator== (const CellStore& left, const CellStore& right)

@ -40,6 +40,7 @@ namespace ESM
{ {
struct CellState; struct CellState;
struct FogState; struct FogState;
struct CellId;
} }
namespace MWWorld namespace MWWorld
@ -60,6 +61,9 @@ namespace MWWorld
private: private:
const MWWorld::ESMStore& mStore;
std::vector<ESM::ESMReader>& mReader;
// Even though fog actually belongs to the player and not cells, // 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. // 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 // Note this is NULL until the cell is explored to save some memory
@ -73,6 +77,7 @@ namespace MWWorld
MWWorld::TimeStamp mLastRespawn; MWWorld::TimeStamp mLastRespawn;
// List of refs owned by this cell
CellRefList<ESM::Activator> mActivators; CellRefList<ESM::Activator> mActivators;
CellRefList<ESM::Potion> mPotions; CellRefList<ESM::Potion> mPotions;
CellRefList<ESM::Apparatus> mAppas; CellRefList<ESM::Apparatus> mAppas;
@ -94,9 +99,95 @@ namespace MWWorld
CellRefList<ESM::Static> mStatics; CellRefList<ESM::Static> mStatics;
CellRefList<ESM::Weapon> mWeapons; 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();
// helper function for forEachInternal
template<class Visitor, class List>
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<class Visitor>
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);
}
/// @note If you get a linker error here, this means the given type can not be stored in a cell. The supported types are
/// defined at the bottom of this file.
template <class T>
CellRefList<T>& get();
public: public:
CellStore (const ESM::Cell *cell_); /// 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 <typename T>
LiveCellRefBase* insert(const LiveCellRef<T>* ref)
{
mHasState = true;
CellRefList<T>& list = get<T>();
LiveCellRefBase* ret = &list.insert(*ref);
updateMergedRefs();
return ret;
}
/// @param readerList The readers to use for loading of the cell on-demand.
CellStore (const ESM::Cell *cell_,
const MWWorld::ESMStore& store,
std::vector<ESM::ESMReader>& readerList);
const ESM::Cell *getCell() const; const ESM::Cell *getCell() const;
@ -108,6 +199,7 @@ namespace MWWorld
bool hasId (const std::string& id) const; bool hasId (const std::string& id) const;
///< May return true for deleted IDs when in preload state. Will return false, if cell is ///< May return true for deleted IDs when in preload state. Will return false, if cell is
/// unloaded. /// 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); Ptr search (const std::string& id);
///< Will return an empty Ptr if cell is not loaded. Does not check references in ///< Will return an empty Ptr if cell is not loaded. Does not check references in
@ -128,55 +220,82 @@ namespace MWWorld
int count() const; int count() const;
///< Return total number of references, including deleted ones. ///< Return total number of references, including deleted ones.
void load (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm); void load ();
///< Load references from content file. ///< Load references from content file.
void preload (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm); void preload ();
///< Build ID list from content file. ///< Build ID list from content file.
/// Call functor (ref) for each reference. functor must return a bool. Returning /// Call visitor (ref) for each reference. visitor must return a bool. Returning
/// false will abort the iteration. /// false will abort the iteration.
/// \attention This function also lists deleted (count 0) objects! /// \attention This function also lists deleted (count 0) objects!
/// \return Iteration completed? /// \return Iteration completed?
/// template<class Visitor>
/// \note Creatures and NPCs are handled last. bool forEach (Visitor& visitor)
template<class Functor>
bool forEach (Functor& functor)
{ {
if (mState != State_Loaded)
return false;
mHasState = true; mHasState = true;
return for (unsigned int i=0; i<mMergedRefs.size(); ++i)
forEachImp (functor, mActivators) && {
forEachImp (functor, mPotions) && if (mMergedRefs[i]->mData.isDeletedByContentFile())
forEachImp (functor, mAppas) && continue;
forEachImp (functor, mArmors) &&
forEachImp (functor, mBooks) && if (!visitor(MWWorld::Ptr(mMergedRefs[i], this)))
forEachImp (functor, mClothes) && return false;
forEachImp (functor, mContainers) && }
forEachImp (functor, mDoors) && return true;
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> /// Call visitor (ref) for each reference of given type. visitor must return a bool. Returning
bool forEachContainer (Functor& functor) /// false will abort the iteration.
/// \attention This function also lists deleted (count 0) objects!
/// \return Iteration completed?
template <class T, class Visitor>
bool forEachType(Visitor& visitor)
{ {
if (mState != State_Loaded)
return false;
mHasState = true; mHasState = true;
return CellRefList<T>& list = get<T>();
forEachImp (functor, mContainers) &&
forEachImp (functor, mCreatures) && for (typename CellRefList<T>::List::iterator it (list.mList.begin()); it!=list.mList.end(); ++it)
forEachImp (functor, mNpcs); {
LiveCellRefBase* base = &*it;
if (mMovedToAnotherCell.find(base) != mMovedToAnotherCell.end())
continue;
if (base->mData.isDeletedByContentFile())
continue;
if (!visitor(MWWorld::Ptr(base, this)))
return false;
}
for (MovedRefTracker::const_iterator it = mMovedHere.begin(); it != mMovedHere.end(); ++it)
{
LiveCellRefBase* base = it->first;
if (dynamic_cast<LiveCellRef<T>*>(base))
if (!visitor(MWWorld::Ptr(base, this)))
return false;
}
return true;
}
/// \todo add const version of forEach
// NOTE: does not account for moved references
// Should be phased out when we have const version of forEach
inline const CellRefList<ESM::Door>& getReadOnlyDoors() const
{
return mDoors;
}
inline const CellRefList<ESM::Static>& getReadOnlyStatics() const
{
return mStatics;
} }
bool isExterior() const; bool isExterior() const;
@ -193,47 +312,31 @@ namespace MWWorld
void writeReferences (ESM::ESMWriter& writer) const; void writeReferences (ESM::ESMWriter& writer) const;
void readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap); struct GetCellStoreCallback
{
public:
///@note must return NULL if the cell is not found
virtual CellStore* getCellStore(const ESM::CellId& cellId) = 0;
};
/// @param callback to use for retrieving of additional CellStore objects by ID (required for resolving moved references)
void readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap, GetCellStoreCallback* callback);
void respawn (); void respawn ();
///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded. ///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
template <class T>
CellRefList<T>& get() {
throw std::runtime_error ("Storage for type " + std::string(typeid(T).name())+ " does not exist in cells");
}
template <class T>
const CellRefList<T>& 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; bool isPointConnected(const int start, const int end) const;
std::list<ESM::Pathgrid::Point> aStarSearch(const int start, const int end) const; std::list<ESM::Pathgrid::Point> aStarSearch(const int start, const int end) const;
private: 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 /// Run through references and store IDs
void listRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm); void listRefs();
void loadRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm); void loadRefs();
void loadRef (ESM::CellRef& ref, bool deleted, const ESMStore& store); void loadRef (ESM::CellRef& ref, bool deleted);
///< Make case-adjustments to \a ref and insert it into the respective container. ///< Make case-adjustments to \a ref and insert it into the respective container.
/// ///
/// Invalid \a ref objects are silently dropped. /// Invalid \a ref objects are silently dropped.
@ -381,12 +484,6 @@ namespace MWWorld
return mWeapons; return mWeapons;
} }
template<>
inline const CellRefList<ESM::Door>& CellStore::getReadOnly<ESM::Door>()
{
return mDoors;
}
bool operator== (const CellStore& left, const CellStore& right); bool operator== (const CellStore& left, const CellStore& right);
bool operator!= (const CellStore& left, const CellStore& right); bool operator!= (const CellStore& left, const CellStore& right);
} }

@ -1,5 +1,5 @@
#ifndef GAME_MWWORLD_CELLFUNCTORS_H #ifndef GAME_MWWORLD_CELLVISITORS_H
#define GAME_MWWORLD_CELLFUNCTORS_H #define GAME_MWWORLD_CELLVISITORS_H
#include <vector> #include <vector>
#include <string> #include <string>
@ -9,7 +9,7 @@
namespace MWWorld namespace MWWorld
{ {
struct ListAndResetObjects struct ListAndResetObjectsVisitor
{ {
std::vector<MWWorld::Ptr> mObjects; std::vector<MWWorld::Ptr> mObjects;

@ -11,46 +11,54 @@
namespace namespace
{ {
template<typename T>
void listCellScripts (MWWorld::LocalScripts& localScripts, struct AddScriptsVisitor
MWWorld::CellRefList<T>& cellRefList, MWWorld::CellStore *cell)
{ {
for (typename MWWorld::CellRefList<T>::List::iterator iter ( AddScriptsVisitor(MWWorld::LocalScripts& scripts)
cellRefList.mList.begin()); : mScripts(scripts)
iter!=cellRefList.mList.end(); ++iter)
{ {
if (!iter->mBase->mScript.empty() && !iter->mData.isDeleted())
{
localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell));
}
} }
} MWWorld::LocalScripts& mScripts;
// Adds scripts for items in containers (containers/npcs/creatures) bool operator()(const MWWorld::Ptr& ptr)
template<typename T>
void listCellScriptsCont (MWWorld::LocalScripts& localScripts,
MWWorld::CellRefList<T>& cellRefList, MWWorld::CellStore *cell)
{
for (typename MWWorld::CellRefList<T>::List::iterator iter (
cellRefList.mList.begin());
iter!=cellRefList.mList.end(); ++iter)
{ {
if (ptr.getRefData().isDeleted())
return true;
std::string script = ptr.getClass().getScript(ptr);
if (!script.empty())
mScripts.add(script, ptr);
return true;
}
};
MWWorld::Ptr containerPtr (&*iter, cell); struct AddContainerItemScriptsVisitor
{
AddContainerItemScriptsVisitor(MWWorld::LocalScripts& scripts)
: mScripts(scripts)
{
}
MWWorld::LocalScripts& mScripts;
bool operator()(const MWWorld::Ptr& containerPtr)
{
MWWorld::ContainerStore& container = containerPtr.getClass().getContainerStore(containerPtr); MWWorld::ContainerStore& container = containerPtr.getClass().getContainerStore(containerPtr);
for(MWWorld::ContainerStoreIterator it3 = container.begin(); it3 != container.end(); ++it3) for(MWWorld::ContainerStoreIterator it = container.begin(); it != container.end(); ++it)
{ {
std::string script = it3->getClass().getScript(*it3); std::string script = it->getClass().getScript(*it);
if(script != "") if(script != "")
{ {
MWWorld::Ptr item = *it3; MWWorld::Ptr item = *it;
item.mCell = cell; item.mCell = containerPtr.getCell();
localScripts.add (script, item); mScripts.add (script, item);
} }
} }
return true;
} }
} };
} }
MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {} MWWorld::LocalScripts::LocalScripts (const MWWorld::ESMStore& store) : mStore (store) {}
@ -116,26 +124,13 @@ void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr)
void MWWorld::LocalScripts::addCell (CellStore *cell) void MWWorld::LocalScripts::addCell (CellStore *cell)
{ {
listCellScripts (*this, cell->get<ESM::Activator>(), cell); AddScriptsVisitor addScriptsVisitor(*this);
listCellScripts (*this, cell->get<ESM::Potion>(), cell); cell->forEach(addScriptsVisitor);
listCellScripts (*this, cell->get<ESM::Apparatus>(), cell);
listCellScripts (*this, cell->get<ESM::Armor>(), cell); AddContainerItemScriptsVisitor addContainerItemScriptsVisitor(*this);
listCellScripts (*this, cell->get<ESM::Book>(), cell); cell->forEachType<ESM::NPC>(addContainerItemScriptsVisitor);
listCellScripts (*this, cell->get<ESM::Clothing>(), cell); cell->forEachType<ESM::Creature>(addContainerItemScriptsVisitor);
listCellScripts (*this, cell->get<ESM::Container>(), cell); cell->forEachType<ESM::Container>(addContainerItemScriptsVisitor);
listCellScriptsCont (*this, cell->get<ESM::Container>(), cell);
listCellScripts (*this, cell->get<ESM::Creature>(), cell);
listCellScriptsCont (*this, cell->get<ESM::Creature>(), cell);
listCellScripts (*this, cell->get<ESM::Door>(), cell);
listCellScripts (*this, cell->get<ESM::Ingredient>(), cell);
listCellScripts (*this, cell->get<ESM::Light>(), cell);
listCellScripts (*this, cell->get<ESM::Lockpick>(), cell);
listCellScripts (*this, cell->get<ESM::Miscellaneous>(), cell);
listCellScripts (*this, cell->get<ESM::NPC>(), cell);
listCellScriptsCont (*this, cell->get<ESM::NPC>(), cell);
listCellScripts (*this, cell->get<ESM::Probe>(), cell);
listCellScripts (*this, cell->get<ESM::Repair>(), cell);
listCellScripts (*this, cell->get<ESM::Weapon>(), cell);
} }
void MWWorld::LocalScripts::clear() void MWWorld::LocalScripts::clear()

@ -182,7 +182,7 @@ namespace MWWorld
mPosition = pos; mPosition = pos;
} }
const ESM::Position& RefData::getPosition() const ESM::Position& RefData::getPosition() const
{ {
return mPosition; return mPosition;
} }

@ -103,7 +103,7 @@ namespace MWWorld
void disable(); void disable();
void setPosition (const ESM::Position& pos); void setPosition (const ESM::Position& pos);
const ESM::Position& getPosition(); const ESM::Position& getPosition() const;
void setCustomData (CustomData *data); void setCustomData (CustomData *data);
///< Set custom data (potentially replacing old custom data). The ownership of \a data is ///< Set custom data (potentially replacing old custom data). The ownership of \a data is

@ -22,7 +22,7 @@
#include "localscripts.hpp" #include "localscripts.hpp"
#include "esmstore.hpp" #include "esmstore.hpp"
#include "class.hpp" #include "class.hpp"
#include "cellfunctors.hpp" #include "cellvisitors.hpp"
#include "cellstore.hpp" #include "cellstore.hpp"
namespace namespace
@ -78,7 +78,7 @@ namespace
} }
} }
struct InsertFunctor struct InsertVisitor
{ {
MWWorld::CellStore& mCell; MWWorld::CellStore& mCell;
bool mRescale; bool mRescale;
@ -86,13 +86,13 @@ namespace
MWPhysics::PhysicsSystem& mPhysics; MWPhysics::PhysicsSystem& mPhysics;
MWRender::RenderingManager& mRendering; MWRender::RenderingManager& mRendering;
InsertFunctor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener, InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener,
MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering); MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering);
bool operator() (const MWWorld::Ptr& ptr); bool operator() (const MWWorld::Ptr& ptr);
}; };
InsertFunctor::InsertFunctor (MWWorld::CellStore& cell, bool rescale, InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, bool rescale,
Loading::Listener& loadingListener, MWPhysics::PhysicsSystem& physics, Loading::Listener& loadingListener, MWPhysics::PhysicsSystem& physics,
MWRender::RenderingManager& rendering) MWRender::RenderingManager& rendering)
: mCell (cell), mRescale (rescale), mLoadingListener (loadingListener), : mCell (cell), mRescale (rescale), mLoadingListener (loadingListener),
@ -100,7 +100,7 @@ namespace
mRendering (rendering) mRendering (rendering)
{} {}
bool InsertFunctor::operator() (const MWWorld::Ptr& ptr) bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
{ {
if (mRescale) if (mRescale)
{ {
@ -116,7 +116,6 @@ namespace
{ {
addObject(ptr, mPhysics, mRendering); addObject(ptr, mPhysics, mRendering);
updateObjectRotation(ptr, mPhysics, mRendering, false); updateObjectRotation(ptr, mPhysics, mRendering, false);
ptr.getClass().adjustPosition (ptr, false);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -129,6 +128,17 @@ namespace
return true; return true;
} }
struct AdjustPositionVisitor
{
bool operator() (const MWWorld::Ptr& ptr)
{
if (!ptr.getRefData().isDeleted() && ptr.getRefData().isEnabled())
ptr.getClass().adjustPosition (ptr, false);
return true;
}
};
} }
@ -196,11 +206,11 @@ namespace MWWorld
void Scene::unloadCell (CellStoreCollection::iterator iter) void Scene::unloadCell (CellStoreCollection::iterator iter)
{ {
std::cout << "Unloading cell\n"; std::cout << "Unloading cell\n";
ListAndResetObjects functor; ListAndResetObjectsVisitor visitor;
(*iter)->forEach<ListAndResetObjects>(functor); (*iter)->forEach<ListAndResetObjectsVisitor>(visitor);
for (std::vector<MWWorld::Ptr>::const_iterator iter2 (functor.mObjects.begin()); for (std::vector<MWWorld::Ptr>::const_iterator iter2 (visitor.mObjects.begin());
iter2!=functor.mObjects.end(); ++iter2) iter2!=visitor.mObjects.end(); ++iter2)
{ {
mPhysics->remove(*iter2); mPhysics->remove(*iter2);
} }
@ -551,8 +561,12 @@ namespace MWWorld
void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener) void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener)
{ {
InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering); InsertVisitor insertVisitor (cell, rescale, *loadingListener, *mPhysics, mRendering);
cell.forEach (functor); cell.forEach (insertVisitor);
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
AdjustPositionVisitor adjustPosVisitor;
cell.forEach (adjustPosVisitor);
} }
void Scene::addObjectToScene (const Ptr& ptr) void Scene::addObjectToScene (const Ptr& ptr)

@ -54,7 +54,6 @@
#include "player.hpp" #include "player.hpp"
#include "manualref.hpp" #include "manualref.hpp"
#include "cellstore.hpp" #include "cellstore.hpp"
#include "cellfunctors.hpp"
#include "containerstore.hpp" #include "containerstore.hpp"
#include "inventorystore.hpp" #include "inventorystore.hpp"
#include "actionteleport.hpp" #include "actionteleport.hpp"
@ -690,12 +689,12 @@ namespace MWWorld
return mWorldScene->searchPtrViaActorId (actorId); return mWorldScene->searchPtrViaActorId (actorId);
} }
struct FindContainerFunctor struct FindContainerVisitor
{ {
Ptr mContainedPtr; Ptr mContainedPtr;
Ptr mResult; Ptr mResult;
FindContainerFunctor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {} FindContainerVisitor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {}
bool operator() (Ptr ptr) bool operator() (Ptr ptr)
{ {
@ -721,11 +720,15 @@ namespace MWWorld
const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells();
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
{ {
FindContainerFunctor functor(ptr); FindContainerVisitor visitor(ptr);
(*cellIt)->forEachContainer(functor); (*cellIt)->forEachType<ESM::Container>(visitor);
if (visitor.mResult.isEmpty())
(*cellIt)->forEachType<ESM::Creature>(visitor);
if (visitor.mResult.isEmpty())
(*cellIt)->forEachType<ESM::NPC>(visitor);
if (!functor.mResult.isEmpty()) if (!visitor.mResult.isEmpty())
return functor.mResult; return visitor.mResult;
} }
return Ptr(); return Ptr();
@ -1149,7 +1152,7 @@ namespace MWWorld
bool newCellActive = mWorldScene->isCellActive(*newCell); bool newCellActive = mWorldScene->isCellActive(*newCell);
if (!currCellActive && newCellActive) if (!currCellActive && newCellActive)
{ {
newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos); newPtr = currCell->moveTo(ptr, newCell);
mWorldScene->addObjectToScene(newPtr); mWorldScene->addObjectToScene(newPtr);
std::string script = newPtr.getClass().getScript(newPtr); std::string script = newPtr.getClass().getScript(newPtr);
@ -1165,17 +1168,16 @@ namespace MWWorld
removeContainerScripts (ptr); removeContainerScripts (ptr);
haveToMove = false; haveToMove = false;
newPtr = ptr.getClass().copyToCell(ptr, *newCell); newPtr = currCell->moveTo(ptr, newCell);
newPtr.getRefData().setBaseNode(0); newPtr.getRefData().setBaseNode(0);
} }
else if (!currCellActive && !newCellActive) else if (!currCellActive && !newCellActive)
newPtr = ptr.getClass().copyToCell(ptr, *newCell); newPtr = currCell->moveTo(ptr, newCell);
else // both cells active else // both cells active
{ {
newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos); newPtr = currCell->moveTo(ptr, newCell);
mRendering->updatePtr(ptr, newPtr); mRendering->updatePtr(ptr, newPtr);
ptr.getRefData().setBaseNode(NULL);
MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr); MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr);
mPhysics->updatePtr(ptr, newPtr); mPhysics->updatePtr(ptr, newPtr);
@ -1192,7 +1194,6 @@ namespace MWWorld
addContainerScripts (newPtr, newCell); addContainerScripts (newPtr, newCell);
} }
} }
ptr.getRefData().setCount(0);
} }
} }
if (haveToMove && newPtr.getRefData().getBaseNode()) if (haveToMove && newPtr.getRefData().getBaseNode())
@ -1708,27 +1709,32 @@ namespace MWWorld
osg::Vec2f World::getNorthVector (CellStore* cell) osg::Vec2f World::getNorthVector (CellStore* cell)
{ {
MWWorld::CellRefList<ESM::Static>& statics = cell->get<ESM::Static>(); MWWorld::Ptr northmarker = cell->search("northmarker");
MWWorld::LiveCellRef<ESM::Static>* ref = statics.find("northmarker");
if (!ref) if (northmarker.isEmpty())
return osg::Vec2f(0, 1); return osg::Vec2f(0, 1);
osg::Quat orient (-ref->mData.getPosition().rot[2], osg::Vec3f(0,0,1)); osg::Quat orient (-northmarker.getRefData().getPosition().rot[2], osg::Vec3f(0,0,1));
osg::Vec3f dir = orient * osg::Vec3f(0,1,0); osg::Vec3f dir = orient * osg::Vec3f(0,1,0);
osg::Vec2f d (dir.x(), dir.y()); osg::Vec2f d (dir.x(), dir.y());
return d; return d;
} }
void World::getDoorMarkers (CellStore* cell, std::vector<World::DoorMarker>& out) struct GetDoorMarkerVisitor
{ {
MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>(); GetDoorMarkerVisitor(std::vector<World::DoorMarker>& out)
CellRefList<ESM::Door>::List& refList = doors.mList; : mOut(out)
for (CellRefList<ESM::Door>::List::iterator it = refList.begin(); it != refList.end(); ++it)
{ {
MWWorld::LiveCellRef<ESM::Door>& ref = *it; }
if (!ref.mData.isEnabled()) std::vector<World::DoorMarker>& mOut;
continue;
bool operator()(const MWWorld::Ptr& ptr)
{
MWWorld::LiveCellRef<ESM::Door>& ref = *static_cast<MWWorld::LiveCellRef<ESM::Door>* >(ptr.getBase());
if (!ref.mData.isEnabled() || ref.mData.isDeleted())
return true;
if (ref.mRef.getTeleport()) if (ref.mRef.getTeleport())
{ {
@ -1744,7 +1750,7 @@ namespace MWWorld
else else
{ {
cellid.mPaged = true; cellid.mPaged = true;
positionToIndex( MWBase::Environment::get().getWorld()->positionToIndex(
ref.mRef.getDoorDest().pos[0], ref.mRef.getDoorDest().pos[0],
ref.mRef.getDoorDest().pos[1], ref.mRef.getDoorDest().pos[1],
cellid.mIndex.mX, cellid.mIndex.mX,
@ -1756,9 +1762,16 @@ namespace MWWorld
newMarker.x = pos.pos[0]; newMarker.x = pos.pos[0];
newMarker.y = pos.pos[1]; newMarker.y = pos.pos[1];
out.push_back(newMarker); mOut.push_back(newMarker);
} }
return true;
} }
};
void World::getDoorMarkers (CellStore* cell, std::vector<World::DoorMarker>& out)
{
GetDoorMarkerVisitor visitor(out);
cell->forEachType<ESM::Door>(visitor);
} }
void World::setWaterHeight(const float height) void World::setWaterHeight(const float height)
@ -2253,25 +2266,40 @@ namespace MWWorld
return osg::Vec3f(0,1,0); return osg::Vec3f(0,1,0);
} }
void World::getContainersOwnedBy (const MWWorld::Ptr& npc, std::vector<MWWorld::Ptr>& out) struct GetContainersOwnedByVisitor
{
GetContainersOwnedByVisitor(const MWWorld::Ptr& owner, std::vector<MWWorld::Ptr>& out)
: mOwner(owner)
, mOut(out)
{
}
MWWorld::Ptr mOwner;
std::vector<MWWorld::Ptr>& mOut;
bool operator()(const MWWorld::Ptr& ptr)
{
if (ptr.getRefData().isDeleted())
return true;
if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), mOwner.getCellRef().getRefId()))
mOut.push_back(ptr);
return true;
}
};
void World::getContainersOwnedBy (const MWWorld::Ptr& owner, std::vector<MWWorld::Ptr>& out)
{ {
const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells();
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
{ {
MWWorld::CellRefList<ESM::Container>& containers = (*cellIt)->get<ESM::Container>(); GetContainersOwnedByVisitor visitor (owner, out);
CellRefList<ESM::Container>::List& refList = containers.mList; (*cellIt)->forEachType<ESM::Container>(visitor);
for (CellRefList<ESM::Container>::List::iterator container = refList.begin(); container != refList.end(); ++container)
{
MWWorld::Ptr ptr (&*container, *cellIt);
if (ptr.getRefData().isDeleted())
continue;
if (Misc::StringUtils::ciEqual(ptr.getCellRef().getOwner(), npc.getCellRef().getRefId()))
out.push_back(ptr);
}
} }
} }
struct ListObjectsFunctor struct ListObjectsVisitor
{ {
std::vector<MWWorld::Ptr> mObjects; std::vector<MWWorld::Ptr> mObjects;
@ -2288,10 +2316,10 @@ namespace MWWorld
const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells(); const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells();
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt) for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
{ {
ListObjectsFunctor functor; ListObjectsVisitor visitor;
(*cellIt)->forEach<ListObjectsFunctor>(functor); (*cellIt)->forEach(visitor);
for (std::vector<MWWorld::Ptr>::iterator it = functor.mObjects.begin(); it != functor.mObjects.end(); ++it) for (std::vector<MWWorld::Ptr>::iterator it = visitor.mObjects.begin(); it != visitor.mObjects.end(); ++it)
if (Misc::StringUtils::ciEqual(it->getCellRef().getOwner(), npc.getCellRef().getRefId())) if (Misc::StringUtils::ciEqual(it->getCellRef().getOwner(), npc.getCellRef().getRefId()))
out.push_back(*it); out.push_back(*it);
} }
@ -2342,7 +2370,8 @@ namespace MWWorld
if (0 == cellStore) { if (0 == cellStore) {
return false; return false;
} }
const DoorList &doors = cellStore->get<ESM::Door>().mList;
const DoorList &doors = cellStore->getReadOnlyDoors().mList;
for (DoorList::const_iterator it = doors.begin(); it != doors.end(); ++it) { for (DoorList::const_iterator it = doors.begin(); it != doors.end(); ++it) {
if (!it->mRef.getTeleport()) { if (!it->mRef.getTeleport()) {
continue; continue;
@ -2364,7 +2393,7 @@ namespace MWWorld
if (0 != source) { if (0 != source) {
// Find door leading to our current teleport door // Find door leading to our current teleport door
// and use it destination to position inside cell. // and use it destination to position inside cell.
const DoorList &doors = source->get<ESM::Door>().mList; const DoorList &doors = source->getReadOnlyDoors().mList;
for (DoorList::const_iterator jt = doors.begin(); jt != doors.end(); ++jt) { for (DoorList::const_iterator jt = doors.begin(); jt != doors.end(); ++jt) {
if (it->mRef.getTeleport() && if (it->mRef.getTeleport() &&
Misc::StringUtils::ciEqual(name, jt->mRef.getDestCell())) Misc::StringUtils::ciEqual(name, jt->mRef.getDestCell()))
@ -2378,7 +2407,7 @@ namespace MWWorld
} }
} }
// Fall back to the first static location. // Fall back to the first static location.
const StaticList &statics = cellStore->get<ESM::Static>().mList; const StaticList &statics = cellStore->getReadOnlyStatics().mList;
if ( statics.begin() != statics.end() ) { if ( statics.begin() != statics.end() ) {
pos = statics.begin()->mRef.getPosition(); pos = statics.begin()->mRef.getPosition();
return true; return true;
@ -2747,7 +2776,7 @@ namespace MWWorld
MWWorld::CellStore *next = getInterior( *i ); MWWorld::CellStore *next = getInterior( *i );
if ( !next ) continue; if ( !next ) continue;
const MWWorld::CellRefList<ESM::Door>& doors = next->getReadOnly<ESM::Door>(); const MWWorld::CellRefList<ESM::Door>& doors = next->getReadOnlyDoors();
const CellRefList<ESM::Door>::List& refList = doors.mList; const CellRefList<ESM::Door>::List& refList = doors.mList;
// Check if any door in the cell leads to an exterior directly // Check if any door in the cell leads to an exterior directly
@ -2807,7 +2836,7 @@ namespace MWWorld
return closestMarker; return closestMarker;
} }
const MWWorld::CellRefList<ESM::Door>& doors = next->getReadOnly<ESM::Door>(); const MWWorld::CellRefList<ESM::Door>& doors = next->getReadOnlyDoors();
const CellRefList<ESM::Door>::List& doorList = doors.mList; const CellRefList<ESM::Door>::List& doorList = doors.mList;
// Check if any door in the cell leads to an exterior directly // Check if any door in the cell leads to an exterior directly
@ -2831,7 +2860,6 @@ namespace MWWorld
} }
} }
} }
return MWWorld::Ptr(); return MWWorld::Ptr();
} }
@ -2888,9 +2916,9 @@ namespace MWWorld
mWeatherManager->update(duration, paused); mWeatherManager->update(duration, paused);
} }
struct AddDetectedReference struct AddDetectedReferenceVisitor
{ {
AddDetectedReference(std::vector<Ptr>& out, Ptr detector, World::DetectionType type, float squaredDist) AddDetectedReferenceVisitor(std::vector<Ptr>& out, Ptr detector, World::DetectionType type, float squaredDist)
: mOut(out), mDetector(detector), mSquaredDist(squaredDist), mType(type) : mOut(out), mDetector(detector), mSquaredDist(squaredDist), mType(type)
{ {
} }
@ -2899,7 +2927,7 @@ namespace MWWorld
Ptr mDetector; Ptr mDetector;
float mSquaredDist; float mSquaredDist;
World::DetectionType mType; World::DetectionType mType;
bool operator() (MWWorld::Ptr ptr) bool operator() (const MWWorld::Ptr& ptr)
{ {
if ((ptr.getRefData().getPosition().asVec3() - mDetector.getRefData().getPosition().asVec3()).length2() >= mSquaredDist) if ((ptr.getRefData().getPosition().asVec3() - mDetector.getRefData().getPosition().asVec3()).length2() >= mSquaredDist)
return true; return true;
@ -2930,7 +2958,7 @@ namespace MWWorld
return true; return true;
} }
bool needToAdd (MWWorld::Ptr ptr, MWWorld::Ptr detector) bool needToAdd (const MWWorld::Ptr& ptr, const MWWorld::Ptr& detector)
{ {
if (mType == World::Detect_Creature) if (mType == World::Detect_Creature)
{ {
@ -2970,13 +2998,13 @@ namespace MWWorld
dist = feetToGameUnits(dist); dist = feetToGameUnits(dist);
AddDetectedReference functor (out, ptr, type, dist*dist); AddDetectedReferenceVisitor visitor (out, ptr, type, dist*dist);
const Scene::CellStoreCollection& active = mWorldScene->getActiveCells(); const Scene::CellStoreCollection& active = mWorldScene->getActiveCells();
for (Scene::CellStoreCollection::const_iterator it = active.begin(); it != active.end(); ++it) for (Scene::CellStoreCollection::const_iterator it = active.begin(); it != active.end(); ++it)
{ {
MWWorld::CellStore* cellStore = *it; MWWorld::CellStore* cellStore = *it;
cellStore->forEach(functor); cellStore->forEach(visitor);
} }
} }
@ -3232,7 +3260,7 @@ namespace MWWorld
interpreterContext.executeActivation(object, actor); interpreterContext.executeActivation(object, actor);
} }
struct ResetActorsFunctor struct ResetActorsVisitor
{ {
bool operator() (Ptr ptr) bool operator() (Ptr ptr)
{ {
@ -3254,8 +3282,8 @@ namespace MWWorld
iter!=mWorldScene->getActiveCells().end(); ++iter) iter!=mWorldScene->getActiveCells().end(); ++iter)
{ {
CellStore* cellstore = *iter; CellStore* cellstore = *iter;
ResetActorsFunctor functor; ResetActorsVisitor visitor;
cellstore->forEach(functor); cellstore->forEach(visitor);
} }
} }

@ -3,12 +3,12 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.hpp" #include "esmwriter.hpp"
void ESM::RefNum::load (ESMReader& esm, bool wide) void ESM::RefNum::load (ESMReader& esm, bool wide, const std::string& tag)
{ {
if (wide) if (wide)
esm.getHNT (*this, "FRMR", 8); esm.getHNT (*this, tag.c_str(), 8);
else else
esm.getHNT (mIndex, "FRMR"); esm.getHNT (mIndex, tag.c_str());
} }
void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const

@ -16,7 +16,7 @@ namespace ESM
unsigned int mIndex; unsigned int mIndex;
int mContentFile; int mContentFile;
void load (ESMReader& esm, bool wide = false); void load (ESMReader& esm, bool wide = false, const std::string& tag = "FRMR");
void save (ESMWriter &esm, bool wide = false, const std::string& tag = "FRMR") const; void save (ESMWriter &esm, bool wide = false, const std::string& tag = "FRMR") const;

Loading…
Cancel
Save