From 8f20d7e2392981517f45d903d2177aa719db570a Mon Sep 17 00:00:00 2001 From: ChipsAhoiMcCoy Date: Fri, 30 Jan 2026 18:28:29 -0800 Subject: [PATCH 1/3] access: fix inventory navigation for multi-tile items, add position speech Fix inconsistent keyboard navigation when moving through multi-tile items in the inventory. Previously, navigating into a large item (e.g., a 3x2 axe) and then back out would exit from a different row than you entered from. Changes: - Add entry point tracking to remember which row/column you entered an item from - Use tracked entry points when exiting items to maintain navigation consistency - Add row and column position to accessibility speech (e.g., "Row 1, Column 3: Short Sword") Co-Authored-By: Claude Opus 4.5 --- Source/controls/plrctrls.cpp | 253 +++++++++++++++++++++++++++++++---- 1 file changed, 227 insertions(+), 26 deletions(-) diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index 01f2f7130..476fbb28b 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -93,6 +93,28 @@ Point ActiveStashSlot = InvalidStashPoint; int PreviousInventoryColumn = -1; bool BeltReturnsToStash = false; +/** + * Tracks the row offset within a multi-tile item when navigating horizontally. + * This ensures that when navigating left into a 2x3 item and then right again, + * we exit from the same row we entered from. + * -1 means no entry point is tracked (single-tile item or not on an item). + */ +int CurrentItemEntryRow = -1; + +/** + * Tracks the column offset within a multi-tile item when navigating vertically. + * This ensures that when navigating up into a 3x2 item and then down again, + * we exit from the same column we entered from. + * -1 means no entry point is tracked. + */ +int CurrentItemEntryColumn = -1; + +/** + * The item ID we're currently tracking entry points for. + * Used to detect when we've moved to a different item. + */ +int8_t CurrentItemId = 0; + const Direction FaceDir[3][3] = { // NONE UP DOWN { Direction::South, Direction::North, Direction::South }, // NONE @@ -712,6 +734,26 @@ StringOrView GetInventorySlotNameForSpeech(int slot) return _("Inventory"); } +/** + * Get the row of a slot in the inventory grid (0-indexed). + */ +int GetSlotRow(int slot) +{ + if (slot < SLOTXY_INV_FIRST || slot > SLOTXY_INV_LAST) + return -1; + return (slot - SLOTXY_INV_FIRST) / INV_ROW_SLOT_SIZE; +} + +/** + * Get the column of a slot in the inventory grid (0-indexed). + */ +int GetSlotColumn(int slot) +{ + if (slot < SLOTXY_INV_FIRST || slot > SLOTXY_INV_LAST) + return -1; + return (slot - SLOTXY_INV_FIRST) % INV_ROW_SLOT_SIZE; +} + void SpeakInventorySlotForAccessibility() { if (MyPlayer == nullptr) @@ -719,6 +761,7 @@ void SpeakInventorySlotForAccessibility() const Player &player = *MyPlayer; const Item *item = nullptr; + std::string positionInfo; if (Slot >= SLOTXY_BELT_FIRST && Slot <= SLOTXY_BELT_LAST) { item = &player.SpdList[Slot - SLOTXY_BELT_FIRST]; @@ -726,6 +769,11 @@ void SpeakInventorySlotForAccessibility() const int invId = GetItemIdOnSlot(Slot); if (invId != 0) item = &player.InvList[invId - 1]; + + // Calculate row and column for inventory position (1-indexed for speech) + int row = GetSlotRow(Slot) + 1; + int column = GetSlotColumn(Slot) + 1; + positionInfo = fmt::format("Row {}, Column {}: ", row, column); } else { switch (Slot) { case SLOTXY_HEAD: @@ -759,16 +807,27 @@ void SpeakInventorySlotForAccessibility() } if (item != nullptr && !item->isEmpty()) { + std::string itemName; if (item->_itype == ItemType::Gold) { const int nGold = item->_ivalue; - SpeakText(fmt::format(fmt::runtime(ngettext("{:s} gold piece", "{:s} gold pieces", nGold)), FormatInteger(nGold)), /*force=*/true); + itemName = fmt::format(fmt::runtime(ngettext("{:s} gold piece", "{:s} gold pieces", nGold)), FormatInteger(nGold)); } else { - SpeakText(item->getName(), /*force=*/true); + itemName = std::string(item->getName()); + } + + if (!positionInfo.empty()) { + SpeakText(StrCat(positionInfo, itemName), /*force=*/true); + } else { + SpeakText(itemName, /*force=*/true); } return; } - SpeakText(StrCat(GetInventorySlotNameForSpeech(Slot), ": ", _("empty")), /*force=*/true); + if (!positionInfo.empty()) { + SpeakText(StrCat(positionInfo, _("empty")), /*force=*/true); + } else { + SpeakText(StrCat(GetInventorySlotNameForSpeech(Slot), ": ", _("empty")), /*force=*/true); + } } /** @@ -821,6 +880,142 @@ int FindFirstSlotOnItem(int8_t itemInvId) return -1; } +/** + * Get a slot from row and column coordinates. + */ +int GetSlotFromRowColumn(int row, int column) +{ + if (row < 0 || row >= 4 || column < 0 || column >= INV_ROW_SLOT_SIZE) + return -1; + return SLOTXY_INV_FIRST + row * INV_ROW_SLOT_SIZE + column; +} + +/** + * Update the entry point tracking for the current item. + * Call this when navigating to a new slot to track which row/column we entered from. + */ +void UpdateItemEntryPoint(int newSlot, AxisDirection dir) +{ + if (newSlot < SLOTXY_INV_FIRST || newSlot > SLOTXY_INV_LAST) { + // Not in inventory grid, clear tracking + CurrentItemEntryRow = -1; + CurrentItemEntryColumn = -1; + CurrentItemId = 0; + return; + } + + const int8_t newItemId = GetItemIdOnSlot(newSlot); + if (newItemId == 0) { + // Empty slot, clear tracking + CurrentItemEntryRow = -1; + CurrentItemEntryColumn = -1; + CurrentItemId = 0; + return; + } + + // Check if we're on the same item + if (newItemId == CurrentItemId) { + // Same item, keep existing entry point + return; + } + + // New item - record entry point based on navigation direction + CurrentItemId = newItemId; + int firstSlot = FindFirstSlotOnItem(newItemId); + if (firstSlot < 0) { + CurrentItemEntryRow = -1; + CurrentItemEntryColumn = -1; + return; + } + + int itemTopRow = GetSlotRow(firstSlot); + int itemLeftColumn = GetSlotColumn(firstSlot); + int slotRow = GetSlotRow(newSlot); + int slotColumn = GetSlotColumn(newSlot); + + // Record the row/column offset within the item + CurrentItemEntryRow = slotRow - itemTopRow; + CurrentItemEntryColumn = slotColumn - itemLeftColumn; +} + +/** + * Get the slot to exit to when leaving a multi-tile item horizontally. + * Uses the tracked entry row to maintain consistent navigation. + */ +int GetHorizontalExitSlot(int currentSlot, bool movingRight) +{ + const int8_t itemId = GetItemIdOnSlot(currentSlot); + if (itemId == 0) + return currentSlot + (movingRight ? 1 : -1); + + int firstSlot = FindFirstSlotOnItem(itemId); + if (firstSlot < 0) + return currentSlot + (movingRight ? 1 : -1); + + Size itemSize = GetItemSizeOnSlot(firstSlot); + int itemTopRow = GetSlotRow(firstSlot); + int itemLeftColumn = GetSlotColumn(firstSlot); + + // Determine which row to exit from + int exitRow = itemTopRow; + if (CurrentItemEntryRow >= 0 && CurrentItemEntryRow < itemSize.height) { + exitRow = itemTopRow + CurrentItemEntryRow; + } + + // Calculate the exit column + int exitColumn; + if (movingRight) { + exitColumn = itemLeftColumn + itemSize.width; // One past the right edge + } else { + exitColumn = itemLeftColumn - 1; // One before the left edge + } + + // Check bounds + if (exitColumn < 0 || exitColumn >= INV_ROW_SLOT_SIZE) + return -1; + + return GetSlotFromRowColumn(exitRow, exitColumn); +} + +/** + * Get the slot to exit to when leaving a multi-tile item vertically. + * Uses the tracked entry column to maintain consistent navigation. + */ +int GetVerticalExitSlot(int currentSlot, bool movingDown) +{ + const int8_t itemId = GetItemIdOnSlot(currentSlot); + if (itemId == 0) + return currentSlot + (movingDown ? INV_ROW_SLOT_SIZE : -INV_ROW_SLOT_SIZE); + + int firstSlot = FindFirstSlotOnItem(itemId); + if (firstSlot < 0) + return currentSlot + (movingDown ? INV_ROW_SLOT_SIZE : -INV_ROW_SLOT_SIZE); + + Size itemSize = GetItemSizeOnSlot(firstSlot); + int itemTopRow = GetSlotRow(firstSlot); + int itemLeftColumn = GetSlotColumn(firstSlot); + + // Determine which column to exit from + int exitColumn = itemLeftColumn; + if (CurrentItemEntryColumn >= 0 && CurrentItemEntryColumn < itemSize.width) { + exitColumn = itemLeftColumn + CurrentItemEntryColumn; + } + + // Calculate the exit row + int exitRow; + if (movingDown) { + exitRow = itemTopRow + itemSize.height; // One past the bottom edge + } else { + exitRow = itemTopRow - 1; // One before the top edge + } + + // Check bounds + if (exitRow < 0 || exitRow >= 4) + return -1; + + return GetSlotFromRowColumn(exitRow, exitColumn); +} + Point FindFirstStashSlotOnItem(StashStruct::StashCell itemInvId) { if (itemInvId == StashStruct::EmptyCell) @@ -1055,12 +1250,12 @@ void InventoryMove(AxisDirection dir) } else if (Slot >= SLOTXY_INV_FIRST && Slot <= SLOTXY_BELT_LAST) { const int8_t itemId = GetItemIdOnSlot(Slot); if (itemId != 0) { - for (int i = 1; i < INV_ROW_SLOT_SIZE && !IsAnyOf(Slot - i + 1, SLOTXY_INV_ROW1_FIRST, SLOTXY_INV_ROW2_FIRST, SLOTXY_INV_ROW3_FIRST, SLOTXY_INV_ROW4_FIRST, SLOTXY_BELT_FIRST); i++) { - if (itemId != GetItemIdOnSlot(Slot - i)) { - Slot -= i; - break; - } + // Use entry-point-aware exit to maintain the row we're on + int exitSlot = GetHorizontalExitSlot(Slot, false); + if (exitSlot >= SLOTXY_INV_FIRST && exitSlot <= SLOTXY_INV_LAST) { + Slot = exitSlot; } + // If exitSlot is invalid (at left edge), don't move } else if (IsNoneOf(Slot, SLOTXY_INV_ROW1_FIRST, SLOTXY_INV_ROW2_FIRST, SLOTXY_INV_ROW3_FIRST, SLOTXY_INV_ROW4_FIRST, SLOTXY_BELT_FIRST)) { Slot -= 1; } @@ -1089,12 +1284,12 @@ void InventoryMove(AxisDirection dir) } else if (Slot >= SLOTXY_INV_FIRST && Slot <= SLOTXY_BELT_LAST) { const int8_t itemId = GetItemIdOnSlot(Slot); if (itemId != 0) { - for (int i = 1; i < INV_ROW_SLOT_SIZE && !IsAnyOf(Slot + i - 1, SLOTXY_INV_ROW1_LAST, SLOTXY_INV_ROW2_LAST, SLOTXY_INV_ROW3_LAST, SLOTXY_INV_ROW4_LAST, SLOTXY_BELT_LAST); i++) { - if (itemId != GetItemIdOnSlot(Slot + i)) { - Slot += i; - break; - } + // Use entry-point-aware exit to maintain the row we're on + int exitSlot = GetHorizontalExitSlot(Slot, true); + if (exitSlot >= SLOTXY_INV_FIRST && exitSlot <= SLOTXY_INV_LAST) { + Slot = exitSlot; } + // If exitSlot is invalid (at right edge), don't move } else if (IsNoneOf(Slot, SLOTXY_INV_ROW1_LAST, SLOTXY_INV_ROW2_LAST, SLOTXY_INV_ROW3_LAST, SLOTXY_INV_ROW4_LAST, SLOTXY_BELT_LAST)) { Slot += 1; } @@ -1138,15 +1333,18 @@ void InventoryMove(AxisDirection dir) } else if (Slot >= SLOTXY_INV_ROW2_FIRST) { const int8_t itemId = GetItemIdOnSlot(Slot); if (itemId != 0) { - for (int i = 1; i < 5; i++) { - if (Slot - i * INV_ROW_SLOT_SIZE < SLOTXY_INV_ROW1_FIRST) { - Slot = InventoryMoveToBody(Slot - (i - 1) * INV_ROW_SLOT_SIZE); - break; - } - if (itemId != GetItemIdOnSlot(Slot - i * INV_ROW_SLOT_SIZE)) { - Slot -= i * INV_ROW_SLOT_SIZE; - break; + // Use entry-point-aware exit to maintain the column we're on + int exitSlot = GetVerticalExitSlot(Slot, false); + if (exitSlot >= SLOTXY_INV_FIRST && exitSlot <= SLOTXY_INV_LAST) { + Slot = exitSlot; + } else if (exitSlot < SLOTXY_INV_FIRST) { + // Would go above inventory, move to body based on current column + int firstSlot = FindFirstSlotOnItem(itemId); + int col = GetSlotColumn(firstSlot); + if (CurrentItemEntryColumn >= 0) { + col += CurrentItemEntryColumn; } + Slot = InventoryMoveToBody(SLOTXY_INV_ROW1_FIRST + col); } } else { Slot -= INV_ROW_SLOT_SIZE; @@ -1194,12 +1392,12 @@ void InventoryMove(AxisDirection dir) } else if (Slot <= SLOTXY_INV_LAST) { const int8_t itemId = GetItemIdOnSlot(Slot); if (itemId != 0) { - for (int i = 1; i < 5 && Slot + i * INV_ROW_SLOT_SIZE <= SLOTXY_BELT_LAST; i++) { - if (itemId != GetItemIdOnSlot(Slot + i * INV_ROW_SLOT_SIZE)) { - Slot += i * INV_ROW_SLOT_SIZE; - break; - } + // Use entry-point-aware exit to maintain the column we're on + int exitSlot = GetVerticalExitSlot(Slot, true); + if (exitSlot >= SLOTXY_INV_FIRST && exitSlot <= SLOTXY_BELT_LAST) { + Slot = exitSlot; } + // If exitSlot is invalid (at bottom edge), don't move } else if (Slot + INV_ROW_SLOT_SIZE <= SLOTXY_BELT_LAST) { Slot += INV_ROW_SLOT_SIZE; } @@ -1211,6 +1409,9 @@ void InventoryMove(AxisDirection dir) if (Slot == initialSlot) return; + // Update entry point tracking for the new slot + UpdateItemEntryPoint(Slot, dir); + if (Slot < SLOTXY_INV_FIRST) { mousePos = InvGetEquipSlotCoordFromInvSlot(static_cast(Slot)); } else { From b84ae823489f07d82ff34a3251c4d6c78b5a1524 Mon Sep 17 00:00:00 2001 From: ChipsAhoiMcCoy Date: Sat, 31 Jan 2026 01:29:04 -0800 Subject: [PATCH 2/3] access: improve belt navigation for accessibility - Always enter belt at slot 1 when navigating down from inventory - Return to exact inventory position when navigating up from belt - Keep left/right navigation within belt area only - Track last inventory slot before entering belt with SlotBeforeBelt Co-Authored-By: Claude Opus 4.5 --- Source/controls/plrctrls.cpp | 103 ++++++++++++++++++++++++++++++----- 1 file changed, 89 insertions(+), 14 deletions(-) diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index 476fbb28b..dbd1cb5e9 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -91,8 +91,15 @@ namespace { int Slot = SLOTXY_INV_FIRST; Point ActiveStashSlot = InvalidStashPoint; int PreviousInventoryColumn = -1; +int PreviousBeltColumn = -1; bool BeltReturnsToStash = false; +/** + * Tracks the actual inventory slot we were on before entering the belt. + * This provides a more reliable way to return to the same position. + */ +int SlotBeforeBelt = -1; + /** * Tracks the row offset within a multi-tile item when navigating horizontally. * This ensures that when navigating left into a 2x3 item and then right again, @@ -1010,8 +1017,17 @@ int GetVerticalExitSlot(int currentSlot, bool movingDown) } // Check bounds - if (exitRow < 0 || exitRow >= 4) + if (exitRow < 0) + return -1; + + // If exiting downward past row 4, try to go to belt + if (exitRow >= 4) { + if (movingDown && exitColumn >= 0 && exitColumn <= 7) { + // Belt only has 8 slots (columns 0-7) + return SLOTXY_BELT_FIRST + exitColumn; + } return -1; + } return GetSlotFromRowColumn(exitRow, exitColumn); } @@ -1101,6 +1117,11 @@ int FindClosestInventorySlot( checkCandidateSlot(i); } + // Also check belt slots + for (int i = SLOTXY_BELT_FIRST; i <= SLOTXY_BELT_LAST; i++) { + checkCandidateSlot(i); + } + return bestSlot; } @@ -1247,7 +1268,13 @@ void InventoryMove(AxisDirection dir) Slot = SLOTXY_HEAD; } else if (Slot == SLOTXY_RING_RIGHT) { Slot = SLOTXY_RING_LEFT; - } else if (Slot >= SLOTXY_INV_FIRST && Slot <= SLOTXY_BELT_LAST) { + } else if (Slot >= SLOTXY_BELT_FIRST && Slot <= SLOTXY_BELT_LAST) { + // Belt navigation - move left within belt only + if (Slot > SLOTXY_BELT_FIRST) { + Slot -= 1; + } + // At belt slot 1, don't move + } else if (Slot >= SLOTXY_INV_FIRST && Slot <= SLOTXY_INV_LAST) { const int8_t itemId = GetItemIdOnSlot(Slot); if (itemId != 0) { // Use entry-point-aware exit to maintain the row we're on @@ -1256,15 +1283,20 @@ void InventoryMove(AxisDirection dir) Slot = exitSlot; } // If exitSlot is invalid (at left edge), don't move - } else if (IsNoneOf(Slot, SLOTXY_INV_ROW1_FIRST, SLOTXY_INV_ROW2_FIRST, SLOTXY_INV_ROW3_FIRST, SLOTXY_INV_ROW4_FIRST, SLOTXY_BELT_FIRST)) { + } else if (IsNoneOf(Slot, SLOTXY_INV_ROW1_FIRST, SLOTXY_INV_ROW2_FIRST, SLOTXY_INV_ROW3_FIRST, SLOTXY_INV_ROW4_FIRST)) { Slot -= 1; } } } } else if (dir.x == AxisDirectionX_RIGHT) { if (isHoldingItem) { - if (Slot >= SLOTXY_INV_FIRST && Slot <= SLOTXY_BELT_LAST) { - if (IsNoneOf(Slot + itemSize.width - 1, SLOTXY_INV_ROW1_LAST, SLOTXY_INV_ROW2_LAST, SLOTXY_INV_ROW3_LAST, SLOTXY_INV_ROW4_LAST, SLOTXY_BELT_LAST)) { + if (Slot >= SLOTXY_BELT_FIRST && Slot <= SLOTXY_BELT_LAST) { + // Belt navigation while holding item + if (Slot < SLOTXY_BELT_LAST) { + Slot += 1; + } + } else if (Slot >= SLOTXY_INV_FIRST && Slot <= SLOTXY_INV_LAST) { + if (IsNoneOf(Slot + itemSize.width - 1, SLOTXY_INV_ROW1_LAST, SLOTXY_INV_ROW2_LAST, SLOTXY_INV_ROW3_LAST, SLOTXY_INV_ROW4_LAST)) { Slot += 1; } } else if (heldItem._itype == ItemType::Ring) { @@ -1281,7 +1313,13 @@ void InventoryMove(AxisDirection dir) Slot = SLOTXY_HAND_RIGHT; } else if (Slot == SLOTXY_HEAD) { Slot = SLOTXY_AMULET; - } else if (Slot >= SLOTXY_INV_FIRST && Slot <= SLOTXY_BELT_LAST) { + } else if (Slot >= SLOTXY_BELT_FIRST && Slot <= SLOTXY_BELT_LAST) { + // Belt navigation - move right within belt only + if (Slot < SLOTXY_BELT_LAST) { + Slot += 1; + } + // At belt slot 8, don't move + } else if (Slot >= SLOTXY_INV_FIRST && Slot <= SLOTXY_INV_LAST) { const int8_t itemId = GetItemIdOnSlot(Slot); if (itemId != 0) { // Use entry-point-aware exit to maintain the row we're on @@ -1290,7 +1328,7 @@ void InventoryMove(AxisDirection dir) Slot = exitSlot; } // If exitSlot is invalid (at right edge), don't move - } else if (IsNoneOf(Slot, SLOTXY_INV_ROW1_LAST, SLOTXY_INV_ROW2_LAST, SLOTXY_INV_ROW3_LAST, SLOTXY_INV_ROW4_LAST, SLOTXY_BELT_LAST)) { + } else if (IsNoneOf(Slot, SLOTXY_INV_ROW1_LAST, SLOTXY_INV_ROW2_LAST, SLOTXY_INV_ROW3_LAST, SLOTXY_INV_ROW4_LAST)) { Slot += 1; } } @@ -1298,7 +1336,18 @@ void InventoryMove(AxisDirection dir) } if (dir.y == AxisDirectionY_UP) { if (isHoldingItem) { - if (Slot >= SLOTXY_INV_ROW2_FIRST) { // general inventory + if (Slot >= SLOTXY_BELT_FIRST && Slot <= SLOTXY_BELT_LAST) { + // Going from belt back to inventory - restore saved slot + int targetSlot = -1; + if (SlotBeforeBelt >= SLOTXY_INV_FIRST && SlotBeforeBelt <= SLOTXY_INV_LAST) { + // Return to the exact slot we were on before entering the belt + targetSlot = SlotBeforeBelt; + } else { + // Fallback: go to row 4, column 1 + targetSlot = SLOTXY_INV_ROW4_FIRST; + } + Slot = targetSlot; + } else if (Slot >= SLOTXY_INV_ROW2_FIRST) { // general inventory Slot -= INV_ROW_SLOT_SIZE; } else if (Slot >= SLOTXY_INV_FIRST) { if (heldItem._itype == ItemType::Ring) { @@ -1330,6 +1379,17 @@ void InventoryMove(AxisDirection dir) Slot = SLOTXY_HAND_RIGHT; } else if (Slot == SLOTXY_HAND_RIGHT) { Slot = SLOTXY_AMULET; + } else if (Slot >= SLOTXY_BELT_FIRST && Slot <= SLOTXY_BELT_LAST) { + // Going from belt back to inventory - restore saved slot + int targetSlot = -1; + if (SlotBeforeBelt >= SLOTXY_INV_FIRST && SlotBeforeBelt <= SLOTXY_INV_LAST) { + // Return to the exact slot we were on before entering the belt + targetSlot = SlotBeforeBelt; + } else { + // Fallback: go to row 4, column 1 + targetSlot = SLOTXY_INV_ROW4_FIRST; + } + Slot = targetSlot; } else if (Slot >= SLOTXY_INV_ROW2_FIRST) { const int8_t itemId = GetItemIdOnSlot(Slot); if (itemId != 0) { @@ -1361,9 +1421,10 @@ void InventoryMove(AxisDirection dir) Slot = SLOTXY_INV_ROW1_LAST - 1; } else if (Slot <= (SLOTXY_INV_ROW4_LAST - (itemSize.height * INV_ROW_SLOT_SIZE))) { Slot += INV_ROW_SLOT_SIZE; - } else if (Slot <= SLOTXY_INV_LAST && heldItem._itype == ItemType::Misc && itemSize == Size { 1, 1 }) { // forcing only 1x1 misc items - if (Slot + INV_ROW_SLOT_SIZE <= SLOTXY_BELT_LAST) - Slot += INV_ROW_SLOT_SIZE; + } else if (Slot >= SLOTXY_INV_ROW4_FIRST && Slot <= SLOTXY_INV_ROW4_LAST && heldItem._itype == ItemType::Misc && itemSize == Size { 1, 1 }) { // forcing only 1x1 misc items + // Save current slot and go to belt slot 1 + SlotBeforeBelt = Slot; + Slot = SLOTXY_BELT_FIRST; } } else { if (Slot == SLOTXY_HEAD) { @@ -1392,13 +1453,25 @@ void InventoryMove(AxisDirection dir) } else if (Slot <= SLOTXY_INV_LAST) { const int8_t itemId = GetItemIdOnSlot(Slot); if (itemId != 0) { - // Use entry-point-aware exit to maintain the column we're on + // Check if this item extends to row 4 (can exit to belt) int exitSlot = GetVerticalExitSlot(Slot, true); - if (exitSlot >= SLOTXY_INV_FIRST && exitSlot <= SLOTXY_BELT_LAST) { + if (exitSlot >= SLOTXY_BELT_FIRST && exitSlot <= SLOTXY_BELT_LAST) { + // Save the current slot for returning later + SlotBeforeBelt = Slot; + // Always go to belt slot 1 for accessibility + Slot = SLOTXY_BELT_FIRST; + } else if (exitSlot >= SLOTXY_INV_FIRST && exitSlot <= SLOTXY_INV_LAST) { + // Moving within inventory (not to belt) Slot = exitSlot; } // If exitSlot is invalid (at bottom edge), don't move - } else if (Slot + INV_ROW_SLOT_SIZE <= SLOTXY_BELT_LAST) { + } else if (Slot >= SLOTXY_INV_ROW4_FIRST && Slot <= SLOTXY_INV_ROW4_LAST) { + // Empty slot in row 4 - can go to belt + SlotBeforeBelt = Slot; + // Always go to belt slot 1 for accessibility + Slot = SLOTXY_BELT_FIRST; + } else if (Slot >= SLOTXY_INV_FIRST && Slot < SLOTXY_INV_ROW4_FIRST) { + // Empty slot in rows 1-3 - move down one row Slot += INV_ROW_SLOT_SIZE; } } @@ -2202,6 +2275,7 @@ void InvalidateInventorySlot() { Slot = -1; ActiveStashSlot = InvalidStashPoint; + SlotBeforeBelt = -1; } /** @@ -2210,6 +2284,7 @@ void InvalidateInventorySlot() void FocusOnInventory() { Slot = SLOTXY_INV_FIRST; + SlotBeforeBelt = -1; ResetInvCursorPosition(); SpeakInventorySlotForAccessibility(); } From b49c22a6cb11e6a71eb69d956dd4f4831c7d3ce1 Mon Sep 17 00:00:00 2001 From: ChipsAhoiMcCoy Date: Sat, 31 Jan 2026 01:57:54 -0800 Subject: [PATCH 3/3] access: simplify belt navigation return behavior Remove slot tracking when entering/exiting the belt. Now consistently returns to row 4 column 1 when navigating up from the belt. Co-Authored-By: Claude Opus 4.5 --- Source/controls/plrctrls.cpp | 42 ++++++------------------------------ 1 file changed, 7 insertions(+), 35 deletions(-) diff --git a/Source/controls/plrctrls.cpp b/Source/controls/plrctrls.cpp index dbd1cb5e9..7444a0710 100644 --- a/Source/controls/plrctrls.cpp +++ b/Source/controls/plrctrls.cpp @@ -94,11 +94,6 @@ int PreviousInventoryColumn = -1; int PreviousBeltColumn = -1; bool BeltReturnsToStash = false; -/** - * Tracks the actual inventory slot we were on before entering the belt. - * This provides a more reliable way to return to the same position. - */ -int SlotBeforeBelt = -1; /** * Tracks the row offset within a multi-tile item when navigating horizontally. @@ -1337,16 +1332,8 @@ void InventoryMove(AxisDirection dir) if (dir.y == AxisDirectionY_UP) { if (isHoldingItem) { if (Slot >= SLOTXY_BELT_FIRST && Slot <= SLOTXY_BELT_LAST) { - // Going from belt back to inventory - restore saved slot - int targetSlot = -1; - if (SlotBeforeBelt >= SLOTXY_INV_FIRST && SlotBeforeBelt <= SLOTXY_INV_LAST) { - // Return to the exact slot we were on before entering the belt - targetSlot = SlotBeforeBelt; - } else { - // Fallback: go to row 4, column 1 - targetSlot = SLOTXY_INV_ROW4_FIRST; - } - Slot = targetSlot; + // Going from belt back to inventory - go to row 4, column 1 + Slot = SLOTXY_INV_ROW4_FIRST; } else if (Slot >= SLOTXY_INV_ROW2_FIRST) { // general inventory Slot -= INV_ROW_SLOT_SIZE; } else if (Slot >= SLOTXY_INV_FIRST) { @@ -1380,16 +1367,8 @@ void InventoryMove(AxisDirection dir) } else if (Slot == SLOTXY_HAND_RIGHT) { Slot = SLOTXY_AMULET; } else if (Slot >= SLOTXY_BELT_FIRST && Slot <= SLOTXY_BELT_LAST) { - // Going from belt back to inventory - restore saved slot - int targetSlot = -1; - if (SlotBeforeBelt >= SLOTXY_INV_FIRST && SlotBeforeBelt <= SLOTXY_INV_LAST) { - // Return to the exact slot we were on before entering the belt - targetSlot = SlotBeforeBelt; - } else { - // Fallback: go to row 4, column 1 - targetSlot = SLOTXY_INV_ROW4_FIRST; - } - Slot = targetSlot; + // Going from belt back to inventory - go to row 4, column 1 + Slot = SLOTXY_INV_ROW4_FIRST; } else if (Slot >= SLOTXY_INV_ROW2_FIRST) { const int8_t itemId = GetItemIdOnSlot(Slot); if (itemId != 0) { @@ -1422,8 +1401,7 @@ void InventoryMove(AxisDirection dir) } else if (Slot <= (SLOTXY_INV_ROW4_LAST - (itemSize.height * INV_ROW_SLOT_SIZE))) { Slot += INV_ROW_SLOT_SIZE; } else if (Slot >= SLOTXY_INV_ROW4_FIRST && Slot <= SLOTXY_INV_ROW4_LAST && heldItem._itype == ItemType::Misc && itemSize == Size { 1, 1 }) { // forcing only 1x1 misc items - // Save current slot and go to belt slot 1 - SlotBeforeBelt = Slot; + // Go to belt slot 1 Slot = SLOTXY_BELT_FIRST; } } else { @@ -1456,9 +1434,7 @@ void InventoryMove(AxisDirection dir) // Check if this item extends to row 4 (can exit to belt) int exitSlot = GetVerticalExitSlot(Slot, true); if (exitSlot >= SLOTXY_BELT_FIRST && exitSlot <= SLOTXY_BELT_LAST) { - // Save the current slot for returning later - SlotBeforeBelt = Slot; - // Always go to belt slot 1 for accessibility + // Go to belt slot 1 for accessibility Slot = SLOTXY_BELT_FIRST; } else if (exitSlot >= SLOTXY_INV_FIRST && exitSlot <= SLOTXY_INV_LAST) { // Moving within inventory (not to belt) @@ -1466,9 +1442,7 @@ void InventoryMove(AxisDirection dir) } // If exitSlot is invalid (at bottom edge), don't move } else if (Slot >= SLOTXY_INV_ROW4_FIRST && Slot <= SLOTXY_INV_ROW4_LAST) { - // Empty slot in row 4 - can go to belt - SlotBeforeBelt = Slot; - // Always go to belt slot 1 for accessibility + // Empty slot in row 4 - go to belt slot 1 Slot = SLOTXY_BELT_FIRST; } else if (Slot >= SLOTXY_INV_FIRST && Slot < SLOTXY_INV_ROW4_FIRST) { // Empty slot in rows 1-3 - move down one row @@ -2275,7 +2249,6 @@ void InvalidateInventorySlot() { Slot = -1; ActiveStashSlot = InvalidStashPoint; - SlotBeforeBelt = -1; } /** @@ -2284,7 +2257,6 @@ void InvalidateInventorySlot() void FocusOnInventory() { Slot = SLOTXY_INV_FIRST; - SlotBeforeBelt = -1; ResetInvCursorPosition(); SpeakInventorySlotForAccessibility(); }