|
|
|
|
@ -8,6 +8,7 @@
|
|
|
|
|
#include <array> |
|
|
|
|
|
|
|
|
|
#include "levels/gendung.h" |
|
|
|
|
#include "lighting.h" |
|
|
|
|
#include "objects.h" |
|
|
|
|
|
|
|
|
|
namespace devilution { |
|
|
|
|
@ -435,139 +436,12 @@ bool path_solid_pieces(Point startPosition, Point destinationPosition)
|
|
|
|
|
|
|
|
|
|
std::optional<Point> FindClosestValidPosition(const std::function<bool(Point)> &posOk, Point startingPosition, unsigned int minimumRadius, unsigned int maximumRadius) |
|
|
|
|
{ |
|
|
|
|
if (minimumRadius > maximumRadius) { |
|
|
|
|
return {}; // No valid search space with the given params.
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (minimumRadius == 0U) { |
|
|
|
|
if (posOk(startingPosition)) { |
|
|
|
|
return startingPosition; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (minimumRadius <= 1U && maximumRadius >= 1U) { |
|
|
|
|
// unrolling the case for radius 1 to save having to guard the corner check in the loop below.
|
|
|
|
|
|
|
|
|
|
Point candidatePosition = startingPosition + Direction::SouthWest; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
candidatePosition = startingPosition + Direction::NorthEast; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Direction::NorthWest; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Direction::SouthEast; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return Crawl(minimumRadius, maximumRadius, [&](auto displacement) -> std::optional<Point> { |
|
|
|
|
Point candidatePosition = startingPosition + displacement; |
|
|
|
|
if (posOk(candidatePosition)) |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (maximumRadius >= 2U) { |
|
|
|
|
for (int i = static_cast<int>(std::max(minimumRadius, 2U)); i <= static_cast<int>(std::min(maximumRadius, 50U)); i++) { |
|
|
|
|
int x = 0; |
|
|
|
|
int y = i; |
|
|
|
|
|
|
|
|
|
// special case the checks when x == 0 to save checking the same tiles twice
|
|
|
|
|
Point candidatePosition = startingPosition + Displacement { x, y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
candidatePosition = startingPosition + Displacement { x, -y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while (x < i - 1) { |
|
|
|
|
x++; |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Displacement { -x, y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Displacement { x, y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Displacement { -x, -y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Displacement { x, -y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// special case for inset corners
|
|
|
|
|
y--; |
|
|
|
|
candidatePosition = startingPosition + Displacement { -x, y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Displacement { x, y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Displacement { -x, -y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Displacement { x, -y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
x++; |
|
|
|
|
|
|
|
|
|
while (y > 0) { |
|
|
|
|
candidatePosition = startingPosition + Displacement { -x, y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Displacement { x, y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Displacement { -x, -y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Displacement { x, -y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
y--; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// as above, special case for y == 0
|
|
|
|
|
candidatePosition = startingPosition + Displacement { -x, y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
candidatePosition = startingPosition + Displacement { x, y }; |
|
|
|
|
if (posOk(candidatePosition)) { |
|
|
|
|
return candidatePosition; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return {}; |
|
|
|
|
return {}; |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#ifdef BUILD_TESTING |
|
|
|
|
|