Skip to content
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
10 changes: 10 additions & 0 deletions conf/mod_ahbot.conf.dist
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@
# If set to zero then no limits are set in place.
# Default 0
#
# AuctionHouseBot.RestockBatchSize
# The maximum amount of stacks of the same item the seller queues in a single
# cycle while restocking it up to its target count. The target count is taken
# from the "mod_auctionhousebot_countOverride" table, or from
# AuctionHouseBot.DuplicatesCount when the item has no row there.
# Without this, a sold out item comes back one stack per cycle only.
# Set to 1 to restore that behaviour.
# Default 5
#
# AuctionHouseBot.DivisibleStacks
# Sell items in stack sizes which depends on the maximum amount per stack.
# For example, an item with max stack size 20 will be sold in 5, 10 15 and 20 stacks, and not at random.
Expand Down Expand Up @@ -121,6 +130,7 @@ AuctionHouseBot.ItemsPerCycle = 200

AuctionHouseBot.ConsiderOnlyBotAuctions = 0
AuctionHouseBot.DuplicatesCount = 0
AuctionHouseBot.RestockBatchSize = 5
AuctionHouseBot.DivisibleStacks = 0
AuctionHouseBot.ElapsingTimeClass = 1
AuctionHouseBot.MinItems = 10000
Expand Down
66 changes: 62 additions & 4 deletions src/AuctionHouseBot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config)
std::vector<uint32> itemCounts(14, 0);

// Get prioritized item IDs
std::vector<uint32> itemsToSell = GetItemsToSell(config, AHBplayer->GetGUID(), itemsInAH);
std::vector<uint32> itemsToSell = GetItemsToSell(config, AHBplayer->GetGUID(), itemsInAH, botItemCounts);

// Loop variables
uint32 nbSold = 0; // Tracing counter
Expand Down Expand Up @@ -1247,7 +1247,7 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config)
// Get Prioritized ItemIDs
// =============================================================================

