From 96e8b337bc51408787dca0c403b381bcc61cb7ab Mon Sep 17 00:00:00 2001 From: antiroot Date: Fri, 8 Jul 2011 20:53:56 +0400 Subject: [PATCH] [11723] Auction House Bot (AHBot) patch applied Thanks to Chris K, cyberium, Dolomit6, grether, Kerbe, Naicisum, Paradox, Xeross and other contributers for creating, long time improvments and patch up-to-date state support. AHBot disabled by default. For enable it you need have ahbot.conf in same dir where mangosd.conf placed and enable options: AuctionHouseBot.Seller.Enabled and/or AuctionHouseBot.Buyer.Enabled Original version ahbot.conf can be found by path: src/game/AuctionHouseBot/ahbot.conf.dist.in Note: chat commands from patch not included in commits and will added later after additional work. Signed-off-by: VladimirMangos --- doc/AuctionHouseBot.txt | 16 + src/game/AuctionHouseBot/AuctionHouseBot.cpp | 1726 ++++++++++++++++++ src/game/AuctionHouseBot/AuctionHouseBot.h | 201 ++ src/game/AuctionHouseBot/ahbot.conf.dist.in | 275 +++ src/game/AuctionHouseMgr.h | 3 + src/game/CMakeLists.txt | 1 + src/game/World.cpp | 14 + src/game/World.h | 3 +- src/shared/Log.cpp | 2 + src/shared/Log.h | 32 +- src/shared/SystemConfig.h.in | 2 + src/shared/revision_nr.h | 2 +- win/VC100/game.vcxproj | 2 + win/VC100/game.vcxproj.filters | 9 + win/VC80/game.vcproj | 8 + win/VC90/game.vcproj | 8 + 16 files changed, 2287 insertions(+), 17 deletions(-) create mode 100644 doc/AuctionHouseBot.txt create mode 100644 src/game/AuctionHouseBot/AuctionHouseBot.cpp create mode 100644 src/game/AuctionHouseBot/AuctionHouseBot.h create mode 100644 src/game/AuctionHouseBot/ahbot.conf.dist.in diff --git a/doc/AuctionHouseBot.txt b/doc/AuctionHouseBot.txt new file mode 100644 index 000000000..7818ed89d --- /dev/null +++ b/doc/AuctionHouseBot.txt @@ -0,0 +1,16 @@ +Auction Houses Bot populates the auction houses with items. +It makes the game feel a bit more active in auction usage part +specially for low-populated servers. Items and prices are chosen +randomly based on the parameters you define. If an auction expires, auctions +are deleted quietly. AHBot will not buy it's own items, and will not receive +mail from the AH or get returned mail. + +=============================================================================== +~~HOW TO CONFIGURE~~ +=============================================================================== + +You must copy config file template as ahbot.conf from src/game/AuctionHouseBot/ahbot.conf.dist.in +to directory wher use store mangosd.conf file, and modify values to appropriate for you state. +Read ahbot.conf option descriptions for details. + +Note: But default AHBot disabled by provided config options values diff --git a/src/game/AuctionHouseBot/AuctionHouseBot.cpp b/src/game/AuctionHouseBot/AuctionHouseBot.cpp new file mode 100644 index 000000000..d0571c62a --- /dev/null +++ b/src/game/AuctionHouseBot/AuctionHouseBot.cpp @@ -0,0 +1,1726 @@ +#include "AuctionHouseBot.h" +#include "ProgressBar.h" +#include "Log.h" +#include "../ObjectMgr.h" +#include "../AuctionHouseMgr.h" +#include "SystemConfig.h" + +// Format is YYYYMMDDRR where RR is the change in the conf file +// for that day. +#define AUCTIONHOUSEBOT_CONF_VERSION 2010102201 + +#include "Policies/SingletonImp.h" + +struct BuyerAuctionEval +{ + BuyerAuctionEval() : AuctionId(0), LastChecked(0), LastExist(0) {} + + uint32 AuctionId; + time_t LastChecked; + time_t LastExist; +}; + +struct BuyerItemInfo +{ + BuyerItemInfo() : ItemCount(0), BuyPrice(0), BidPrice(0), MinBuyPrice(0), MinBidPrice(0) {} + + uint32 ItemCount; + double BuyPrice; + double BidPrice; + uint32 MinBuyPrice; + uint32 MinBidPrice; +}; + +typedef std::map BuyerItemInfoMap; +typedef std::map CheckEntryMap; + +struct AHB_Buyer_Config +{ + public: + AHB_Buyer_Config() : m_houseType(AUCTION_HOUSE_NEUTRAL) {} + + void Initialize(AuctionHouseType houseType) + { + m_houseType = houseType; + } + + AuctionHouseType GetHouseType() const { return m_houseType; } + + public: + BuyerItemInfoMap SameItemInfo; + CheckEntryMap CheckedEntry; + uint32 FactionChance; + bool BuyerEnabled; + uint32 BuyerPriceRatio; + + private: + AuctionHouseType m_houseType; +}; + +struct RandomArrayEntry +{ + uint32 color; + uint32 itemclass; +}; + +typedef std::vector RandomArray; + +struct SellerItemClassInfo +{ + SellerItemClassInfo() : AmountOfItems(0), MissItems(0), Quantity(0) {} + + uint32 AmountOfItems; + uint32 MissItems; + uint32 Quantity; + +}; + +struct SellerItemInfo +{ + SellerItemInfo() : AmountOfItems(0), MissItems(0), PriceRatio(0) {} + + uint32 AmountOfItems; + uint32 MissItems; + uint32 PriceRatio; + + SellerItemClassInfo ItemClassInfos[MAX_ITEM_CLASS]; +}; + +class AHB_Seller_Config +{ + public: + AHB_Seller_Config() : m_houseType(AUCTION_HOUSE_NEUTRAL) + { + } + + ~AHB_Seller_Config() {} + + void Initialize(AuctionHouseType houseType) + { + m_houseType = houseType; + } + + AuctionHouseType GetHouseType() const { return m_houseType; } + + uint32 LastMissedItem; + + void SetMinTime(uint32 value) + { + m_minTime = value; + } + uint32 GetMinTime() const + { + if (m_minTime < 1) + return 1; + else if ((m_maxTime) && (m_minTime > m_maxTime)) + return m_maxTime; + else + return m_minTime; + } + + void SetMaxTime(uint32 value) { m_maxTime = value; } + uint32 GetMaxTime() const { return m_maxTime; } + // Data access classified by item class and item quality // + void SetItemsAmountPerClass(AuctionQuality quality, ItemClass itemclass, uint32 amount) { m_ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems=amount * m_ItemInfo[quality].ItemClassInfos[itemclass].Quantity; } + uint32 GetItemsAmountPerClass(AuctionQuality quality, ItemClass itemclass) const { return m_ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems; } + void SetItemsQuantityPerClass(AuctionQuality quality, ItemClass itemclass, uint32 qty) { m_ItemInfo[quality].ItemClassInfos[itemclass].Quantity=qty; } + uint32 GetItemsQuantityPerClass(AuctionQuality quality, ItemClass itemclass) const { return m_ItemInfo[quality].ItemClassInfos[itemclass].Quantity; } + void SetMissedItemsPerClass(AuctionQuality quality, ItemClass itemclass, uint32 found) + { + if (m_ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems > found ) + m_ItemInfo[quality].ItemClassInfos[itemclass].MissItems=m_ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems - found; + else + m_ItemInfo[quality].ItemClassInfos[itemclass].MissItems = 0; + } + uint32 GetMissedItemsPerClass(AuctionQuality quality, ItemClass itemclass) const { return m_ItemInfo[quality].ItemClassInfos[itemclass].MissItems; } + + // Data for every quality of item // + void SetItemsAmountPerQuality(AuctionQuality quality, uint32 cnt) { m_ItemInfo[quality].AmountOfItems=cnt; } + uint32 GetItemsAmountPerQuality(AuctionQuality quality) const { return m_ItemInfo[quality].AmountOfItems; } + void SetPriceRatioPerQuality(AuctionQuality quality, uint32 value) { m_ItemInfo[quality].PriceRatio=value; } + uint32 GetPriceRatioPerQuality(AuctionQuality quality) const { return m_ItemInfo[quality].PriceRatio; } + + private: + AuctionHouseType m_houseType; + uint32 m_minTime; + uint32 m_maxTime; + SellerItemInfo m_ItemInfo[MAX_AUCTION_QUALITY]; +}; + +// This class handle all Buyer method +// (holder of AuctionBotConfig for each auction house type) +class AuctionBotBuyer : public AuctionBotAgent +{ + public: + AuctionBotBuyer(); + ~AuctionBotBuyer(); + + bool Initialize() override; + bool Update(AuctionHouseType houseType) override; + + void LoadConfig(); + void addNewAuctionBuyerBotBid(AHB_Buyer_Config& config); + + private: + uint32 m_CheckInterval; + AHB_Buyer_Config m_HouseConfig[MAX_AUCTION_HOUSE_TYPE]; + + void LoadBuyerValues(AHB_Buyer_Config& config); + bool IsBuyableEntry(uint32 buyoutPrice, double InGame_BuyPrice, double MaxBuyablePrice, uint32 MinBuyPrice, uint32 MaxChance, uint32 ChanceRatio); + bool IsBidableEntry(uint32 bidPrice, double InGame_BuyPrice, double MaxBidablePrice, uint32 MinBidPrice, uint32 MaxChance, uint32 ChanceRatio); + void PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice); + void BuyEntry(AuctionEntry* auction); + void PrepareListOfEntry(AHB_Buyer_Config& config); + uint32 GetBuyableEntry(AHB_Buyer_Config& config); +}; + +// This class handle all Selling method +// (holder of AHB_Seller_Config data for each auction house type) +class AuctionBotSeller : public AuctionBotAgent +{ + public: + typedef std::vector ItemPool; + + AuctionBotSeller(); + ~AuctionBotSeller(); + + bool Initialize() override; + bool Update(AuctionHouseType houseType) override; + + void addNewAuctions(AHB_Seller_Config& config); + void SetItemsRatio(uint32* al, uint32* ho, uint32* ne); + void SetItemsAmount(uint32* grey_i, uint32* white_i, uint32* green_i, uint32* blue_i, uint32* purple_i, uint32* orange_i, uint32* yellow_i); + void LoadConfig(); + + private: + AHB_Seller_Config m_HouseConfig[MAX_AUCTION_HOUSE_TYPE]; + + ItemPool m_ItemPool[MAX_AUCTION_QUALITY][MAX_ITEM_CLASS]; + + void LoadSellerValues(AHB_Seller_Config& config); + uint32 SetStat(AHB_Seller_Config& config); + bool getRandomArray( AHB_Seller_Config& config, RandomArray& ra, const std::vector >& addedItem ); + void SetPricesOfItem(ItemPrototype const *itemProto, AHB_Seller_Config& config, uint32& buyp, uint32& bidp, uint32 stackcnt, ItemQualities itemQuality); + void LoadItemsQuantity(AHB_Seller_Config& config); +}; + +INSTANTIATE_SINGLETON_1( AuctionHouseBot ); +INSTANTIATE_SINGLETON_1( AuctionBotConfig ); + +//== AuctionBotConfig functions ============================ + +bool AuctionBotConfig::Initialize() +{ + char const* cfg_file = _AUCTIONHOUSEBOT_CONFIG; + if (!m_AhBotCfg.SetSource(cfg_file)) + { + sLog.outString("AHBOT is Disabled. Unable to open configuration file(%s). ", _AUCTIONHOUSEBOT_CONFIG); + setConfig(CONFIG_UINT32_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO, 0); + setConfig(CONFIG_UINT32_AHBOT_HORDE_ITEM_AMOUNT_RATIO, 0); + setConfig(CONFIG_UINT32_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO, 0); + return false; + } + else + sLog.outString("AHBot using configuration file %s",_AUCTIONHOUSEBOT_CONFIG); + + GetConfigFromFile(); + + if (!getConfig(CONFIG_BOOL_AHBOT_BUYER_ENABLED) && !getConfig(CONFIG_BOOL_AHBOT_SELLER_ENABLED)) + { + sLog.outString("AHBOT is Disabled. (If you want to use it please set config in 'ahbot.conf')"); + return false; + } + + if ((getConfig(CONFIG_UINT32_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO)==0) && (getConfig(CONFIG_UINT32_AHBOT_HORDE_ITEM_AMOUNT_RATIO)==0) && (getConfig(CONFIG_UINT32_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO)==0) && + !getConfig(CONFIG_BOOL_AHBOT_BUYER_ALLIANCE_ENABLED) && !getConfig(CONFIG_BOOL_AHBOT_BUYER_HORDE_ENABLED) && !getConfig(CONFIG_BOOL_AHBOT_BUYER_NEUTRAL_ENABLED)) + { + sLog.outString("All feature of AuctionHouseBot are disabled! (If you want to use it please set config in 'ahbot.conf')"); + return false; + } + if ((getConfig(CONFIG_UINT32_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO)==0) && (getConfig(CONFIG_UINT32_AHBOT_HORDE_ITEM_AMOUNT_RATIO)==0) && (getConfig(CONFIG_UINT32_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO)==0)) + sLog.outString("AuctionHouseBot SELLER is disabled! (If you want to use it please set config in 'ahbot.conf')"); + + if (!getConfig(CONFIG_BOOL_AHBOT_BUYER_ALLIANCE_ENABLED) && !getConfig(CONFIG_BOOL_AHBOT_BUYER_HORDE_ENABLED) && !getConfig(CONFIG_BOOL_AHBOT_BUYER_NEUTRAL_ENABLED)) + sLog.outString("AuctionHouseBot BUYER is disabled! (If you want to use it please set config in 'ahbot.conf')"); + + m_ItemsPerCycleBoost = getConfig(CONFIG_UINT32_AHBOT_ITEMS_PER_CYCLE_BOOST); + m_ItemsPerCycleNormal = getConfig(CONFIG_UINT32_AHBOT_ITEMS_PER_CYCLE_NORMAL); + return true; +} + +void AuctionBotConfig::setConfig(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue) +{ + setConfig(index, m_AhBotCfg.GetIntDefault(fieldname,defvalue)); + if (int32(getConfig(index)) < 0) + { + sLog.outError("AHBot: %s (%i) can't be negative. Using %u instead.", fieldname, int32(getConfig(index)), defvalue); + setConfig(index, defvalue); + } +} + +void AuctionBotConfig::setConfigMax(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 maxvalue) +{ + setConfig(index, m_AhBotCfg.GetIntDefault(fieldname,defvalue)); + if (getConfig(index) > maxvalue) + { + sLog.outError("AHBot: %s (%u) must be in range 0...%u. Using %u instead.", fieldname, getConfig(index), maxvalue, maxvalue); + setConfig(index, maxvalue); + } +} + +void AuctionBotConfig::setConfigMinMax(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 minvalue, uint32 maxvalue) +{ + setConfig(index, m_AhBotCfg.GetIntDefault(fieldname,defvalue)); + if (getConfig(index) > maxvalue) + { + sLog.outError("AHBot: %s (%u) must be in range %u...%u. Using %u instead.", fieldname, getConfig(index), minvalue, maxvalue, maxvalue); + setConfig(index, maxvalue); + } + if (getConfig(index) < minvalue) + { + sLog.outError("AHBot: %s (%u) must be in range %u...%u. Using %u instead.", fieldname, getConfig(index), minvalue, maxvalue, minvalue); + setConfig(index, minvalue); + } +} + +void AuctionBotConfig::setConfig(AuctionBotConfigBoolValues index, char const* fieldname, bool defvalue) +{ + setConfig(index, m_AhBotCfg.GetBoolDefault(fieldname,defvalue)); +} + +//Get AuctionHousebot configuration file +void AuctionBotConfig::GetConfigFromFile() +{ + //Check config file version + if (m_AhBotCfg.GetIntDefault("ConfVersion", 0) != AUCTIONHOUSEBOT_CONF_VERSION) + sLog.outError("AHBot: Configuration file version doesn't match expected version. Some config variables may be wrong or missing."); + + setConfigMax(CONFIG_UINT32_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO , "AuctionHouseBot.Alliance.Items.Amount.Ratio" , 0, 10000); + setConfigMax(CONFIG_UINT32_AHBOT_HORDE_ITEM_AMOUNT_RATIO , "AuctionHouseBot.Horde.Items.Amount.Ratio" , 0, 10000); + setConfigMax(CONFIG_UINT32_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO , "AuctionHouseBot.Neutral.Items.Amount.Ratio" , 0, 10000); + + SetAHBotIncludes(m_AhBotCfg.GetStringDefault("AuctionHouseBot.forceIncludeItems", "")); + SetAHBotExcludes(m_AhBotCfg.GetStringDefault("AuctionHouseBot.forceExcludeItems", "")); + + setConfig(CONFIG_BOOL_AHBOT_BUYER_ALLIANCE_ENABLED , "AuctionHouseBot.Buyer.Alliance.Enabled" , false); + setConfig(CONFIG_BOOL_AHBOT_BUYER_HORDE_ENABLED , "AuctionHouseBot.Buyer.Horde.Enabled" , false); + setConfig(CONFIG_BOOL_AHBOT_BUYER_NEUTRAL_ENABLED , "AuctionHouseBot.Buyer.Neutral.Enabled" , false); + + setConfig(CONFIG_BOOL_AHBOT_ITEMS_VENDOR , "AuctionHouseBot.Items.Vendor" , false); + setConfig(CONFIG_BOOL_AHBOT_ITEMS_LOOT , "AuctionHouseBot.Items.Loot" , true); + setConfig(CONFIG_BOOL_AHBOT_ITEMS_MISC , "AuctionHouseBot.Items.Misc" , false); + + setConfig(CONFIG_BOOL_AHBOT_BIND_NO , "AuctionHouseBot.Bind.No" , true); + setConfig(CONFIG_BOOL_AHBOT_BIND_PICKUP , "AuctionHouseBot.Bind.Pickup" , false); + setConfig(CONFIG_BOOL_AHBOT_BIND_EQUIP , "AuctionHouseBot.Bind.Equip" , true); + setConfig(CONFIG_BOOL_AHBOT_BIND_USE , "AuctionHouseBot.Bind.Use" , true); + setConfig(CONFIG_BOOL_AHBOT_BIND_QUEST , "AuctionHouseBot.Bind.Quest" , false); + setConfig(CONFIG_BOOL_AHBOT_LOCKBOX_ENABLED , "AuctionHouseBot.LockBox.Enabled" , false); + + setConfig(CONFIG_BOOL_AHBOT_BUYPRICE_SELLER , "AuctionHouseBot.BuyPrice.Seller" , true); + + setConfig(CONFIG_UINT32_AHBOT_ITEMS_PER_CYCLE_BOOST , "AuctionHouseBot.ItemsPerCycle.Boost" , 1000); + setConfig(CONFIG_UINT32_AHBOT_ITEMS_PER_CYCLE_NORMAL , "AuctionHouseBot.ItemsPerCycle.Normal" , 10); + + setConfig(CONFIG_UINT32_AHBOT_ITEM_MIN_ITEM_LEVEL , "AuctionHouseBot.Items.ItemLevel.Min" , 0); + setConfig(CONFIG_UINT32_AHBOT_ITEM_MAX_ITEM_LEVEL , "AuctionHouseBot.Items.ItemLevel.Max" , 0); + setConfig(CONFIG_UINT32_AHBOT_ITEM_MIN_REQ_LEVEL , "AuctionHouseBot.Items.ReqLevel.Min" , 0); + setConfig(CONFIG_UINT32_AHBOT_ITEM_MAX_REQ_LEVEL , "AuctionHouseBot.Items.ReqLevel.Max" , 0); + setConfig(CONFIG_UINT32_AHBOT_ITEM_MIN_SKILL_RANK , "AuctionHouseBot.Items.ReqSkill.Min" , 0); + setConfig(CONFIG_UINT32_AHBOT_ITEM_MAX_SKILL_RANK , "AuctionHouseBot.Items.ReqSkill.Max" , 0); + + setConfig(CONFIG_UINT32_AHBOT_ITEM_GREY_AMOUNT , "AuctionHouseBot.Items.Amount.Grey" , 0); + setConfig(CONFIG_UINT32_AHBOT_ITEM_WHITE_AMOUNT , "AuctionHouseBot.Items.Amount.White" , 2000); + setConfig(CONFIG_UINT32_AHBOT_ITEM_GREEN_AMOUNT , "AuctionHouseBot.Items.Amount.Green" , 2500); + setConfig(CONFIG_UINT32_AHBOT_ITEM_BLUE_AMOUNT , "AuctionHouseBot.Items.Amount.Blue" , 1500); + setConfig(CONFIG_UINT32_AHBOT_ITEM_PURPLE_AMOUNT , "AuctionHouseBot.Items.Amount.Purple" , 500); + setConfig(CONFIG_UINT32_AHBOT_ITEM_ORANGE_AMOUNT , "AuctionHouseBot.Items.Amount.Orange" , 0); + setConfig(CONFIG_UINT32_AHBOT_ITEM_YELLOW_AMOUNT , "AuctionHouseBot.Items.Amount.Yellow" , 0); + + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_CONSUMABLE_AMOUNT , "AuctionHouseBot.Class.Consumable" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_CONTAINER_AMOUNT , "AuctionHouseBot.Class.Container" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_WEAPON_AMOUNT , "AuctionHouseBot.Class.Weapon" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_GEM_AMOUNT , "AuctionHouseBot.Class.Gem" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_ARMOR_AMOUNT , "AuctionHouseBot.Class.Armor" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_REAGENT_AMOUNT , "AuctionHouseBot.Class.Reagent" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_PROJECTILE_AMOUNT , "AuctionHouseBot.Class.Projectile" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_AMOUNT , "AuctionHouseBot.Class.TradeGood" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_GENERIC_AMOUNT , "AuctionHouseBot.Class.Generic" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_RECIPE_AMOUNT , "AuctionHouseBot.Class.Recipe" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_QUIVER_AMOUNT , "AuctionHouseBot.Class.Quiver" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_QUEST_AMOUNT , "AuctionHouseBot.Class.Quest" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_KEY_AMOUNT , "AuctionHouseBot.Class.Key" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_MISC_AMOUNT , "AuctionHouseBot.Class.Misc" , 10, 10); + setConfigMax(CONFIG_UINT32_AHBOT_CLASS_GLYPH_AMOUNT , "AuctionHouseBot.Class.Glyph" , 10, 10); + + setConfig(CONFIG_UINT32_AHBOT_ALLIANCE_PRICE_RATIO , "AuctionHouseBot.Alliance.Price.Ratio" , 100); + setConfig(CONFIG_UINT32_AHBOT_HORDE_PRICE_RATIO , "AuctionHouseBot.Horde.Price.Ratio" , 100); + setConfig(CONFIG_UINT32_AHBOT_NEUTRAL_PRICE_RATIO , "AuctionHouseBot.Neutral.Price.Ratio" , 100); + + setConfig(CONFIG_UINT32_AHBOT_MINTIME , "AuctionHouseBot.MinTime" , 1); + setConfig(CONFIG_UINT32_AHBOT_MAXTIME , "AuctionHouseBot.MaxTime" , 72); + + setConfigMinMax(CONFIG_UINT32_AHBOT_BUYER_CHANCE_RATIO_ALLIANCE, "AuctionHouseBot.Buyer.Alliance.Chance.Ratio", 3, 1, 100); + setConfigMinMax(CONFIG_UINT32_AHBOT_BUYER_CHANCE_RATIO_HORDE , "AuctionHouseBot.Buyer.Horde.Chance.Ratio" , 3, 1, 100); + setConfigMinMax(CONFIG_UINT32_AHBOT_BUYER_CHANCE_RATIO_NEUTRAL , "AuctionHouseBot.Buyer.Neutral.Chance.Ratio" , 3, 1, 100); + setConfigMinMax(CONFIG_UINT32_AHBOT_BUYER_RECHECK_INTERVAL , "AuctionHouseBot.Buyer.Recheck.Interval" , 20,1, DAY/MINUTE); + + setConfig(CONFIG_BOOL_AHBOT_DEBUG_SELLER , "AuctionHouseBot.DEBUG.Seller" , false); + setConfig(CONFIG_BOOL_AHBOT_DEBUG_BUYER , "AuctionHouseBot.DEBUG.Buyer" , false); + setConfig(CONFIG_BOOL_AHBOT_SELLER_ENABLED , "AuctionHouseBot.Seller.Enabled" , false); + setConfig(CONFIG_BOOL_AHBOT_BUYER_ENABLED , "AuctionHouseBot.Buyer.Enabled" , false); + setConfig(CONFIG_BOOL_AHBOT_BUYPRICE_BUYER , "AuctionHouseBot.Buyer.Buyprice" , true); + + setConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MIN_REQ_LEVEL , "AuctionHouseBot.Class.Misc.Mount.ReqLevel.Min" , 0); + setConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MAX_REQ_LEVEL , "AuctionHouseBot.Class.Misc.Mount.ReqLevel.Max" , 0); + setConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MIN_SKILL_RANK , "AuctionHouseBot.Class.Misc.Mount.ReqSkill.Min" , 0); + setConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MAX_SKILL_RANK , "AuctionHouseBot.Class.Misc.Mount.ReqSkill.Max" , 0); + setConfig(CONFIG_UINT32_AHBOT_CLASS_GLYPH_MIN_REQ_LEVEL , "AuctionHouseBot.Class.Glyph.ReqLevel.Min" , 0); + setConfig(CONFIG_UINT32_AHBOT_CLASS_GLYPH_MAX_REQ_LEVEL , "AuctionHouseBot.Class.Glyph.ReqLevel.Max" , 0); + setConfig(CONFIG_UINT32_AHBOT_CLASS_GLYPH_MIN_ITEM_LEVEL , "AuctionHouseBot.Class.Glyph.ItemLevel.Min" , 0); + setConfig(CONFIG_UINT32_AHBOT_CLASS_GLYPH_MAX_ITEM_LEVEL , "AuctionHouseBot.Class.Glyph.ItemLevel.Max" , 0); + setConfig(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_MIN_ITEM_LEVEL , "AuctionHouseBot.Class.TradeGood.ItemLevel.Min" , 0); + setConfig(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_MAX_ITEM_LEVEL , "AuctionHouseBot.Class.TradeGood.ItemLevel.Max" , 0); + setConfig(CONFIG_UINT32_AHBOT_CLASS_CONTAINER_MIN_ITEM_LEVEL , "AuctionHouseBot.Class.Container.ItemLevel.Min" , 0); + setConfig(CONFIG_UINT32_AHBOT_CLASS_CONTAINER_MAX_ITEM_LEVEL , "AuctionHouseBot.Class.Container.ItemLevel.Max" , 0); +} + +bool AuctionBotConfig::Reload() +{ + if (m_AhBotCfg.Reload()) + { + GetConfigFromFile(); + return true; + } + return false; +} + +char const* AuctionBotConfig::GetItemClassName(ItemClass itemclass) +{ + ItemClassEntry const* itemClassEntry = sItemClassStore.LookupEntry(itemclass); + return itemClassEntry ? itemClassEntry->name[sWorld.GetDefaultDbcLocale()] : ""; +} + +char const* AuctionBotConfig::GetHouseTypeName(AuctionHouseType houseType) +{ + char const* names[MAX_AUCTION_HOUSE_TYPE] = { "Alliance", "Horde", "Neutral" }; + return names[houseType]; +} + +uint32 AuctionBotConfig::getConfigItemAmountRatio(AuctionHouseType houseType) const +{ + switch (houseType) + { + case AUCTION_HOUSE_ALLIANCE: return getConfig(CONFIG_UINT32_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO); + case AUCTION_HOUSE_HORDE: return getConfig(CONFIG_UINT32_AHBOT_HORDE_ITEM_AMOUNT_RATIO); + default: return getConfig(CONFIG_UINT32_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO); + } +} + +bool AuctionBotConfig::getConfigBuyerEnabled(AuctionHouseType houseType) const +{ + switch (houseType) + { + case AUCTION_HOUSE_ALLIANCE: return getConfig(CONFIG_BOOL_AHBOT_BUYER_ALLIANCE_ENABLED); + case AUCTION_HOUSE_HORDE: return getConfig(CONFIG_BOOL_AHBOT_BUYER_HORDE_ENABLED); + default: return getConfig(CONFIG_BOOL_AHBOT_BUYER_NEUTRAL_ENABLED); + } +} + +//== AuctionBotBuyer functions ============================= + +AuctionBotBuyer::AuctionBotBuyer() +{ + // Define faction for our main data class. + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + m_HouseConfig[i].Initialize(AuctionHouseType(i)); +} + +AuctionBotBuyer::~AuctionBotBuyer() +{ +} + +bool AuctionBotBuyer::Initialize() +{ + LoadConfig(); + + bool active_house = false; + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + { + if (m_HouseConfig[i].BuyerEnabled) + { + active_house = true; + break; + } + } + if (!active_house) + return false; + + //load Check interval + m_CheckInterval = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_BUYER_RECHECK_INTERVAL) * MINUTE; + DETAIL_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot buyer interval between 2 check = %u", m_CheckInterval); + sLog.SetLogFilter(LOG_FILTER_AHBOT_BUYER, !sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_DEBUG_BUYER)); + return true; +} + +void AuctionBotBuyer::LoadBuyerValues(AHB_Buyer_Config& config) +{ + uint32 FactionChance; + switch(config.GetHouseType()) + { + case AUCTION_HOUSE_ALLIANCE: + config.BuyerPriceRatio = sAuctionBotConfig.getConfig( CONFIG_UINT32_AHBOT_ALLIANCE_PRICE_RATIO )+50; + FactionChance = sAuctionBotConfig.getConfig( CONFIG_UINT32_AHBOT_BUYER_CHANCE_RATIO_ALLIANCE ); + break; + case AUCTION_HOUSE_HORDE: + config.BuyerPriceRatio = sAuctionBotConfig.getConfig( CONFIG_UINT32_AHBOT_HORDE_PRICE_RATIO )+50; + FactionChance = sAuctionBotConfig.getConfig( CONFIG_UINT32_AHBOT_BUYER_CHANCE_RATIO_HORDE ); + break; + default: + config.BuyerPriceRatio = sAuctionBotConfig.getConfig( CONFIG_UINT32_AHBOT_NEUTRAL_PRICE_RATIO )+50; + FactionChance = sAuctionBotConfig.getConfig( CONFIG_UINT32_AHBOT_BUYER_CHANCE_RATIO_NEUTRAL ); + break; + } + config.FactionChance=5000*FactionChance; +} + +void AuctionBotBuyer::LoadConfig() +{ + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + { + m_HouseConfig[i].BuyerEnabled = sAuctionBotConfig.getConfigBuyerEnabled(AuctionHouseType(i)); + if (m_HouseConfig[i].BuyerEnabled) + LoadBuyerValues(m_HouseConfig[i]); + } +} + +uint32 AuctionBotBuyer::GetBuyableEntry(AHB_Buyer_Config& config) +{ + config.SameItemInfo.clear(); + uint32 count=0; + time_t Now=time(NULL); + + AuctionHouseObject::AuctionEntryMapBounds bounds = sAuctionMgr.GetAuctionsMap(config.GetHouseType())->GetAuctionsBounds(); + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr) + { + AuctionEntry *Aentry = itr->second; + Item *item = sAuctionMgr.GetAItem(Aentry->itemGuidLow); + if (item) + { + ItemPrototype const *prototype = item->GetProto(); + if (prototype) + { + ++config.SameItemInfo[item->GetEntry()].ItemCount; // Structure constructor will make sure Element are correctly initialised if entry is created here. + config.SameItemInfo[item->GetEntry()].BuyPrice =config.SameItemInfo[item->GetEntry()].BuyPrice + (itr->second->buyout/item->GetCount()); + config.SameItemInfo[item->GetEntry()].BidPrice =config.SameItemInfo[item->GetEntry()].BidPrice + (itr->second->startbid/item->GetCount()); + if (itr->second->buyout != 0) + { + if (itr->second->buyout/item->GetCount() < config.SameItemInfo[item->GetEntry()].MinBuyPrice) + config.SameItemInfo[item->GetEntry()].MinBuyPrice = itr->second->buyout/item->GetCount(); + else if (config.SameItemInfo[item->GetEntry()].MinBuyPrice == 0) + config.SameItemInfo[item->GetEntry()].MinBuyPrice = itr->second->buyout/item->GetCount(); + } + if (itr->second->startbid/item->GetCount() < config.SameItemInfo[item->GetEntry()].MinBidPrice) + config.SameItemInfo[item->GetEntry()].MinBidPrice = itr->second->startbid/item->GetCount(); + else if (config.SameItemInfo[item->GetEntry()].MinBidPrice == 0) + config.SameItemInfo[item->GetEntry()].MinBidPrice = itr->second->startbid/item->GetCount(); + + if (!Aentry->owner) + { + + if ((Aentry->bid!=0) && Aentry->bidder) // Add bided by player + { + config.CheckedEntry[Aentry->Id].LastExist=Now; + config.CheckedEntry[Aentry->Id].AuctionId=Aentry->Id; + ++count; + } + } + else + { + if (Aentry->bid!=0) + { + if (Aentry->bidder) + { + config.CheckedEntry[Aentry->Id].LastExist=Now; + config.CheckedEntry[Aentry->Id].AuctionId=Aentry->Id; + ++count; + } + } + else + { + config.CheckedEntry[Aentry->Id].LastExist=Now; + config.CheckedEntry[Aentry->Id].AuctionId=Aentry->Id; + ++count; + } + } + } + } + } + + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: %u items added to buyable vector for ah type: %u",count, config.GetHouseType()); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: SameItemInfo size = %u", config.SameItemInfo.size()); + return count; +} + +void AuctionBotBuyer::PrepareListOfEntry(AHB_Buyer_Config& config) +{ + time_t Now=time(NULL)-5; + + for (CheckEntryMap::iterator itr=config.CheckedEntry.begin();itr != config.CheckedEntry.end();) + { + if (itr->second.LastExist < (Now-5)) + config.CheckedEntry.erase(itr++); + else + ++itr; + } + + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: CheckedEntry size = %u",config.CheckedEntry.size()); +} + +bool AuctionBotBuyer::IsBuyableEntry(uint32 buyoutPrice, double InGame_BuyPrice, double MaxBuyablePrice, uint32 MinBuyPrice, uint32 MaxChance, uint32 ChanceRatio) +{ + double ratio=0; + uint32 Chance=0; + + if (buyoutPrice <= MinBuyPrice) + { + if (buyoutPrice <= MaxBuyablePrice) + Chance=MaxChance; + else + { + + if ((buyoutPrice > 0) && (MaxBuyablePrice > 0)) + { + ratio = buyoutPrice / MaxBuyablePrice; + if (ratio < 10) + Chance=MaxChance - (ratio*(MaxChance/10)); + else Chance=1; + } + } + } + else if (buyoutPrice <= InGame_BuyPrice) + { + if (buyoutPrice <= MaxBuyablePrice) + Chance=MaxChance/5; + else + { + + if ((buyoutPrice > 0) && (MaxBuyablePrice > 0)) + { + ratio = buyoutPrice / MaxBuyablePrice; + if (ratio < 10) + Chance=(MaxChance/5) - (ratio*(MaxChance/50)); + else Chance=1; + } + } + } + else if (buyoutPrice <= MaxBuyablePrice) + Chance = MaxChance/10; + else + { + if ((buyoutPrice > 0) && (MaxBuyablePrice > 0)) + { + ratio = buyoutPrice / MaxBuyablePrice; + if (ratio < 10) + Chance=(MaxChance/5) - (ratio*(MaxChance/50)); + else Chance=0; + } + else Chance = 0; + } + uint32 RandNum = urand(1,ChanceRatio); + if (RandNum<=Chance) + { + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: WIN BUY! Chance = %u, num = %u.",Chance, RandNum); + return true; + } + else + { + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot:LOOSE BUY! Chance = %u, num = %u.",Chance, RandNum); + return false; + } +} + +bool AuctionBotBuyer::IsBidableEntry(uint32 bidPrice, double InGame_BuyPrice, double MaxBidablePrice, uint32 MinBidPrice, uint32 MaxChance, uint32 ChanceRatio) +{ + double ratio=0; + uint32 Chance=0; + + if (bidPrice <= MinBidPrice) + { + if ((InGame_BuyPrice != 0) && (bidPrice < (InGame_BuyPrice - (InGame_BuyPrice / 30)))) + Chance=MaxChance; + else + { + if (bidPrice < MaxBidablePrice) + { + ratio = MaxBidablePrice / bidPrice; + if (ratio < 3) + Chance = ((MaxChance/500)*ratio); + else + Chance = (MaxChance/500); + } + } + } + else if (bidPrice < (InGame_BuyPrice - (InGame_BuyPrice / 30))) + Chance=(MaxChance/10); + else + { + if (bidPrice < MaxBidablePrice) + { + ratio = MaxBidablePrice / bidPrice; + if (ratio < 4) + Chance = ((MaxChance/1000)*ratio); + else + Chance = (MaxChance/1000); + } + } + uint32 RandNum = urand(1,ChanceRatio); + if (RandNum<=Chance) + { + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: WIN BID! Chance = %u, num = %u.",Chance, RandNum); + return true; + } else + { + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: LOOSE BID! Chance = %u, num = %u.",Chance, RandNum); + return false; + } +} + +void AuctionBotBuyer::PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice) +{ + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: Bid placed to entry %u, %.2fg", auction->Id, float(bidPrice) / 10000.0f); + auction->UpdateBid(bidPrice); +} + +void AuctionBotBuyer::BuyEntry(AuctionEntry* auction) +{ + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: Entry %u buyed at %.2fg", auction->Id, float(auction->buyout) / 10000.0f); + auction->UpdateBid(auction->buyout); +} + +void AuctionBotBuyer::addNewAuctionBuyerBotBid(AHB_Buyer_Config& config) +{ + AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(config.GetHouseType()); + + PrepareListOfEntry(config); + + time_t Now = time(NULL); + uint32 BuyCycles; + if (config.CheckedEntry.size() > sAuctionBotConfig.GetItemPerCycleBoost()) + { + BuyCycles=sAuctionBotConfig.GetItemPerCycleBoost(); + BASIC_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: Boost value used for Buyer! (if this happens often adjust both ItemsPerCycle in ahbot.conf)"); + } + else + BuyCycles=sAuctionBotConfig.GetItemPerCycleNormal(); + + for (CheckEntryMap::iterator itr =config.CheckedEntry.begin(); itr != config.CheckedEntry.end();) + { + AuctionEntry* auction = auctionHouse->GetAuction(itr->second.AuctionId); + if (!auction || auction->moneyDeliveryTime) // is auction not active now + { + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: Entry %u on ah %u doesn't exists, perhaps bought already?", + itr->second.AuctionId, auction->GetHouseId()); + + config.CheckedEntry.erase(itr++); + continue; + } + + if ((itr->second.LastChecked != 0) && ((Now - itr->second.LastChecked) <= m_CheckInterval)) + { + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: In time interval wait for entry %u!", auction->Id); + ++itr; + continue; + } + + if (BuyCycles == 0) + break; + + uint32 MaxChance=5000; + + Item *item = sAuctionMgr.GetAItem(auction->itemGuidLow); + if (!item) // auction item not accessible, possible auction in payment pending mode + { + config.CheckedEntry.erase(itr++); + continue; + } + + ItemPrototype const *prototype = item->GetProto(); + + uint32 BasePrice = sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_BUYPRICE_BUYER) ? prototype->BuyPrice : prototype->SellPrice; + BasePrice *= item->GetCount(); + + double MaxBuyablePrice = ( BasePrice * config.BuyerPriceRatio )/100; + BuyerItemInfoMap::iterator sameitem_itr = config.SameItemInfo.find(item->GetEntry()); + uint32 buyoutPrice = auction->buyout/item->GetCount(); + + uint32 bidPrice; + uint32 bidPriceByItem; + if (auction->bid >= auction->startbid) + { + bidPrice = auction->GetAuctionOutBid(); + bidPriceByItem = auction->bid/item->GetCount(); + } + else + { + bidPrice = auction->startbid; + bidPriceByItem = auction->startbid/item->GetCount(); + } + + double InGame_BuyPrice; + double InGame_BidPrice; + if (sameitem_itr==config.SameItemInfo.end()) + { + InGame_BuyPrice=0; + InGame_BidPrice=0; + } + else + { + if (sameitem_itr->second.ItemCount == 1) MaxBuyablePrice = MaxBuyablePrice * 5; // if only one item exist can be buyed if the price is high too. + InGame_BuyPrice=sameitem_itr->second.BuyPrice/sameitem_itr->second.ItemCount; + InGame_BidPrice=sameitem_itr->second.BidPrice/sameitem_itr->second.ItemCount; + } + + double MaxBidablePrice = MaxBuyablePrice - ( MaxBuyablePrice / 30); // Max Bidable price defined to 70% of max buyable price + + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: Auction added with data:"); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: MaxPrice of Entry %u is %.1fg.", itr->second.AuctionId, MaxBuyablePrice / 10000); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: GamePrice buy=%.1fg, bid=%.1fg.",InGame_BuyPrice/10000, InGame_BidPrice / 10000); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: Minimal price see in AH Buy=%ug, Bid=%ug.", + sameitem_itr->second.MinBuyPrice / 10000,sameitem_itr->second.MinBidPrice / 10000); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: Actual Entry price, Buy=%ug, Bid=%ug.", buyoutPrice / 10000, bidPrice/ 10000); + + if (!auction->owner) // Original auction owner + { + MaxChance = MaxChance / 5; // if Owner is AHBot this mean player placed bid on this auction. We divide by 5 chance for AhBuyer to place bid on it. (This make more challenge than ignore entry) + } + if (auction->buyout != 0) // Is the item directly buyable? + { + if (IsBuyableEntry(buyoutPrice, InGame_BuyPrice, MaxBuyablePrice, sameitem_itr->second.MinBuyPrice, MaxChance, config.FactionChance)) + { + if (IsBidableEntry(bidPriceByItem, InGame_BuyPrice, MaxBidablePrice, sameitem_itr->second.MinBidPrice, MaxChance/2, config.FactionChance)) + if (urand(0,5)==0) PlaceBidToEntry(auction, bidPrice); else BuyEntry(auction); + else + BuyEntry(auction); + } + else + { + if (IsBidableEntry(bidPriceByItem, InGame_BuyPrice, MaxBidablePrice, sameitem_itr->second.MinBidPrice, MaxChance/2, config.FactionChance)) + PlaceBidToEntry(auction, bidPrice); + } + } + else // buyout = 0 mean only bid are possible + if (IsBidableEntry(bidPriceByItem, InGame_BuyPrice, MaxBidablePrice, sameitem_itr->second.MinBidPrice,MaxChance, config.FactionChance)) + PlaceBidToEntry(auction, bidPrice); + + itr->second.LastChecked = Now; + --BuyCycles; + + ++itr; + } +} + +bool AuctionBotBuyer::Update(AuctionHouseType houseType) +{ + if (sAuctionBotConfig.getConfigBuyerEnabled(houseType)) + { + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: %s buying ...", AuctionBotConfig::GetHouseTypeName(houseType)); + if (GetBuyableEntry(m_HouseConfig[houseType]) > 0) + addNewAuctionBuyerBotBid(m_HouseConfig[houseType]); + return true; + } + else return false; +} + +//== AuctionBotSeller functions ============================ + +AuctionBotSeller::AuctionBotSeller() +{ + // Define faction for our main data class. + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + m_HouseConfig[i].Initialize(AuctionHouseType(i)); +} + +AuctionBotSeller::~AuctionBotSeller() +{ +} + +bool AuctionBotSeller::Initialize() +{ + std::vector npcItems; + std::vector lootItems; + std::vector includeItems; + std::vector excludeItems; + + sLog.outString("AHBot seller filters:"); + sLog.outString(); + + { + std::stringstream includeStream(sAuctionBotConfig.GetAHBotIncludes()); + std::string temp; + while (getline(includeStream,temp, ',')) + includeItems.push_back(atoi(temp.c_str())); + } + + { + std::stringstream excludeStream(sAuctionBotConfig.GetAHBotExcludes()); + std::string temp; + while (getline(excludeStream,temp, ',')) + excludeItems.push_back(atoi(temp.c_str())); + + } + sLog.outString("Forced Inclusion " SIZEFMTD " items", includeItems.size()); + sLog.outString("Forced Exclusion " SIZEFMTD " items", excludeItems.size()); + sLog.outString(); + + sLog.outString("Loading npc vendor items for filter.."); + if (QueryResult* result = WorldDatabase.Query("SELECT DISTINCT item FROM npc_vendor")) + { + BarGoLink bar(result->GetRowCount()); + do + { + bar.step(); + Field* fields = result->Fetch(); + npcItems.push_back(fields[0].GetUInt32()); + + } while (result->NextRow()); + delete result; + } + else + { + BarGoLink bar(1); + bar.step(); + } + sLog.outString("Npc vendor filter has " SIZEFMTD " items", npcItems.size()); + sLog.outString(); + + sLog.outString("Loading loot items for filter.."); + if (QueryResult* result = WorldDatabase.PQuery( + "SELECT `item` FROM `creature_loot_template` UNION " + "SELECT `item` FROM `disenchant_loot_template` UNION " + "SELECT `item` FROM `fishing_loot_template` UNION " + "SELECT `item` FROM `gameobject_loot_template` UNION " + "SELECT `item` FROM `item_loot_template` UNION " + "SELECT `item` FROM `milling_loot_template` UNION " + "SELECT `item` FROM `pickpocketing_loot_template` UNION " + "SELECT `item` FROM `prospecting_loot_template` UNION " + "SELECT `item` FROM `skinning_loot_template`")) + { + BarGoLink bar(result->GetRowCount()); + do + { + bar.step(); + Field* fields = result->Fetch(); + lootItems.push_back(fields[0].GetUInt32()); + } while (result->NextRow()); + delete result; + } + else + { + BarGoLink bar(1); + bar.step(); + } + sLog.outString("Loot filter has " SIZEFMTD " items", lootItems.size()); + sLog.outString(); + + sLog.outString("Sorting and cleaning items for AHBot seller..."); + + uint32 itemsAdded = 0; + + BarGoLink bar(sItemStorage.MaxEntry); + for (uint32 itemID = 0; itemID < sItemStorage.MaxEntry; ++itemID) + { + ItemPrototype const* prototype = sObjectMgr.GetItemPrototype(itemID); + + bar.step(); + + if (!prototype) + continue; + + // skip items with too high quality (code can't propertly work with its) + if (prototype->Quality >= MAX_AUCTION_QUALITY) + continue; + + // forced exclude filter + bool isExcludeItem = false; + for (size_t i = 0; (i < excludeItems.size() && (!isExcludeItem)); ++i) + if (itemID ==excludeItems[i]) + isExcludeItem = true; + if (isExcludeItem) + continue; + + // forced include filter + bool isForcedIncludeItem = false; + for (size_t i = 0; (i < includeItems.size() && (!isForcedIncludeItem)); ++i) + if (itemID == includeItems[i]) + isForcedIncludeItem = true; + + if (isForcedIncludeItem) + { + m_ItemPool[prototype->Quality][prototype->Class].push_back(itemID); + ++itemsAdded; + continue; + } + + // bounding filters + switch (prototype->Bonding) + { + case NO_BIND: + if (!sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_BIND_NO)) + continue; + break; + case BIND_WHEN_PICKED_UP: + if (!sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_BIND_PICKUP)) + continue; + break; + case BIND_WHEN_EQUIPPED: + if (!sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_BIND_EQUIP)) + continue; + break; + case BIND_WHEN_USE: + if (!sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_BIND_USE)) + continue; + break; + case BIND_QUEST_ITEM: + if (!sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_BIND_QUEST)) + continue; + break; + default: + continue; + } + + // no price filter + if (sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_BUYPRICE_SELLER)) + { + if(prototype->BuyPrice == 0) + continue; + } + else + { + if (prototype->SellPrice == 0) + continue; + } + + // vendor filter + if (!sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_ITEMS_VENDOR)) + { + bool isVendorItem = false; + for (size_t i = 0; (i < npcItems.size()) && (!isVendorItem); ++i) + if (itemID == npcItems[i]) + isVendorItem = true; + + if (isVendorItem) + continue; + } + + // loot filter + if (!sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_ITEMS_LOOT)) + { + bool isLootItem = false; + for (size_t i = 0; (i < lootItems.size()) && (!isLootItem); ++i) + if (itemID == lootItems[i]) + isLootItem = true; + if (isLootItem) + continue; + } + + // not vendor/loot filter + if (!sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_ITEMS_MISC)) + { + bool isVendorItem = false; + bool isLootItem = false; + + for (size_t i = 0; (i < npcItems.size()) && (!isVendorItem); ++i) + if (itemID == npcItems[i]) + isVendorItem = true; + + for (size_t i = 0; (i < lootItems.size()) && (!isLootItem); ++i) + if (itemID == lootItems[i]) + isLootItem = true; + + if ((!isLootItem) && (!isVendorItem)) + continue; + } + + // item class/subclass specific filters + switch (prototype->Class) + { + case ITEM_CLASS_ARMOR: + case ITEM_CLASS_WEAPON: + { + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_MIN_ITEM_LEVEL)) + if (prototype->ItemLevel < value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_MAX_ITEM_LEVEL)) + if (prototype->ItemLevel > value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_MIN_REQ_LEVEL)) + if (prototype->RequiredLevel < value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_MAX_REQ_LEVEL)) + if (prototype->RequiredLevel > value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_MIN_SKILL_RANK)) + if (prototype->RequiredSkillRank < value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_MAX_SKILL_RANK)) + if (prototype->RequiredSkillRank > value) + continue; + break; + } + case ITEM_CLASS_RECIPE: + case ITEM_CLASS_CONSUMABLE: + case ITEM_CLASS_PROJECTILE: + { + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_MIN_REQ_LEVEL)) + if (prototype->RequiredLevel < value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_MAX_REQ_LEVEL)) + if (prototype->RequiredLevel > value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_MIN_SKILL_RANK)) + if (prototype->RequiredSkillRank < value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_MAX_SKILL_RANK)) + if (prototype->RequiredSkillRank > value) + continue; + break; + } + case ITEM_CLASS_MISC: + if (prototype->SubClass==ITEM_SUBCLASS_JUNK_MOUNT) + { + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MIN_REQ_LEVEL)) + if (prototype->RequiredLevel < value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MAX_REQ_LEVEL)) + if (prototype->RequiredLevel > value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MIN_SKILL_RANK)) + if (prototype->RequiredSkillRank < value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MAX_SKILL_RANK)) + if (prototype->RequiredSkillRank > value) + continue; + } + + if (prototype->Flags & ITEM_FLAG_LOOTABLE) + { + // skip any not locked lootable items (mostly quest specific or reward cases) + if (!prototype->LockID) + continue; + + if (!sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_LOCKBOX_ENABLED)) + continue; + } + + break; + case ITEM_CLASS_GLYPH: + { + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GLYPH_MIN_REQ_LEVEL)) + if (prototype->RequiredLevel < value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GLYPH_MAX_REQ_LEVEL)) + if (prototype->RequiredLevel > value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GLYPH_MIN_ITEM_LEVEL)) + if (prototype->RequiredLevel < value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GLYPH_MAX_ITEM_LEVEL)) + if (prototype->RequiredLevel > value) + continue; + break; + } + case ITEM_CLASS_TRADE_GOODS: + { + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_MIN_ITEM_LEVEL)) + if (prototype->ItemLevel < value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_MAX_ITEM_LEVEL)) + if (prototype->ItemLevel > value) + continue; + break; + } + case ITEM_CLASS_CONTAINER: + case ITEM_CLASS_QUIVER: + { + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONTAINER_MIN_ITEM_LEVEL)) + if (prototype->ItemLevel < value) + continue; + if (uint32 value = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONTAINER_MAX_ITEM_LEVEL)) + if (prototype->ItemLevel > value) + continue; + break; + } + } + + m_ItemPool[prototype->Quality][prototype->Class].push_back(itemID); + ++itemsAdded; + } + + if (!itemsAdded) + { + sLog.outError("AuctionHouseBot seller not have items, disabled."); + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO, 0); + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_HORDE_ITEM_AMOUNT_RATIO, 0); + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO, 0); + return false; + } + + sLog.outString("AuctionHouseBot seller will use %u items to fill auction house (according your config choices)", itemsAdded); + + LoadConfig(); + + sLog.outString("Items loaded \tGrey\tWhite\tGreen\tBlue\tPurple\tOrange\tYellow"); + for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i) + sLog.outString("%-18s\t" SIZEFMTD "\t" SIZEFMTD "\t" SIZEFMTD "\t" SIZEFMTD "\t" SIZEFMTD "\t" SIZEFMTD "\t" SIZEFMTD, + sAuctionBotConfig.GetItemClassName(ItemClass(i)), + m_ItemPool[0][i].size(), m_ItemPool[1][i].size(), m_ItemPool[2][i].size(), + m_ItemPool[3][i].size(), m_ItemPool[4][i].size(), m_ItemPool[5][i].size(), + m_ItemPool[6][i].size()); + + sLog.outString(); + sLog.outString("AHBot seller configuration data loaded and initilized"); + + sLog.SetLogFilter(LOG_FILTER_AHBOT_SELLER, !sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_DEBUG_SELLER)); + return true; +} + +void AuctionBotSeller::LoadConfig() +{ + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + if (sAuctionBotConfig.getConfigItemAmountRatio(AuctionHouseType(i))) + LoadSellerValues(m_HouseConfig[i]); +} + +void AuctionBotSeller::LoadItemsQuantity(AHB_Seller_Config& config) +{ + uint32 ratio = sAuctionBotConfig.getConfigItemAmountRatio(config.GetHouseType()); + + config.SetItemsAmountPerQuality(AUCTION_QUALITY_GREY, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_GREY_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_WHITE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_WHITE_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_GREEN, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_GREEN_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_BLUE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_BLUE_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_PURPLE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_PURPLE_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_ORANGE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_ORANGE_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_YELLOW, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ITEM_YELLOW_AMOUNT) * ratio / 100); + + // Set quantity wanted but only on possible item color + // This avoid any no-exist class-color items selection by random items create function + // ============================================================================================ + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_CONSUMABLE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_CONTAINER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_WEAPON, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_GEM, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_ARMOR, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_PROJECTILE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_RECIPE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_QUIVER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_QUEST, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_QUEST_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_KEY, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_MISC, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREY, ITEM_CLASS_GLYPH, 0); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONSUMABLE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_CONTAINER, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONTAINER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_WEAPON, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_GEM, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GEM_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_ARMOR, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_REAGENT, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_REAGENT_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_PROJECTILE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_PROJECTILE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_GENERIC, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GENERIC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_RECIPE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_RECIPE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_QUIVER, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_QUIVER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_QUEST, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_QUEST_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_KEY, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_KEY_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_MISC, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_GLYPH, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GLYPH_AMOUNT)); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONSUMABLE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_CONTAINER, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONTAINER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_WEAPON, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_GEM, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GEM_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_ARMOR, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_PROJECTILE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_PROJECTILE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_RECIPE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_RECIPE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_QUIVER, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_QUIVER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_QUEST, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_QUEST_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_KEY, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_KEY_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_MISC, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_GLYPH, 0); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONSUMABLE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_CONTAINER, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONTAINER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_WEAPON, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_GEM, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GEM_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_ARMOR, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_PROJECTILE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_PROJECTILE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_RECIPE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_RECIPE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_QUIVER, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_QUIVER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_QUEST, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_QUEST_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_KEY, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_MISC, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_GLYPH, 0); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONSUMABLE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_CONTAINER, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONTAINER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_WEAPON, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_GEM, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GEM_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_ARMOR, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_PROJECTILE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_PROJECTILE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_RECIPE, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_RECIPE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_QUIVER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_QUEST, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_QUEST_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_KEY, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_MISC, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_GLYPH, 0); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_CONSUMABLE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_CONTAINER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_WEAPON, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_GEM, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_ARMOR, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_PROJECTILE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_RECIPE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_QUIVER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_QUEST, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_KEY, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_MISC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_GLYPH, 0); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_CONSUMABLE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_CONTAINER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_WEAPON, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_GEM, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_ARMOR, sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_PROJECTILE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_TRADE_GOODS, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_RECIPE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_QUIVER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_QUEST, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_KEY, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_MISC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_GLYPH, 0); + // ============================================================================================ + + // Set the best value to get nearest amount of items wanted + for (uint32 j = 0; j < MAX_AUCTION_QUALITY; ++j) + { + uint32 indice = config.GetItemsAmountPerQuality(AuctionQuality(j)) / + (sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONSUMABLE_AMOUNT) + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_CONTAINER_AMOUNT) + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_WEAPON_AMOUNT) + + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GEM_AMOUNT) + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_ARMOR_AMOUNT) + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_REAGENT_AMOUNT) + + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_PROJECTILE_AMOUNT) + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_AMOUNT) + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GENERIC_AMOUNT) + + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_RECIPE_AMOUNT) + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_QUIVER_AMOUNT) + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_QUEST_AMOUNT) + + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_KEY_AMOUNT) + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_MISC_AMOUNT) + sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_CLASS_GLYPH_AMOUNT)); + for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i) + config.SetItemsAmountPerClass(AuctionQuality(j), ItemClass(i), indice); + } +} + +void AuctionBotSeller::LoadSellerValues(AHB_Seller_Config& config) +{ + LoadItemsQuantity(config); + uint32 PriceRatio; + switch(config.GetHouseType()) + { + case AUCTION_HOUSE_ALLIANCE: + PriceRatio = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_ALLIANCE_PRICE_RATIO); + break; + case AUCTION_HOUSE_HORDE: + PriceRatio = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_HORDE_PRICE_RATIO); + break; + default: + PriceRatio = sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_NEUTRAL_PRICE_RATIO); + break; + } + config.SetPriceRatioPerQuality(AUCTION_QUALITY_GREY,PriceRatio); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_WHITE,PriceRatio); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_GREEN,PriceRatio); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_BLUE,PriceRatio); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_PURPLE,PriceRatio); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_ORANGE,PriceRatio); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_YELLOW,PriceRatio); + + //load min and max auction times + config.SetMinTime(sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_MINTIME)); + config.SetMaxTime(sAuctionBotConfig.getConfig(CONFIG_UINT32_AHBOT_MAXTIME)); + + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: minTime = %u", config.GetMinTime()); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: maxTime = %u", config.GetMaxTime()); + + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: For AH type %u",config.GetHouseType()); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: GreyItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_GREY)); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: WhiteItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_WHITE)); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: GreenItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_GREEN)); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: BlueItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_BLUE)); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: PurpleItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_PURPLE)); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: OrangeItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_ORANGE)); + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: YellowItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_YELLOW)); + +} + +// Set static of items on one AH faction. +// Fill ItemInfos object with real content of AH. +uint32 AuctionBotSeller::SetStat(AHB_Seller_Config& config) +{ + std::vector > ItemsInAH(MAX_AUCTION_QUALITY, std::vector< uint32 > (MAX_ITEM_CLASS)); + + AuctionHouseObject::AuctionEntryMapBounds bounds = sAuctionMgr.GetAuctionsMap(config.GetHouseType())->GetAuctionsBounds(); + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr) + { + AuctionEntry *Aentry = itr->second; + Item *item = sAuctionMgr.GetAItem(Aentry->itemGuidLow); + if (item) + { + ItemPrototype const *prototype = item->GetProto(); + if (prototype) + { + if (!Aentry->owner) // Add only ahbot items + { + ++ItemsInAH[prototype->Quality][prototype->Class]; + } + } + } + } + uint32 count=0; + for (uint32 j=0; j >& addedItem ) +{ + ra.clear(); + bool Ok=false; + + for (uint32 j = 0; j < MAX_AUCTION_QUALITY; ++j) + { + for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i) + { + if ((config.GetMissedItemsPerClass(AuctionQuality(j), ItemClass(i)) > addedItem[j][i]) && !m_ItemPool[j][i].empty()) + { + RandomArrayEntry miss_item; + miss_item.color = j; + miss_item.itemclass = i; + ra.push_back(miss_item); + Ok=true; + } + } + } + return Ok; +} + +// Set items price. All important value are passed by address. +void AuctionBotSeller::SetPricesOfItem(ItemPrototype const *itemProto, AHB_Seller_Config& config, uint32& buyp, uint32& bidp, uint32 stackcnt, ItemQualities itemQuality) +{ + double temp_buyp = buyp * stackcnt * + (itemQuality < MAX_AUCTION_QUALITY ? config.GetPriceRatioPerQuality(AuctionQuality(itemQuality)) : 1) ; + + double randrange = temp_buyp * 0.4; + buyp = (urand(temp_buyp-randrange, temp_buyp+randrange)/100)+1; + double urandrange=buyp*40; + double temp_bidp = buyp*50; + bidp = (urand(temp_bidp-urandrange, temp_bidp+urandrange)/100)+1; +} + +void AuctionBotSeller::SetItemsRatio(uint32* al, uint32* ho, uint32* ne) +{ + if (al) + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO, *al < 10000 ? *al : 10000); + if (ho) + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_HORDE_ITEM_AMOUNT_RATIO, *ho < 10000 ? *ho : 10000); + if (ne) + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO, *ne < 10000 ? *ne : 10000); + + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + LoadItemsQuantity(m_HouseConfig[i]); +} + +void AuctionBotSeller::SetItemsAmount(uint32* grey_i, uint32* white_i, uint32* green_i, uint32* blue_i, uint32* purple_i, uint32* orange_i, uint32* yellow_i) +{ + if (grey_i) + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_ITEM_GREY_AMOUNT, *grey_i); + if (white_i) + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_ITEM_WHITE_AMOUNT, *white_i); + if (green_i) + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_ITEM_GREEN_AMOUNT, *green_i); + if (blue_i) + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_ITEM_BLUE_AMOUNT, *blue_i); + if (purple_i) + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_ITEM_PURPLE_AMOUNT, *purple_i); + if (orange_i) + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_ITEM_ORANGE_AMOUNT, *orange_i); + if (yellow_i) + sAuctionBotConfig.setConfig(CONFIG_UINT32_AHBOT_ITEM_YELLOW_AMOUNT, *yellow_i); + + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + LoadItemsQuantity(m_HouseConfig[i]); +} + +// Add new auction to one of the factions. +// Faction and setting assossiated is defined passed argument ( config ) +void AuctionBotSeller::addNewAuctions(AHB_Seller_Config& config) +{ + uint32 items; + + // If there is large amount of items missed we can use boost value to get fast filled AH + if (config.LastMissedItem > sAuctionBotConfig.GetItemPerCycleBoost()) + { + items=sAuctionBotConfig.GetItemPerCycleBoost(); + BASIC_FILTER_LOG(LOG_FILTER_AHBOT_BUYER, "AHBot: Boost value used to fill AH! (if this happens often adjust both ItemsPerCycle in ahbot.conf)"); + } + else items=sAuctionBotConfig.GetItemPerCycleNormal(); + + uint32 houseid; + switch (config.GetHouseType()) + { + case AUCTION_HOUSE_ALLIANCE: houseid = 1; break; + case AUCTION_HOUSE_HORDE: houseid = 6; break; + default: houseid = 7; break; + } + + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(houseid); + + AuctionHouseObject* auctionHouse = sAuctionMgr.GetAuctionsMap(config.GetHouseType()); + + RandomArray randArray; + std::vector > ItemsAdded(MAX_AUCTION_QUALITY,std::vector (MAX_ITEM_CLASS)); + // Main loop + // getRandomArray will give what categories of items should be added (return true if there is at least 1 items missed) + while (getRandomArray(config,randArray, ItemsAdded) && (items>0)) + { + --items; + + // Select random position from missed items table + uint32 pos = (urand(0,randArray.size()-1)); + + // Set itemID with random item ID for selected categories and color, from m_ItemPool table + uint32 itemID = m_ItemPool[randArray[pos].color][randArray[pos].itemclass][urand(0,m_ItemPool[randArray[pos].color][randArray[pos].itemclass].size()-1)]; + ++ ItemsAdded[randArray[pos].color][randArray[pos].itemclass]; // Helper table to avoid rescan from DB in this loop. (has we add item in random orders) + + if (!itemID) + { + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: Item entry 0 auction creating attempt."); + continue; + } + + ItemPrototype const* prototype = sObjectMgr.GetItemPrototype(itemID); + if (!prototype) + { + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: Unknown item %u auction creating attempt.", itemID); + continue; + } + + uint32 stackCount = urand(1, prototype->GetMaxStackSize()); + + + Item* item = Item::CreateItem(itemID, stackCount); + if (!item) + { + sLog.outError("AHBot: Item::CreateItem() returned NULL for item %u (stack: %u)", itemID, stackCount); + return; + } + + uint32 buyoutPrice; + uint32 bidPrice = 0; + // Not sure if i will keep the next test + if (sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_BUYPRICE_SELLER)) + buyoutPrice = prototype->BuyPrice * item->GetCount(); + else + buyoutPrice = prototype->SellPrice * item->GetCount(); + // Price of items are set here + SetPricesOfItem(prototype, config, buyoutPrice, bidPrice, stackCount, ItemQualities(prototype->Quality)); + + auctionHouse->AddAuction(ahEntry, item, urand(config.GetMinTime(), config.GetMaxTime()) * HOUR, bidPrice, buyoutPrice); + } +} + +bool AuctionBotSeller::Update(AuctionHouseType houseType) +{ + if (sAuctionBotConfig.getConfigItemAmountRatio(houseType) > 0) + { + DEBUG_FILTER_LOG(LOG_FILTER_AHBOT_SELLER, "AHBot: %s selling ...", AuctionBotConfig::GetHouseTypeName(houseType)); + if (SetStat(m_HouseConfig[houseType])) + addNewAuctions(m_HouseConfig[houseType]); + return true; + } + else + return false; +} + +//== AuctionHouseBot functions ============================= + +AuctionHouseBot::AuctionHouseBot() : m_Buyer(NULL), m_Seller(NULL), m_OperationSelector(0) +{ +} + +AuctionHouseBot::~AuctionHouseBot() +{ + delete m_Buyer; + delete m_Seller; +} + +void AuctionHouseBot::InitilizeAgents() +{ + if (sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_SELLER_ENABLED)) + { + delete m_Seller; + m_Seller = new AuctionBotSeller(); + if (!m_Seller->Initialize()) + { + delete m_Seller; + m_Seller = NULL; + } + } + if (sAuctionBotConfig.getConfig(CONFIG_BOOL_AHBOT_BUYER_ENABLED)) + { + delete m_Buyer; + m_Buyer = new AuctionBotBuyer(); + if (!m_Buyer->Initialize()) + { + delete m_Buyer; + m_Buyer = NULL; + } + } +} + +void AuctionHouseBot::Initialize() +{ + if (sAuctionBotConfig.Initialize()) + InitilizeAgents(); +} + +void AuctionHouseBot::SetItemsRatio(uint32* al, uint32* ho, uint32* ne) +{ + if (AuctionBotSeller* seller = dynamic_cast(m_Seller)) + seller->SetItemsRatio( al, ho, ne); +} + +void AuctionHouseBot::SetItemsAmount(uint32* grey_i, uint32* white_i, uint32* green_i, uint32* blue_i, uint32* purple_i, uint32* orange_i, uint32* yellow_i) +{ + if (AuctionBotSeller* seller = dynamic_cast(m_Seller)) + seller->SetItemsAmount(grey_i, white_i, green_i, blue_i, purple_i, orange_i, yellow_i); +} + +bool AuctionHouseBot::ReloadAllConfig() +{ + if (!sAuctionBotConfig.Reload()) + { + sLog.outError("AHBot: Error while trying to reload config from file!"); + return false; + } + + InitilizeAgents(); + return true; +} + +void AuctionHouseBot::PrepareStatusInfos(AuctionHouseBotStatusInfo& statusInfo) +{ + for (uint32 i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + { + statusInfo[i].ItemsCount = 0; + + for (int j = 0; j < MAX_AUCTION_QUALITY; ++j) + statusInfo[i].QualityInfo[j] = 0; + + AuctionHouseObject::AuctionEntryMapBounds bounds = sAuctionMgr.GetAuctionsMap(AuctionHouseType(i))->GetAuctionsBounds(); + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr) + { + AuctionEntry *Aentry = itr->second; + if (Item *item = sAuctionMgr.GetAItem(Aentry->itemGuidLow)) + { + ItemPrototype const *prototype = item->GetProto(); + if (!Aentry->owner) // Add only ahbot items + { + if (prototype->Quality < MAX_AUCTION_QUALITY) + ++statusInfo[i].QualityInfo[prototype->Quality]; + + ++statusInfo[i].ItemsCount; + } + } + } + } +} + +void AuctionHouseBot::Rebuild(bool all) +{ + for (uint32 i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + { + AuctionHouseObject::AuctionEntryMapBounds bounds = sAuctionMgr.GetAuctionsMap(AuctionHouseType(i))->GetAuctionsBounds(); + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr) + if (!itr->second->owner) // ahbot auction + if (all || itr->second->bid == 0) // expire now auction if no bid or forced + itr->second->expireTime = sWorld.GetGameTime(); + } +} + +void AuctionHouseBot::Update() +{ + // nothing do... + if (!m_Buyer && !m_Seller) + return; + + // scan all possible update cases until first success + for (uint32 count = 0; count < 2*MAX_AUCTION_HOUSE_TYPE; ++count) + { + bool successStep = false; + + if (m_OperationSelector < MAX_AUCTION_HOUSE_TYPE) + { + if (m_Seller) + successStep = m_Seller->Update(AuctionHouseType(m_OperationSelector)); + } + else + { + if (m_Buyer) + successStep = m_Buyer->Update(AuctionHouseType(m_OperationSelector - MAX_AUCTION_HOUSE_TYPE)); + } + + ++m_OperationSelector; + if (m_OperationSelector >= 2*MAX_AUCTION_HOUSE_TYPE) + m_OperationSelector = 0; + + // one success update per call + if (successStep) + break; + } +} diff --git a/src/game/AuctionHouseBot/AuctionHouseBot.h b/src/game/AuctionHouseBot/AuctionHouseBot.h new file mode 100644 index 000000000..331e07eaa --- /dev/null +++ b/src/game/AuctionHouseBot/AuctionHouseBot.h @@ -0,0 +1,201 @@ +#ifndef AUCTION_HOUSE_BOT_H +#define AUCTION_HOUSE_BOT_H + +#include "../World.h" +#include "Config/Config.h" +#include "../AuctionHouseMgr.h" +#include "../SharedDefines.h" +#include "../Item.h" + +// shadow of ItemQualities with skipped ITEM_QUALITY_HEIRLOOM, anything after ITEM_QUALITY_ARTIFACT(6) in fact +enum AuctionQuality +{ + AUCTION_QUALITY_GREY = ITEM_QUALITY_POOR, + AUCTION_QUALITY_WHITE = ITEM_QUALITY_NORMAL, + AUCTION_QUALITY_GREEN = ITEM_QUALITY_UNCOMMON, + AUCTION_QUALITY_BLUE = ITEM_QUALITY_RARE, + AUCTION_QUALITY_PURPLE = ITEM_QUALITY_EPIC, + AUCTION_QUALITY_ORANGE = ITEM_QUALITY_LEGENDARY, + AUCTION_QUALITY_YELLOW = ITEM_QUALITY_ARTIFACT, +}; + +#define MAX_AUCTION_QUALITY 7 + +enum AuctionBotConfigUInt32Values +{ + CONFIG_UINT32_AHBOT_MAXTIME, + CONFIG_UINT32_AHBOT_MINTIME, + CONFIG_UINT32_AHBOT_ITEMS_PER_CYCLE_BOOST, + CONFIG_UINT32_AHBOT_ITEMS_PER_CYCLE_NORMAL, + CONFIG_UINT32_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO, + CONFIG_UINT32_AHBOT_HORDE_ITEM_AMOUNT_RATIO, + CONFIG_UINT32_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO, + CONFIG_UINT32_AHBOT_ITEM_MIN_ITEM_LEVEL, + CONFIG_UINT32_AHBOT_ITEM_MAX_ITEM_LEVEL, + CONFIG_UINT32_AHBOT_ITEM_MIN_REQ_LEVEL, + CONFIG_UINT32_AHBOT_ITEM_MAX_REQ_LEVEL, + CONFIG_UINT32_AHBOT_ITEM_MIN_SKILL_RANK, + CONFIG_UINT32_AHBOT_ITEM_MAX_SKILL_RANK, + CONFIG_UINT32_AHBOT_ITEM_GREY_AMOUNT, + CONFIG_UINT32_AHBOT_ITEM_WHITE_AMOUNT, + CONFIG_UINT32_AHBOT_ITEM_GREEN_AMOUNT, + CONFIG_UINT32_AHBOT_ITEM_BLUE_AMOUNT, + CONFIG_UINT32_AHBOT_ITEM_PURPLE_AMOUNT, + CONFIG_UINT32_AHBOT_ITEM_ORANGE_AMOUNT, + CONFIG_UINT32_AHBOT_ITEM_YELLOW_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_CONSUMABLE_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_CONTAINER_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_WEAPON_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_GEM_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_ARMOR_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_REAGENT_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_PROJECTILE_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_GENERIC_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_RECIPE_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_QUIVER_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_QUEST_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_KEY_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_MISC_AMOUNT, + CONFIG_UINT32_AHBOT_CLASS_GLYPH_AMOUNT, + CONFIG_UINT32_AHBOT_ALLIANCE_PRICE_RATIO, + CONFIG_UINT32_AHBOT_HORDE_PRICE_RATIO, + CONFIG_UINT32_AHBOT_NEUTRAL_PRICE_RATIO, + CONFIG_UINT32_AHBOT_BUYER_CHANCE_RATIO_ALLIANCE, + CONFIG_UINT32_AHBOT_BUYER_CHANCE_RATIO_HORDE, + CONFIG_UINT32_AHBOT_BUYER_CHANCE_RATIO_NEUTRAL, + CONFIG_UINT32_AHBOT_BUYER_RECHECK_INTERVAL, + CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MIN_REQ_LEVEL, + CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MAX_REQ_LEVEL, + CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MIN_SKILL_RANK, + CONFIG_UINT32_AHBOT_CLASS_MISC_MOUNT_MAX_SKILL_RANK, + CONFIG_UINT32_AHBOT_CLASS_GLYPH_MIN_REQ_LEVEL, + CONFIG_UINT32_AHBOT_CLASS_GLYPH_MAX_REQ_LEVEL, + CONFIG_UINT32_AHBOT_CLASS_GLYPH_MIN_ITEM_LEVEL, + CONFIG_UINT32_AHBOT_CLASS_GLYPH_MAX_ITEM_LEVEL, + CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_MIN_ITEM_LEVEL, + CONFIG_UINT32_AHBOT_CLASS_TRADEGOOD_MAX_ITEM_LEVEL, + CONFIG_UINT32_AHBOT_CLASS_CONTAINER_MIN_ITEM_LEVEL, + CONFIG_UINT32_AHBOT_CLASS_CONTAINER_MAX_ITEM_LEVEL, + CONFIG_UINT32_AHBOT_UINT32_COUNT +}; + +enum AuctionBotConfigBoolValues +{ + CONFIG_BOOL_AHBOT_BUYER_ALLIANCE_ENABLED, + CONFIG_BOOL_AHBOT_BUYER_HORDE_ENABLED, + CONFIG_BOOL_AHBOT_BUYER_NEUTRAL_ENABLED, + CONFIG_BOOL_AHBOT_ITEMS_VENDOR, + CONFIG_BOOL_AHBOT_ITEMS_LOOT, + CONFIG_BOOL_AHBOT_ITEMS_MISC, + CONFIG_BOOL_AHBOT_BIND_NO, + CONFIG_BOOL_AHBOT_BIND_PICKUP, + CONFIG_BOOL_AHBOT_BIND_EQUIP, + CONFIG_BOOL_AHBOT_BIND_USE, + CONFIG_BOOL_AHBOT_BIND_QUEST, + CONFIG_BOOL_AHBOT_BUYPRICE_SELLER, + CONFIG_BOOL_AHBOT_BUYPRICE_BUYER, + CONFIG_BOOL_AHBOT_DEBUG_SELLER, + CONFIG_BOOL_AHBOT_DEBUG_BUYER, + CONFIG_BOOL_AHBOT_SELLER_ENABLED, + CONFIG_BOOL_AHBOT_BUYER_ENABLED, + CONFIG_BOOL_AHBOT_LOCKBOX_ENABLED, + CONFIG_UINT32_AHBOT_BOOL_COUNT +}; + +// All basic config data used by other AHBot classes for self-configure. +class AuctionBotConfig +{ + public: + AuctionBotConfig() {} + + bool Initialize(); + const char* GetAHBotIncludes() const { return m_AHBotIncludes.c_str(); } + const char* GetAHBotExcludes() const { return m_AHBotExcludes.c_str(); } + + uint32 getConfig(AuctionBotConfigUInt32Values index) const { return m_configUint32Values[index]; } + bool getConfig(AuctionBotConfigBoolValues index) const { return m_configBoolValues[index]; } + void setConfig(AuctionBotConfigBoolValues index, bool value) { m_configBoolValues[index]=value; } + void setConfig(AuctionBotConfigUInt32Values index, uint32 value) { m_configUint32Values[index]=value; } + + uint32 getConfigItemAmountRatio(AuctionHouseType houseType) const; + bool getConfigBuyerEnabled(AuctionHouseType houseType) const; + + + uint32 GetItemPerCycleBoost() const { return m_ItemsPerCycleBoost; } + uint32 GetItemPerCycleNormal() const { return m_ItemsPerCycleNormal; } + bool Reload(); + + static char const* GetItemClassName(ItemClass itemclass); + static char const* GetHouseTypeName(AuctionHouseType houseType); + + private: + std::string m_AHBotIncludes; + std::string m_AHBotExcludes; + Config m_AhBotCfg; + uint32 m_ItemsPerCycleBoost; + uint32 m_ItemsPerCycleNormal; + + uint32 m_configUint32Values[CONFIG_UINT32_AHBOT_UINT32_COUNT]; + bool m_configBoolValues[CONFIG_UINT32_AHBOT_BOOL_COUNT]; + + void SetAHBotIncludes(const std::string& AHBotIncludes) { m_AHBotIncludes = AHBotIncludes; } + void SetAHBotExcludes(const std::string& AHBotExcludes) { m_AHBotExcludes = AHBotExcludes; } + + void setConfig(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue); + void setConfigMax(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 maxvalue); + void setConfigMinMax(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 minvalue, uint32 maxvalue); + void setConfig(AuctionBotConfigBoolValues index, char const* fieldname, bool defvalue); + void GetConfigFromFile(); +}; + +#define sAuctionBotConfig MaNGOS::Singleton::Instance() + +class AuctionBotAgent +{ + public: + AuctionBotAgent() {} + virtual ~AuctionBotAgent() {} + public: + virtual bool Initialize() =0; + virtual bool Update(AuctionHouseType houseType) =0; +}; + +struct AuctionHouseBotStatusInfoPerType +{ + uint32 ItemsCount; + uint32 QualityInfo[MAX_AUCTION_QUALITY]; +}; + +typedef AuctionHouseBotStatusInfoPerType AuctionHouseBotStatusInfo[MAX_AUCTION_HOUSE_TYPE]; + +// This class handle both Selling and Buying method +// (holder of AuctionBotBuyer and AuctionBotSeller objects) +class AuctionHouseBot +{ + public: + AuctionHouseBot(); + ~AuctionHouseBot(); + + void Update(); + void Initialize(); + + // Followed method is mainly used by level3.cpp for ingame/console command + void SetItemsRatio(uint32* al, uint32* ho, uint32* ne); + void SetItemsAmount(uint32* grey_i, uint32* white_i, uint32* green_i, uint32* blue_i, uint32* purple_i, uint32* orange_i, uint32* yellow_i); + bool ReloadAllConfig(); + void Rebuild(bool all); + + void PrepareStatusInfos(AuctionHouseBotStatusInfo& statusInfo); + private: + void InitilizeAgents(); + + AuctionBotAgent* m_Buyer; + AuctionBotAgent* m_Seller; + + uint32 m_OperationSelector; // 0..2*MAX_AUCTION_HOUSE_TYPE-1 +}; + +#define sAuctionBot MaNGOS::Singleton::Instance() + +#endif diff --git a/src/game/AuctionHouseBot/ahbot.conf.dist.in b/src/game/AuctionHouseBot/ahbot.conf.dist.in new file mode 100644 index 000000000..afb5324b9 --- /dev/null +++ b/src/game/AuctionHouseBot/ahbot.conf.dist.in @@ -0,0 +1,275 @@ +################################################ +# MANGOS Auction House Bot Configuration file # +################################################ + +[AhbotConf] +ConfVersion=2010102201 + +################################################################################################################### +# AUCTION HOUSE BOT SETTINGS +# +# AuctionHouseBot.Seller.Enabled +# General enable or disable AuctionHouseBot Seller fonctionality +# Default 0 (Disabled) +# +# AuctionHouseBot.DEBUG.Seller +# Enable or disable AuctionHouseBot Seller debug mode +# Default 0 (Disabled) +# +# AuctionHouseBot.Alliance.Items.Amount.Ratio +# Enable/Disable (disabled if 0) the part of AHBot that puts items up for auction on Alliance AH +# Default 100 (Enabled with 100% of items specified in AuctionHouse.Items.Amount.color section) +# +# AuctionHouseBot.Horde.Items.Amount.Ratio +# Enable/Disable (disabled if 0) the part of AHBot that puts items up for auction on Horde AH +# Default 100 (Enabled with 100% of items specified in AuctionHouse.Items.Amount.color section) +# +# AuctionHouseBot.Neutral.Items.Amount.Ratio +# Enable/Disable (disabled if 0) the part of AHBot that puts items up for auction on Neutral AH +# Default 100 (Enabled with 100% of items specified in AuctionHouse.Items.Amount.color section) +# +# AuctionHouseBot.MinTime +# Minimum time for the new auction +# Default 1 (Hour) +# +# AuctionHouseBot.MaxTime +# Maximum time for the new auction +# Default 72 (Hours) +# +# AuctionHouseBot.Items.Vendor +# Include items that can be bought from vendors. +# Default 0 +# +# AuctionHouseBot.Items.Loot +# Include items that can be looted or fished for. +# Default 1 +# +# AuctionHouseBot.Items.Misc +# Include misc. items. +# Default 0 +# +# AuctionHouseBot.Bind.* +# Indicates which bonding types to allow the bot to put up for auction +# No - Items that don't bind Default 1 (Allowed) +# Pickup - Items that bind on pickup Default 0 (Not Allowed) +# Equip - Items that bind on equip Default 1 (Allowed) +# Use - Items that bind on use Default 1 (Allowed) +# Quest - Quest Items Default 0 (Not Allowed) +# +# AuctionHouseBot.LockBox.Enabled +# Enable or not lockbox in auctionhouse +# Default 0 (Disabled) +# +# AuctionHouseBot.ItemsPerCycle.Boost +# This value is used to fill DB faster than normal when there is more than this value missed items. +# Normaly this value is used only first start of the server with empty auction table. +# Default 1000 +# +# AuctionHouseBot.ItemsPerCycle.Normal +# This value is used to fill DB normal way with less cpu/db using. +# Normaly this value is used always when auction table is already initialised. +# Default 20 +# +# AuctionHouseBot.BuyPrice.Seller +# Should the Seller use BuyPrice or SellPrice to determine Bid Prices +# Default 1 (use SellPrice) +# +# AuctionHouseBot.Alliance.Price.Ratio +# Define the price of selled item here for the Alliance Auction House +# Default 100 +# +# AuctionHouseBot.Horde.Price.Ratio +# Define the price of selled item here for the Horde Auction House +# Default 100 +# +# AuctionHouseBot.Alliance.Price.Ratio +# Define the price of selled item here for the Neutral Auction House +# Default 100 +# +# AuctionHouseBot.Items.ItemLevel.* +# Prevent seller from listing items below/above this item level +# Default 0 (Disabled) +# +# AuctionHouseBot.Items.ReqLevel.* +# Prevent seller from listing items below/above this required level +# Default 0 (Disabled) +# +# AuctionHouseBot.Items.ReqSkill.* +# Prevent seller from listing items below/above this skill level +# Default 0 (Disabled) +# +# AuctionHouseBot.Items.Amount.* +# Define here for every items quality how many item you whant to be show in Auction House +# This value will be adjusted by AuctionHouseBot.FACTION.Items.Amount.Ratio to define exact amount of +# items will be show on Auction House +# Default 0, 2000, 2500, 1500, 1000, 0, 0 (grey, white, green, blue, purple, orange, yellow) +# +# AustionHouseBot.Class.* +# Here you can set the class of items you prefer to be show on AH +# These value is preference value, it's not percentage. So the maximum is 10. +# The minimum is 0 (disabled). +# Default 6,4,8,3,8,1,2,10,1,6,1,1,1,5,3 +# +# +# ITEM FINE TUNING +# The following are usefull for limiting what character levels can +# benefit from the auction house +# +# AuctionHouseBot.Class.Misc.Mount.ReqLevel.* +# Prevent seller from listing mounts below/above this required level +# Default 0 +# +# AuctionHouseBot.Class.Misc.Mount.ReqSkill.* +# Prevent seller from listing mounts below/above this skill level +# Default 0 +# +# AuctionHouseBot.Class.Glyph.ReqLevel.* +# Prevent seller from listing glyphs below/above this required level +# Default 0 +# +# AuctionHouseBot.Class.Glyph.ItemLevel.* +# Prevent seller from listing glyphs below/above this item level +# Default 0 +# +# AuctionHouseBot.Class.TradeGood.ItemLevel.* +# Prevent seller from listing trade good items below/above this item level +# Default 0 +# +# AuctionHouseBot.Class.Container.ItemLevel.* +# Prevent seller from listing contianers below/above this item level +# Default 0 +# +# AuctionHouseBot.forceIncludeItems +# Include these items and ignore ALL filters +# List of ids with delimiter ',' +# Default "" +# +# AuctionHouseBot.forceExcludeItems +# Exclude these items even if they would pass the filters +# List of ids with delimiter ',' +# Example "21878,27774,27811,28117,28122,43949" (this removes zzOld items) +# Default "" +# +################################################################################################################### + +AuctionHouseBot.Seller.Enabled = 0 +AuctionHouseBot.DEBUG.Seller = 0 + +AuctionHouseBot.Alliance.Items.Amount.Ratio = 100 +AuctionHouseBot.Horde.Items.Amount.Ratio = 100 +AuctionHouseBot.Neutral.Items.Amount.Ratio = 100 + +AuctionHouseBot.MinTime = 1 +AuctionHouseBot.MaxTime = 72 + +AuctionHouseBot.Items.Vendor = 0 +AuctionHouseBot.Items.Loot = 1 +AuctionHouseBot.Items.Misc = 0 +AuctionHouseBot.Bind.No = 1 +AuctionHouseBot.Bind.Pickup = 0 +AuctionHouseBot.Bind.Equip = 1 +AuctionHouseBot.Bind.Use = 1 +AuctionHouseBot.Bind.Quest = 0 +AuctionHouseBot.LockBox.Enabled = 0 + +AuctionHouseBot.ItemsPerCycle.Boost = 1000 +AuctionHouseBot.ItemsPerCycle.Normal = 20 +AuctionHouseBot.BuyPrice.Seller = 1 +AuctionHouseBot.Alliance.Price.Ratio = 200 +AuctionHouseBot.Horde.Price.Ratio = 200 +AuctionHouseBot.Neutral.Price.Ratio = 200 + +AuctionHouseBot.Items.ItemLevel.Min = 0 +AuctionHouseBot.Items.ItemLevel.Max = 0 +AuctionHouseBot.Items.ReqLevel.Min = 0 +AuctionHouseBot.Items.ReqLevel.Max = 0 +AuctionHouseBot.Items.ReqSkill.Min = 0 +AuctionHouseBot.Items.ReqSkill.Max = 0 + +AuctionHouseBot.Items.Amount.Grey = 0 +AuctionHouseBot.Items.Amount.White = 2000 +AuctionHouseBot.Items.Amount.Green = 2500 +AuctionHouseBot.Items.Amount.Blue = 1500 +AuctionHouseBot.Items.Amount.Purple = 1000 +AuctionHouseBot.Items.Amount.Orange = 0 +AuctionHouseBot.Items.Amount.Yellow = 0 + +AuctionHouseBot.Class.Consumable = 6 +AuctionHouseBot.Class.Container = 4 +AuctionHouseBot.Class.Weapon = 8 +AuctionHouseBot.Class.Gem = 3 +AuctionHouseBot.Class.Armor = 8 +AuctionHouseBot.Class.Reagent = 1 +AuctionHouseBot.Class.Projectile = 2 +AuctionHouseBot.Class.TradeGood = 10 +AuctionHouseBot.Class.Generic = 1 +AuctionHouseBot.Class.Recipe = 6 +AuctionHouseBot.Class.Quiver = 1 +AuctionHouseBot.Class.Quest = 1 +AuctionHouseBot.Class.Key = 1 +AuctionHouseBot.Class.Misc = 5 +AuctionHouseBot.Class.Glyph = 3 + +AuctionHouseBot.Class.Misc.Mount.ReqLevel.Min = 0 +AuctionHouseBot.Class.Misc.Mount.ReqLevel.Max = 0 +AuctionHouseBot.Class.Misc.Mount.ReqSkill.Min = 0 +AuctionHouseBot.Class.Misc.Mount.ReqSkill.Max = 0 +AuctionHouseBot.Class.Glyph.ReqLevel.Min = 0 +AuctionHouseBot.Class.Glyph.ReqLevel.Max = 0 +AuctionHouseBot.Class.Glyph.ItemLevel.Min = 0 +AuctionHouseBot.Class.Glyph.ItemLevel.Max = 0 +AuctionHouseBot.Class.TradeGood.ItemLevel.Min = 0 +AuctionHouseBot.Class.TradeGood.ItemLevel.Max = 0 +AuctionHouseBot.Class.Container.ItemLevel.Min = 0 +AuctionHouseBot.Class.Container.ItemLevel.Max = 0 + +AuctionHouseBot.forceIncludeItems = "" +AuctionHouseBot.forceExcludeItems = "" + +################################################################################################################### +# Buyer config +# +# AuctionHouseBot.Buyer.Enabled +# General enable or disable AuctionHouseBot Buyer fonctionality +# Default 0 (Disabled) +# +# AuctionHouseBot.DEBUG.Buyer +# Enable or disable AuctionHouseBot Buyer debug mode +# Default 0 (Disabled) +# +# AuctionHouseBot.Buyer.FACTION.Enabled +# Enable or disable buyer independently by faction +# +# AuctionHouseBot.BuyPrice.Buyer +# Should the Buyer use BuyPrice or SellPrice to determine Bid Prices +# Default 0 (use SellPrice) +# +# AuctionHouseBot.Buyer.Recheck.Interval +# This specify time interval (in minute) between two evaluation of the same selled item. +# The less this value is, the more you give chance for item to be buyed by ahbot. +# Default 20 (20min.) +# +# AuctionHouseBot.Buyer.Alliance.Chance.Ratio +# When the evaluation of the entry is done you will have "x" chance for this entry to be buyed. +# The chance ratio is simply (x/chance ratio) +# For ex : If the evaluation give you 5000(maximum chance) chance and ratio is set 3 +# you will have 5000 chance on 15000(3*5000) random number +# This for every faction independently +# Default 3 (literaly 1 chance by 3) +# +################################################################################################################### + +AuctionHouseBot.Buyer.Enabled = 0 +AuctionHouseBot.DEBUG.Buyer = 0 + +AuctionHouseBot.Buyer.Alliance.Enabled = 1 +AuctionHouseBot.Buyer.Horde.Enabled = 1 +AuctionHouseBot.Buyer.Neutral.Enabled = 1 + +AuctionHouseBot.Buyer.Buyprice = 1 + +AuctionHouseBot.Buyer.Recheck.Interval = 20 + +AuctionHouseBot.Buyer.Alliance.Chance.Ratio = 3 +AuctionHouseBot.Buyer.Horde.Chance.Ratio = 3 +AuctionHouseBot.Buyer.Neutral.Chance.Ratio = 3 diff --git a/src/game/AuctionHouseMgr.h b/src/game/AuctionHouseMgr.h index 2c205bb9f..57e797d32 100644 --- a/src/game/AuctionHouseMgr.h +++ b/src/game/AuctionHouseMgr.h @@ -100,11 +100,14 @@ class AuctionHouseObject } typedef std::map AuctionEntryMap; + typedef std::pair AuctionEntryMapBounds; uint32 GetCount() { return AuctionsMap.size(); } AuctionEntryMap *GetAuctions() { return &AuctionsMap; } + AuctionEntryMapBounds GetAuctionsBounds() const {return AuctionEntryMapBounds(AuctionsMap.begin(), AuctionsMap.end()); } + void AddAuction(AuctionEntry *ah) { MANGOS_ASSERT( ah ); diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt index 3dc82768b..8f72c54c8 100644 --- a/src/game/CMakeLists.txt +++ b/src/game/CMakeLists.txt @@ -21,6 +21,7 @@ file(GLOB_RECURSE game_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp *.h) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/vmap + ${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouseBot ${CMAKE_SOURCE_DIR}/dep/include/g3dlite ${CMAKE_SOURCE_DIR}/dep/include ${CMAKE_SOURCE_DIR}/src/shared diff --git a/src/game/World.cpp b/src/game/World.cpp index 0b6a44a39..2f96f5392 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -61,6 +61,7 @@ #include "WaypointManager.h" #include "GMTicketMgr.h" #include "Util.h" +#include "AuctionHouseBot/AuctionHouseBot.h" #include "CharacterDatabaseCleaner.h" INSTANTIATE_SINGLETON_1( World ); @@ -1320,6 +1321,9 @@ void World::SetInitialWorldSettings() m_timers[WUPDATE_CORPSES].SetInterval(20*MINUTE*IN_MILLISECONDS); m_timers[WUPDATE_DELETECHARS].SetInterval(DAY*IN_MILLISECONDS); // check for chars to delete every day + // for AhBot + m_timers[WUPDATE_AHBOT].SetInterval(20*IN_MILLISECONDS); // every 20 sec + //to set mailtimer to return mails every day between 4 and 5 am //mailtimer is increased when updating auctions //one second is 1000 -(tested on win system) @@ -1364,6 +1368,9 @@ void World::SetInitialWorldSettings() // Delete all characters which have been deleted X days before Player::DeleteOldCharacters(); + sLog.outString("Initialize AuctionHouseBot..."); + sAuctionBot.Initialize(); + sLog.outString( "WORLD: World initialized" ); uint32 uStartInterval = WorldTimer::getMSTimeDiff(uStartTime, WorldTimer::getMSTime()); @@ -1463,6 +1470,13 @@ void World::Update(uint32 diff) sAuctionMgr.Update(); } + ///
  • Handle AHBot operations + if (m_timers[WUPDATE_AHBOT].Passed()) + { + sAuctionBot.Update(); + m_timers[WUPDATE_AHBOT].Reset(); + } + ///
  • Handle session updates UpdateSessions(diff); diff --git a/src/game/World.h b/src/game/World.h index 15c69cad0..840cf12b1 100644 --- a/src/game/World.h +++ b/src/game/World.h @@ -77,7 +77,8 @@ enum WorldTimers WUPDATE_CORPSES = 3, WUPDATE_EVENTS = 4, WUPDATE_DELETECHARS = 5, - WUPDATE_COUNT = 6 + WUPDATE_AHBOT = 6, + WUPDATE_COUNT = 7 }; /// Configuration elements diff --git a/src/shared/Log.cpp b/src/shared/Log.cpp index 075a9ef4c..1c5048f39 100644 --- a/src/shared/Log.cpp +++ b/src/shared/Log.cpp @@ -48,6 +48,8 @@ LogFilterData logFilterData[LOG_FILTER_COUNT] = { "combat", "LogFilter_Combat", false }, { "spell_cast", "LogFilter_SpellCast", false }, { "db_stricted_check", "LogFilter_DbStrictedCheck", true }, + { "ahbot_seller", "LogFilter_AhbotSeller", true }, + { "ahbot_buyer", "LogFilter_AhbotBuyer", true }, }; enum LogType diff --git a/src/shared/Log.h b/src/shared/Log.h index 8502d4421..6c1962686 100644 --- a/src/shared/Log.h +++ b/src/shared/Log.h @@ -36,23 +36,25 @@ enum LogLevel // bitmask (not forgot update logFilterData content) enum LogFilters { - LOG_FILTER_TRANSPORT_MOVES = 0x0001, // any related to transport moves - LOG_FILTER_CREATURE_MOVES = 0x0002, // creature move by cells - LOG_FILTER_VISIBILITY_CHANGES = 0x0004, // update visibility for diff objects and players - LOG_FILTER_ACHIEVEMENT_UPDATES= 0x0008, // achievement update broadcasts - LOG_FILTER_WEATHER = 0x0010, // weather changes - LOG_FILTER_PLAYER_STATS = 0x0020, // player save data - LOG_FILTER_SQL_TEXT = 0x0040, // raw SQL text send to DB engine - LOG_FILTER_PLAYER_MOVES = 0x0080, // player moves by grid/cell - LOG_FILTER_PERIODIC_AFFECTS = 0x0100, // DoT/HoT apply trace - LOG_FILTER_AI_AND_MOVEGENSS = 0x0200, // AI/movement generators debug output - LOG_FILTER_DAMAGE = 0x0400, // Direct/Area damage trace - LOG_FILTER_COMBAT = 0x0800, // attack states/roll attack results/etc - LOG_FILTER_SPELL_CAST = 0x1000, // spell cast/aura apply/spell proc events - LOG_FILTER_DB_STRICTED_CHECK = 0x2000, // stricted DB data checks output (with possible false reports) for DB devs + LOG_FILTER_TRANSPORT_MOVES = 0x0001, // 0 any related to transport moves + LOG_FILTER_CREATURE_MOVES = 0x0002, // 1 creature move by cells + LOG_FILTER_VISIBILITY_CHANGES = 0x0004, // 2 update visibility for diff objects and players + LOG_FILTER_ACHIEVEMENT_UPDATES= 0x0008, // 3 achievement update broadcasts + LOG_FILTER_WEATHER = 0x0010, // 4 weather changes + LOG_FILTER_PLAYER_STATS = 0x0020, // 5 player save data + LOG_FILTER_SQL_TEXT = 0x0040, // 6 raw SQL text send to DB engine + LOG_FILTER_PLAYER_MOVES = 0x0080, // 7 player moves by grid/cell + LOG_FILTER_PERIODIC_AFFECTS = 0x0100, // 8 DoT/HoT apply trace + LOG_FILTER_AI_AND_MOVEGENSS = 0x0200, // 9 AI/movement generators debug output + LOG_FILTER_DAMAGE = 0x0400, // 10 Direct/Area damage trace + LOG_FILTER_COMBAT = 0x0800, // 11 attack states/roll attack results/etc + LOG_FILTER_SPELL_CAST = 0x1000, // 12 spell cast/aura apply/spell proc events + LOG_FILTER_DB_STRICTED_CHECK = 0x2000, // 13 stricted DB data checks output (with possible false reports) for DB devs + LOG_FILTER_AHBOT_SELLER = 0x4000, // 14 Auction House Bot seller part + LOG_FILTER_AHBOT_BUYER = 0x8000, // 15 Auction House Bot buyer part }; -#define LOG_FILTER_COUNT 14 +#define LOG_FILTER_COUNT 16 struct LogFilterData { diff --git a/src/shared/SystemConfig.h.in b/src/shared/SystemConfig.h.in index 3857c3575..3492acd76 100644 --- a/src/shared/SystemConfig.h.in +++ b/src/shared/SystemConfig.h.in @@ -71,6 +71,7 @@ # endif # define _MANGOSD_CONFIG SYSCONFDIR"mangosd.conf" # define _REALMD_CONFIG SYSCONFDIR"realmd.conf" +# define _AUCTIONHOUSEBOT_CONFIG SYSCONFDIR"ahbot.conf" #else # if defined (__FreeBSD__) # define _ENDIAN_PLATFORM "FreeBSD_"ARCHITECTURE" (" _ENDIAN_STRING ")" @@ -89,6 +90,7 @@ # endif # define _MANGOSD_CONFIG SYSCONFDIR"mangosd.conf" # define _REALMD_CONFIG SYSCONFDIR"realmd.conf" +# define _AUCTIONHOUSEBOT_CONFIG SYSCONFDIR"ahbot.conf" #endif #define _FULLVERSION(REVD,REVT,REVN,REVH) _PACKAGENAME "/" _VERSION(REVD,REVT,REVN,REVH) " for " _ENDIAN_PLATFORM diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index ab21699b3..dd9c0aa9e 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "11722" + #define REVISION_NR "11723" #endif // __REVISION_NR_H__ diff --git a/win/VC100/game.vcxproj b/win/VC100/game.vcxproj index e28cf1990..be7d6ba9e 100644 --- a/win/VC100/game.vcxproj +++ b/win/VC100/game.vcxproj @@ -359,6 +359,7 @@ + @@ -525,6 +526,7 @@ + diff --git a/win/VC100/game.vcxproj.filters b/win/VC100/game.vcxproj.filters index 8f35ad5b3..69d61d84d 100644 --- a/win/VC100/game.vcxproj.filters +++ b/win/VC100/game.vcxproj.filters @@ -22,6 +22,9 @@ {64bb42b8-e7ba-4247-b337-492f644daeeb} + + {481ad376-5cba-439d-af8c-2ef73de2ed8b} + {948284d3-9d89-4609-8cdd-28a213edb53e} @@ -460,6 +463,9 @@ World/Handlers + + AhBot + vmaps @@ -886,6 +892,9 @@ Object + + AhBot + vmaps diff --git a/win/VC80/game.vcproj b/win/VC80/game.vcproj index fa3bea34a..e0f7fa391 100644 --- a/win/VC80/game.vcproj +++ b/win/VC80/game.vcproj @@ -1145,6 +1145,14 @@ RelativePath="..\..\src\game\ArenaTeam.h" > + + + + diff --git a/win/VC90/game.vcproj b/win/VC90/game.vcproj index 4e4e13ed7..fa647e2c2 100644 --- a/win/VC90/game.vcproj +++ b/win/VC90/game.vcproj @@ -1138,6 +1138,14 @@ RelativePath="..\..\src\game\ArenaTeam.h" > + + + +