diff --git a/data/items/items.xml b/data/items/items.xml
index 75d92f76447..9419a89262b 100644
--- a/data/items/items.xml
+++ b/data/items/items.xml
@@ -37971,18 +37971,21 @@
-
+
-
+
-
+
@@ -37995,6 +37998,7 @@
-
+
@@ -38002,12 +38006,14 @@
-
+
-
+
@@ -38020,96 +38026,112 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -40302,10 +40324,12 @@
-
+
-
+
-
diff --git a/data/modules/scripts/gamestore/init.lua b/data/modules/scripts/gamestore/init.lua
index ee1315e4cdd..11fdd3866c4 100644
--- a/data/modules/scripts/gamestore/init.lua
+++ b/data/modules/scripts/gamestore/init.lua
@@ -1491,7 +1491,7 @@ function GameStore.processItemPurchase(player, offerId, offerCount, moveable)
end
local inbox = player:getSlotItem(CONST_SLOT_STORE_INBOX)
- if inbox and inbox:getEmptySlots() > offerCount then
+ if inbox then
for t = 1, offerCount do
local inboxItem = inbox:addItem(offerId, offerCount or 1)
if moveable ~= true and inboxItem then
@@ -1509,7 +1509,7 @@ function GameStore.processChargesPurchase(player, itemtype, name, charges, movea
end
local inbox = player:getSlotItem(CONST_SLOT_STORE_INBOX)
- if inbox and inbox:getEmptySlots() > 1 then
+ if inbox then
local inboxItem = inbox:addItem(itemtype, charges)
if moveable ~= true and inboxItem then
@@ -1570,7 +1570,7 @@ function GameStore.processStackablePurchase(player, offerId, offerCount, offerNa
end
local inbox = player:getSlotItem(CONST_SLOT_STORE_INBOX)
- if inbox and inbox:getEmptySlots() > 0 then
+ if inbox then
if (isKeg and offerCount > 500) or offerCount > 100 then
local parcel = inbox:addItem(PARCEL_ID, 1)
parcel:setAttribute(ITEM_ATTRIBUTE_STORE, systemTime());
@@ -1627,7 +1627,7 @@ function GameStore.processHouseRelatedPurchase(player, offer)
if type(itemIds) ~= "table" then
itemIds = { itemIds }
end
- if inbox and inbox:getEmptySlots() >= #itemIds then
+ if inbox then
for _, itemId in ipairs(itemIds) do
local decoKit = inbox:addItem(23398, 1)
if decoKit then
@@ -1642,6 +1642,7 @@ function GameStore.processHouseRelatedPurchase(player, offer)
end
end
end
+ player:sendUpdateContainer(inbox)
else
return error({ code = 0, message = "Please make sure you have free slots in your store inbox." })
end
diff --git a/src/config/config_definitions.hpp b/src/config/config_definitions.hpp
index f6df1d37b46..56c68b5db5e 100644
--- a/src/config/config_definitions.hpp
+++ b/src/config/config_definitions.hpp
@@ -154,7 +154,7 @@ enum integerConfig_t {
STATUS_PORT,
STAIRHOP_DELAY,
MAX_CONTAINER,
- MAX_ITEM,
+ MAX_CONTAINER_ITEM,
MARKET_OFFER_DURATION,
DEPOT_BOXES,
FREE_DEPOT_LIMIT,
diff --git a/src/config/configmanager.cpp b/src/config/configmanager.cpp
index 5bed1cd17ba..8fa823fe96e 100644
--- a/src/config/configmanager.cpp
+++ b/src/config/configmanager.cpp
@@ -233,7 +233,7 @@ bool ConfigManager::load() {
integer[WHITE_SKULL_TIME] = getGlobalNumber(L, "whiteSkullTime", 15 * 60 * 1000);
integer[STAIRHOP_DELAY] = getGlobalNumber(L, "stairJumpExhaustion", 2000);
integer[MAX_CONTAINER] = getGlobalNumber(L, "maxContainer", 500);
- integer[MAX_ITEM] = getGlobalNumber(L, "maxItem", 10000);
+ integer[MAX_CONTAINER_ITEM] = getGlobalNumber(L, "maxItem", 5000);
integer[EXP_FROM_PLAYERS_LEVEL_RANGE] = getGlobalNumber(L, "expFromPlayersLevelRange", 75);
integer[CHECK_EXPIRED_MARKET_OFFERS_EACH_MINUTES] = getGlobalNumber(L, "checkExpiredMarketOffersEachMinutes", 60);
integer[MAX_MARKET_OFFERS_AT_A_TIME_PER_PLAYER] = getGlobalNumber(L, "maxMarketOffersAtATimePerPlayer", 100);
diff --git a/src/enums/item_attribute.hpp b/src/enums/item_attribute.hpp
index 40934aa61ee..a245f3d5eb9 100644
--- a/src/enums/item_attribute.hpp
+++ b/src/enums/item_attribute.hpp
@@ -44,6 +44,7 @@ enum ItemAttribute_t : uint64_t {
STORE = 31,
CUSTOM = 32,
LOOTMESSAGE_SUFFIX = 33,
+ STORE_INBOX_CATEGORY = 34,
};
enum ItemDecayState_t : uint8_t {
diff --git a/src/game/game.cpp b/src/game/game.cpp
index 2564736aefc..da9aec2d660 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -4108,7 +4108,7 @@ void Game::playerStashWithdraw(uint32_t playerId, uint16_t itemId, uint32_t coun
}
}
-void Game::playerSeekInContainer(uint32_t playerId, uint8_t containerId, uint16_t index) {
+void Game::playerSeekInContainer(uint32_t playerId, uint8_t containerId, uint16_t index, uint8_t containerCategory) {
Player* player = getPlayerByID(playerId);
if (!player) {
return;
@@ -4119,6 +4119,12 @@ void Game::playerSeekInContainer(uint32_t playerId, uint8_t containerId, uint16_
return;
}
+ if (container->getID() == ITEM_STORE_INBOX) {
+ auto enumName = magic_enum::enum_name(static_cast(containerCategory)).data();
+ container->setAttribute(ItemAttribute_t::STORE_INBOX_CATEGORY, enumName);
+ g_logger().debug("Setting new container with store inbox category name {}", enumName);
+ }
+
if ((index % container->capacity()) != 0 || index >= container->size()) {
return;
}
diff --git a/src/game/game.hpp b/src/game/game.hpp
index 8b7f7597e5d..4ebc928f4ff 100644
--- a/src/game/game.hpp
+++ b/src/game/game.hpp
@@ -295,7 +295,7 @@ class Game {
void playerWrapableItem(uint32_t playerId, const Position &pos, uint8_t stackPos, const uint16_t itemId);
void playerWriteItem(uint32_t playerId, uint32_t windowTextId, const std::string &text);
void playerBrowseField(uint32_t playerId, const Position &pos);
- void playerSeekInContainer(uint32_t playerId, uint8_t containerId, uint16_t index);
+ void playerSeekInContainer(uint32_t playerId, uint8_t containerId, uint16_t index, uint8_t containerCategory);
void playerUpdateHouseWindow(uint32_t playerId, uint8_t listId, uint32_t windowTextId, const std::string &text);
void playerRequestTrade(uint32_t playerId, const Position &pos, uint8_t stackPos, uint32_t tradePlayerId, uint16_t itemId);
void playerAcceptTrade(uint32_t playerId);
diff --git a/src/items/containers/container.cpp b/src/items/containers/container.cpp
index 8c1683c47cd..723760ac781 100644
--- a/src/items/containers/container.cpp
+++ b/src/items/containers/container.cpp
@@ -16,8 +16,11 @@
Container::Container(uint16_t type) :
Container(type, items[type].maxItems) {
- if (getID() == ITEM_GOLD_POUCH) {
+ m_maxItems = static_cast(g_configManager().getNumber(MAX_CONTAINER_ITEM));
+ if (getID() == ITEM_GOLD_POUCH || getID() == ITEM_STORE_INBOX) {
pagination = true;
+ m_maxItems = 2000;
+ maxSize = 32;
}
}
@@ -371,22 +374,21 @@ ReturnValue Container::queryAdd(int32_t addIndex, const Thing &addThing, uint32_
}
if (const Container* topParentContainer = getTopParentContainer()) {
- uint32_t maxItem = static_cast(g_configManager().getNumber(MAX_ITEM));
if (const Container* addContainer = item->getContainer()) {
uint32_t addContainerCount = addContainer->getContainerHoldingCount() + 1;
uint32_t maxContainer = static_cast(g_configManager().getNumber(MAX_CONTAINER));
if (addContainerCount + topParentContainer->getContainerHoldingCount() > maxContainer) {
- return RETURNVALUE_NOTPOSSIBLE;
+ return RETURNVALUE_CONTAINERISFULL;
}
uint32_t addItemCount = addContainer->getItemHoldingCount() + 1;
- if (addItemCount + topParentContainer->getItemHoldingCount() > maxItem) {
- return RETURNVALUE_NOTPOSSIBLE;
+ if (addItemCount + topParentContainer->getItemHoldingCount() > m_maxItems) {
+ return RETURNVALUE_CONTAINERISFULL;
}
}
- if (topParentContainer->getItemHoldingCount() + 1 > maxItem) {
- return RETURNVALUE_NOTPOSSIBLE;
+ if (topParentContainer->getItemHoldingCount() + 1 > m_maxItems) {
+ return RETURNVALUE_CONTAINERISFULL;
}
}
diff --git a/src/items/containers/container.hpp b/src/items/containers/container.hpp
index 30bc4003229..3ea2a2ac1a2 100644
--- a/src/items/containers/container.hpp
+++ b/src/items/containers/container.hpp
@@ -168,6 +168,7 @@ class Container : public Item, public Cylinder {
protected:
std::ostringstream &getContentDescription(std::ostringstream &os, bool oldProtocol) const;
+ uint32_t m_maxItems;
uint32_t maxSize;
uint32_t totalWeight = 0;
ItemDeque itemlist;
diff --git a/src/items/functions/item/attribute.hpp b/src/items/functions/item/attribute.hpp
index 20cf4369435..4a68cc0ec7b 100644
--- a/src/items/functions/item/attribute.hpp
+++ b/src/items/functions/item/attribute.hpp
@@ -57,6 +57,7 @@ class ItemAttributeHelper {
case ItemAttribute_t::PLURALNAME:
case ItemAttribute_t::SPECIAL:
case ItemAttribute_t::LOOTMESSAGE_SUFFIX:
+ case ItemAttribute_t::STORE_INBOX_CATEGORY:
return true;
default:
return false;
diff --git a/src/items/functions/item/item_parse.cpp b/src/items/functions/item/item_parse.cpp
index b3324f8dd73..2172326f097 100644
--- a/src/items/functions/item/item_parse.cpp
+++ b/src/items/functions/item/item_parse.cpp
@@ -56,7 +56,6 @@ void ItemParse::initParse(const std::string &tmpStrValue, pugi::xml_node attribu
ItemParse::parseMagicLevelPoint(tmpStrValue, valueAttribute, itemType);
ItemParse::parseFieldAbsorbPercent(tmpStrValue, valueAttribute, itemType);
ItemParse::parseAbsorbPercent(tmpStrValue, valueAttribute, itemType);
-
ItemParse::parseSupressDrunk(tmpStrValue, valueAttribute, itemType);
ItemParse::parseField(tmpStrValue, attributeNode, valueAttribute, itemType);
ItemParse::parseReplaceable(tmpStrValue, valueAttribute, itemType);
@@ -73,6 +72,7 @@ void ItemParse::initParse(const std::string &tmpStrValue, pugi::xml_node attribu
ItemParse::parseCleavePercent(tmpStrValue, valueAttribute, itemType);
ItemParse::parseReflectDamage(tmpStrValue, valueAttribute, itemType);
ItemParse::parseTransformOnUse(tmpStrValue, valueAttribute, itemType);
+ ItemParse::parsePrimaryType(tmpStrValue, valueAttribute, itemType);
}
void ItemParse::parseDummyRate(pugi::xml_node attributeNode, ItemType &itemType) {
@@ -940,3 +940,9 @@ void ItemParse::parseTransformOnUse(const std::string_view &tmpStrValue, pugi::x
itemType.m_transformOnUse = pugi::cast(valueAttribute.value());
}
}
+
+void ItemParse::parsePrimaryType(const std::string_view &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType) {
+ if (tmpStrValue == "primarytype") {
+ itemType.m_primaryType = asLowerCaseString(valueAttribute.as_string());
+ }
+}
diff --git a/src/items/functions/item/item_parse.hpp b/src/items/functions/item/item_parse.hpp
index 28a8e71fc53..510129df918 100644
--- a/src/items/functions/item/item_parse.hpp
+++ b/src/items/functions/item/item_parse.hpp
@@ -155,6 +155,7 @@ const phmap::flat_hash_map ItemParseAttribut
{ "cleavepercent", ITEM_PARSE_CLEAVEPERCENT },
{ "reflectdamage", ITEM_PARSE_REFLECTDAMAGE },
{ "reflectpercentall", ITEM_PARSE_REFLECTPERCENTALL },
+ { "primarytype", ITEM_PARSE_PRIMARYTYPE },
};
const phmap::flat_hash_map ItemTypesMap = {
@@ -308,6 +309,7 @@ class ItemParse : public Items {
static void parseCleavePercent(const std::string &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType);
static void parseReflectDamage(const std::string &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType);
static void parseTransformOnUse(const std::string_view &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType);
+ static void parsePrimaryType(const std::string_view &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType);
private:
// Parent of the function: static void parseField
diff --git a/src/items/item.cpp b/src/items/item.cpp
index a33ce1c39dd..5dca9c257e5 100644
--- a/src/items/item.cpp
+++ b/src/items/item.cpp
@@ -794,6 +794,17 @@ Attr_ReadValue Item::readAttr(AttrTypes_t attr, PropStream &propStream) {
break;
}
+ case ATTR_STORE_INBOX_CATEGORY: {
+ std::string category;
+ if (!propStream.readString(category)) {
+ g_logger().error("[{}] failed to read store inbox category from item {}", __FUNCTION__, getName());
+ return ATTR_READ_ERROR;
+ }
+
+ setAttribute(ItemAttribute_t::STORE_INBOX_CATEGORY, category);
+ break;
+ }
+
default:
return ATTR_READ_ERROR;
}
@@ -954,6 +965,10 @@ void Item::serializeAttr(PropWriteStream &propWriteStream) const {
propWriteStream.write(ATTR_AMOUNT);
propWriteStream.write(getAttribute(AMOUNT));
}
+ if (hasAttribute(STORE_INBOX_CATEGORY)) {
+ propWriteStream.write(ATTR_STORE_INBOX_CATEGORY);
+ propWriteStream.writeString(getString(ItemAttribute_t::STORE_INBOX_CATEGORY));
+ }
// Serialize custom attributes, only serialize if the map not is empty
if (hasCustomAttribute()) {
diff --git a/src/items/item.hpp b/src/items/item.hpp
index 2d4c3a5a4d2..c6b3f82413f 100644
--- a/src/items/item.hpp
+++ b/src/items/item.hpp
@@ -35,7 +35,7 @@ class Item;
class ItemProperties {
public:
template
- T getAttribute(ItemAttribute_t type) const {
+ const T &getAttribute(ItemAttribute_t type) const {
if constexpr (std::is_same_v) {
return getString(type);
} else {
@@ -46,7 +46,9 @@ class ItemProperties {
);
}
g_logger().error("Failed to convert attribute for type {}", fmt::underlying(type));
- return {};
+
+ static T defaultType;
+ return defaultType;
}
bool hasAttribute(ItemAttribute_t type) const {
diff --git a/src/items/items.hpp b/src/items/items.hpp
index 59a65d0d8db..6e58cddd19c 100644
--- a/src/items/items.hpp
+++ b/src/items/items.hpp
@@ -233,6 +233,7 @@ class ItemType {
std::string description;
std::string runeSpellName;
std::string vocationString;
+ std::string m_primaryType;
std::unique_ptr abilities;
std::unique_ptr conditionDamage;
diff --git a/src/items/items_definitions.hpp b/src/items/items_definitions.hpp
index 85dee43bf1a..fec5c424fb8 100644
--- a/src/items/items_definitions.hpp
+++ b/src/items/items_definitions.hpp
@@ -60,6 +60,7 @@ enum ReturnValue {
RETURNVALUE_CANNOTPICKUP,
RETURNVALUE_THISISIMPOSSIBLE,
RETURNVALUE_DEPOTISFULL,
+ RETURNVALUE_CONTAINERISFULL,
RETURNVALUE_CREATUREDOESNOTEXIST,
RETURNVALUE_CANNOTUSETHISOBJECT,
RETURNVALUE_PLAYERWITHTHISNAMEISNOTONLINE,
@@ -234,6 +235,7 @@ enum AttrTypes_t {
ATTR_AMOUNT = 39,
ATTR_TIER = 40,
ATTR_CUSTOM = 41,
+ ATTR_STORE_INBOX_CATEGORY = 42,
// Always the last
ATTR_NONE = 0
@@ -261,6 +263,15 @@ enum ImbuementTypes_t : int64_t {
IMBUEMENT_INCREASE_CAPACITY = 17
};
+enum class StoreInboxCategory_t : uint8_t {
+ All,
+ Consumable,
+ Bundle,
+ Furniture,
+ Houses,
+ Extra
+};
+
enum SlotPositionBits : uint32_t {
SLOTP_WHEREEVER = 0xFFFFFFFF,
SLOTP_HEAD = 1 << 0,
@@ -465,6 +476,7 @@ enum ItemParseAttributes_t {
ITEM_PARSE_CLEAVEPERCENT,
ITEM_PARSE_REFLECTPERCENTALL,
ITEM_PARSE_REFLECTDAMAGE,
+ ITEM_PARSE_PRIMARYTYPE,
};
struct ImbuementInfo {
diff --git a/src/lua/functions/creatures/player/player_functions.cpp b/src/lua/functions/creatures/player/player_functions.cpp
index c616053a5e4..ec76c89e735 100644
--- a/src/lua/functions/creatures/player/player_functions.cpp
+++ b/src/lua/functions/creatures/player/player_functions.cpp
@@ -1894,6 +1894,25 @@ int PlayerFunctions::luaPlayerSendContainer(lua_State* L) {
return 1;
}
+int PlayerFunctions::luaPlayerSendUpdateContainer(lua_State* L) {
+ // player:sendUpdateContainer(container)
+ Player* player = getUserdata(L, 1);
+ if (!player) {
+ lua_pushnil(L);
+ return 1;
+ }
+
+ Container* container = getUserdata(L, 2);
+ if (!container) {
+ reportErrorFunc("Container is nullptr");
+ return 1;
+ }
+
+ player->onSendContainer(container);
+ pushBoolean(L, true);
+ return 1;
+}
+
int PlayerFunctions::luaPlayerGetMoney(lua_State* L) {
// player:getMoney()
Player* player = getUserdata(L, 1);
diff --git a/src/lua/functions/creatures/player/player_functions.hpp b/src/lua/functions/creatures/player/player_functions.hpp
index 294c77de52e..83abc83b1f4 100644
--- a/src/lua/functions/creatures/player/player_functions.hpp
+++ b/src/lua/functions/creatures/player/player_functions.hpp
@@ -173,6 +173,7 @@ class PlayerFunctions final : LuaScriptInterface {
registerMethod(L, "Player", "removeStashItem", PlayerFunctions::luaPlayerRemoveStashItem);
registerMethod(L, "Player", "removeItem", PlayerFunctions::luaPlayerRemoveItem);
registerMethod(L, "Player", "sendContainer", PlayerFunctions::luaPlayerSendContainer);
+ registerMethod(L, "Player", "sendUpdateContainer", PlayerFunctions::luaPlayerSendUpdateContainer);
registerMethod(L, "Player", "getMoney", PlayerFunctions::luaPlayerGetMoney);
registerMethod(L, "Player", "addMoney", PlayerFunctions::luaPlayerAddMoney);
@@ -503,6 +504,7 @@ class PlayerFunctions final : LuaScriptInterface {
static int luaPlayerRemoveStashItem(lua_State* L);
static int luaPlayerRemoveItem(lua_State* L);
static int luaPlayerSendContainer(lua_State* L);
+ static int luaPlayerSendUpdateContainer(lua_State* L);
static int luaPlayerGetMoney(lua_State* L);
static int luaPlayerAddMoney(lua_State* L);
diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp
index d2c435663bd..dd386e13a0b 100644
--- a/src/server/network/protocol/protocolgame.cpp
+++ b/src/server/network/protocol/protocolgame.cpp
@@ -207,6 +207,33 @@ namespace {
}
}
}
+
+ /**
+ * @brief Sends the container category to the network message.
+ *
+ * @note The default value is "all", which is the first enum (0). The message must always start with "All".
+ *
+ * @details for example of enum see the StoreInboxCategory_t
+ *
+ * @param msg The network message to send the category to.
+ */
+ template
+ void sendContainerCategory(NetworkMessage &msg, uint8_t categoryType = 0) {
+ msg.addByte(categoryType);
+
+ const uint8_t enumCount = magic_enum::enum_count();
+ msg.addByte(enumCount - 1);
+
+ for (auto value : magic_enum::enum_values()) {
+ if (value == T::All) {
+ continue;
+ }
+
+ msg.addByte(static_cast(value));
+ msg.addString(magic_enum::enum_name(value).data());
+ }
+ }
+
} // namespace
ProtocolGame::ProtocolGame(Connection_ptr initConnection) :
@@ -278,7 +305,7 @@ void ProtocolGame::AddItem(NetworkMessage &msg, uint16_t id, uint8_t count, uint
msg.addByte(0x01); // Brand-new
}
- if (it.isWrapKit) {
+ if (it.isWrapKit && !oldProtocol) {
msg.add(0x00);
}
}
@@ -409,7 +436,7 @@ void ProtocolGame::AddItem(NetworkMessage &msg, const Item* item) {
}
}
- if (it.isWrapKit) {
+ if (it.isWrapKit && !oldProtocol) {
uint16_t unWrapId = item->getCustomAttribute("unWrapId") ? static_cast(item->getCustomAttribute("unWrapId")->getInteger()) : 0;
if (unWrapId != 0) {
msg.add(unWrapId);
@@ -3092,7 +3119,8 @@ void ProtocolGame::parseBrowseField(NetworkMessage &msg) {
void ProtocolGame::parseSeekInContainer(NetworkMessage &msg) {
uint8_t containerId = msg.getByte();
uint16_t index = msg.get();
- addGameTask(&Game::playerSeekInContainer, player->getID(), containerId, index);
+ auto primaryType = msg.getByte();
+ addGameTask(&Game::playerSeekInContainer, player->getID(), containerId, index, primaryType);
}
// Send methods
@@ -4209,6 +4237,10 @@ void ProtocolGame::sendUnjustifiedPoints(const uint8_t &dayProgress, const uint8
}
void ProtocolGame::sendContainer(uint8_t cid, const Container* container, bool hasParent, uint16_t firstIndex) {
+ if (!player) {
+ return;
+ }
+
NetworkMessage msg;
msg.addByte(0x6E);
@@ -4222,6 +4254,22 @@ void ProtocolGame::sendContainer(uint8_t cid, const Container* container, bool h
msg.addString(container->getName());
}
+ const auto &enumName = container->getAttribute(ItemAttribute_t::STORE_INBOX_CATEGORY);
+ uint32_t totalCountToSend = 0;
+ std::vector
- itemsStoreInboxToSend;
+ if (container->getID() == ITEM_STORE_INBOX && enumName != "All") {
+ for (Item* item : container->getItemList()) {
+ uint16_t unWrapId = item->getCustomAttribute("unWrapId") ? static_cast(item->getCustomAttribute("unWrapId")->getInteger()) : 0;
+ if (unWrapId != 0) {
+ const auto &itemType = Item::items.getItemType(unWrapId);
+ if (itemType.m_primaryType == asLowerCaseString(enumName)) {
+ itemsStoreInboxToSend.push_back(item);
+ totalCountToSend++;
+ }
+ }
+ }
+ }
+
msg.addByte(container->capacity());
msg.addByte(hasParent ? 0x01 : 0x00);
@@ -4235,6 +4283,9 @@ void ProtocolGame::sendContainer(uint8_t cid, const Container* container, bool h
msg.addByte(container->hasPagination() ? 0x01 : 0x00); // Pagination
uint32_t containerSize = container->size();
+ if (totalCountToSend != 0) {
+ containerSize = totalCountToSend;
+ }
msg.add(containerSize);
msg.add(firstIndex);
@@ -4248,6 +4299,11 @@ void ProtocolGame::sendContainer(uint8_t cid, const Container* container, bool h
if (firstIndex >= containerSize) {
msg.addByte(0x00);
+ } else if (container->getID() == ITEM_STORE_INBOX && !itemsStoreInboxToSend.empty()) {
+ msg.addByte(std::min(maxItemsToSend, containerSize));
+ for (const auto item : itemsStoreInboxToSend) {
+ AddItem(msg, item);
+ }
} else {
msg.addByte(std::min(maxItemsToSend, containerSize));
@@ -4256,9 +4312,20 @@ void ProtocolGame::sendContainer(uint8_t cid, const Container* container, bool h
for (ItemDeque::const_iterator it = itemList.begin() + firstIndex, end = itemList.end(); i < maxItemsToSend && it != end; ++it, ++i) {
AddItem(msg, *it);
}
+ }
- msg.addByte(0x00);
- msg.addByte(0x00);
+ if (!oldProtocol) {
+ if (container->getID() == ITEM_STORE_INBOX) {
+ auto category = magic_enum::enum_cast(enumName);
+ if (category.has_value()) {
+ sendContainerCategory(msg, static_cast(category.value()));
+ } else {
+ sendContainerCategory(msg);
+ }
+ } else {
+ msg.addByte(0x00);
+ msg.addByte(0x00);
+ }
}
writeToOutputBuffer(msg);
}
diff --git a/src/utils/tools.cpp b/src/utils/tools.cpp
index e990e8ba8a3..09e0867472e 100644
--- a/src/utils/tools.cpp
+++ b/src/utils/tools.cpp
@@ -1258,6 +1258,9 @@ const char* getReturnMessage(ReturnValue value) {
case RETURNVALUE_DEPOTISFULL:
return "You cannot put more items in this depot.";
+ case RETURNVALUE_CONTAINERISFULL:
+ return "You cannot put more items in this container.";
+
case RETURNVALUE_CANNOTUSETHISOBJECT:
return "You cannot use this object.";