Merge branch 'thewickedmarkerofthewest' into 'master'

Emulate vanilla closest marker preference (#8187)

Closes #8187

See merge request OpenMW/openmw!4401
pull/3236/head
psi29a 2 months ago
commit 34e32b7392

@ -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…
Cancel
Save