Skip to content

Commit

Permalink
Shuffle items around when auto-equipping so less inv space is required
Browse files Browse the repository at this point in the history
  • Loading branch information
ephphatha authored and AJenbo committed Oct 21, 2024
1 parent 38edb84 commit 1012595
Showing 1 changed file with 37 additions and 17 deletions.
54 changes: 37 additions & 17 deletions Source/inv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -636,9 +636,10 @@ std::optional<inv_xy_slot> FindSlotUnderCursor(Point cursorPosition)
* @param player The player whose inventory will be checked.
* @param slotIndex The 0-based index of the slot to put the item on.
* @param itemSize The size of the item to be checked.
* @param itemIndexToIgnore can be used to check if an item of the given size would fit if the item with the given (positive) ID was removed.
* @return 'True' in case the item can be placed on the specified player's inventory slot and 'False' otherwise.
*/
bool CheckItemFitsInInventorySlot(const Player &player, int slotIndex, const Size &itemSize)
bool CheckItemFitsInInventorySlot(const Player &player, int slotIndex, const Size &itemSize, int itemIndexToIgnore)
{
int yy = (slotIndex > 0) ? (10 * (slotIndex / 10)) : 0;

Expand All @@ -648,8 +649,8 @@ bool CheckItemFitsInInventorySlot(const Player &player, int slotIndex, const Siz
}
int xx = (slotIndex > 0) ? (slotIndex % 10) : 0;
for (int i = 0; i < itemSize.width; i++) {
if (xx >= 10 || player.InvGrid[xx + yy] != 0) {
// The item is too wide to fit in the specified column, or one of the cells is occupied
if (xx >= 10 || !(player.InvGrid[xx + yy] == 0 || std::abs(player.InvGrid[xx + yy]) - 1 == itemIndexToIgnore)) {
// The item is too wide to fit in the specified column, or one of the cells is occupied (and not by the item we're planning on removing)
return false;
}
xx++;
Expand All @@ -663,18 +664,19 @@ bool CheckItemFitsInInventorySlot(const Player &player, int slotIndex, const Siz
* @brief Finds the first slot that could fit an item of the given size
* @param player Player whose inventory will be checked.
* @param itemSize Dimensions of the item.
* @param itemIndexToIgnore Can be used if you want to find whether the new item would fit with this item removed, without performing unnecessary actions.
* @return The first slot that could fit the item or an empty optional.
*/
std::optional<int> FindSlotForItem(const Player &player, const Size &itemSize)
std::optional<int> FindSlotForItem(const Player &player, const Size &itemSize, int itemIndexToIgnore = -1)
{
if (itemSize.height == 1) {
for (int i = 30; i <= 39; i++) {
if (CheckItemFitsInInventorySlot(player, i, itemSize))
if (CheckItemFitsInInventorySlot(player, i, itemSize, itemIndexToIgnore))
return i;
}
for (int x = 9; x >= 0; x--) {
for (int y = 2; y >= 0; y--) {
if (CheckItemFitsInInventorySlot(player, 10 * y + x, itemSize))
if (CheckItemFitsInInventorySlot(player, 10 * y + x, itemSize, itemIndexToIgnore))
return 10 * y + x;
}
}
Expand All @@ -684,7 +686,7 @@ std::optional<int> FindSlotForItem(const Player &player, const Size &itemSize)
if (itemSize.height == 2) {
for (int x = 10 - itemSize.width; x >= 0; x--) {
for (int y = 0; y < 3; y++) {
if (CheckItemFitsInInventorySlot(player, 10 * y + x, itemSize))
if (CheckItemFitsInInventorySlot(player, 10 * y + x, itemSize, itemIndexToIgnore))
return 10 * y + x;
}
}
Expand All @@ -693,20 +695,20 @@ std::optional<int> FindSlotForItem(const Player &player, const Size &itemSize)

if (itemSize == Size { 1, 3 }) {
for (int i = 0; i < 20; i++) {
if (CheckItemFitsInInventorySlot(player, i, itemSize))
if (CheckItemFitsInInventorySlot(player, i, itemSize, itemIndexToIgnore))
return i;
}
return {};
}

if (itemSize == Size { 2, 3 }) {
for (int i = 0; i < 9; i++) {
if (CheckItemFitsInInventorySlot(player, i, itemSize))
if (CheckItemFitsInInventorySlot(player, i, itemSize, itemIndexToIgnore))
return i;
}

for (int i = 10; i < 19; i++) {
if (CheckItemFitsInInventorySlot(player, i, itemSize))
if (CheckItemFitsInInventorySlot(player, i, itemSize, itemIndexToIgnore))
return i;
}
return {};
Expand All @@ -715,6 +717,18 @@ std::optional<int> FindSlotForItem(const Player &player, const Size &itemSize)
app_fatal(StrCat("Unknown item size: ", itemSize.width, "x", itemSize.height));
}

/**
* @brief Checks if the given item could be placed on the specified players inventory if the other item was removed.
* @param player The player whose inventory will be checked.
* @param item The item to be checked.
* @param itemIndexToIgnore The inventory index of the item that we assume will be removed.
* @return 'True' if the item could fit with the other item removed and 'False' otherwise.
*/
bool CouldFitItemInInventory(const Player &player, const Item &item, int itemIndexToIgnore)
{
return static_cast<bool>(FindSlotForItem(player, GetInventorySize(item), itemIndexToIgnore));
}

void CheckInvCut(Player &player, Point cursorPosition, bool automaticMove, bool dropItem)
{
if (player._pmode > PM_WALK_SIDEWAYS) {
Expand Down Expand Up @@ -829,7 +843,7 @@ void CheckInvCut(Player &player, Point cursorPosition, bool automaticMove, bool
// No space to move right hand item to inventory, abort.
break;
}
if (!CanFitItemInInventory(player, player.InvBody[INVLOC_HAND_LEFT])) {
if (!CouldFitItemInInventory(player, player.InvBody[INVLOC_HAND_LEFT], iv)) {
// No space for left item. Move back right item to right hand and abort.
player.InvBody[INVLOC_HAND_RIGHT] = player.InvList[player._pNumInv - 1];
player.RemoveInvItem(player._pNumInv - 1, false);
Expand All @@ -845,17 +859,23 @@ void CheckInvCut(Player &player, Point cursorPosition, bool automaticMove, bool
break;
}
// Then empty the identified InvBody slot (invloc) and hand over to AutoEquip
if (invloc != NUM_INVLOC) {
if (!player.InvBody[invloc].isEmpty()) {
if (AutoPlaceItemInInventory(player, player.InvBody[invloc])) {
player.InvBody[invloc].clear();
}
}
if (invloc != NUM_INVLOC
&& !player.InvBody[invloc].isEmpty()
&& CouldFitItemInInventory(player, player.InvBody[invloc], iv)) {
holdItem = player.InvBody[invloc].pop();
}
automaticallyMoved = AutoEquip(player, player.InvList[iv], true, &player == MyPlayer);
if (automaticallyMoved) {
successSound = ItemInvSnds[ItemCAnimTbl[player.InvList[iv]._iCurs]];
player.RemoveInvItem(iv, false);

// If we're holding an item at this point we just lifted it from a body slot to make room for the original item, so we need to put it into the inv
if (!holdItem.isEmpty() && AutoPlaceItemInInventory(player, holdItem)) {
holdItem.clear();
} // there should never be a situation where holdItem is not empty but we fail to place it into the inventory given the checks earlier... leave it on the hand in this case.
} else if (!holdItem.isEmpty()) {
// We somehow failed to equip the item in the slot we already checked should hold it? Better put this item back...
player.InvBody[invloc] = holdItem.pop();
}
}
} else {
Expand Down

0 comments on commit 1012595

Please sign in to comment.