diff --git a/src/AuctionHouseBot.cpp b/src/AuctionHouseBot.cpp index 0773084..2134e8b 100644 --- a/src/AuctionHouseBot.cpp +++ b/src/AuctionHouseBot.cpp @@ -382,6 +382,11 @@ void AuctionHouseBot::Buy(Player* AHBplayer, AHBConfig* config, WorldSession* se // Get price overrides auto [avgPrice, minPrice] = config->GetPriceOverrideForItem(prototype->ItemId); + if (minPrice > avgPrice) + { + minPrice = avgPrice; + } + uint64 maxPrice = (avgPrice + ( avgPrice - minPrice )); uint64 SellPriceValue = maxPrice > 0 ? maxPrice : prototype->SellPrice; uint64 BuyPriceValue = avgPrice > 0 ? avgPrice : prototype->BuyPrice; @@ -791,6 +796,20 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) uint32 itemID = itemsToSell[cnt]; + // Priority-list picks (price-override items) must respect their per-item + // count override too, mirroring getElement()'s cap for random picks. + // A capped pick falls through to the rarity-tier selection below. + if (itemID != 0) + { + uint32 effectiveMax = config->DuplicatesCount; + uint32 countOverride = config->GetCountOverrideForItem(itemID); + if (countOverride > 0) + effectiveMax = countOverride; + + if (effectiveMax > 0 && botItemCounts[itemID] >= effectiveMax) + itemID = 0; + } + // Update Auctions count for current Bot uint32 botAuctionsCount = nbOfAuctions + cnt; @@ -821,7 +840,7 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) itemTypeSelectedToSell = AHB_GREY_I; itemID = getElement(config->GreyItemsVec, urand(0, config->GreyItemsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); } - else if (itemID == 0 && !config->GreyTradeGoodsVec.empty() && (currentGreyTG < maxGreyTG)) + if (itemID == 0 && !config->GreyTradeGoodsVec.empty() && (currentGreyTG < maxGreyTG)) { itemTypeSelectedToSell = AHB_GREY_TG; itemID = getElement(config->GreyTradeGoodsVec, urand(0, config->GreyTradeGoodsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); @@ -829,13 +848,13 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) // Normal - else if (itemID == 0 && !config->WhiteItemsVec.empty() && (currentWhiteItems < maxWhiteI)) + if (itemID == 0 && !config->WhiteItemsVec.empty() && (currentWhiteItems < maxWhiteI)) { itemTypeSelectedToSell = AHB_WHITE_I; itemID = getElement(config->WhiteItemsVec, urand(0, config->WhiteItemsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); } - else if (itemID == 0 && !config->WhiteTradeGoodsVec.empty() && (currentWhiteTG < maxWhiteTG)) + if (itemID == 0 && !config->WhiteTradeGoodsVec.empty() && (currentWhiteTG < maxWhiteTG)) { itemTypeSelectedToSell = AHB_WHITE_TG; itemID = getElement(config->WhiteTradeGoodsVec, urand(0, config->WhiteTradeGoodsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); @@ -843,13 +862,13 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) // Uncommon - else if (itemID == 0 && !config->GreenItemsVec.empty() && (currentGreenItems < maxGreenI)) + if (itemID == 0 && !config->GreenItemsVec.empty() && (currentGreenItems < maxGreenI)) { itemTypeSelectedToSell = AHB_GREEN_I; itemID = getElement(config->GreenItemsVec, urand(0, config->GreenItemsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); } - else if (itemID == 0 && !config->GreenTradeGoodsVec.empty() && (currentGreenTG < maxGreenTG)) + if (itemID == 0 && !config->GreenTradeGoodsVec.empty() && (currentGreenTG < maxGreenTG)) { itemTypeSelectedToSell = AHB_GREEN_TG; itemID = getElement(config->GreenTradeGoodsVec, urand(0, config->GreenTradeGoodsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); @@ -857,13 +876,13 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) // Rare - else if (itemID == 0 && !config->BlueItemsVec.empty() && (currentBlueItems < maxBlueI)) + if (itemID == 0 && !config->BlueItemsVec.empty() && (currentBlueItems < maxBlueI)) { itemTypeSelectedToSell = AHB_BLUE_I; itemID = getElement(config->BlueItemsVec, urand(0, config->BlueItemsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); } - else if (itemID == 0 && !config->BlueTradeGoodsVec.empty() && (currentBlueTG < maxBlueTG)) + if (itemID == 0 && !config->BlueTradeGoodsVec.empty() && (currentBlueTG < maxBlueTG)) { itemTypeSelectedToSell = AHB_BLUE_TG; itemID = getElement(config->BlueTradeGoodsVec, urand(0, config->BlueTradeGoodsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); @@ -871,13 +890,13 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) // Epic - else if (itemID == 0 && !config->PurpleItemsVec.empty() && (currentPurpleItems < maxPurpleI)) + if (itemID == 0 && !config->PurpleItemsVec.empty() && (currentPurpleItems < maxPurpleI)) { itemTypeSelectedToSell = AHB_PURPLE_I; itemID = getElement(config->PurpleItemsVec, urand(0, config->PurpleItemsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); } - else if (itemID == 0 && !config->PurpleTradeGoodsVec.empty() && (currentPurpleTG < maxPurpleTG)) + if (itemID == 0 && !config->PurpleTradeGoodsVec.empty() && (currentPurpleTG < maxPurpleTG)) { itemTypeSelectedToSell = AHB_PURPLE_TG; itemID = getElement(config->PurpleTradeGoodsVec, urand(0, config->PurpleTradeGoodsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); @@ -885,13 +904,13 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) // Legendary - else if (itemID == 0 && !config->OrangeItemsVec.empty() && (currentOrangeItems < maxOrangeI)) + if (itemID == 0 && !config->OrangeItemsVec.empty() && (currentOrangeItems < maxOrangeI)) { itemTypeSelectedToSell = AHB_ORANGE_I; itemID = getElement(config->OrangeItemsVec, urand(0, config->OrangeItemsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); } - else if (itemID == 0 && !config->OrangeTradeGoodsVec.empty() && (currentOrangeTG < maxOrangeTG)) + if (itemID == 0 && !config->OrangeTradeGoodsVec.empty() && (currentOrangeTG < maxOrangeTG)) { itemTypeSelectedToSell = AHB_ORANGE_TG; itemID = getElement(config->OrangeTradeGoodsVec, urand(0, config->OrangeTradeGoodsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); @@ -899,13 +918,13 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) // Artifact - else if (itemID == 0 && !config->YellowItemsVec.empty() && (currentYellowItems < maxYellowI)) + if (itemID == 0 && !config->YellowItemsVec.empty() && (currentYellowItems < maxYellowI)) { itemTypeSelectedToSell = AHB_YELLOW_I; itemID = getElement(config->YellowItemsVec, urand(0, config->YellowItemsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); } - else if (itemID == 0 && !config->YellowTradeGoodsVec.empty() && (currentYellowTG < maxYellowTG)) + if (itemID == 0 && !config->YellowTradeGoodsVec.empty() && (currentYellowTG < maxYellowTG)) { itemTypeSelectedToSell = AHB_YELLOW_TG; itemID = getElement(config->YellowTradeGoodsVec, urand(0, config->YellowTradeGoodsVec.size() - 1), _id, config->DuplicatesCount, botItemCounts, config); @@ -916,7 +935,7 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) if (itemID == 0) { loopBrk++; - return; + continue; } // Retrieve information about the selected item @@ -931,7 +950,7 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) LOG_ERROR("module", "AHBot [{}]: could not get prototype of item {}", _id, itemID); } - return; + continue; } Item* item = Item::CreateItem(itemID, 1, AHBplayer); @@ -945,7 +964,7 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) LOG_ERROR("module", "AHBot [{}]: could not create item from prototype {}", _id, itemID); } - return; + continue; } // Start interacting with the item by adding a random property @@ -968,7 +987,7 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) } item->RemoveFromUpdateQueueOf(AHBplayer); - return; + continue; } // Determine the price @@ -1789,29 +1808,9 @@ void AuctionHouseBot::Initialize(AHBConfig* allianceConfig, AHBConfig* hordeConf _hordeConfig = hordeConfig; _neutralConfig = neutralConfig; - // Load price overrides once and make them globally available - static bool priceOverridesLoaded = false; - if (!priceOverridesLoaded) - { - _neutralConfig->LoadPriceOverrides(); // Load once using the neutral config - priceOverridesLoaded = true; - } - - // Share the loaded price overrides across all configurations - _allianceConfig->itemPriceOverrides = _neutralConfig->itemPriceOverrides; - _hordeConfig->itemPriceOverrides = _neutralConfig->itemPriceOverrides; - - // Load per-item count overrides once and make them globally available - static bool countOverridesLoaded = false; - if (!countOverridesLoaded) - { - _neutralConfig->LoadCountOverrides(); // Load once using the neutral config - countOverridesLoaded = true; - } - - // Share the loaded count overrides across all configurations - _allianceConfig->itemCountOverrides = _neutralConfig->itemCountOverrides; - _hordeConfig->itemCountOverrides = _neutralConfig->itemCountOverrides; + // Price and count overrides are loaded and shared across configurations by + // AHBot_WorldScript::LoadSharedOverrides(), once per startup/reload cycle, + // before any bot is constructed. } // Helper function to join GUIDs into a comma-separated string diff --git a/src/AuctionHouseBotConfig.cpp b/src/AuctionHouseBotConfig.cpp index edbfdcf..1cd9260 100644 --- a/src/AuctionHouseBotConfig.cpp +++ b/src/AuctionHouseBotConfig.cpp @@ -3494,6 +3494,10 @@ std::set AHBConfig::getCommaSeparatedIntegers(std::string text) void AHBConfig::LoadPriceOverrides() { + // Full reload semantics: rows deleted from the table must disappear from + // the in-memory map too, not linger until restart. + itemPriceOverrides.clear(); + QueryResult result = WorldDatabase.Query("SELECT item, avgPrice, minPrice FROM mod_auctionhousebot_priceOverride"); if (!result) @@ -3509,6 +3513,12 @@ void AHBConfig::LoadPriceOverrides() uint64 avgPrice = fields[1].Get(); uint64 minPrice = fields[2].Get(); + if (minPrice > avgPrice) + { + LOG_WARN("module", "AHBConfig: price override for item {} has minPrice {} > avgPrice {}, clamping minPrice to avgPrice", itemId, minPrice, avgPrice); + minPrice = avgPrice; + } + itemPriceOverrides[itemId] = std::make_tuple(avgPrice, minPrice); } while (result->NextRow()); @@ -3528,6 +3538,10 @@ std::tuple AHBConfig::GetPriceOverrideForItem(uint32 itemId) con void AHBConfig::LoadCountOverrides() { + // Full reload semantics: rows deleted from the table must disappear from + // the in-memory map too, not linger until restart. + itemCountOverrides.clear(); + QueryResult result = WorldDatabase.Query("SELECT item, targetCount FROM mod_auctionhousebot_countOverride"); if (!result) diff --git a/src/AuctionHouseBotWorldScript.cpp b/src/AuctionHouseBotWorldScript.cpp index 98d1a43..b30c8ad 100644 --- a/src/AuctionHouseBotWorldScript.cpp +++ b/src/AuctionHouseBotWorldScript.cpp @@ -128,6 +128,8 @@ void AHBot_WorldScript::OnBeforeConfigLoad(bool reload) gHordeConfig->Initialize(gBotsId); gNeutralConfig->Initialize(gBotsId); + LoadSharedOverrides(); + // Start again the bots PopulateBots(); } @@ -145,6 +147,8 @@ void AHBot_WorldScript::OnStartup() gHordeConfig->Initialize (gBotsId); gNeutralConfig->Initialize (gBotsId); + LoadSharedOverrides(); + // // Starts the bots // @@ -182,6 +186,21 @@ void AHBot_WorldScript::DeleteBots() } +void AHBot_WorldScript::LoadSharedOverrides() +{ + // Load once using the neutral config, then share across all configurations. + // Called on startup and on every config reload, so .reload config keeps + // mod_auctionhousebot_priceOverride and mod_auctionhousebot_countOverride current. + gNeutralConfig->LoadPriceOverrides(); + gNeutralConfig->LoadCountOverrides(); + + gAllianceConfig->itemPriceOverrides = gNeutralConfig->itemPriceOverrides; + gHordeConfig->itemPriceOverrides = gNeutralConfig->itemPriceOverrides; + + gAllianceConfig->itemCountOverrides = gNeutralConfig->itemCountOverrides; + gHordeConfig->itemCountOverrides = gNeutralConfig->itemCountOverrides; +} + void AHBot_WorldScript::PopulateBots() { uint32 account = sConfigMgr->GetOption("AuctionHouseBot.Account", 0); diff --git a/src/AuctionHouseBotWorldScript.h b/src/AuctionHouseBotWorldScript.h index 069b049..dd4baef 100644 --- a/src/AuctionHouseBotWorldScript.h +++ b/src/AuctionHouseBotWorldScript.h @@ -16,6 +16,7 @@ class AHBot_WorldScript : public WorldScript private: void DeleteBots(); void PopulateBots(); + void LoadSharedOverrides(); public: AHBot_WorldScript();