diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 9d9a5e9c54d..306f9ac83fe 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -803,12 +803,33 @@ void Player::closeContainer(uint8_t cid) { OpenContainer openContainer = it->second; Container* container = openContainer.container; + if (container && container->isAnyKindOfRewardChest() && !hasOtherRewardContainerOpen(container)) { + removeEmptyRewards(); + } openContainers.erase(it); if (container && container->getID() == ITEM_BROWSEFIELD) { container->decrementReferenceCounter(); } } +void Player::removeEmptyRewards() { + std::erase_if(rewardMap, [this](const auto &rewardBag) { + auto [id, reward] = rewardBag; + if (reward->empty()) { + getRewardChest()->removeItem(reward); + reward->decrementReferenceCounter(); + return true; + } + return false; + }); +} + +bool Player::hasOtherRewardContainerOpen(const Container* container) const { + return std::ranges::any_of(openContainers.begin(), openContainers.end(), [container](const auto &containerPair) { + return containerPair.second.container != container && containerPair.second.container->isAnyKindOfRewardContainer(); + }); +} + void Player::setContainerIndex(uint8_t cid, uint16_t index) { auto it = openContainers.find(cid); if (it == openContainers.end()) { diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 5f159f0ec37..5d9a2b94082 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -2898,4 +2898,7 @@ class Player final : public Creature, public Cylinder, public Bankable { void updateDamageReductionFromItemImbuement(std::array &combatReductionMap, Item* item, uint16_t combatTypeIndex) const; void updateDamageReductionFromItemAbility(std::array &combatReductionMap, const Item* item, uint16_t combatTypeIndex) const; double_t calculateDamageReduction(double_t currentTotal, int16_t resistance) const; + + void removeEmptyRewards(); + bool hasOtherRewardContainerOpen(const Container* container) const; }; diff --git a/src/items/containers/container.cpp b/src/items/containers/container.cpp index fbe9486c3bb..acc9d88f9ab 100644 --- a/src/items/containers/container.cpp +++ b/src/items/containers/container.cpp @@ -352,6 +352,29 @@ bool Container::isHoldingItemWithId(const uint16_t id) const { return false; } +bool Container::isInsideContainerWithId(const uint16_t id) const { + auto nextParent = parent; + while (nextParent != nullptr && nextParent->getContainer()) { + if (nextParent->getContainer()->getID() == id) { + return true; + } + nextParent = nextParent->getRealParent(); + } + return false; +} + +bool Container::isAnyKindOfRewardChest() const { + return getID() == ITEM_REWARD_CHEST || getID() == ITEM_REWARD_CONTAINER && parent && parent->getContainer() && parent->getContainer()->getID() == ITEM_REWARD_CHEST || isBrowseFieldAndHoldsRewardChest(); +} + +bool Container::isAnyKindOfRewardContainer() const { + return getID() == ITEM_REWARD_CHEST || getID() == ITEM_REWARD_CONTAINER || isHoldingItemWithId(ITEM_REWARD_CONTAINER) || isInsideContainerWithId(ITEM_REWARD_CONTAINER); +} + +bool Container::isBrowseFieldAndHoldsRewardChest() const { + return getID() == ITEM_BROWSEFIELD && isHoldingItemWithId(ITEM_REWARD_CHEST); +} + void Container::onAddContainerItem(Item* item) { SpectatorHashSet spectators; g_game().map.getSpectators(spectators, getPosition(), false, true, 2, 2, 2, 2); diff --git a/src/items/containers/container.hpp b/src/items/containers/container.hpp index b58929b3628..b758d83182e 100644 --- a/src/items/containers/container.hpp +++ b/src/items/containers/container.hpp @@ -170,6 +170,11 @@ class Container : public Item, public Cylinder { virtual void removeItem(Thing* thing, bool sendUpdateToClient = false); + bool isAnyKindOfRewardChest() const; + bool isAnyKindOfRewardContainer() const; + bool isBrowseFieldAndHoldsRewardChest() const; + bool isInsideContainerWithId(const uint16_t id) const; + protected: std::ostringstream &getContentDescription(std::ostringstream &os, bool oldProtocol) const; diff --git a/src/lua/creature/actions.cpp b/src/lua/creature/actions.cpp index 34fa1cba896..73bea2f4b43 100644 --- a/src/lua/creature/actions.cpp +++ b/src/lua/creature/actions.cpp @@ -310,6 +310,10 @@ ReturnValue Actions::internalUseItem(Player* player, const Position &pos, uint8_ // reward chest if (container->getRewardChest() != nullptr && container->getParent()) { + if (!player->hasOtherRewardContainerOpen(container->getParent()->getContainer())) { + player->removeEmptyRewards(); + } + RewardChest* playerRewardChest = player->getRewardChest(); if (playerRewardChest->empty()) { return RETURNVALUE_REWARDCHESTISEMPTY;