feat: add auto-sell grey items on vendor open

When 'Auto Sell Greys' is enabled in Settings > Gameplay, all grey
(ItemQuality::POOR) items in the backpack and extra bags are sold
automatically when opening a vendor window. Items with no sell price
are skipped. A system chat message reports the number of items sold
and total gold received. The setting persists to ~/.wowee/settings.cfg
under the key auto_sell_grey.
This commit is contained in:
Kelsi 2026-03-17 20:21:06 -07:00
parent e62ae8b03e
commit 072f256af6
4 changed files with 75 additions and 1 deletions

View file

@ -21197,6 +21197,68 @@ void GameHandler::handleListInventory(network::Packet& packet) {
vendorWindowOpen = true;
gossipWindowOpen = false; // Close gossip if vendor opens
// Auto-sell grey items if enabled
if (autoSellGrey_ && currentVendorItems.vendorGuid != 0) {
uint32_t totalSellPrice = 0;
int itemsSold = 0;
// Helper lambda to attempt selling a poor-quality slot
auto tryAutoSell = [&](const ItemSlot& slot, uint64_t itemGuid) {
if (slot.empty()) return;
if (slot.item.quality != ItemQuality::POOR) return;
// Determine sell price (slot cache first, then item info fallback)
uint32_t sp = slot.item.sellPrice;
if (sp == 0) {
if (auto* info = getItemInfo(slot.item.itemId); info && info->valid)
sp = info->sellPrice;
}
if (sp == 0 || itemGuid == 0) return;
BuybackItem sold;
sold.itemGuid = itemGuid;
sold.item = slot.item;
sold.count = 1;
buybackItems_.push_front(sold);
if (buybackItems_.size() > 12) buybackItems_.pop_back();
pendingSellToBuyback_[itemGuid] = sold;
sellItem(currentVendorItems.vendorGuid, itemGuid, 1);
totalSellPrice += sp;
++itemsSold;
};
// Backpack slots
for (int i = 0; i < inventory.getBackpackSize(); ++i) {
uint64_t guid = backpackSlotGuids_[i];
if (guid == 0) guid = resolveOnlineItemGuid(inventory.getBackpackSlot(i).item.itemId);
tryAutoSell(inventory.getBackpackSlot(i), guid);
}
// Extra bag slots
for (int b = 0; b < inventory.NUM_BAG_SLOTS; ++b) {
uint64_t bagGuid = equipSlotGuids_[19 + b];
for (int s = 0; s < inventory.getBagSize(b); ++s) {
uint64_t guid = 0;
if (bagGuid != 0) {
auto it = containerContents_.find(bagGuid);
if (it != containerContents_.end() && s < static_cast<int>(it->second.numSlots))
guid = it->second.slotGuids[s];
}
if (guid == 0) guid = resolveOnlineItemGuid(inventory.getBagSlot(b, s).item.itemId);
tryAutoSell(inventory.getBagSlot(b, s), guid);
}
}
if (itemsSold > 0) {
uint32_t gold = totalSellPrice / 10000;
uint32_t silver = (totalSellPrice % 10000) / 100;
uint32_t copper = totalSellPrice % 100;
char buf[128];
std::snprintf(buf, sizeof(buf),
"|cffaaaaaaAuto-sold %d grey item%s for %ug %us %uc.|r",
itemsSold, itemsSold == 1 ? "" : "s", gold, silver, copper);
addSystemChatMessage(buf);
}
}
// Play vendor sound
if (npcVendorCallback_ && currentVendorItems.vendorGuid != 0) {
auto entity = entityManager.getEntity(currentVendorItems.vendorGuid);

View file

@ -592,8 +592,9 @@ void GameScreen::render(game::GameHandler& gameHandler) {
}
}
// Apply auto-loot setting to GameHandler every frame (cheap bool sync)
// Apply auto-loot / auto-sell settings to GameHandler every frame (cheap bool sync)
gameHandler.setAutoLoot(pendingAutoLoot);
gameHandler.setAutoSellGrey(pendingAutoSellGrey);
// Zone entry detection — fire a toast when the renderer's zone name changes
if (auto* rend = core::Application::getInstance().getRenderer()) {
@ -16328,6 +16329,11 @@ void GameScreen::renderSettingsWindow() {
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Automatically pick up all items when looting");
if (ImGui::Checkbox("Auto Sell Greys", &pendingAutoSellGrey)) {
saveSettings();
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Automatically sell all grey (poor quality) items when opening a vendor");
ImGui::Spacing();
ImGui::Text("Bags");
@ -18328,6 +18334,7 @@ void GameScreen::saveSettings() {
// Gameplay
out << "auto_loot=" << (pendingAutoLoot ? 1 : 0) << "\n";
out << "auto_sell_grey=" << (pendingAutoSellGrey ? 1 : 0) << "\n";
out << "graphics_preset=" << static_cast<int>(currentGraphicsPreset) << "\n";
out << "ground_clutter_density=" << pendingGroundClutterDensity << "\n";
out << "shadows=" << (pendingShadows ? 1 : 0) << "\n";
@ -18469,6 +18476,7 @@ void GameScreen::loadSettings() {
else if (key == "activity_volume") pendingActivityVolume = std::clamp(std::stoi(val), 0, 100);
// Gameplay
else if (key == "auto_loot") pendingAutoLoot = (std::stoi(val) != 0);
else if (key == "auto_sell_grey") pendingAutoSellGrey = (std::stoi(val) != 0);
else if (key == "graphics_preset") {
int presetVal = std::clamp(std::stoi(val), 0, 4);
currentGraphicsPreset = static_cast<GraphicsPreset>(presetVal);