diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index 3a7d48fac..3de803eed 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -15,6 +15,7 @@ #include "cursor.h" #include "doom.h" #include "engine/point.hpp" +#include "engine/points_in_rectangle_range.hpp" #include "gmenu.h" #include "help.h" #include "hwcursor.hpp" @@ -124,61 +125,72 @@ int GetDistanceRanged(Point destination) return Players[MyPlayerId].position.future.ExactDistance(destination); } -/** - * @todo The loops in this function are iterating through tiles offset from the player position. This - * could be accomplished by looping over the values in the Direction enum and making use of - * Point math instead of nested loops from [-1, 1]. - */ void FindItemOrObject() { - int mx = Players[MyPlayerId].position.future.x; - int my = Players[MyPlayerId].position.future.y; + Point futurePosition = Players[MyPlayerId].position.future; int rotations = 5; - // As the player can not stand on the edge of the map this is safe from OOB - for (int xx = -1; xx < 2; xx++) { - for (int yy = -1; yy < 2; yy++) { - if (dItem[mx + xx][my + yy] <= 0) - continue; - int i = dItem[mx + xx][my + yy] - 1; - auto &item = Items[i]; - if (item.isEmpty() - || item._iSelFlag == 0) - continue; - int newRotations = GetRotaryDistance({ mx + xx, my + yy }); - if (rotations < newRotations) - continue; - if (xx != 0 && yy != 0 && GetDistance({ mx + xx, my + yy }, 1) == 0) - continue; - rotations = newRotations; - pcursitem = i; - cursPosition = Point { mx, my } + Displacement { xx, yy }; + auto searchArea = PointsInRectangleRangeColMajor { Rectangle { futurePosition, 1 } }; + + for (Point targetPosition : searchArea) { + // As the player can not stand on the edge of the map this is safe from OOB + int8_t itemId = dItem[targetPosition.x][targetPosition.y] - 1; + if (itemId < 0) { + // there shouldn't be any items that occupy multiple ground tiles, but just in case only considering positive indexes here + + continue; } + auto &item = Items[itemId]; + if (item.isEmpty() || item._iSelFlag == 0) { + continue; + } + + int newRotations = GetRotaryDistance(targetPosition); + if (rotations < newRotations) { + continue; + } + if (targetPosition != futurePosition && GetDistance(targetPosition, 1) == 0) { + // Don't check the tile we're leaving if the player is walking + continue; + } + rotations = newRotations; + pcursitem = itemId; + cursPosition = targetPosition; } - if (leveltype == DTYPE_TOWN || pcursitem != -1) + if (leveltype == DTYPE_TOWN || pcursitem != -1) { return; // Don't look for objects in town + } - for (int xx = -1; xx < 2; xx++) { - for (int yy = -1; yy < 2; yy++) { - if (dObject[mx + xx][my + yy] == 0) - continue; - int o = abs(dObject[mx + xx][my + yy]) - 1; - if (Objects[o]._oSelFlag == 0) - continue; - if (xx == 0 && yy == 0 && Objects[o]._oDoorFlag) - continue; // Ignore doorway so we don't get stuck behind barrels - int newRotations = GetRotaryDistance({ mx + xx, my + yy }); - if (rotations < newRotations) - continue; - if (xx != 0 && yy != 0 && GetDistance({ mx + xx, my + yy }, 1) == 0) - continue; - if (Objects[o].IsDisabled()) - continue; - rotations = newRotations; - pcursobj = o; - cursPosition = Point { mx, my } + Displacement { xx, yy }; + for (Point targetPosition : searchArea) { + int8_t objectId = abs(dObject[targetPosition.x][targetPosition.y]) - 1; + if (objectId < 0) { + continue; + } + + Object &object = Objects[objectId]; + if (object._oSelFlag == 0) { + continue; + } + if (targetPosition == futurePosition && object._oDoorFlag) { + continue; // Ignore doorway so we don't get stuck behind barrels } + + int newRotations = GetRotaryDistance(targetPosition); + if (rotations < newRotations) { + continue; + } + if (targetPosition != futurePosition && GetDistance(targetPosition, 1) == 0) { + // Don't check the tile we're leaving if the player is walking + continue; + } + if (object.IsDisabled()) { + continue; + } + + rotations = newRotations; + pcursobj = objectId; + cursPosition = targetPosition; } }