Skip to content

Commit

Permalink
feat: add again remove reward containers if is empty (#1610)
Browse files Browse the repository at this point in the history
The feature was originally reverted due to concerns about security and stability, as detailed in pull request: #1364.

Having since stabilized the underlying foundation by transitioning from raw pointers to automatic memory management, we are now able to re-implement this feature safely.
  • Loading branch information
dudantas authored Oct 21, 2023
1 parent 15f7d01 commit 4ad577d
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/creatures/players/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -790,11 +790,31 @@ void Player::closeContainer(uint8_t cid) {
OpenContainer openContainer = it->second;
std::shared_ptr<Container> container = openContainer.container;

if (container && container->isAnyKindOfRewardChest() && !hasOtherRewardContainerOpen(container)) {
removeEmptyRewards();
}
openContainers.erase(it);
if (container && container->getID() == ITEM_BROWSEFIELD) {
}
}

void Player::removeEmptyRewards() {
std::erase_if(rewardMap, [this](const auto &rewardBag) {
auto [id, reward] = rewardBag;
if (reward->empty()) {
getRewardChest()->removeItem(reward);
return true;
}
return false;
});
}

bool Player::hasOtherRewardContainerOpen(const std::shared_ptr<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()) {
Expand Down
3 changes: 3 additions & 0 deletions src/creatures/players/player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2915,4 +2915,7 @@ class Player final : public Creature, public Cylinder, public Bankable {
void updateDamageReductionFromItemImbuement(std::array<double_t, COMBAT_COUNT> &combatReductionMap, std::shared_ptr<Item> item, uint16_t combatTypeIndex) const;
void updateDamageReductionFromItemAbility(std::array<double_t, COMBAT_COUNT> &combatReductionMap, std::shared_ptr<Item> item, uint16_t combatTypeIndex) const;
double_t calculateDamageReduction(double_t currentTotal, int16_t resistance) const;

void removeEmptyRewards();
bool hasOtherRewardContainerOpen(const std::shared_ptr<Container> container) const;
};
23 changes: 23 additions & 0 deletions src/items/containers/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,29 @@ bool Container::isHoldingItemWithId(const uint16_t id) {
return false;
}

bool Container::isInsideContainerWithId(const uint16_t id) {
auto nextParent = getParent();
while (nextParent != nullptr && nextParent->getContainer()) {
if (nextParent->getContainer()->getID() == id) {
return true;
}
nextParent = nextParent->getRealParent();
}
return false;
}

bool Container::isAnyKindOfRewardChest() {
return getID() == ITEM_REWARD_CHEST || getID() == ITEM_REWARD_CONTAINER && getParent() && getParent()->getContainer() && getParent()->getContainer()->getID() == ITEM_REWARD_CHEST || isBrowseFieldAndHoldsRewardChest();
}

bool Container::isAnyKindOfRewardContainer() {
return getID() == ITEM_REWARD_CHEST || getID() == ITEM_REWARD_CONTAINER || isHoldingItemWithId(ITEM_REWARD_CONTAINER) || isInsideContainerWithId(ITEM_REWARD_CONTAINER);
}

bool Container::isBrowseFieldAndHoldsRewardChest() {
return getID() == ITEM_BROWSEFIELD && isHoldingItemWithId(ITEM_REWARD_CHEST);
}

void Container::onAddContainerItem(std::shared_ptr<Item> item) {
auto spectators = Spectators().find<Player>(getPosition(), false, 2, 2, 2, 2);

Expand Down
5 changes: 5 additions & 0 deletions src/items/containers/container.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ class Container : public Item, public Cylinder {

virtual void removeItem(std::shared_ptr<Thing> thing, bool sendUpdateToClient = false);

bool isAnyKindOfRewardChest();
bool isAnyKindOfRewardContainer();
bool isBrowseFieldAndHoldsRewardChest();
bool isInsideContainerWithId(const uint16_t id);

protected:
std::ostringstream &getContentDescription(std::ostringstream &os, bool oldProtocol);

Expand Down
4 changes: 4 additions & 0 deletions src/lua/creature/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,10 @@ ReturnValue Actions::internalUseItem(std::shared_ptr<Player> player, const Posit

// reward chest
if (container->getRewardChest() != nullptr && container->getParent()) {
if (!player->hasOtherRewardContainerOpen(container->getParent()->getContainer())) {
player->removeEmptyRewards();
}

std::shared_ptr<RewardChest> playerRewardChest = player->getRewardChest();
if (playerRewardChest->empty()) {
return RETURNVALUE_REWARDCHESTISEMPTY;
Expand Down

0 comments on commit 4ad577d

Please sign in to comment.