From 0d68aed1f734779b17ab65a31b4d9b60882167f1 Mon Sep 17 00:00:00 2001 From: Eric Robinson <68359262+kphoenix137@users.noreply.github.com> Date: Wed, 27 Mar 2024 13:37:55 -0400 Subject: [PATCH] Sort inventory (#7040) --- Source/diablo.cpp | 17 ++++++++++++ Source/inv.cpp | 66 +++++++++++++++++++++++++++++++++++++++++++++++ Source/inv.h | 5 ++++ 3 files changed, 88 insertions(+) diff --git a/Source/diablo.cpp b/Source/diablo.cpp index ab71edbe7..1130a5fc2 100644 --- a/Source/diablo.cpp +++ b/Source/diablo.cpp @@ -42,6 +42,7 @@ #include "help.h" #include "hwcursor.hpp" #include "init.h" +#include "inv.h" #include "levels/drlg_l1.h" #include "levels/drlg_l2.h" #include "levels/drlg_l3.h" @@ -1954,6 +1955,14 @@ void InitKeymapActions() [] { ToggleChatLog(); }); + sgOptions.Keymapper.AddAction( + "SortInv", + N_("Sort Inventory"), + N_("Sorts the inventory."), + 'R', + [] { + ReorganizeInventory(*MyPlayer); + }); #ifdef _DEBUG sgOptions.Keymapper.AddAction( "OpenConsole", @@ -2423,6 +2432,14 @@ void InitPadmapActions() }, nullptr, CanPlayerTakeAction); + sgOptions.Padmapper.AddAction( + "SortInv", + N_("Sort Inventory"), + N_("Sorts the inventory."), + ControllerButton_NONE, + [] { + ReorganizeInventory(*MyPlayer); + }); sgOptions.Padmapper.AddAction( "ChatLog", N_("Chat Log"), diff --git a/Source/inv.cpp b/Source/inv.cpp index cc5eb5fae..f10da7574 100644 --- a/Source/inv.cpp +++ b/Source/inv.cpp @@ -1362,6 +1362,72 @@ bool AutoPlaceItemInInventory(Player &player, const Item &item, bool persistItem app_fatal(StrCat("Unknown item size: ", itemSize.width, "x", itemSize.height)); } +std::vector SortItemsBySize(Player &player) +{ + std::vector> itemSizes; // Pair of item size and its index in InvList + itemSizes.reserve(player._pNumInv); // Reserves space for the number of items in the player's inventory + + for (int i = 0; i < player._pNumInv; i++) { + Size size = GetInventorySize(player.InvList[i]); + itemSizes.emplace_back(size, i); + } + + // Sort items by height first, then by width + std::sort(itemSizes.begin(), itemSizes.end(), [](const auto &a, const auto &b) { + if (a.first.height == b.first.height) return a.first.width > b.first.width; + return a.first.height > b.first.height; + }); + + // Extract sorted indices + std::vector sortedIndices; + sortedIndices.reserve(itemSizes.size()); // Pre-allocate the necessary capacity + + for (const auto &itemSize : itemSizes) { + sortedIndices.push_back(itemSize.second); + } + + return sortedIndices; +} + +void ReorganizeInventory(Player &player) +{ + // Sort items by size + std::vector sortedIndices = SortItemsBySize(player); + + // Temporary storage for items and a copy of InvGrid + std::vector tempStorage(player._pNumInv); + std::array originalInvGrid; // Declare an array for InvGrid copy + std::copy(std::begin(player.InvGrid), std::end(player.InvGrid), std::begin(originalInvGrid)); // Copy InvGrid to originalInvGrid + + // Move items to temporary storage and clear inventory slots + for (int i = 0; i < player._pNumInv; ++i) { + tempStorage[i] = player.InvList[i]; + player.InvList[i] = {}; + } + player._pNumInv = 0; // Reset inventory count + std::fill(std::begin(player.InvGrid), std::end(player.InvGrid), 0); // Clear InvGrid + + // Attempt to place items back, now from the temp storage + bool reorganizationFailed = false; + for (int index : sortedIndices) { + Item &item = tempStorage[index]; + if (!AutoPlaceItemInInventory(player, item, true, false)) { + reorganizationFailed = true; + break; + } + } + + // If reorganization failed, restore items and InvGrid from tempStorage and originalInvGrid + if (reorganizationFailed) { + for (Item &item : tempStorage) { + if (!item.isEmpty()) { + player.InvList[player._pNumInv++] = item; + } + } + std::copy(std::begin(originalInvGrid), std::end(originalInvGrid), std::begin(player.InvGrid)); // Restore InvGrid + } +} + int RoomForGold() { int amount = 0; diff --git a/Source/inv.h b/Source/inv.h index e2adba649..b33af0e30 100644 --- a/Source/inv.h +++ b/Source/inv.h @@ -165,6 +165,11 @@ bool AutoPlaceItemInInventory(Player &player, const Item &item, bool persistItem */ bool AutoPlaceItemInBelt(Player &player, const Item &item, bool persistItem = false, bool sendNetworkMessage = false); +/** + * @brief Sort player inventory. + */ +void ReorganizeInventory(Player &player); + /** * @brief Calculate the maximum aditional gold that may fit in the user's inventory */