|
|
|
@ -2830,33 +2830,99 @@ namespace MWWorld
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void World::teleportToClosestMarker (const MWWorld::Ptr& ptr,
|
|
|
|
|
const std::string& id)
|
|
|
|
|
MWWorld::Ptr World::getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id )
|
|
|
|
|
{
|
|
|
|
|
Ogre::Vector3 worldPos;
|
|
|
|
|
if (!findInteriorPositionInWorldSpace(ptr.getCell(), worldPos))
|
|
|
|
|
worldPos = mPlayer->getLastKnownExteriorPosition();
|
|
|
|
|
// Search for a 'nearest' marker, counting each cell between the starting
|
|
|
|
|
// cell and the exterior as a distance of 1. If an exterior is found, jump
|
|
|
|
|
// to the nearest exterior marker, without further interior searching.
|
|
|
|
|
std::set< std::string >checkedCells;
|
|
|
|
|
std::set< std::string >currentCells;
|
|
|
|
|
std::set< std::string >nextCells;
|
|
|
|
|
nextCells.insert( ptr.getCell()->getCell()->mName );
|
|
|
|
|
while ( !nextCells.empty() ) {
|
|
|
|
|
currentCells = nextCells;
|
|
|
|
|
nextCells.clear();
|
|
|
|
|
for( std::set< std::string >::const_iterator i = currentCells.begin(); i != currentCells.end(); ++i ) {
|
|
|
|
|
MWWorld::CellStore *next = getInterior( *i );
|
|
|
|
|
checkedCells.insert( *i );
|
|
|
|
|
if ( !next ) continue;
|
|
|
|
|
|
|
|
|
|
MWWorld::Ptr closestMarker;
|
|
|
|
|
float closestDistance = FLT_MAX;
|
|
|
|
|
MWWorld::CellRefList<ESM::Static>& statics = next->get<ESM::Static>();
|
|
|
|
|
CellRefList<ESM::Static>::List& staticList = statics.mList;
|
|
|
|
|
for (CellRefList<ESM::Static>::List::iterator it = staticList.begin(); it != staticList.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
MWWorld::LiveCellRef<ESM::Static>& ref = *it;
|
|
|
|
|
if ( id == ref.mRef.getRefId() ) {
|
|
|
|
|
return MWWorld::Ptr( &ref, next );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::vector<MWWorld::Ptr> markers;
|
|
|
|
|
mCells.getExteriorPtrs(id, markers);
|
|
|
|
|
MWWorld::CellRefList<ESM::Door>& doors = next->get<ESM::Door>();
|
|
|
|
|
CellRefList<ESM::Door>::List& doorList = doors.mList;
|
|
|
|
|
|
|
|
|
|
for (std::vector<MWWorld::Ptr>::iterator it = markers.begin(); it != markers.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
ESM::Position pos = it->getRefData().getPosition();
|
|
|
|
|
Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos);
|
|
|
|
|
float distance = worldPos.squaredDistance(markerPos);
|
|
|
|
|
if (distance < closestDistance)
|
|
|
|
|
{
|
|
|
|
|
closestDistance = distance;
|
|
|
|
|
closestMarker = *it;
|
|
|
|
|
// Check if any door in the cell leads to an exterior directly
|
|
|
|
|
for (CellRefList<ESM::Door>::List::iterator it = doorList.begin(); it != doorList.end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
MWWorld::LiveCellRef<ESM::Door>& ref = *it;
|
|
|
|
|
|
|
|
|
|
if ( id == ref.mRef.getRefId() ) {
|
|
|
|
|
return MWWorld::Ptr( &ref, next );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ref.mRef.getTeleport()) continue;
|
|
|
|
|
|
|
|
|
|
if (ref.mRef.getDestCell().empty())
|
|
|
|
|
{
|
|
|
|
|
Ogre::Vector3 worldPos = Ogre::Vector3(ref.mRef.getDoorDest().pos);
|
|
|
|
|
float closestDistance = FLT_MAX;
|
|
|
|
|
|
|
|
|
|
MWWorld::Ptr closestMarker;
|
|
|
|
|
std::vector<MWWorld::Ptr> markers;
|
|
|
|
|
mCells.getExteriorPtrs(id, markers);
|
|
|
|
|
for (std::vector<MWWorld::Ptr>::iterator it2 = markers.begin(); it2 != markers.end(); ++it2)
|
|
|
|
|
{
|
|
|
|
|
ESM::Position pos = it2->getRefData().getPosition();
|
|
|
|
|
Ogre::Vector3 markerPos = Ogre::Vector3(pos.pos);
|
|
|
|
|
float distance = worldPos.squaredDistance(markerPos);
|
|
|
|
|
if (distance < closestDistance)
|
|
|
|
|
{
|
|
|
|
|
closestDistance = distance;
|
|
|
|
|
closestMarker = *it2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return closestMarker;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::string dest = ref.mRef.getDestCell();
|
|
|
|
|
if ( !checkedCells.count(dest) && !currentCells.count(dest) )
|
|
|
|
|
nextCells.insert(dest);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return MWWorld::Ptr();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void World::teleportToClosestMarker (const MWWorld::Ptr& ptr,
|
|
|
|
|
const std::string& id)
|
|
|
|
|
{
|
|
|
|
|
MWWorld::Ptr closestMarker = getClosestMarker( ptr, id );
|
|
|
|
|
|
|
|
|
|
if ( closestMarker.isEmpty() )
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "Failed to teleport: no closest marker found" << std::endl;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MWWorld::ActionTeleport action("", closestMarker.getRefData().getPosition());
|
|
|
|
|
std::string cellName;
|
|
|
|
|
if ( !closestMarker.mCell->isExterior() )
|
|
|
|
|
cellName = closestMarker.mCell->getCell()->mName;
|
|
|
|
|
|
|
|
|
|
MWWorld::ActionTeleport action(cellName, closestMarker.getRefData().getPosition());
|
|
|
|
|
action.execute(ptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|