std::vector<uint32> AuctionHouseBot::GetItemsToSell(AHBConfig* config, ObjectGuid /* botGuid */, const std::unordered_set<uint32>& itemsInAH)
std::vector<uint32> AuctionHouseBot::GetItemsToSell(AHBConfig* config, ObjectGuid /* botGuid */, const std::unordered_set<uint32>& itemsInAH, const std::unordered_map<uint32, uint32>& botItemCounts)
{
//std::vector<uint32> prioritizedItemIDs;
std::vector<uint32> allItemIDs;
Expand Down Expand Up @@ -1286,17 +1286,74 @@ std::vector<uint32> AuctionHouseBot::GetItemsToSell(AHBConfig* config, ObjectGui
std::vector<uint32> yellowItemsBin(config->YellowItemsBin.begin(), config->YellowItemsBin.end());


// 1. Items with price overrides that are not listed by the bot yet (randomized order)
// How many stacks of an item are missing from its target count. The target is
// the per-item countOverride, else the global DuplicatesCount, else 1 stack -
// the same precedence the listing cap in Sell() applies. Capped by
// RestockBatchSize so a single item cannot eat the whole ItemsPerCycle budget.
auto missingStacks = [&](uint32 itemID) -> uint32
{
uint32 target = config->GetCountOverrideForItem(itemID);

if (target == 0)
{
target = config->DuplicatesCount;
}

if (target == 0)
{
target = 1;
}

auto listed = botItemCounts.find(itemID);
uint32 current = (listed != botItemCounts.end()) ? listed->second : 0;

if (current >= target)
{
return 0;
}

uint32 batch = config->RestockBatchSize > 0 ? config->RestockBatchSize : 1;

return std::min(target - current, batch);
};

// Queue every stack an item is short of, keeping the copies adjacent so a
// sold out item is restocked as a batch instead of one stack per cycle.
auto appendMissingStacks = [&](const std::vector<uint32>& items)
{
for (auto const& itemID : items)
{
allItemIDs.insert(allItemIDs.end(), missingStacks(itemID), itemID);
}
};

// 1. Items with price overrides below their target count (randomized order),
// sold out ones first, then the ones still partially stocked
std::vector<uint32> itemsWithOverridesNotListed;
std::vector<uint32> itemsWithOverridesBelowTarget;

for (const auto& [itemID, _] : config->itemPriceOverrides)
{
if (missingStacks(itemID) == 0)
{
continue;
}

if (itemsInAH.find(itemID) == itemsInAH.end())
{
itemsWithOverridesNotListed.push_back(itemID);
}
else
{
itemsWithOverridesBelowTarget.push_back(itemID);
}
}

std::shuffle(itemsWithOverridesNotListed.begin(), itemsWithOverridesNotListed.end(), std::mt19937(std::random_device()()));
allItemIDs.insert(allItemIDs.end(), itemsWithOverridesNotListed.begin(), itemsWithOverridesNotListed.end());
std::shuffle(itemsWithOverridesBelowTarget.begin(), itemsWithOverridesBelowTarget.end(), std::mt19937(std::random_device()()));

appendMissingStacks(itemsWithOverridesNotListed);
appendMissingStacks(itemsWithOverridesBelowTarget);

// 2. Items for which price overrides do exist (randomized order)
std::vector<uint32> itemsWithOverrides;
Expand Down Expand Up @@ -1339,6 +1396,7 @@ std::vector<uint32> AuctionHouseBot::GetItemsToSell(AHBConfig* config, ObjectGui
// Log the number of items to sell
if(config->TraceSeller)
{
LOG_INFO("module", "AHBot [{}]: restocking {} sold out and {} understocked price override items", _id, itemsWithOverridesNotListed.size(), itemsWithOverridesBelowTarget.size());
LOG_INFO("module", "AHBot [{}]: GetItemsToSell returning {} items", _id, allItemIDs.size());
}

Expand Down
2 changes: 1 addition & 1 deletion src/AuctionHouseBot.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class AuctionHouseBot

ObjectGuid::LowType GetAHBplayerGUID() { return _id; };

std::vector<uint32> GetItemsToSell(AHBConfig* config, ObjectGuid botGuid, const std::unordered_set<uint32>& itemsInAH);
std::vector<uint32> GetItemsToSell(AHBConfig* config, ObjectGuid botGuid, const std::unordered_set<uint32>& itemsInAH, const std::unordered_map<uint32, uint32>& botItemCounts);
bool IsItemListedByBot(uint32 itemID, uint32 ahID, ObjectGuid botGuid);
bool IsItemInAuctionHouse(uint32 itemID, uint32 ahID);
std::vector<uint32> GetAllItemIDs(uint32 ahID);
Expand Down
3 changes: 3 additions & 0 deletions src/AuctionHouseBotConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ AHBConfig::AHBConfig(uint32 ahid, AHBConfig* conf)
Bind_When_Use = conf->Bind_When_Use;
Bind_Quest_Item = conf->Bind_Quest_Item;
DuplicatesCount = conf->DuplicatesCount;
RestockBatchSize = conf->RestockBatchSize;
ElapsingTimeClass = conf->ElapsingTimeClass;
DivisibleStacks = conf->DivisibleStacks;
DisablePermEnchant = conf->DisablePermEnchant;
Expand Down Expand Up @@ -532,6 +533,7 @@ void AHBConfig::Reset()
Bind_When_Use = false;
Bind_Quest_Item = false;
DuplicatesCount = 0;
RestockBatchSize = 5;
ElapsingTimeClass = 1;
DivisibleStacks = false;

Expand Down Expand Up @@ -2069,6 +2071,7 @@ void AHBConfig::InitializeFromFile()
SellAtMarketPrice = sConfigMgr->GetOption<bool> ("AuctionHouseBot.UseMarketPriceForSeller", false);
MarketResetThreshold = sConfigMgr->GetOption<uint32>("AuctionHouseBot.MarketResetThreshold" , 25);
DuplicatesCount = sConfigMgr->GetOption<uint32>("AuctionHouseBot.DuplicatesCount" , 0);
RestockBatchSize = sConfigMgr->GetOption<uint32>("AuctionHouseBot.RestockBatchSize" , 5);
DivisibleStacks = sConfigMgr->GetOption<bool> ("AuctionHouseBot.DivisibleStacks" , false);
ElapsingTimeClass = sConfigMgr->GetOption<uint32>("AuctionHouseBot.ElapsingTimeClass" , 1);
ConsiderOnlyBotAuctions = sConfigMgr->GetOption<bool> ("AuctionHouseBot.ConsiderOnlyBotAuctions", false);
Expand Down
1 change: 1 addition & 0 deletions src/AuctionHouseBotConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ class AHBConfig
bool Bind_Quest_Item;

uint32 DuplicatesCount;
uint32 RestockBatchSize;
uint32 ElapsingTimeClass;

bool DivisibleStacks;
Expand Down
Loading