From 1d18d3ff4cb5a6f28b7f0d7ca03f076a5794a447 Mon Sep 17 00:00:00 2001 From: Jordan Ayers Date: Thu, 12 Feb 2015 22:27:47 -0600 Subject: [PATCH] Add a full search to findInteriorPositionInWorldSpace. Part of OMW Bug #1533 Implement a search for one of the 'nearest' exterior cells. In this case, 'nearest' means the fewest number of cells away via door markers. This causes the world map position to update immediately after teleporting, unless the new cell has no connecting path to an exterior. Intervention spells and Jail travel will be much closer to vanialla Morrowind, except for in Mournhold. --- apps/openmw/mwworld/worldimp.cpp | 49 +++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 188f3cdad..23cef1596 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2784,18 +2784,45 @@ namespace MWWorld { if (cell->isExterior()) return false; - MWWorld::CellRefList& doors = cell->get(); - CellRefList::List& refList = doors.mList; - // Check if any door in the cell leads to an exterior directly - for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) - { - MWWorld::LiveCellRef& ref = *it; - if (ref.mRef.getTeleport() && ref.mRef.getDestCell().empty()) - { - ESM::Position pos = ref.mRef.getDoorDest(); - result = Ogre::Vector3(pos.pos); - return true; + // Search for a 'nearest' exterior, counting each cell between the starting + // cell and the exterior as a distance of 1. Will fail for isolated interiors. + std::set< std::string >checkedCells; + std::set< std::string >currentCells; + std::set< std::string >nextCells; + nextCells.insert( cell->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 ); + if ( !next ) continue; + + MWWorld::CellRefList& doors = next->get(); + CellRefList::List& refList = doors.mList; + + // Check if any door in the cell leads to an exterior directly + for (CellRefList::List::iterator it = refList.begin(); it != refList.end(); ++it) + { + MWWorld::LiveCellRef& ref = *it; + if (!ref.mRef.getTeleport()) continue; + + if (ref.mRef.getDestCell().empty()) + { + ESM::Position pos = ref.mRef.getDoorDest(); + result = Ogre::Vector3(pos.pos); + return true; + } + else + { + std::string dest = ref.mRef.getDestCell(); + if ( !checkedCells.count(dest) && !currentCells.count(dest) ) + nextCells.insert(dest); + } + } + + checkedCells.insert( *i ); } }