mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-19 19:53:53 +00:00
Merge pull request #840 from scrawl/movedrefs
Object movement between cells
This commit is contained in:
commit
bdae572264
32 changed files with 638 additions and 332 deletions
|
@ -62,7 +62,7 @@ add_openmw_dir (mwsound
|
|||
|
||||
add_openmw_dir (mwworld
|
||||
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
|
||||
actionequip timestamp actionalchemy cellstore actionapply actioneat
|
||||
store esmstore recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
|
||||
|
|
|
@ -130,6 +130,6 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Activator> *ref =
|
||||
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 =
|
||||
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
|
||||
|
|
|
@ -382,7 +382,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Armor> *ref =
|
||||
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
|
||||
|
|
|
@ -187,7 +187,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Book> *ref =
|
||||
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
|
||||
|
|
|
@ -276,7 +276,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Clothing> *ref =
|
||||
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
|
||||
|
|
|
@ -293,7 +293,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Container> *ref =
|
||||
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
|
||||
|
|
|
@ -600,7 +600,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Creature> *ref =
|
||||
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
|
||||
|
|
|
@ -310,7 +310,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Door> *ref =
|
||||
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
|
||||
|
|
|
@ -185,7 +185,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Ingredient> *ref =
|
||||
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
|
||||
|
|
|
@ -217,7 +217,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Light> *ref =
|
||||
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
|
||||
|
|
|
@ -166,7 +166,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Lockpick> *ref =
|
||||
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
|
||||
|
|
|
@ -215,13 +215,14 @@ namespace MWClass
|
|||
MWWorld::ManualRef newRef(store, base);
|
||||
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
|
||||
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.getRefData().setCount(1);
|
||||
} else {
|
||||
MWWorld::LiveCellRef<ESM::Miscellaneous> *ref =
|
||||
ptr.get<ESM::Miscellaneous>();
|
||||
newPtr = MWWorld::Ptr(&cell.get<ESM::Miscellaneous>().insert(*ref), &cell);
|
||||
newPtr = MWWorld::Ptr(cell.insert(ref), &cell);
|
||||
}
|
||||
return newPtr;
|
||||
}
|
||||
|
|
|
@ -1130,7 +1130,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::NPC> *ref =
|
||||
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
|
||||
|
|
|
@ -178,7 +178,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Potion> *ref =
|
||||
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
|
||||
|
|
|
@ -165,7 +165,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Probe> *ref =
|
||||
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
|
||||
|
|
|
@ -160,7 +160,7 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Repair> *ref =
|
||||
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
|
||||
|
|
|
@ -60,6 +60,6 @@ namespace MWClass
|
|||
MWWorld::LiveCellRef<ESM::Static> *ref =
|
||||
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 =
|
||||
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
|
||||
|
|
|
@ -44,9 +44,9 @@ namespace MWMechanics
|
|||
return MWWorld::Ptr(); // check interior cells only
|
||||
|
||||
// Check all the doors in this cell
|
||||
MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>();
|
||||
MWWorld::CellRefList<ESM::Door>::List& refList = doors.mList;
|
||||
MWWorld::CellRefList<ESM::Door>::List::iterator it = refList.begin();
|
||||
const MWWorld::CellRefList<ESM::Door>& doors = cell->getReadOnlyDoors();
|
||||
const MWWorld::CellRefList<ESM::Door>::List& refList = doors.mList;
|
||||
MWWorld::CellRefList<ESM::Door>::List::const_iterator it = refList.begin();
|
||||
osg::Vec3f pos(actor.getRefData().getPosition().asVec3());
|
||||
|
||||
/// 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::
|
||||
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
|
||||
&& 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
|
||||
|
|
|
@ -300,14 +300,16 @@ namespace MWScript
|
|||
}
|
||||
catch(std::exception&)
|
||||
{
|
||||
// cell not found, move to exterior instead (vanilla PositionCell compatibility)
|
||||
const ESM::Cell* cell = MWBase::Environment::get().getWorld()->getExterior(cellID);
|
||||
int cx,cy;
|
||||
MWBase::Environment::get().getWorld()->positionToIndex(x,y,cx,cy);
|
||||
store = MWBase::Environment::get().getWorld()->getExterior(cx,cy);
|
||||
if(!cell)
|
||||
{
|
||||
runtime.getContext().report ("unknown cell (" + cellID + ")");
|
||||
std::cerr << "unknown cell (" << cellID << ")\n";
|
||||
std::string error = "PositionCell: unknown interior cell (" + cellID + "), moving to exterior instead";
|
||||
runtime.getContext().report (error);
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
if(store)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "cells.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/esmwriter.hpp>
|
||||
#include <components/esm/defs.hpp>
|
||||
|
@ -23,7 +25,7 @@ MWWorld::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
|
|||
|
||||
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;
|
||||
|
@ -36,7 +38,7 @@ MWWorld::CellStore *MWWorld::Cells::getCellStore (const ESM::Cell *cell)
|
|||
if (result==mExteriors.end())
|
||||
{
|
||||
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
|
||||
{
|
||||
if (cell.getState()!=CellStore::State_Loaded)
|
||||
cell.load (mStore, mReader);
|
||||
cell.load ();
|
||||
|
||||
ESM::CellState cellState;
|
||||
|
||||
|
@ -114,13 +116,12 @@ MWWorld::CellStore *MWWorld::Cells::getExterior (int x, int y)
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Multiple plugin support for landscape data is much easier than for references. The last plugin wins.
|
||||
result->second.load (mStore, mReader);
|
||||
result->second.load ();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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)
|
||||
{
|
||||
result->second.load (mStore, mReader);
|
||||
result->second.load ();
|
||||
}
|
||||
|
||||
return &result->second;
|
||||
|
@ -158,13 +159,13 @@ MWWorld::Ptr MWWorld::Cells::getPtr (const std::string& name, CellStore& cell,
|
|||
bool searchInContainers)
|
||||
{
|
||||
if (cell.getState()==CellStore::State_Unloaded)
|
||||
cell.preload (mStore, mReader);
|
||||
cell.preload ();
|
||||
|
||||
if (cell.getState()==CellStore::State_Preloaded)
|
||||
{
|
||||
if (cell.hasId (name))
|
||||
{
|
||||
cell.load (mStore, mReader);
|
||||
cell.load ();
|
||||
}
|
||||
else
|
||||
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,
|
||||
const std::map<int, int>& contentFileMap)
|
||||
{
|
||||
|
@ -321,9 +345,9 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
|
|||
catch (...)
|
||||
{
|
||||
// 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();
|
||||
return true;
|
||||
/// \todo log
|
||||
}
|
||||
|
||||
state.load (reader);
|
||||
|
@ -333,9 +357,11 @@ bool MWWorld::Cells::readRecord (ESM::ESMReader& reader, uint32_t type,
|
|||
cellStore->readFog(reader);
|
||||
|
||||
if (cellStore->getState()!=CellStore::State_Loaded)
|
||||
cellStore->load (mStore, mReader);
|
||||
cellStore->load ();
|
||||
|
||||
cellStore->readReferences (reader, contentFileMap);
|
||||
GetCellStoreCallback callback(*this);
|
||||
|
||||
cellStore->readReferences (reader, contentFileMap, &callback);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -47,13 +47,16 @@ namespace
|
|||
|
||||
template<typename T>
|
||||
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());
|
||||
iter!=actorList.mList.end(); ++iter)
|
||||
{
|
||||
MWWorld::Ptr actor (&*iter, cell);
|
||||
|
||||
if (toIgnore.find(&*iter) != toIgnore.end())
|
||||
continue;
|
||||
|
||||
if (actor.getClass().getCreatureStats (actor).matchesActorId (actorId) && actor.getRefData().getCount() > 0)
|
||||
return actor;
|
||||
}
|
||||
|
@ -141,6 +144,28 @@ namespace
|
|||
ref.load (state);
|
||||
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
|
||||
|
@ -179,8 +204,121 @@ namespace MWWorld
|
|||
return (ref.mRef.mRefnum == pRefnum);
|
||||
}
|
||||
|
||||
CellStore::CellStore (const ESM::Cell *cell)
|
||||
: mCell (cell), mState (State_Unloaded), mHasState (false), mLastRespawn(0,0)
|
||||
void CellStore::moveFrom(const Ptr &object, CellStore *from)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -212,85 +350,50 @@ namespace MWWorld
|
|||
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)
|
||||
{
|
||||
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);
|
||||
SearchVisitor searchVisitor;
|
||||
searchVisitor.mIdToFind = id;
|
||||
forEach(searchVisitor);
|
||||
|
||||
mHasState = oldState;
|
||||
|
||||
return Ptr();
|
||||
return searchVisitor.mFound;
|
||||
}
|
||||
|
||||
Ptr CellStore::searchViaActorId (int id)
|
||||
{
|
||||
if (Ptr ptr = ::searchViaActorId (mNpcs, id, this))
|
||||
if (Ptr ptr = ::searchViaActorId (mNpcs, id, this, mMovedToAnotherCell))
|
||||
return ptr;
|
||||
|
||||
if (Ptr ptr = ::searchViaActorId (mCreatures, id, this))
|
||||
if (Ptr ptr = ::searchViaActorId (mCreatures, id, this, mMovedToAnotherCell))
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -309,37 +412,17 @@ namespace MWWorld
|
|||
|
||||
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();
|
||||
return mMergedRefs.size();
|
||||
}
|
||||
|
||||
void CellStore::load (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm)
|
||||
void CellStore::load ()
|
||||
{
|
||||
if (mState!=State_Loaded)
|
||||
{
|
||||
if (mState==State_Preloaded)
|
||||
mIds.clear();
|
||||
|
||||
loadRefs (store, esm);
|
||||
loadRefs ();
|
||||
|
||||
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)
|
||||
{
|
||||
listRefs (store, esm);
|
||||
listRefs ();
|
||||
|
||||
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);
|
||||
|
||||
if (mCell->mContextList.empty())
|
||||
|
@ -404,8 +489,10 @@ namespace MWWorld
|
|||
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);
|
||||
|
||||
if (mCell->mContextList.empty())
|
||||
|
@ -432,7 +519,7 @@ namespace MWWorld
|
|||
continue;
|
||||
}
|
||||
|
||||
loadRef (ref, deleted, store);
|
||||
loadRef (ref, deleted);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,8 +528,10 @@ namespace MWWorld
|
|||
{
|
||||
ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it);
|
||||
|
||||
loadRef (ref, false, store);
|
||||
loadRef (ref, false);
|
||||
}
|
||||
|
||||
updateMergedRefs();
|
||||
}
|
||||
|
||||
bool CellStore::isExterior() const
|
||||
|
@ -470,10 +559,12 @@ namespace MWWorld
|
|||
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);
|
||||
|
||||
const MWWorld::ESMStore& store = mStore;
|
||||
|
||||
switch (store.find (ref.mRefID))
|
||||
{
|
||||
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, mStatics);
|
||||
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,
|
||||
const std::map<int, int>& contentFileMap)
|
||||
void CellStore::readReferences (ESM::ESMReader& reader, const std::map<int, int>& contentFileMap, GetCellStoreCallback* callback)
|
||||
{
|
||||
mHasState = true;
|
||||
|
||||
|
@ -695,6 +795,48 @@ namespace MWWorld
|
|||
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)
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace ESM
|
|||
{
|
||||
struct CellState;
|
||||
struct FogState;
|
||||
struct CellId;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
|
@ -60,6 +61,9 @@ namespace MWWorld
|
|||
|
||||
private:
|
||||
|
||||
const MWWorld::ESMStore& mStore;
|
||||
std::vector<ESM::ESMReader>& mReader;
|
||||
|
||||
// Even though fog actually belongs to the player and not cells,
|
||||
// it makes sense to store it here since we need it once for each cell.
|
||||
// Note this is NULL until the cell is explored to save some memory
|
||||
|
@ -73,6 +77,7 @@ namespace MWWorld
|
|||
|
||||
MWWorld::TimeStamp mLastRespawn;
|
||||
|
||||
// List of refs owned by this cell
|
||||
CellRefList<ESM::Activator> mActivators;
|
||||
CellRefList<ESM::Potion> mPotions;
|
||||
CellRefList<ESM::Apparatus> mAppas;
|
||||
|
@ -94,9 +99,95 @@ namespace MWWorld
|
|||
CellRefList<ESM::Static> mStatics;
|
||||
CellRefList<ESM::Weapon> mWeapons;
|
||||
|
||||
typedef std::map<LiveCellRefBase*, MWWorld::CellStore*> MovedRefTracker;
|
||||
// References owned by a different cell that have been moved here.
|
||||
// <reference, cell the reference originally came from>
|
||||
MovedRefTracker mMovedHere;
|
||||
// References owned by this cell that have been moved to another cell.
|
||||
// <reference, cell the reference was moved to>
|
||||
MovedRefTracker mMovedToAnotherCell;
|
||||
|
||||
// Merged list of ref's currently in this cell - i.e. with added refs from mMovedHere, removed refs from mMovedToAnotherCell
|
||||
std::vector<LiveCellRefBase*> mMergedRefs;
|
||||
|
||||
/// Moves object from the given cell to this cell.
|
||||
void moveFrom(const MWWorld::Ptr& object, MWWorld::CellStore* from);
|
||||
|
||||
/// Repopulate mMergedRefs.
|
||||
void updateMergedRefs();
|
||||
|
||||
// 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:
|
||||
|
||||
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;
|
||||
|
||||
|
@ -108,6 +199,7 @@ namespace MWWorld
|
|||
bool hasId (const std::string& id) const;
|
||||
///< May return true for deleted IDs when in preload state. Will return false, if cell is
|
||||
/// unloaded.
|
||||
/// @note Will not account for moved references which may exist in Loaded state. Use search() instead if the cell is loaded.
|
||||
|
||||
Ptr search (const std::string& id);
|
||||
///< Will return an empty Ptr if cell is not loaded. Does not check references in
|
||||
|
@ -128,55 +220,82 @@ namespace MWWorld
|
|||
int count() const;
|
||||
///< 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.
|
||||
|
||||
void preload (const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
|
||||
void preload ();
|
||||
///< 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.
|
||||
/// \attention This function also lists deleted (count 0) objects!
|
||||
/// \return Iteration completed?
|
||||
///
|
||||
/// \note Creatures and NPCs are handled last.
|
||||
template<class Functor>
|
||||
bool forEach (Functor& functor)
|
||||
template<class Visitor>
|
||||
bool forEach (Visitor& visitor)
|
||||
{
|
||||
if (mState != State_Loaded)
|
||||
return false;
|
||||
|
||||
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);
|
||||
for (unsigned int i=0; i<mMergedRefs.size(); ++i)
|
||||
{
|
||||
if (mMergedRefs[i]->mData.isDeletedByContentFile())
|
||||
continue;
|
||||
|
||||
if (!visitor(MWWorld::Ptr(mMergedRefs[i], this)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class Functor>
|
||||
bool forEachContainer (Functor& functor)
|
||||
/// Call visitor (ref) for each reference of given type. visitor must return a bool. Returning
|
||||
/// 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;
|
||||
|
||||
return
|
||||
forEachImp (functor, mContainers) &&
|
||||
forEachImp (functor, mCreatures) &&
|
||||
forEachImp (functor, mNpcs);
|
||||
CellRefList<T>& list = get<T>();
|
||||
|
||||
for (typename CellRefList<T>::List::iterator it (list.mList.begin()); it!=list.mList.end(); ++it)
|
||||
{
|
||||
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;
|
||||
|
@ -193,47 +312,31 @@ namespace MWWorld
|
|||
|
||||
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 ();
|
||||
///< 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;
|
||||
|
||||
std::list<ESM::Pathgrid::Point> aStarSearch(const int start, const int end) const;
|
||||
|
||||
private:
|
||||
|
||||
template<class Functor, class List>
|
||||
bool forEachImp (Functor& functor, List& list)
|
||||
{
|
||||
for (typename List::List::iterator iter (list.mList.begin()); iter!=list.mList.end();
|
||||
++iter)
|
||||
{
|
||||
if (iter->mData.isDeletedByContentFile())
|
||||
continue;
|
||||
if (!functor (MWWorld::Ptr(&*iter, this)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Run through references and store IDs
|
||||
void listRefs(const MWWorld::ESMStore &store, std::vector<ESM::ESMReader> &esm);
|
||||
void 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.
|
||||
///
|
||||
/// Invalid \a ref objects are silently dropped.
|
||||
|
@ -381,12 +484,6 @@ namespace MWWorld
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef GAME_MWWORLD_CELLFUNCTORS_H
|
||||
#define GAME_MWWORLD_CELLFUNCTORS_H
|
||||
#ifndef GAME_MWWORLD_CELLVISITORS_H
|
||||
#define GAME_MWWORLD_CELLVISITORS_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
@ -9,7 +9,7 @@
|
|||
|
||||
namespace MWWorld
|
||||
{
|
||||
struct ListAndResetObjects
|
||||
struct ListAndResetObjectsVisitor
|
||||
{
|
||||
std::vector<MWWorld::Ptr> mObjects;
|
||||
|
|
@ -11,46 +11,54 @@
|
|||
|
||||
namespace
|
||||
{
|
||||
template<typename T>
|
||||
void listCellScripts (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 (!iter->mBase->mScript.empty() && !iter->mData.isDeleted())
|
||||
{
|
||||
localScripts.add (iter->mBase->mScript, MWWorld::Ptr (&*iter, cell));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adds scripts for items in containers (containers/npcs/creatures)
|
||||
template<typename T>
|
||||
void listCellScriptsCont (MWWorld::LocalScripts& localScripts,
|
||||
MWWorld::CellRefList<T>& cellRefList, MWWorld::CellStore *cell)
|
||||
struct AddScriptsVisitor
|
||||
{
|
||||
for (typename MWWorld::CellRefList<T>::List::iterator iter (
|
||||
cellRefList.mList.begin());
|
||||
iter!=cellRefList.mList.end(); ++iter)
|
||||
AddScriptsVisitor(MWWorld::LocalScripts& scripts)
|
||||
: mScripts(scripts)
|
||||
{
|
||||
}
|
||||
MWWorld::LocalScripts& mScripts;
|
||||
|
||||
MWWorld::Ptr containerPtr (&*iter, cell);
|
||||
bool operator()(const MWWorld::Ptr& ptr)
|
||||
{
|
||||
if (ptr.getRefData().isDeleted())
|
||||
return true;
|
||||
|
||||
std::string script = ptr.getClass().getScript(ptr);
|
||||
|
||||
if (!script.empty())
|
||||
mScripts.add(script, ptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct AddContainerItemScriptsVisitor
|
||||
{
|
||||
AddContainerItemScriptsVisitor(MWWorld::LocalScripts& scripts)
|
||||
: mScripts(scripts)
|
||||
{
|
||||
}
|
||||
MWWorld::LocalScripts& mScripts;
|
||||
|
||||
bool operator()(const MWWorld::Ptr& 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 != "")
|
||||
{
|
||||
MWWorld::Ptr item = *it3;
|
||||
item.mCell = cell;
|
||||
localScripts.add (script, item);
|
||||
}
|
||||
MWWorld::Ptr item = *it;
|
||||
item.mCell = containerPtr.getCell();
|
||||
mScripts.add (script, item);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
listCellScripts (*this, cell->get<ESM::Activator>(), cell);
|
||||
listCellScripts (*this, cell->get<ESM::Potion>(), cell);
|
||||
listCellScripts (*this, cell->get<ESM::Apparatus>(), cell);
|
||||
listCellScripts (*this, cell->get<ESM::Armor>(), cell);
|
||||
listCellScripts (*this, cell->get<ESM::Book>(), cell);
|
||||
listCellScripts (*this, cell->get<ESM::Clothing>(), cell);
|
||||
listCellScripts (*this, cell->get<ESM::Container>(), cell);
|
||||
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);
|
||||
AddScriptsVisitor addScriptsVisitor(*this);
|
||||
cell->forEach(addScriptsVisitor);
|
||||
|
||||
AddContainerItemScriptsVisitor addContainerItemScriptsVisitor(*this);
|
||||
cell->forEachType<ESM::NPC>(addContainerItemScriptsVisitor);
|
||||
cell->forEachType<ESM::Creature>(addContainerItemScriptsVisitor);
|
||||
cell->forEachType<ESM::Container>(addContainerItemScriptsVisitor);
|
||||
}
|
||||
|
||||
void MWWorld::LocalScripts::clear()
|
||||
|
|
|
@ -182,7 +182,7 @@ namespace MWWorld
|
|||
mPosition = pos;
|
||||
}
|
||||
|
||||
const ESM::Position& RefData::getPosition()
|
||||
const ESM::Position& RefData::getPosition() const
|
||||
{
|
||||
return mPosition;
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace MWWorld
|
|||
void disable();
|
||||
|
||||
void setPosition (const ESM::Position& pos);
|
||||
const ESM::Position& getPosition();
|
||||
const ESM::Position& getPosition() const;
|
||||
|
||||
void setCustomData (CustomData *data);
|
||||
///< Set custom data (potentially replacing old custom data). The ownership of \a data is
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "localscripts.hpp"
|
||||
#include "esmstore.hpp"
|
||||
#include "class.hpp"
|
||||
#include "cellfunctors.hpp"
|
||||
#include "cellvisitors.hpp"
|
||||
#include "cellstore.hpp"
|
||||
|
||||
namespace
|
||||
|
@ -78,7 +78,7 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
struct InsertFunctor
|
||||
struct InsertVisitor
|
||||
{
|
||||
MWWorld::CellStore& mCell;
|
||||
bool mRescale;
|
||||
|
@ -86,13 +86,13 @@ namespace
|
|||
MWPhysics::PhysicsSystem& mPhysics;
|
||||
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);
|
||||
|
||||
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,
|
||||
MWRender::RenderingManager& rendering)
|
||||
: mCell (cell), mRescale (rescale), mLoadingListener (loadingListener),
|
||||
|
@ -100,7 +100,7 @@ namespace
|
|||
mRendering (rendering)
|
||||
{}
|
||||
|
||||
bool InsertFunctor::operator() (const MWWorld::Ptr& ptr)
|
||||
bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
|
||||
{
|
||||
if (mRescale)
|
||||
{
|
||||
|
@ -116,7 +116,6 @@ namespace
|
|||
{
|
||||
addObject(ptr, mPhysics, mRendering);
|
||||
updateObjectRotation(ptr, mPhysics, mRendering, false);
|
||||
ptr.getClass().adjustPosition (ptr, false);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
@ -129,6 +128,17 @@ namespace
|
|||
|
||||
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)
|
||||
{
|
||||
std::cout << "Unloading cell\n";
|
||||
ListAndResetObjects functor;
|
||||
ListAndResetObjectsVisitor visitor;
|
||||
|
||||
(*iter)->forEach<ListAndResetObjects>(functor);
|
||||
for (std::vector<MWWorld::Ptr>::const_iterator iter2 (functor.mObjects.begin());
|
||||
iter2!=functor.mObjects.end(); ++iter2)
|
||||
(*iter)->forEach<ListAndResetObjectsVisitor>(visitor);
|
||||
for (std::vector<MWWorld::Ptr>::const_iterator iter2 (visitor.mObjects.begin());
|
||||
iter2!=visitor.mObjects.end(); ++iter2)
|
||||
{
|
||||
mPhysics->remove(*iter2);
|
||||
}
|
||||
|
@ -551,8 +561,12 @@ namespace MWWorld
|
|||
|
||||
void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener)
|
||||
{
|
||||
InsertFunctor functor (cell, rescale, *loadingListener, *mPhysics, mRendering);
|
||||
cell.forEach (functor);
|
||||
InsertVisitor insertVisitor (cell, rescale, *loadingListener, *mPhysics, mRendering);
|
||||
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)
|
||||
|
|
|
@ -54,7 +54,6 @@
|
|||
#include "player.hpp"
|
||||
#include "manualref.hpp"
|
||||
#include "cellstore.hpp"
|
||||
#include "cellfunctors.hpp"
|
||||
#include "containerstore.hpp"
|
||||
#include "inventorystore.hpp"
|
||||
#include "actionteleport.hpp"
|
||||
|
@ -690,12 +689,12 @@ namespace MWWorld
|
|||
return mWorldScene->searchPtrViaActorId (actorId);
|
||||
}
|
||||
|
||||
struct FindContainerFunctor
|
||||
struct FindContainerVisitor
|
||||
{
|
||||
Ptr mContainedPtr;
|
||||
Ptr mResult;
|
||||
|
||||
FindContainerFunctor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {}
|
||||
FindContainerVisitor(const Ptr& containedPtr) : mContainedPtr(containedPtr) {}
|
||||
|
||||
bool operator() (Ptr ptr)
|
||||
{
|
||||
|
@ -721,11 +720,15 @@ namespace MWWorld
|
|||
const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells();
|
||||
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
|
||||
{
|
||||
FindContainerFunctor functor(ptr);
|
||||
(*cellIt)->forEachContainer(functor);
|
||||
FindContainerVisitor visitor(ptr);
|
||||
(*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())
|
||||
return functor.mResult;
|
||||
if (!visitor.mResult.isEmpty())
|
||||
return visitor.mResult;
|
||||
}
|
||||
|
||||
return Ptr();
|
||||
|
@ -1149,7 +1152,7 @@ namespace MWWorld
|
|||
bool newCellActive = mWorldScene->isCellActive(*newCell);
|
||||
if (!currCellActive && newCellActive)
|
||||
{
|
||||
newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos);
|
||||
newPtr = currCell->moveTo(ptr, newCell);
|
||||
mWorldScene->addObjectToScene(newPtr);
|
||||
|
||||
std::string script = newPtr.getClass().getScript(newPtr);
|
||||
|
@ -1165,17 +1168,16 @@ namespace MWWorld
|
|||
removeContainerScripts (ptr);
|
||||
haveToMove = false;
|
||||
|
||||
newPtr = ptr.getClass().copyToCell(ptr, *newCell);
|
||||
newPtr = currCell->moveTo(ptr, newCell);
|
||||
newPtr.getRefData().setBaseNode(0);
|
||||
}
|
||||
else if (!currCellActive && !newCellActive)
|
||||
newPtr = ptr.getClass().copyToCell(ptr, *newCell);
|
||||
newPtr = currCell->moveTo(ptr, newCell);
|
||||
else // both cells active
|
||||
{
|
||||
newPtr = ptr.getClass().copyToCell(ptr, *newCell, pos);
|
||||
newPtr = currCell->moveTo(ptr, newCell);
|
||||
|
||||
mRendering->updatePtr(ptr, newPtr);
|
||||
ptr.getRefData().setBaseNode(NULL);
|
||||
MWBase::Environment::get().getSoundManager()->updatePtr (ptr, newPtr);
|
||||
mPhysics->updatePtr(ptr, newPtr);
|
||||
|
||||
|
@ -1192,7 +1194,6 @@ namespace MWWorld
|
|||
addContainerScripts (newPtr, newCell);
|
||||
}
|
||||
}
|
||||
ptr.getRefData().setCount(0);
|
||||
}
|
||||
}
|
||||
if (haveToMove && newPtr.getRefData().getBaseNode())
|
||||
|
@ -1708,27 +1709,32 @@ namespace MWWorld
|
|||
|
||||
osg::Vec2f World::getNorthVector (CellStore* cell)
|
||||
{
|
||||
MWWorld::CellRefList<ESM::Static>& statics = cell->get<ESM::Static>();
|
||||
MWWorld::LiveCellRef<ESM::Static>* ref = statics.find("northmarker");
|
||||
if (!ref)
|
||||
MWWorld::Ptr northmarker = cell->search("northmarker");
|
||||
|
||||
if (northmarker.isEmpty())
|
||||
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::Vec2f d (dir.x(), dir.y());
|
||||
return d;
|
||||
}
|
||||
|
||||
void World::getDoorMarkers (CellStore* cell, std::vector<World::DoorMarker>& out)
|
||||
struct GetDoorMarkerVisitor
|
||||
{
|
||||
MWWorld::CellRefList<ESM::Door>& doors = cell->get<ESM::Door>();
|
||||
CellRefList<ESM::Door>::List& refList = doors.mList;
|
||||
for (CellRefList<ESM::Door>::List::iterator it = refList.begin(); it != refList.end(); ++it)
|
||||
GetDoorMarkerVisitor(std::vector<World::DoorMarker>& out)
|
||||
: mOut(out)
|
||||
{
|
||||
MWWorld::LiveCellRef<ESM::Door>& ref = *it;
|
||||
}
|
||||
|
||||
if (!ref.mData.isEnabled())
|
||||
continue;
|
||||
std::vector<World::DoorMarker>& mOut;
|
||||
|
||||
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())
|
||||
{
|
||||
|
@ -1744,7 +1750,7 @@ namespace MWWorld
|
|||
else
|
||||
{
|
||||
cellid.mPaged = true;
|
||||
positionToIndex(
|
||||
MWBase::Environment::get().getWorld()->positionToIndex(
|
||||
ref.mRef.getDoorDest().pos[0],
|
||||
ref.mRef.getDoorDest().pos[1],
|
||||
cellid.mIndex.mX,
|
||||
|
@ -1756,9 +1762,16 @@ namespace MWWorld
|
|||
|
||||
newMarker.x = pos.pos[0];
|
||||
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)
|
||||
|
@ -2253,25 +2266,40 @@ namespace MWWorld
|
|||
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();
|
||||
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
|
||||
{
|
||||
MWWorld::CellRefList<ESM::Container>& containers = (*cellIt)->get<ESM::Container>();
|
||||
CellRefList<ESM::Container>::List& refList = containers.mList;
|
||||
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);
|
||||
}
|
||||
GetContainersOwnedByVisitor visitor (owner, out);
|
||||
(*cellIt)->forEachType<ESM::Container>(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
struct ListObjectsFunctor
|
||||
struct ListObjectsVisitor
|
||||
{
|
||||
std::vector<MWWorld::Ptr> mObjects;
|
||||
|
||||
|
@ -2288,10 +2316,10 @@ namespace MWWorld
|
|||
const Scene::CellStoreCollection& collection = mWorldScene->getActiveCells();
|
||||
for (Scene::CellStoreCollection::const_iterator cellIt = collection.begin(); cellIt != collection.end(); ++cellIt)
|
||||
{
|
||||
ListObjectsFunctor functor;
|
||||
(*cellIt)->forEach<ListObjectsFunctor>(functor);
|
||||
ListObjectsVisitor visitor;
|
||||
(*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()))
|
||||
out.push_back(*it);
|
||||
}
|
||||
|
@ -2342,7 +2370,8 @@ namespace MWWorld
|
|||
if (0 == cellStore) {
|
||||
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) {
|
||||
if (!it->mRef.getTeleport()) {
|
||||
continue;
|
||||
|
@ -2364,7 +2393,7 @@ namespace MWWorld
|
|||
if (0 != source) {
|
||||
// Find door leading to our current teleport door
|
||||
// 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) {
|
||||
if (it->mRef.getTeleport() &&
|
||||
Misc::StringUtils::ciEqual(name, jt->mRef.getDestCell()))
|
||||
|
@ -2378,7 +2407,7 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
// 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() ) {
|
||||
pos = statics.begin()->mRef.getPosition();
|
||||
return true;
|
||||
|
@ -2747,7 +2776,7 @@ namespace MWWorld
|
|||
MWWorld::CellStore *next = getInterior( *i );
|
||||
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;
|
||||
|
||||
// Check if any door in the cell leads to an exterior directly
|
||||
|
@ -2807,7 +2836,7 @@ namespace MWWorld
|
|||
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;
|
||||
|
||||
// Check if any door in the cell leads to an exterior directly
|
||||
|
@ -2831,7 +2860,6 @@ namespace MWWorld
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MWWorld::Ptr();
|
||||
}
|
||||
|
||||
|
@ -2888,9 +2916,9 @@ namespace MWWorld
|
|||
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)
|
||||
{
|
||||
}
|
||||
|
@ -2899,7 +2927,7 @@ namespace MWWorld
|
|||
Ptr mDetector;
|
||||
float mSquaredDist;
|
||||
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)
|
||||
return true;
|
||||
|
@ -2930,7 +2958,7 @@ namespace MWWorld
|
|||
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)
|
||||
{
|
||||
|
@ -2970,13 +2998,13 @@ namespace MWWorld
|
|||
|
||||
dist = feetToGameUnits(dist);
|
||||
|
||||
AddDetectedReference functor (out, ptr, type, dist*dist);
|
||||
AddDetectedReferenceVisitor visitor (out, ptr, type, dist*dist);
|
||||
|
||||
const Scene::CellStoreCollection& active = mWorldScene->getActiveCells();
|
||||
for (Scene::CellStoreCollection::const_iterator it = active.begin(); it != active.end(); ++it)
|
||||
{
|
||||
MWWorld::CellStore* cellStore = *it;
|
||||
cellStore->forEach(functor);
|
||||
cellStore->forEach(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3232,7 +3260,7 @@ namespace MWWorld
|
|||
interpreterContext.executeActivation(object, actor);
|
||||
}
|
||||
|
||||
struct ResetActorsFunctor
|
||||
struct ResetActorsVisitor
|
||||
{
|
||||
bool operator() (Ptr ptr)
|
||||
{
|
||||
|
@ -3254,8 +3282,8 @@ namespace MWWorld
|
|||
iter!=mWorldScene->getActiveCells().end(); ++iter)
|
||||
{
|
||||
CellStore* cellstore = *iter;
|
||||
ResetActorsFunctor functor;
|
||||
cellstore->forEach(functor);
|
||||
ResetActorsVisitor visitor;
|
||||
cellstore->forEach(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
#include "esmreader.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)
|
||||
esm.getHNT (*this, "FRMR", 8);
|
||||
esm.getHNT (*this, tag.c_str(), 8);
|
||||
else
|
||||
esm.getHNT (mIndex, "FRMR");
|
||||
esm.getHNT (mIndex, tag.c_str());
|
||||
}
|
||||
|
||||
void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace ESM
|
|||
unsigned int mIndex;
|
||||
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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue