mirror of
https://github.com/NathanHandley/mod-ah-bot-plus.git
synced 2026-01-13 09:17:21 +00:00
Added config, prevent buyerbot from buying overpriced vendor items, refactored advancedPricingMultiplier out of calculateItemValue()
This commit is contained in:
@@ -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<float>(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<float>(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<float>(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<uint32>("AuctionHouseBot.Buyer.BuyCandidatesPerBuyCycle", 1);
|
||||
BuyingBotAcceptablePriceModifier = sConfigMgr->GetOption<float>("AuctionHouseBot.Buyer.AcceptablePriceModifier", 1);
|
||||
PreventOverpayingForVendorItems = sConfigMgr->GetOption<bool>("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<uint32>();
|
||||
vendorItemsPrices = std::vector<uint32>(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>();
|
||||
uint32_t itemPrice = pFields[1].Get<uint32>();
|
||||
vendorItemsPrices[itemID] = itemPrice;
|
||||
} while (result->NextRow());
|
||||
}
|
||||
}
|
||||
@@ -132,6 +132,7 @@ private:
|
||||
uint32 ListingExpireTimeInSecondsMin;
|
||||
uint32 ListingExpireTimeInSecondsMax;
|
||||
float BuyingBotAcceptablePriceModifier;
|
||||
std::vector<uint32> vendorItemsPrices;
|
||||
std::string AHCharactersGUIDsForQuery;
|
||||
uint32 ItemsPerCycle;
|
||||
bool DisabledItemTextFilter;
|
||||
@@ -263,6 +264,7 @@ private:
|
||||
uint32 ListedItemIDMin;
|
||||
uint32 ListedItemIDMax;
|
||||
std::set<uint32> 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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user