mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 15:59:54 +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 #8132: Actors without hello responses turn to face the player
|
||||||
Bug #8171: Items with more than 100% health can be repaired
|
Bug #8171: Items with more than 100% health can be repaired
|
||||||
Bug #8172: Openmw-cs crashes when viewing `Dantooine, Sea`
|
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 #1415: Infinite fall failsafe
|
||||||
Feature #2566: Handle NAM9 records for manual cell references
|
Feature #2566: Handle NAM9 records for manual cell references
|
||||||
Feature #3501: OpenMW-CS: Instance Editing - Shortcuts for axial locking
|
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 World::getClosestMarkerFromExteriorPosition(const osg::Vec3f& worldPos, const ESM::RefId& id)
|
||||||
{
|
{
|
||||||
MWWorld::ConstPtr closestMarker;
|
const ESM::ExteriorCellLocation posIndex = ESM::positionToExteriorCellLocation(worldPos.x(), worldPos.y());
|
||||||
float closestDistance = std::numeric_limits<float>::max();
|
|
||||||
|
|
||||||
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);
|
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)
|
for (const Ptr& marker : markers)
|
||||||
{
|
{
|
||||||
osg::Vec3f markerPos = marker.getRefData().getPosition().asVec3();
|
const osg::Vec3f markerPos = marker.getRefData().getPosition().asVec3();
|
||||||
float distance = (worldPos - markerPos).length2();
|
const ESM::ExteriorCellLocation index = ESM::positionToExteriorCellLocation(markerPos.x(), markerPos.y());
|
||||||
if (distance < closestDistance)
|
|
||||||
|
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;
|
if (gridSize < minGridSize)
|
||||||
closestMarker = marker;
|
{
|
||||||
|
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;
|
return closestMarker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue