Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: clone items in market, checking if item exists in depot before creating an offer #736

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
carlospess0a marked this conversation as resolved.
Show resolved Hide resolved
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