mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 03:59:56 +00:00
Emulate vanilla closest marker preference (#8187)
This commit is contained in:
parent
4ac1b13871
commit
77d2f18f83
2 changed files with 58 additions and 8 deletions
|
@ -193,6 +193,7 @@
|
|||
Bug #8132: Actors without hello responses turn to face the player
|
||||
Bug #8171: Items with more than 100% health can be repaired
|
||||
Bug #8172: Openmw-cs crashes when viewing `Dantooine, Sea`
|
||||
Bug #8187: Intervention effects should use Chebyshev distance to determine the closest marker
|
||||
Feature #1415: Infinite fall failsafe
|
||||
Feature #2566: Handle NAM9 records for manual cell references
|
||||
Feature #3501: OpenMW-CS: Instance Editing - Shortcuts for axial locking
|
||||
|
|
|
@ -3257,22 +3257,71 @@ namespace MWWorld
|
|||
|
||||
MWWorld::ConstPtr World::getClosestMarkerFromExteriorPosition(const osg::Vec3f& worldPos, const ESM::RefId& id)
|
||||
{
|
||||
MWWorld::ConstPtr closestMarker;
|
||||
float closestDistance = std::numeric_limits<float>::max();
|
||||
const ESM::ExteriorCellLocation posIndex = ESM::positionToExteriorCellLocation(worldPos.x(), worldPos.y());
|
||||
|
||||
std::vector<MWWorld::Ptr> markers;
|
||||
// Potential optimization: don't scan the entire world for markers and actually do the Todd spiral
|
||||
std::vector<Ptr> markers;
|
||||
mWorldModel.getExteriorPtrs(id, markers);
|
||||
|
||||
struct MarkerInfo
|
||||
{
|
||||
Ptr mPtr;
|
||||
int mColumn, mRow; // Local coordinates in the valid marker grid
|
||||
};
|
||||
std::vector<MarkerInfo> validMarkers;
|
||||
validMarkers.reserve(markers.size());
|
||||
|
||||
// The idea is to collect all markers that belong to the smallest possible square grid around worldPos
|
||||
// They are grouped with their position on that grid's edge where the origin is the SW corner
|
||||
int minGridSize = std::numeric_limits<int>::max();
|
||||
for (const Ptr& marker : markers)
|
||||
{
|
||||
osg::Vec3f markerPos = marker.getRefData().getPosition().asVec3();
|
||||
float distance = (worldPos - markerPos).length2();
|
||||
if (distance < closestDistance)
|
||||
const osg::Vec3f markerPos = marker.getRefData().getPosition().asVec3();
|
||||
const ESM::ExteriorCellLocation index = ESM::positionToExteriorCellLocation(markerPos.x(), markerPos.y());
|
||||
|
||||
const int deltaX = index.mX - posIndex.mX;
|
||||
const int deltaY = index.mY - posIndex.mY;
|
||||
const int gridSize = std::max(std::abs(deltaX), std::abs(deltaY)) * 2;
|
||||
if (gridSize == 0)
|
||||
return marker;
|
||||
|
||||
if (gridSize <= minGridSize)
|
||||
{
|
||||
closestDistance = distance;
|
||||
closestMarker = marker;
|
||||
if (gridSize < minGridSize)
|
||||
{
|
||||
validMarkers.clear();
|
||||
minGridSize = gridSize;
|
||||
}
|
||||
validMarkers.push_back({ marker, gridSize / 2 + deltaX, gridSize / 2 + deltaY });
|
||||
}
|
||||
}
|
||||
|
||||
ConstPtr closestMarker;
|
||||
if (validMarkers.empty())
|
||||
return closestMarker;
|
||||
if (validMarkers.size() == 1)
|
||||
return validMarkers[0].mPtr;
|
||||
|
||||
// All the markers are on the edge of the grid
|
||||
// Break ties by picking the earliest marker on SW -> SE -> NE -> NW -> SW path
|
||||
int earliestDistance = std::numeric_limits<int>::max();
|
||||
for (const MarkerInfo& marker : validMarkers)
|
||||
{
|
||||
int distance = 0;
|
||||
if (marker.mRow == 0) // South edge (plus SW and SE corners)
|
||||
distance = marker.mColumn;
|
||||
else if (marker.mColumn == minGridSize) // East edge and NE corner
|
||||
distance = minGridSize + marker.mRow;
|
||||
else if (marker.mRow == minGridSize) // North edge and NW corner
|
||||
distance = minGridSize * 3 - marker.mColumn;
|
||||
else // West edge
|
||||
distance = minGridSize * 4 - marker.mRow;
|
||||
if (distance < earliestDistance)
|
||||
{
|
||||
closestMarker = marker.mPtr;
|
||||
earliestDistance = distance;
|
||||
}
|
||||
}
|
||||
return closestMarker;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue