diff --git a/.gitignore b/.gitignore index e2eab6ac8..5162797f4 100644 --- a/.gitignore +++ b/.gitignore @@ -262,6 +262,8 @@ _pkginfo.txt *.[Cc]ache # but keep track of directories ending in .cache !*.[Cc]ache/ +# except for a top-level .cache directory (clangd uses /.cache/clangd for temporary files) +/.cache/ # Others ClientBin/ @@ -435,7 +437,7 @@ DerivedData/ # End of https://www.gitignore.io/api/xcode -# Don't accidently commit the diabdat.mpq +# Don't accidently commit the diabdat.mpq or any other MPQ files *.mpq ### Nintendo Switch ### @@ -444,9 +446,6 @@ exefs/main /docs/html/ -# MPQ files -*.mpq - # ddraw wrapper configuration file ddraw_settings.ini Brewfile.lock.json diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index 899ef36dd..d6d70fe21 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -760,18 +760,45 @@ void ResetInvCursorPosition() SetCursorPos(mousePos); } -int FindClosestInventorySlot(Point mousePos) +int FindClosestInventorySlot( + Point mousePos, const Item &heldItem, + tl::function_ref distanceFunction = [](Point mousePos, int slot) { return mousePos.ManhattanDistance(GetSlotCoord(slot)); }) { int shortestDistance = std::numeric_limits::max(); int bestSlot = 0; - for (int i = 0; i < NUM_XY_SLOTS; i++) { - int distance = mousePos.ManhattanDistance(GetSlotCoord(i)); + auto checkCandidateSlot = [&](int slot) { + int distance = distanceFunction(mousePos, slot); if (distance < shortestDistance) { shortestDistance = distance; - bestSlot = i; + bestSlot = slot; + } + }; + + if (heldItem.isEmpty()) { + for (int i = SLOTXY_HEAD; i <= SLOTXY_CHEST; i++) { + checkCandidateSlot(i); + } + } else { + if (heldItem._itype == ItemType::Ring) { + for (int i : { SLOTXY_RING_LEFT, SLOTXY_RING_RIGHT }) { + checkCandidateSlot(i); + } + } else if (heldItem.isWeapon()) { + checkCandidateSlot(SLOTXY_HAND_LEFT); + } else if (heldItem.isShield()) { + checkCandidateSlot(SLOTXY_HAND_RIGHT); + } else if (heldItem.isHelm()) { + checkCandidateSlot(SLOTXY_HEAD); + } else if (heldItem.isArmor()) { + checkCandidateSlot(SLOTXY_CHEST); + } else if (heldItem._itype == ItemType::Amulet) { + checkCandidateSlot(SLOTXY_AMULET); } } + for (int i = SLOTXY_INV_FIRST; i <= SLOTXY_INV_LAST; i++) { + checkCandidateSlot(i); + } return bestSlot; } @@ -812,15 +839,15 @@ void InventoryMove(AxisDirection dir) { Point mousePos = MousePosition; + const Item &heldItem = MyPlayer->HoldItem; // normalize slots if (Slot < 0) - Slot = FindClosestInventorySlot(mousePos); + Slot = FindClosestInventorySlot(mousePos, heldItem); else if (Slot > SLOTXY_BELT_LAST) Slot = SLOTXY_BELT_LAST; const int initialSlot = Slot; - const Item &heldItem = MyPlayer->HoldItem; const bool isHoldingItem = !heldItem.isEmpty(); Size itemSize = isHoldingItem ? GetInventorySize(heldItem) : Size { 1 }; @@ -1083,8 +1110,9 @@ void StashMove(AxisDirection dir) if (dir.x == AxisDirectionX_NONE && dir.y == AxisDirectionY_NONE) return; + Item &holdItem = MyPlayer->HoldItem; if (Slot < 0 && ActiveStashSlot == InvalidStashPoint) { - int invSlot = FindClosestInventorySlot(MousePosition); + int invSlot = FindClosestInventorySlot(MousePosition, holdItem); Point invSlotCoord = GetSlotCoord(invSlot); int invDistance = MousePosition.ManhattanDistance(invSlotCoord); @@ -1101,7 +1129,6 @@ void StashMove(AxisDirection dir) ActiveStashSlot = stashSlot; } - Item &holdItem = MyPlayer->HoldItem; Size itemSize = holdItem.isEmpty() ? Size { 1, 1 } : GetInventorySize(holdItem); if (dir.y == AxisDirectionY_UP) { @@ -1128,7 +1155,7 @@ void StashMove(AxisDirection dir) // If we're in the leftmost column (or hovering over an item on the left side of the inventory) or // left side of the body and we're moving left we need to move into the closest stash column - if (IsAnyOf(firstSlot, SLOTXY_HEAD, SLOTXY_HAND_LEFT, SLOTXY_RING_LEFT, SLOTXY_INV_ROW1_FIRST, SLOTXY_INV_ROW2_FIRST, SLOTXY_INV_ROW3_FIRST, SLOTXY_INV_ROW4_FIRST)) { + if (IsAnyOf(firstSlot, SLOTXY_HEAD, SLOTXY_HAND_LEFT, SLOTXY_RING_LEFT, SLOTXY_AMULET, SLOTXY_CHEST, SLOTXY_INV_ROW1_FIRST, SLOTXY_INV_ROW2_FIRST, SLOTXY_INV_ROW3_FIRST, SLOTXY_INV_ROW4_FIRST)) { Point slotCoord = GetSlotCoord(Slot); InvalidateInventorySlot(); ActiveStashSlot = FindClosestStashSlot(slotCoord) - Displacement { itemSize.width - 1, 0 }; @@ -1167,7 +1194,16 @@ void StashMove(AxisDirection dir) } else { Point stashSlotCoord = GetStashSlotCoord(ActiveStashSlot); Point rightPanelCoord = { GetRightPanel().position.x, stashSlotCoord.y }; - Slot = FindClosestInventorySlot(rightPanelCoord); + Slot = FindClosestInventorySlot(rightPanelCoord, holdItem, [](Point mousePos, int slot) { + Point slotPos = GetSlotCoord(slot); + // Exagerrate the vertical difference so that moving from the top 6 rows of the + // stash is more likely to land on a body slot. The value 3 was found by trial and + // error, this allows moving from the top row of the stash to the head while + // empty-handed while 4 causes the amulet to be preferenced (due to less vertical + // distance) and 2 causes the left hand to be preferenced (due to less horizontal + // distance). + return std::abs(mousePos.y - slotPos.y) * 3 + std::abs(mousePos.x - slotPos.x); + }); ActiveStashSlot = InvalidStashPoint; BeltReturnsToStash = false; } @@ -1857,7 +1893,7 @@ void PerformPrimaryAction() TryIconCurs(); NewCursor(CURSOR_HAND); } else if (GetRightPanel().contains(MousePosition) || GetMainPanel().contains(MousePosition)) { - int inventorySlot = (Slot >= 0) ? Slot : FindClosestInventorySlot(MousePosition); + int inventorySlot = (Slot >= 0) ? Slot : FindClosestInventorySlot(MousePosition, MyPlayer->HoldItem); int jumpSlot = inventorySlot; // If the cursor is over an inventory slot we may need to adjust it due to pasting items of different sizes over each other if (inventorySlot >= SLOTXY_INV_FIRST && inventorySlot <= SLOTXY_INV_LAST) {