Core/Items: Implement Sell All Junk button at vendors

This commit is contained in:
agatho
2026-02-12 22:12:40 +01:00
committed by Shauren
parent 57166618f3
commit b18f615ddc
6 changed files with 94 additions and 1 deletions

View File

@@ -145,6 +145,7 @@ void WorldSession::SendFeatureSystemStatusGlueScreen()
WorldPackets::System::MirrorVarSingle vars[] =
{
{ "raidLockoutExtendEnabled"sv, "1"sv },
{ "sellAllJunkEnabled"sv, "1"sv },
{ "bypassItemLevelScalingCode"sv, "0"sv },
{ "shop2Enabled"sv, "0"sv },
{ "bpayStoreEnable"sv, "0"sv },

View File

@@ -427,6 +427,81 @@ void WorldSession::HandleSellItemOpcode(WorldPackets::Item::SellItem const& sell
_player->SendSellError(*sellResult, creature, sellItem.ItemGUID);
}
void WorldSession::HandleSellAllJunkItems(WorldPackets::Item::SellAllJunkItems const& sellAllJunkItems)
{
Creature* creature = GetPlayer()->GetNPCIfCanInteractWith(sellAllJunkItems.VendorGUID, UNIT_NPC_FLAG_VENDOR, UNIT_NPC_FLAG_2_NONE);
if (!creature)
{
_player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, nullptr, ObjectGuid::Empty);
return;
}
if ((creature->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_SELL_VENDOR) != 0)
{
_player->SendSellError(SELL_ERR_CANT_SELL_TO_THIS_MERCHANT, creature, ObjectGuid::Empty);
return;
}
// collect junk items first - can't modify inventory while iterating
std::vector<Item*> junkItems;
_player->ForEachItem(ItemSearchLocation::Inventory, [this, &junkItems](Item* item)
{
if (item->GetQuality() != ITEM_QUALITY_POOR)
return ItemSearchCallbackResult::Continue;
if (item->GetSellPrice(_player) == 0)
return ItemSearchCallbackResult::Continue;
if (item->IsRefundable())
return ItemSearchCallbackResult::Continue;
if (_player->GetLootGUID() == item->GetGUID())
return ItemSearchCallbackResult::Continue;
if (item->IsNotEmptyBag())
return ItemSearchCallbackResult::Continue;
// check per-bag junk sell exclusion
if (item->GetBagSlot() == INVENTORY_SLOT_BAG_0)
{
if (_player->IsBackpackSellJunkDisabled())
return ItemSearchCallbackResult::Continue;
}
else
{
uint32 bagIndex = item->GetBagSlot() - INVENTORY_SLOT_BAG_START;
if (bagIndex < _player->m_activePlayerData->BagSlotFlags.size()
&& _player->GetBagSlotFlags(bagIndex).HasFlag(BagSlotFlags::ExcludeJunkSell))
return ItemSearchCallbackResult::Continue;
}
junkItems.push_back(item);
return ItemSearchCallbackResult::Continue;
});
for (Item* item : junkItems)
{
uint32 sellPrice = item->GetSellPrice(_player);
uint64 money = uint64(sellPrice) * item->GetCount();
using BuybackStorageType = std::remove_cvref_t<decltype(_player->m_activePlayerData->BuybackPrice[0])>;
if (money > std::numeric_limits<BuybackStorageType>::max())
continue;
if (!_player->ModifyMoney(money))
continue;
_player->UpdateCriteria(CriteriaType::MoneyEarnedFromSales, money);
_player->UpdateCriteria(CriteriaType::SellItemsToVendors, 1);
_player->RemoveItem(item->GetBagSlot(), item->GetSlot(), true);
_player->ItemRemovedQuestCheck(item->GetEntry(), item->GetCount());
RemoveItemFromUpdateQueueOf(item, _player);
_player->AddItemToBuyBackSlot(item);
}
}
void WorldSession::HandleBuybackItem(WorldPackets::Item::BuyBackItem& packet)
{
TC_LOG_DEBUG("network", "WORLD: Received CMSG_BUYBACK_ITEM: Vendor {}, Slot: {}", packet.VendorGUID.ToString(), packet.Slot);

View File

@@ -137,6 +137,11 @@ void SellItem::Read()
_worldPacket >> Amount;
}
void SellAllJunkItems::Read()
{
_worldPacket >> VendorGUID;
}
WorldPacket const* ItemTimeUpdate::Write()
{
_worldPacket << ItemGuid;

View File

@@ -184,6 +184,16 @@ namespace WorldPackets
uint32 Amount = 0;
};
class SellAllJunkItems final : public ClientPacket
{
public:
explicit SellAllJunkItems(WorldPacket&& packet) : ClientPacket(CMSG_SELL_ALL_JUNK_ITEMS, std::move(packet)) { }
void Read() override;
ObjectGuid VendorGUID;
};
class ItemTimeUpdate final : public ServerPacket
{
public:

View File

@@ -990,7 +990,7 @@ void OpcodeTable::InitializeClientOpcodes()
DEFINE_HANDLER(CMSG_SEAMLESS_TRANSFER_COMPLETE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_SELECT_WOW_LABS_AREA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_SELF_RES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSelfResOpcode);
DEFINE_HANDLER(CMSG_SELL_ALL_JUNK_ITEMS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_SELL_ALL_JUNK_ITEMS, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSellAllJunkItems);
DEFINE_HANDLER(CMSG_SELL_ITEM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSellItemOpcode);
DEFINE_HANDLER(CMSG_SEND_CHARACTER_CLUB_INVITATION, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_SEND_CONTACT_LIST, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleContactListOpcode);

View File

@@ -448,6 +448,7 @@ namespace WorldPackets
class RepairItem;
class ReadItem;
class SellItem;
class SellAllJunkItems;
class SplitItem;
class SwapInvItem;
class SwapItem;
@@ -1536,6 +1537,7 @@ class TC_GAME_API WorldSession
void HandleDestroyItemOpcode(WorldPackets::Item::DestroyItem& destroyItem);
void HandleAutoEquipItemOpcode(WorldPackets::Item::AutoEquipItem& autoEquipItem);
void HandleSellItemOpcode(WorldPackets::Item::SellItem const& sellItem);
void HandleSellAllJunkItems(WorldPackets::Item::SellAllJunkItems const& sellAllJunkItems);
void HandleBuyItemOpcode(WorldPackets::Item::BuyItem& packet);
void HandleListInventoryOpcode(WorldPackets::NPC::Hello& packet);
void HandleAutoStoreBagItemOpcode(WorldPackets::Item::AutoStoreBagItem& packet);