From 1b169974ff0050d3fbaff26e3df2136755ad3f87 Mon Sep 17 00:00:00 2001 From: zeb <37308742+zeb139@users.noreply.github.com> Date: Wed, 17 Sep 2025 11:26:23 -0400 Subject: [PATCH 1/2] Added config, prevent buyerbot from buying overpriced vendor items, refactored advancedPricingMultiplier out of calculateItemValue() --- README.md | 2 +- conf/mod_ahbot.conf.dist | 9 ++ src/AuctionHouseBot.cpp | 241 +++++++++++++++++++++++---------------- src/AuctionHouseBot.h | 4 + 4 files changed, 155 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 915e78c..1e11120 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Notes: ## Buying Bot Behavior -1. **Determining Items to Buy:** Every minute the buyer bot will select (BuyCanditatesPerBuyCycle) items currently up for auction which are listed by players as potential purchase items. +1. **Determining Items to Buy:** Every minute the buyer bot will select (BuyCandidatesPerBuyCycle) items currently up for auction which are listed by players as potential purchase items. 2. **Price Willing to Pay:** The buyer bot will use the same item price calculation the seller bot uses, including the random +/- 25%, and that calculated price is then multiplied by (AcceptablePriceModifier) which then becomes the price the buyer will be willing to spend. 3. **Buying it:** If the price calculated is higher than the buy out price, then the bot will buy it out. If not, it will test to see if it has been bidded on by a bot and if not, if the bid price is below the price it is willing to pay. If so, it will bid (outbid, so just over current bid). diff --git a/conf/mod_ahbot.conf.dist b/conf/mod_ahbot.conf.dist index d421def..2db3079 100644 --- a/conf/mod_ahbot.conf.dist +++ b/conf/mod_ahbot.conf.dist @@ -155,11 +155,20 @@ AuctionHouseBot.Neutral.MaxItems = 15000 # want the buyer to be more stingy (0.5 means buyer will pay up to 50% # of what the seller sells for), but do not go lower than 0 # Default: 1 +# +# AuctionHouseBot.Buyer.PreventOverpayingForVendorItems +# When enabled, the buyer bot will avoid purchasing auction house items +# that are being sold for more than the vendor sell price. This prevents +# players from "gaming" the economy by flipping vendor items. +# If disabled, the bot may still purchase vendor items above vendor value +# if they fall within the acceptable price modifier rules. +# Default: 1 ############################################################################### AuctionHouseBot.Buyer.Enabled = 0 AuctionHouseBot.Buyer.BuyCandidatesPerBuyCycle = 1 AuctionHouseBot.Buyer.AcceptablePriceModifier = 1 +AuctionHouseBot.Buyer.PreventOverpayingForVendorItems = 1 ############################################################################### # AuctionHouseBot.ListProportion.* diff --git a/src/AuctionHouseBot.cpp b/src/AuctionHouseBot.cpp index 8c66958..7a7e618 100644 --- a/src/AuctionHouseBot.cpp +++ b/src/AuctionHouseBot.cpp @@ -276,6 +276,111 @@ void AuctionHouseBot::calculateItemValue(ItemTemplate const* itemProto, uint64& float classQualityPriceMultiplier = PriceMultiplierCategoryQuality[itemProto->Class][itemProto->Quality]; + float advancedPricingMultiplier = getAdvancedPricingMultiplier(itemProto); + + // Grab the minimum prices + uint64 PriceMinimumCenterBase = 1000; + auto it = PriceMinimumCenterBaseOverridesByItemID.find(itemProto->ItemId); + if (it != PriceMinimumCenterBaseOverridesByItemID.end()) + PriceMinimumCenterBase = it->second; + else + { + switch (itemProto->Class) + { + case ITEM_CLASS_CONSUMABLE: PriceMinimumCenterBase = PriceMinimumCenterBaseConsumable; break; + case ITEM_CLASS_CONTAINER: PriceMinimumCenterBase = PriceMinimumCenterBaseContainer; break; + case ITEM_CLASS_WEAPON: PriceMinimumCenterBase = PriceMinimumCenterBaseWeapon; break; + case ITEM_CLASS_GEM: PriceMinimumCenterBase = PriceMinimumCenterBaseGem; break; + case ITEM_CLASS_REAGENT: PriceMinimumCenterBase = PriceMinimumCenterBaseReagent; break; + case ITEM_CLASS_ARMOR: PriceMinimumCenterBase = PriceMinimumCenterBaseArmor; break; + case ITEM_CLASS_PROJECTILE: PriceMinimumCenterBase = PriceMinimumCenterBaseProjectile; break; + case ITEM_CLASS_TRADE_GOODS: PriceMinimumCenterBase = PriceMinimumCenterBaseTradeGood; break; + case ITEM_CLASS_GENERIC: PriceMinimumCenterBase = PriceMinimumCenterBaseGeneric; break; + case ITEM_CLASS_RECIPE: PriceMinimumCenterBase = PriceMinimumCenterBaseRecipe; break; + case ITEM_CLASS_QUIVER: PriceMinimumCenterBase = PriceMinimumCenterBaseQuiver; break; + case ITEM_CLASS_QUEST: PriceMinimumCenterBase = PriceMinimumCenterBaseQuest; break; + case ITEM_CLASS_KEY: PriceMinimumCenterBase = PriceMinimumCenterBaseKey; break; + case ITEM_CLASS_MISC: PriceMinimumCenterBase = PriceMinimumCenterBaseMisc; break; + case ITEM_CLASS_GLYPH: PriceMinimumCenterBase = PriceMinimumCenterBaseGlyph; break; + default: break; + } + } + + // Set the minimum price + if (outBuyoutPrice < PriceMinimumCenterBase) + outBuyoutPrice = urand(PriceMinimumCenterBase * (1.0f - BuyoutVariationReducePercent), PriceMinimumCenterBase * (1.0f + BuyoutVariationAddPercent)); + else + outBuyoutPrice = urand(outBuyoutPrice * (1.0f - BuyoutVariationReducePercent), outBuyoutPrice * (1.0f + BuyoutVariationAddPercent)); + + // Ensure no multipliers are zero or negative + if (classPriceMultiplier <= 0.0f) + classPriceMultiplier = 1.0f; + if (qualityPriceMultplier <= 0.0f) + qualityPriceMultplier = 1.0f; + if (classQualityPriceMultiplier <= 0.0f) + classQualityPriceMultiplier = 1.0f; + if (advancedPricingMultiplier <= 0.0f) + advancedPricingMultiplier = 1.0f; + + // Grab any item level price multipliers + float itemLevelPriceMultplier = 0.0f; + switch (itemProto->Class) + { + case ITEM_CLASS_CONSUMABLE: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryConsumable; break; + case ITEM_CLASS_CONTAINER: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryContainer; break; + case ITEM_CLASS_WEAPON: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryWeapon; break; + case ITEM_CLASS_GEM: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryGem; break; + case ITEM_CLASS_REAGENT: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryReagent; break; + case ITEM_CLASS_ARMOR: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryArmor; break; + case ITEM_CLASS_PROJECTILE: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryProjectile; break; + case ITEM_CLASS_TRADE_GOODS: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryTradeGood; break; + case ITEM_CLASS_GENERIC: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryGeneric; break; + case ITEM_CLASS_RECIPE: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryRecipe; break; + case ITEM_CLASS_QUIVER: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryQuiver; break; + case ITEM_CLASS_QUEST: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryQuest; break; + case ITEM_CLASS_KEY: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryKey; break; + case ITEM_CLASS_MISC: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryMisc; break; + case ITEM_CLASS_GLYPH: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryGlyph; break; + default: break; + } + + // Multiply the price based on multipliers + outBuyoutPrice *= qualityPriceMultplier; + outBuyoutPrice *= classPriceMultiplier; + outBuyoutPrice *= classQualityPriceMultiplier; + outBuyoutPrice *= static_cast(advancedPricingMultiplier); + + // Only apply item level multiplier if set, and no advanced pricing has been enabled + if (itemLevelPriceMultplier > 0.0f && itemProto->ItemLevel > 0 && advancedPricingMultiplier == 1.0f) + outBuyoutPrice *= itemProto->ItemLevel * itemLevelPriceMultplier; + + // If a vendor sells this item, make the price at least that high + if (itemProto->SellPrice > outBuyoutPrice) + outBuyoutPrice = itemProto->SellPrice; + + // Avoid price overflows + if (outBuyoutPrice > MaxBuyoutPriceInCopper) + outBuyoutPrice = MaxBuyoutPriceInCopper; + + // Calculate a bid price based on a variance against buyout price + float sellVarianceBidPriceTopPercent = 1.0f - BidVariationHighReducePercent; + float sellVarianceBidPriceBottomPercent = 1.0f - BidVariationLowReducePercent; + outBidPrice = urand(sellVarianceBidPriceBottomPercent * outBuyoutPrice, sellVarianceBidPriceTopPercent * outBuyoutPrice); + + // If variance brought price below sell price, bring it back up to avoid making money off vendoring AH items + if (outBuyoutPrice < itemProto->SellPrice) + { + float minLowPriceAddVariancePercent = 1.0f + BuyoutBelowVendorVariationAddPercent; + outBuyoutPrice = urand(itemProto->SellPrice, minLowPriceAddVariancePercent * itemProto->SellPrice); + } + + // Bid price can never be below sell price + if (outBidPrice < itemProto->SellPrice) + outBidPrice = itemProto->SellPrice; +} + +float AuctionHouseBot::getAdvancedPricingMultiplier(ItemTemplate const* itemProto) +{ /* "ADVANCED" SUBCLASS PRICE MULTIPLIER FORMULA NOTES 1. multiplierHelper = log(1 + b * ItemLevel) @@ -390,105 +495,7 @@ void AuctionHouseBot::calculateItemValue(ItemTemplate const* itemProto, uint64& } } - // Grab the minimum prices - uint64 PriceMinimumCenterBase = 1000; - auto it = PriceMinimumCenterBaseOverridesByItemID.find(itemProto->ItemId); - if (it != PriceMinimumCenterBaseOverridesByItemID.end()) - PriceMinimumCenterBase = it->second; - else - { - switch (itemProto->Class) - { - case ITEM_CLASS_CONSUMABLE: PriceMinimumCenterBase = PriceMinimumCenterBaseConsumable; break; - case ITEM_CLASS_CONTAINER: PriceMinimumCenterBase = PriceMinimumCenterBaseContainer; break; - case ITEM_CLASS_WEAPON: PriceMinimumCenterBase = PriceMinimumCenterBaseWeapon; break; - case ITEM_CLASS_GEM: PriceMinimumCenterBase = PriceMinimumCenterBaseGem; break; - case ITEM_CLASS_REAGENT: PriceMinimumCenterBase = PriceMinimumCenterBaseReagent; break; - case ITEM_CLASS_ARMOR: PriceMinimumCenterBase = PriceMinimumCenterBaseArmor; break; - case ITEM_CLASS_PROJECTILE: PriceMinimumCenterBase = PriceMinimumCenterBaseProjectile; break; - case ITEM_CLASS_TRADE_GOODS: PriceMinimumCenterBase = PriceMinimumCenterBaseTradeGood; break; - case ITEM_CLASS_GENERIC: PriceMinimumCenterBase = PriceMinimumCenterBaseGeneric; break; - case ITEM_CLASS_RECIPE: PriceMinimumCenterBase = PriceMinimumCenterBaseRecipe; break; - case ITEM_CLASS_QUIVER: PriceMinimumCenterBase = PriceMinimumCenterBaseQuiver; break; - case ITEM_CLASS_QUEST: PriceMinimumCenterBase = PriceMinimumCenterBaseQuest; break; - case ITEM_CLASS_KEY: PriceMinimumCenterBase = PriceMinimumCenterBaseKey; break; - case ITEM_CLASS_MISC: PriceMinimumCenterBase = PriceMinimumCenterBaseMisc; break; - case ITEM_CLASS_GLYPH: PriceMinimumCenterBase = PriceMinimumCenterBaseGlyph; break; - default: break; - } - } - - // Set the minimum price - if (outBuyoutPrice < PriceMinimumCenterBase) - outBuyoutPrice = urand(PriceMinimumCenterBase * (1.0f - BuyoutVariationReducePercent), PriceMinimumCenterBase * (1.0f + BuyoutVariationAddPercent)); - else - outBuyoutPrice = urand(outBuyoutPrice * (1.0f - BuyoutVariationReducePercent), outBuyoutPrice * (1.0f + BuyoutVariationAddPercent)); - - // Ensure no multipliers are zero or negative - if (classPriceMultiplier <= 0.0f) - classPriceMultiplier = 1.0f; - if (qualityPriceMultplier <= 0.0f) - qualityPriceMultplier = 1.0f; - if (classQualityPriceMultiplier <= 0.0f) - classQualityPriceMultiplier = 1.0f; - if (advancedPricingMultiplier <= 0.0f) - advancedPricingMultiplier = 1.0f; - - // Grab any item level price multipliers - float itemLevelPriceMultplier = 0.0f; - switch (itemProto->Class) - { - case ITEM_CLASS_CONSUMABLE: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryConsumable; break; - case ITEM_CLASS_CONTAINER: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryContainer; break; - case ITEM_CLASS_WEAPON: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryWeapon; break; - case ITEM_CLASS_GEM: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryGem; break; - case ITEM_CLASS_REAGENT: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryReagent; break; - case ITEM_CLASS_ARMOR: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryArmor; break; - case ITEM_CLASS_PROJECTILE: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryProjectile; break; - case ITEM_CLASS_TRADE_GOODS: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryTradeGood; break; - case ITEM_CLASS_GENERIC: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryGeneric; break; - case ITEM_CLASS_RECIPE: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryRecipe; break; - case ITEM_CLASS_QUIVER: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryQuiver; break; - case ITEM_CLASS_QUEST: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryQuest; break; - case ITEM_CLASS_KEY: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryKey; break; - case ITEM_CLASS_MISC: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryMisc; break; - case ITEM_CLASS_GLYPH: itemLevelPriceMultplier = PriceMultiplierItemLevelCategoryGlyph; break; - default: break; - } - - // Multiply the price based on multipliers - outBuyoutPrice *= qualityPriceMultplier; - outBuyoutPrice *= classPriceMultiplier; - outBuyoutPrice *= classQualityPriceMultiplier; - outBuyoutPrice *= static_cast(advancedPricingMultiplier); - - // Only apply item level multiplier if set, and no advanced pricing has been enabled - if (itemLevelPriceMultplier > 0.0f && itemProto->ItemLevel > 0 && advancedPricingMultiplier == 1.0f) - outBuyoutPrice *= itemProto->ItemLevel * itemLevelPriceMultplier; - - // If a vendor sells this item, make the price at least that high - if (itemProto->SellPrice > outBuyoutPrice) - outBuyoutPrice = itemProto->SellPrice; - - // Avoid price overflows - if (outBuyoutPrice > MaxBuyoutPriceInCopper) - outBuyoutPrice = MaxBuyoutPriceInCopper; - - // Calculate a bid price based on a variance against buyout price - float sellVarianceBidPriceTopPercent = 1.0f - BidVariationHighReducePercent; - float sellVarianceBidPriceBottomPercent = 1.0f - BidVariationLowReducePercent; - outBidPrice = urand(sellVarianceBidPriceBottomPercent * outBuyoutPrice, sellVarianceBidPriceTopPercent * outBuyoutPrice); - - // If variance brought price below sell price, bring it back up to avoid making money off vendoring AH items - if (outBuyoutPrice < itemProto->SellPrice) - { - float minLowPriceAddVariancePercent = 1.0f + BuyoutBelowVendorVariationAddPercent; - outBuyoutPrice = urand(itemProto->SellPrice, minLowPriceAddVariancePercent * itemProto->SellPrice); - } - - // Bid price can never be below sell price - if (outBidPrice < itemProto->SellPrice) - outBidPrice = itemProto->SellPrice; + return static_cast(advancedPricingMultiplier); } void AuctionHouseBot::populatetemClassSeedListForItemClass(uint32 itemClass, uint32 itemClassSeedWeight) @@ -1043,9 +1050,19 @@ void AuctionHouseBot::addNewAuctionBuyerBotBid(Player* AHBplayer, AHBConfig *con if (auction->buyout != 0 && auction->buyout < willingToPayForStackPrice) doBuyout = true; - else if (auction->startbid < willingToPayForStackPrice && auction->GetAuctionOutBid() < willingToPayForStackPrice) + else if (auction->startbid < willingToPayForStackPrice && (auction->startbid + auction->GetAuctionOutBid()) < willingToPayForStackPrice) doBid = true; + // Check that the item isn't listed above Vendor sell price + if (PreventOverpayingForVendorItems) + { + if (doBuyout && auction->buyout >= vendorItemsPrices[prototype->ItemId]){ + doBuyout = false; + } + if (doBid && (auction->startbid + auction->GetAuctionOutBid()) >= vendorItemsPrices[prototype->ItemId]) + doBid = false; + } + if (debug_Out) { LOG_INFO("module", "-------------------------------------------------"); @@ -1223,6 +1240,9 @@ void AuctionHouseBot::InitializeConfiguration() // Buyer Bot BuyingBotBuyCandidatesPerBuyCycle = sConfigMgr->GetOption("AuctionHouseBot.Buyer.BuyCandidatesPerBuyCycle", 1); BuyingBotAcceptablePriceModifier = sConfigMgr->GetOption("AuctionHouseBot.Buyer.AcceptablePriceModifier", 1); + PreventOverpayingForVendorItems = sConfigMgr->GetOption("AuctionHouseBot.Buyer.PreventOverpayingForVendorItems", true); + if (PreventOverpayingForVendorItems) + populateVendorItemsPrices(); // Stack Ratios RandomStackRatioConsumable = GetRandomStackValue("AuctionHouseBot.ListingStack.RandomRatio.Consumable", 50); @@ -1592,3 +1612,24 @@ const char* AuctionHouseBot::GetCategoryName(ItemClass category) default: return "Unknown"; } } + +void AuctionHouseBot::populateVendorItemsPrices() +{ + // Load vendor items' prices into a vector for fast lookup + QueryResult r = WorldDatabase.Query("SELECT MAX(entry) FROM item_template"); + Field* f = r->Fetch(); + uint32_t numItems = f[0].Get(); + vendorItemsPrices = std::vector(numItems, UINT32_MAX); + + QueryResult result = WorldDatabase.Query("SELECT v.entry, MIN(v.SellPrice) AS SellPrice FROM item_template v JOIN npc_vendor p ON v.entry = p.item GROUP BY v.entry"); + if (result) + { + do + { + Field* pFields = result->Fetch(); + uint32_t itemID = pFields[0].Get(); + uint32_t itemPrice = pFields[1].Get(); + vendorItemsPrices[itemID] = itemPrice; + } while (result->NextRow()); + } +} \ No newline at end of file diff --git a/src/AuctionHouseBot.h b/src/AuctionHouseBot.h index 23ac8a3..2978739 100644 --- a/src/AuctionHouseBot.h +++ b/src/AuctionHouseBot.h @@ -132,6 +132,7 @@ private: uint32 ListingExpireTimeInSecondsMin; uint32 ListingExpireTimeInSecondsMax; float BuyingBotAcceptablePriceModifier; + std::vector vendorItemsPrices; std::string AHCharactersGUIDsForQuery; uint32 ItemsPerCycle; bool DisabledItemTextFilter; @@ -263,6 +264,7 @@ private: uint32 ListedItemIDMin; uint32 ListedItemIDMax; std::set ListedItemIDExceptionItems; + bool PreventOverpayingForVendorItems; AHBConfig AllianceConfig; AHBConfig HordeConfig; @@ -272,6 +274,7 @@ private: uint32 getStackSizeForItem(ItemTemplate const* itemProto) const; void calculateItemValue(ItemTemplate const* itemProto, uint64& outBidPrice, uint64& outBuyoutPrice); + float getAdvancedPricingMultiplier(ItemTemplate const* itemProto); void populatetemClassSeedListForItemClass(uint32 itemClass, uint32 itemClassSeedWeight); void populateItemClassProportionList(); ItemTemplate const* getProducedItemFromRecipe(ItemTemplate const* recipeItemTemplate); @@ -279,6 +282,7 @@ private: int getRandomValidItemClassForNewListing(); void addNewAuctions(Player* AHBplayer, AHBConfig *config); void addNewAuctionBuyerBotBid(Player* AHBplayer, AHBConfig *config); + void populateVendorItemsPrices(); AuctionHouseBot(); From 4fdfa5059792dbf8fffe140fd0ab8cca0ca06904 Mon Sep 17 00:00:00 2001 From: NathanHandley Date: Thu, 18 Sep 2025 08:58:07 -0500 Subject: [PATCH 2/2] Fix bid amount; Fix not buying 0 price vendor items There were two bugs: - If "Prevent Overpay" was enabled, the bot wouldn't pay for anything not sold by a vendor at all (since the price was zero) - The bid math implemented (using startbid) wasn't right, because it ignored if any bids were applied to it beyond that. Now it properly accounts for it. --- src/AuctionHouseBot.cpp | 52 ++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/src/AuctionHouseBot.cpp b/src/AuctionHouseBot.cpp index 7a7e618..cc94575 100644 --- a/src/AuctionHouseBot.cpp +++ b/src/AuctionHouseBot.cpp @@ -1041,26 +1041,44 @@ void AuctionHouseBot::addNewAuctionBuyerBotBid(Player* AHBplayer, AHBConfig *con uint64 discardBidPrice = 0; calculateItemValue(prototype, discardBidPrice, willingToSpendPerItemPrice); willingToSpendPerItemPrice = (uint64)((float)willingToSpendPerItemPrice * BuyingBotAcceptablePriceModifier); - uint64 willingToPayForStackPrice = willingToSpendPerItemPrice * pItem->GetCount(); // Determine if it's a bid, buyout, or skip bool doBuyout = false; bool doBid = false; + uint64 curAuctionBidAmount = 0; + uint64 calcBidAmount = 0; if (auction->buyout != 0 && auction->buyout < willingToPayForStackPrice) doBuyout = true; - else if (auction->startbid < willingToPayForStackPrice && (auction->startbid + auction->GetAuctionOutBid()) < willingToPayForStackPrice) - doBid = true; + else + { + if (auction->bid == 0 && auction->startbid <= willingToPayForStackPrice) + { + doBid = true; + calcBidAmount = auction->startbid; + } + else if (auction->bid != 0 && (auction->bid + auction->GetAuctionOutBid()) < willingToPayForStackPrice) + { + doBid = true; + calcBidAmount = auction->bid + auction->GetAuctionOutBid(); + } + } // Check that the item isn't listed above Vendor sell price - if (PreventOverpayingForVendorItems) + bool preventedOverpayingForVendorItem = false; + if (PreventOverpayingForVendorItems && vendorItemsPrices[prototype->ItemId] > 0) { - if (doBuyout && auction->buyout >= vendorItemsPrices[prototype->ItemId]){ + if (doBuyout && auction->buyout > vendorItemsPrices[prototype->ItemId]) + { doBuyout = false; + preventedOverpayingForVendorItem = true; } - if (doBid && (auction->startbid + auction->GetAuctionOutBid()) >= vendorItemsPrices[prototype->ItemId]) + if (doBid && calcBidAmount > vendorItemsPrices[prototype->ItemId]) + { doBid = false; + preventedOverpayingForVendorItem = true; + } } if (debug_Out) @@ -1076,7 +1094,8 @@ void AuctionHouseBot::addNewAuctionBuyerBotBid(Player* AHBplayer, AHBConfig *con LOG_INFO("module", "AHBuyer: Item Info:"); LOG_INFO("module", "AHBuyer: Item ID: {}", prototype->ItemId); LOG_INFO("module", "AHBuyer: Vendor Buy Price: {}", prototype->BuyPrice); - LOG_INFO("module", "AHBuyer: Vendor Sell Price: {}", prototype->SellPrice); + LOG_INFO("module", "AHBuyer: Vendor Sell Price (Base): {}", prototype->SellPrice); + LOG_INFO("module", "AHBuyer: Vender Sell Price (Vendor): {}", vendorItemsPrices[prototype->ItemId]); LOG_INFO("module", "AHBuyer: Deposit: {}", auction->deposit); LOG_INFO("module", "AHBuyer: Bonding: {}", prototype->Bonding); LOG_INFO("module", "AHBuyer: Quality: {}", prototype->Quality); @@ -1086,28 +1105,23 @@ void AuctionHouseBot::addNewAuctionBuyerBotBid(Player* AHBplayer, AHBConfig *con LOG_INFO("module", "AHBuyer: Starting Bid: {}", auction->startbid); LOG_INFO("module", "AHBuyer: Current Bid: {}", auction->bid); LOG_INFO("module", "AHBuyer: Buyout Price: {}", auction->buyout); - LOG_INFO("module", "AHBuyer: Willing To Pay Per Item Price: {}", willingToSpendPerItemPrice); - LOG_INFO("module", "AHBuyer: Willing To Pay For Stack Price: {}", willingToPayForStackPrice); + LOG_INFO("module", "AHBuyer: Willing To Pay Per Item Price (Buyout): {}", willingToSpendPerItemPrice); + LOG_INFO("module", "AHBuyer: Willing To Pay For Stack Price (Buyout): {}", willingToPayForStackPrice); + LOG_INFO("module", "AHBuyer: Willing To Pay For a Bid: {}", calcBidAmount); LOG_INFO("module", "AHBuyer: Decided to Buyout?: {}", doBuyout); LOG_INFO("module", "AHBuyer: Decided to Bid?: {}", doBid); + LOG_INFO("module", "AHBuyer: Stopped from buying due to 'PreventOverpayingForVendorItems'?: {}", preventedOverpayingForVendorItem); LOG_INFO("module", "-------------------------------------------------"); } if (doBid) { auto trans = CharacterDatabase.BeginTransaction(); - // Perform outbid - uint32 bidAmount = 0; - if (auction->bid == 0) - bidAmount = auction->startbid; - else - bidAmount = auction->GetAuctionOutBid(); - if (auction->bidder) - sAuctionMgr->SendAuctionOutbiddedMail(auction, bidAmount, AHBplayer, trans); + sAuctionMgr->SendAuctionOutbiddedMail(auction, calcBidAmount, AHBplayer, trans); auction->bidder = AHBplayer->GetGUID(); - auction->bid = bidAmount; + auction->bid = calcBidAmount; sAuctionMgr->GetAuctionHouseSearcher()->UpdateBid(auction); @@ -1632,4 +1646,4 @@ void AuctionHouseBot::populateVendorItemsPrices() vendorItemsPrices[itemID] = itemPrice; } while (result->NextRow()); } -} \ No newline at end of file +}