diff --git a/Source/diablo.cpp b/Source/diablo.cpp index 16deb0c75..a21c1d710 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -5,6 +5,7 @@ */ #include #include +#include #include #include #include @@ -2260,25 +2261,24 @@ void CycleTrackerTargetKeyPressed() std::optional FindNearestGroundItemId(Point playerPosition) { - if (ActiveItemCount == 0) - return std::nullopt; - std::optional bestId; int bestDistance = 0; - for (uint8_t i = 0; i < ActiveItemCount; i++) { - const int itemId = ActiveItems[i]; - if (itemId < 0 || itemId > MAXITEMS) - continue; + for (int y = 0; y < MAXDUNY; ++y) { + for (int x = 0; x < MAXDUNX; ++x) { + const int itemId = std::abs(dItem[x][y]) - 1; + if (itemId < 0 || itemId > MAXITEMS) + continue; - const Item &item = Items[itemId]; - if (item._iClass == ICLASS_NONE) - continue; + const Item &item = Items[itemId]; + if (item.isEmpty() || item._iClass == ICLASS_NONE) + continue; - const int distance = playerPosition.WalkingDistance(item.position); - if (!bestId || distance < bestDistance) { - bestId = itemId; - bestDistance = distance; + const int distance = playerPosition.WalkingDistance(Point { x, y }); + if (!bestId || distance < bestDistance) { + bestId = itemId; + bestDistance = distance; + } } } @@ -2303,24 +2303,36 @@ struct TrackerCandidate { std::vector result; result.reserve(ActiveItemCount); - for (uint8_t i = 0; i < ActiveItemCount; i++) { - const int itemId = ActiveItems[i]; - if (itemId < 0 || itemId > MAXITEMS) - continue; + const int minX = std::max(0, playerPosition.x - maxDistance); + const int minY = std::max(0, playerPosition.y - maxDistance); + const int maxX = std::min(MAXDUNX - 1, playerPosition.x + maxDistance); + const int maxY = std::min(MAXDUNY - 1, playerPosition.y + maxDistance); - const Item &item = Items[itemId]; - if (item._iClass == ICLASS_NONE) - continue; + std::array seen {}; - const int distance = playerPosition.WalkingDistance(item.position); - if (distance > maxDistance) - continue; + for (int y = minY; y <= maxY; ++y) { + for (int x = minX; x <= maxX; ++x) { + const int itemId = std::abs(dItem[x][y]) - 1; + if (itemId < 0 || itemId > MAXITEMS) + continue; + if (seen[itemId]) + continue; + seen[itemId] = true; - result.push_back(TrackerCandidate { - .id = itemId, - .distance = distance, - .name = item.getName(), - }); + const Item &item = Items[itemId]; + if (item.isEmpty() || item._iClass == ICLASS_NONE) + continue; + + const int distance = playerPosition.WalkingDistance(Point { x, y }); + if (distance > maxDistance) + continue; + + result.push_back(TrackerCandidate { + .id = itemId, + .distance = distance, + .name = item.getName(), + }); + } } std::sort(result.begin(), result.end(), [](const TrackerCandidate &a, const TrackerCandidate &b) { return IsBetterTrackerCandidate(a, b); }); @@ -2361,29 +2373,41 @@ struct TrackerCandidate { std::vector result; result.reserve(ActiveMonsterCount); - for (size_t i = 0; i < ActiveMonsterCount; i++) { - const int monsterId = static_cast(ActiveMonsters[i]); - if (monsterId < 0 || monsterId >= static_cast(MaxMonsters)) - continue; + const int minX = std::max(0, playerPosition.x - maxDistance); + const int minY = std::max(0, playerPosition.y - maxDistance); + const int maxX = std::min(MAXDUNX - 1, playerPosition.x + maxDistance); + const int maxY = std::min(MAXDUNY - 1, playerPosition.y + maxDistance); - const Monster &monster = Monsters[monsterId]; - if (monster.isInvalid) - continue; - if ((monster.flags & MFLAG_HIDDEN) != 0) - continue; - if (monster.hitPoints <= 0) - continue; + std::array seen {}; - const Point monsterPosition { monster.position.tile }; - const int distance = playerPosition.WalkingDistance(monsterPosition); - if (distance > maxDistance) - continue; + for (int y = minY; y <= maxY; ++y) { + for (int x = minX; x <= maxX; ++x) { + const int monsterId = std::abs(dMonster[x][y]) - 1; + if (monsterId < 0 || monsterId >= static_cast(MaxMonsters)) + continue; + if (seen[monsterId]) + continue; + seen[monsterId] = true; - result.push_back(TrackerCandidate { - .id = monsterId, - .distance = distance, - .name = monster.name(), - }); + const Monster &monster = Monsters[monsterId]; + if (monster.isInvalid) + continue; + if ((monster.flags & MFLAG_HIDDEN) != 0) + continue; + if (monster.hitPoints <= 0) + continue; + + const Point monsterPosition { monster.position.tile }; + const int distance = playerPosition.WalkingDistance(monsterPosition); + if (distance > maxDistance) + continue; + + result.push_back(TrackerCandidate { + .id = monsterId, + .distance = distance, + .name = monster.name(), + }); + } } std::sort(result.begin(), result.end(), [](const TrackerCandidate &a, const TrackerCandidate &b) { return IsBetterTrackerCandidate(a, b); }); @@ -2486,30 +2510,34 @@ std::optional FindNearestUnopenedChestObjectId(Point playerPosition) std::optional FindNearestMonsterId(Point playerPosition) { - if (ActiveMonsterCount == 0) - return std::nullopt; - std::optional bestId; int bestDistance = 0; - for (size_t i = 0; i < ActiveMonsterCount; i++) { - const int monsterId = static_cast(ActiveMonsters[i]); - if (monsterId < 0 || monsterId >= static_cast(MaxMonsters)) - continue; + std::array seen {}; - const Monster &monster = Monsters[monsterId]; - if (monster.isInvalid) - continue; - if ((monster.flags & MFLAG_HIDDEN) != 0) - continue; - if (monster.hitPoints <= 0) - continue; + for (int y = 0; y < MAXDUNY; ++y) { + for (int x = 0; x < MAXDUNX; ++x) { + const int monsterId = std::abs(dMonster[x][y]) - 1; + if (monsterId < 0 || monsterId >= static_cast(MaxMonsters)) + continue; + if (seen[monsterId]) + continue; + seen[monsterId] = true; - const Point monsterPosition { monster.position.tile }; - const int distance = playerPosition.WalkingDistance(monsterPosition); - if (!bestId || distance < bestDistance) { - bestId = monsterId; - bestDistance = distance; + const Monster &monster = Monsters[monsterId]; + if (monster.isInvalid) + continue; + if ((monster.flags & MFLAG_HIDDEN) != 0) + continue; + if (monster.hitPoints <= 0) + continue; + + const Point monsterPosition { monster.position.tile }; + const int distance = playerPosition.WalkingDistance(monsterPosition); + if (!bestId || distance < bestDistance) { + bestId = monsterId; + bestDistance = distance; + } } }