Skip to content

Commit

Permalink
[Bug] fixes clone items in market, checking if item exists in depot b…
Browse files Browse the repository at this point in the history
…efore create a offer (opentibiabr#736)
  • Loading branch information
carlospess0a authored and dudantas committed Feb 7, 2023
1 parent e707a93 commit 9d1b284
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 17 deletions.
17 changes: 17 additions & 0 deletions src/creatures/players/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6305,6 +6305,23 @@ std::pair<std::vector<Item*>, std::map<uint16_t, std::map<uint8_t, uint32_t>>> P
return std::make_pair(itemVector, lockerItems);
}

std::pair<std::vector<Item*>, uint16_t> Player::getLockerItemsAndCountById(DepotLocker &depotLocker, uint8_t tier, uint16_t itemId)
{
std::vector<Item*> lockerItems;
auto [itemVector, itemMap] = requestLockerItems(&depotLocker, false, tier);
uint16_t totalCount = 0;
for (auto item : itemVector) {
if (!item || item->getID() != itemId) {
continue;
}

totalCount++;
lockerItems.push_back(item);
}

return std::make_pair(lockerItems, totalCount);
}

bool Player::saySpell(
SpeakClasses type,
const std::string& text,
Expand Down
14 changes: 14 additions & 0 deletions src/creatures/players/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -2056,6 +2056,20 @@ class Player final : public Creature, public Cylinder

std::pair<std::vector<Item*>, std::map<uint16_t, std::map<uint8_t, uint32_t>>> requestLockerItems(DepotLocker *depotLocker, bool sendToClient = false, uint8_t tier = 0) const;

/**
This function returns a pair of an array of items and a 16-bit integer from a DepotLocker instance, a 8-bit byte and a 16-bit integer.
@param depotLocker The instance of DepotLocker from which to retrieve items.
@param tier The 8-bit byte that specifies the level of the tier to search.
@param itemId The 16-bit integer that specifies the ID of the item to search for.
@return A pair of an array of items and a 16-bit integer, where the array of items is filled with all items from the
locker with the specified id and the 16-bit integer is the total items found.
*/
std::pair<std::vector<Item*>, uint16_t> getLockerItemsAndCountById(
DepotLocker &depotLocker,
uint8_t tier,
uint16_t itemId
);

bool saySpell(
SpeakClasses type,
const std::string& text,
Expand Down
50 changes: 33 additions & 17 deletions src/game/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2126,9 +2126,12 @@ Item* Game::transformItem(Item* item, uint16_t newId, int32_t newCount /*= -1*/)

ReturnValue Game::internalTeleport(Thing* thing, const Position& newPos, bool pushMove/* = true*/, uint32_t flags /*= 0*/)
{
if (newPos == thing->getPosition()) {
return RETURNVALUE_NOERROR;
} else if (thing->isRemoved()) {
if (thing == nullptr) {
SPDLOG_ERROR("[{}] thing is nullptr", __FUNCTION__);
return RETURNVALUE_NOTPOSSIBLE;
}

if (thing->isRemoved()) {
return RETURNVALUE_NOTPOSSIBLE;
}

Expand Down Expand Up @@ -7419,7 +7422,8 @@ void Game::playerBrowseMarketOwnHistory(uint32_t playerId)
player->sendMarketBrowseOwnHistory(buyOffers, sellOffers);
}

void removeOfferItems(Player &player, DepotLocker &depotLocker, const ItemType &itemType, uint16_t amount, uint8_t tier, std::ostringstream &offerStatus)
namespace {
bool removeOfferItems(Player &player, DepotLocker &depotLocker, const ItemType &itemType, uint16_t amount, uint8_t tier, std::ostringstream &offerStatus)
{
uint16_t removeAmount = amount;
if (
Expand All @@ -7435,15 +7439,20 @@ void removeOfferItems(Player &player, DepotLocker &depotLocker, const ItemType &
removeAmount = 0;
} else {
offerStatus << "Failed to remove stash items from player " << player.getName();
return;
return false;
}
}

auto [itemVector, totalCount] = player.getLockerItemsAndCountById(depotLocker, tier, itemType.id);
if (removeAmount > 0) {
auto [itemVector, itemMap] = player.requestLockerItems(&depotLocker, false, tier);
if (totalCount == 0 || itemVector.size() == 0) {
offerStatus << "Player " << player.getName() << " not have item for create offer";
return false;
}

uint32_t count = 0;
for (auto item : itemVector) {
if (itemType.id != item->getID()) {
if (!item) {
continue;
}

Expand All @@ -7457,29 +7466,30 @@ void removeOfferItems(Player &player, DepotLocker &depotLocker, const ItemType &
ret != RETURNVALUE_NOERROR
)
{
SPDLOG_ERROR("{} - Create offer internal remove item error code: {}", __FUNCTION__, ret);
offerStatus << "Failed to remove items from player " << player.getName();
break;
offerStatus << "Failed to remove items from player " << player.getName() << " error: " << getReturnMessage(ret);
return false;
}

if (removeAmount == 0) {
break;
return false;
}
} else {
count += Item::countByType(item, -1);
if (count > amount) {
break;
offerStatus << "Current count value " << count << " is greater than expected amount value " << amount;
return false;
}
auto ret = g_game().internalRemoveItem(item);
if (ret != RETURNVALUE_NOERROR) {
SPDLOG_ERROR("{} - Create offer internal remove item error code: {}", __FUNCTION__, ret);
offerStatus << "Failed to remove items from player " << player.getName();
break;
offerStatus << "Failed to remove items from player " << player.getName() << " error: " << getReturnMessage(ret);
return false;
}
}
}
}
return true;
}
} // namespace

bool checkCanInitCreateMarketOffer(const Player *player, uint8_t type, const ItemType &it, uint16_t amount, uint64_t price, std::ostringstream &offerStatus)
{
Expand Down Expand Up @@ -7582,7 +7592,10 @@ void Game::playerCreateMarketOffer(uint32_t playerId, uint8_t type, uint16_t ite

account.RemoveCoins(static_cast<uint32_t>(amount));
} else {
removeOfferItems(*player, *depotLocker, it, amount, tier, offerStatus);
if (!removeOfferItems(*player, *depotLocker, it, amount, tier, offerStatus)) {
SPDLOG_ERROR("[{}] failed to remove item with id {}, from player {}, errorcode: {}", __FUNCTION__, it.id, player->getName(), offerStatus.str());
return;
}
}

g_game().removeMoney(player, fee, 0, true);
Expand Down Expand Up @@ -7792,7 +7805,10 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16
account.RegisterCoinsTransaction(account::COIN_REMOVE, amount,
"Sold on Market");
} else {
removeOfferItems(*player, *depotLocker, it, amount, offer.tier, offerStatus);
if (!removeOfferItems(*player, *depotLocker, it, amount, offer.tier, offerStatus)) {
SPDLOG_ERROR("[{}] failed to remove item with id {}, from player {}, errorcode: {}", __FUNCTION__, it.id, player->getName(), offerStatus.str());
return;
}
}
player->setBankBalance(player->getBankBalance() + totalPrice);

Expand Down

0 comments on commit 9d1b284

Please sign in to comment.