From 9700bb8b17a2228e6720696b1cdba65dedc88cf3 Mon Sep 17 00:00:00 2001 From: Kewin Rausch Date: Fri, 23 Aug 2024 07:20:35 +0200 Subject: [PATCH 1/7] Initialization fixed to be performed at script startup; included copyright in the new source files --- src/AuctionHouseBotAuctionHouseScript.cpp | 4 ++ src/AuctionHouseBotCommon.cpp | 4 ++ src/AuctionHouseBotConfig.cpp | 45 +++++++++++------------ src/AuctionHouseBotMailScript.cpp | 4 ++ src/AuctionHouseBotScript.cpp | 5 --- src/AuctionHouseBotWorldScript.cpp | 20 ++++------ 6 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/AuctionHouseBotAuctionHouseScript.cpp b/src/AuctionHouseBotAuctionHouseScript.cpp index 1811b70..48efaf1 100644 --- a/src/AuctionHouseBotAuctionHouseScript.cpp +++ b/src/AuctionHouseBotAuctionHouseScript.cpp @@ -1,3 +1,7 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + */ + #include "AuctionHouseMgr.h" #include "AuctionHouseBot.h" diff --git a/src/AuctionHouseBotCommon.cpp b/src/AuctionHouseBotCommon.cpp index c0564c9..e71507e 100644 --- a/src/AuctionHouseBotCommon.cpp +++ b/src/AuctionHouseBotCommon.cpp @@ -1,3 +1,7 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + */ + #include "AuctionHouseBot.h" #include "AuctionHouseBotCommon.h" #include "AuctionHouseBotConfig.h" diff --git a/src/AuctionHouseBotConfig.cpp b/src/AuctionHouseBotConfig.cpp index 5353ab7..3dba5cb 100644 --- a/src/AuctionHouseBotConfig.cpp +++ b/src/AuctionHouseBotConfig.cpp @@ -1949,6 +1949,7 @@ void AHBConfig::Initialize(std::set botsIds) { InitializeFromFile(); InitializeFromSql(botsIds); + InitializeBins(); } void AHBConfig::InitializeFromFile() @@ -3259,13 +3260,14 @@ void AHBConfig::InitializeBins() // Perform reporting and the last check: if no items are disabled or in the whitelist clear the bin making the selling useless // - LOG_INFO("module", "Configuration for ah {}", AHID); + LOG_INFO("module", "===== AHBot ===================="); + LOG_INFO("module", "AHBot: Configuration for ah {}", AHID); if (SellerWhiteList.size() == 0) { if (DisableItemStore.size() == 0) { - LOG_ERROR("module", "No items are disabled or in the whitelist! Selling will be disabled!"); + LOG_ERROR("module", "AHBot: No items are disabled or in the whitelist! Selling will be disabled!"); GreyTradeGoodsBin.clear(); WhiteTradeGoodsBin.clear(); @@ -3287,30 +3289,27 @@ void AHBConfig::InitializeBins() return; } - LOG_INFO("module", "{} disabled items", uint32(DisableItemStore.size())); + LOG_INFO("module", "AHBot: {} disabled items", uint32(DisableItemStore.size())); } else { - LOG_INFO("module", "Using a whitelist of {} items", uint32(SellerWhiteList.size())); - } - - // if (DebugOutConfig) - // { - LOG_INFO("module", "loaded {} grey trade goods", uint32(GreyTradeGoodsBin.size())); - LOG_INFO("module", "loaded {} white trade goods", uint32(WhiteTradeGoodsBin.size())); - LOG_INFO("module", "loaded {} green trade goods", uint32(GreenTradeGoodsBin.size())); - LOG_INFO("module", "loaded {} blue trade goods", uint32(BlueTradeGoodsBin.size())); - LOG_INFO("module", "loaded {} purple trade goods", uint32(PurpleTradeGoodsBin.size())); - LOG_INFO("module", "loaded {} orange trade goods", uint32(OrangeTradeGoodsBin.size())); - LOG_INFO("module", "loaded {} yellow trade goods", uint32(YellowTradeGoodsBin.size())); - LOG_INFO("module", "loaded {} grey items" , uint32(GreyItemsBin.size())); - LOG_INFO("module", "loaded {} white items" , uint32(WhiteItemsBin.size())); - LOG_INFO("module", "loaded {} green items" , uint32(GreenItemsBin.size())); - LOG_INFO("module", "loaded {} blue items" , uint32(BlueItemsBin.size())); - LOG_INFO("module", "loaded {} purple items" , uint32(PurpleItemsBin.size())); - LOG_INFO("module", "loaded {} orange items" , uint32(OrangeItemsBin.size())); - LOG_INFO("module", "loaded {} yellow items" , uint32(YellowItemsBin.size())); - // } + LOG_INFO("module", "AHBot: Using a whitelist of {} items", uint32(SellerWhiteList.size())); + } + + LOG_INFO("module", "AHBot: loaded {} grey trade goods", uint32(GreyTradeGoodsBin.size())); + LOG_INFO("module", "AHBot: loaded {} white trade goods", uint32(WhiteTradeGoodsBin.size())); + LOG_INFO("module", "AHBot: loaded {} green trade goods", uint32(GreenTradeGoodsBin.size())); + LOG_INFO("module", "AHBot: loaded {} blue trade goods", uint32(BlueTradeGoodsBin.size())); + LOG_INFO("module", "AHBot: loaded {} purple trade goods", uint32(PurpleTradeGoodsBin.size())); + LOG_INFO("module", "AHBot: loaded {} orange trade goods", uint32(OrangeTradeGoodsBin.size())); + LOG_INFO("module", "AHBot: loaded {} yellow trade goods", uint32(YellowTradeGoodsBin.size())); + LOG_INFO("module", "AHBot: loaded {} grey items" , uint32(GreyItemsBin.size())); + LOG_INFO("module", "AHBot: loaded {} white items" , uint32(WhiteItemsBin.size())); + LOG_INFO("module", "AHBot: loaded {} green items" , uint32(GreenItemsBin.size())); + LOG_INFO("module", "AHBot: loaded {} blue items" , uint32(BlueItemsBin.size())); + LOG_INFO("module", "AHBot: loaded {} purple items" , uint32(PurpleItemsBin.size())); + LOG_INFO("module", "AHBot: loaded {} orange items" , uint32(OrangeItemsBin.size())); + LOG_INFO("module", "AHBot: loaded {} yellow items" , uint32(YellowItemsBin.size())); } std::set AHBConfig::getCommaSeparatedIntegers(std::string text) diff --git a/src/AuctionHouseBotMailScript.cpp b/src/AuctionHouseBotMailScript.cpp index 5c3dee2..c636943 100644 --- a/src/AuctionHouseBotMailScript.cpp +++ b/src/AuctionHouseBotMailScript.cpp @@ -1,3 +1,7 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + */ + #include "AuctionHouseBot.h" #include "AuctionHouseBotCommon.h" #include "AuctionHouseBotMailScript.h" diff --git a/src/AuctionHouseBotScript.cpp b/src/AuctionHouseBotScript.cpp index 5cf7149..bf05c54 100644 --- a/src/AuctionHouseBotScript.cpp +++ b/src/AuctionHouseBotScript.cpp @@ -2,15 +2,10 @@ * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 */ -// #include "ScriptMgr.h" #include "AuctionHouseBot.h" #include "AuctionHouseBotAuctionHouseScript.h" #include "AuctionHouseBotMailScript.h" #include "AuctionHouseBotWorldScript.h" -// #include "Log.h" -// #include "Mail.h" -// #include "Player.h" -// #include "WorldSession.h" // ============================================================================= // This provides the effective startup of the module by istanciating the scripts diff --git a/src/AuctionHouseBotWorldScript.cpp b/src/AuctionHouseBotWorldScript.cpp index 5238fa2..74d2084 100644 --- a/src/AuctionHouseBotWorldScript.cpp +++ b/src/AuctionHouseBotWorldScript.cpp @@ -1,3 +1,7 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + */ + #include "Config.h" #include "Log.h" @@ -84,14 +88,6 @@ void AHBot_WorldScript::OnBeforeConfigLoad(bool /*reload*/) LOG_ERROR("server.loading", "AHBot: no characters registered for account {}", account); return; } - - // - // Preparare the global configuration for all factions using the configuration just read - // - - gAllianceConfig->Initialize(gBotsId); - gHordeConfig->Initialize (gBotsId); - gNeutralConfig->Initialize (gBotsId); } void AHBot_WorldScript::OnStartup() @@ -99,12 +95,12 @@ void AHBot_WorldScript::OnStartup() LOG_INFO("server.loading", "Initialize AuctionHouseBot..."); // - // Initialize the configuration items bins here, when items has been handled by the object manager + // Initialize the configuration // - gAllianceConfig->InitializeBins(); - gHordeConfig->InitializeBins (); - gNeutralConfig->InitializeBins (); + gAllianceConfig->Initialize(gBotsId); + gHordeConfig->Initialize (gBotsId); + gNeutralConfig->Initialize (gBotsId); // // Starts the amount of bots read furing the configuration phase From f8e0d89200b3b0eb69e253818a35a7302773542f Mon Sep 17 00:00:00 2001 From: Kewin Rausch Date: Fri, 23 Aug 2024 08:27:42 +0200 Subject: [PATCH 2/7] Handle of the configuration reloading in the correct way from the command line (cleanup and initialization of new elements) --- src/AuctionHouseBotConfig.cpp | 1 - src/AuctionHouseBotWorldScript.cpp | 79 ++++++++++++++++++++++++++++-- src/AuctionHouseBotWorldScript.h | 4 ++ 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/AuctionHouseBotConfig.cpp b/src/AuctionHouseBotConfig.cpp index 3dba5cb..66bb447 100644 --- a/src/AuctionHouseBotConfig.cpp +++ b/src/AuctionHouseBotConfig.cpp @@ -3260,7 +3260,6 @@ void AHBConfig::InitializeBins() // Perform reporting and the last check: if no items are disabled or in the whitelist clear the bin making the selling useless // - LOG_INFO("module", "===== AHBot ===================="); LOG_INFO("module", "AHBot: Configuration for ah {}", AHID); if (SellerWhiteList.size() == 0) diff --git a/src/AuctionHouseBotWorldScript.cpp b/src/AuctionHouseBotWorldScript.cpp index 74d2084..bb49361 100644 --- a/src/AuctionHouseBotWorldScript.cpp +++ b/src/AuctionHouseBotWorldScript.cpp @@ -18,7 +18,7 @@ AHBot_WorldScript::AHBot_WorldScript() : WorldScript("AHBot_WorldScript") } -void AHBot_WorldScript::OnBeforeConfigLoad(bool /*reload*/) +void AHBot_WorldScript::OnBeforeConfigLoad(bool reload) { // // Retrieve how many bots shall be operating on the auction market @@ -88,6 +88,38 @@ void AHBot_WorldScript::OnBeforeConfigLoad(bool /*reload*/) LOG_ERROR("server.loading", "AHBot: no characters registered for account {}", account); return; } + + // + // Start the bots only if the operation is a reload, otherwise let the OnStartup do the job + // + + if (reload) + { + if (debug) + { + LOG_INFO("module", "AHBot: Reloading the bots"); + } + + // + // Clear the bots array; this way they wont be used anymore during the initialization stage. + // + + DeleteBots(); + + // + // Reload the configuration for the auction houses + // + + gAllianceConfig->Initialize(gBotsId); + gHordeConfig->Initialize (gBotsId); + gNeutralConfig->Initialize (gBotsId); + + // + // Start again the bots + // + + PopulateBots(); + } } void AHBot_WorldScript::OnStartup() @@ -95,7 +127,7 @@ void AHBot_WorldScript::OnStartup() LOG_INFO("server.loading", "Initialize AuctionHouseBot..."); // - // Initialize the configuration + // Initialize the configuration (done only once at startup) // gAllianceConfig->Initialize(gBotsId); @@ -103,11 +135,52 @@ void AHBot_WorldScript::OnStartup() gNeutralConfig->Initialize (gBotsId); // - // Starts the amount of bots read furing the configuration phase + // Starts the bots // + PopulateBots(); +} + +void AHBot_WorldScript::DeleteBots() +{ + // + // Save the old bots references. + // + + std::set oldBots; + + for (AuctionHouseBot* bot: gBots) + { + oldBots.insert(bot); + } + + // + // Clear the bot list + // + + gBots.clear(); + + // + // Free the resources used up by the old bots + // + + for (AuctionHouseBot* bot: oldBots) + { + delete bot; + } +} + + +void AHBot_WorldScript::PopulateBots() +{ uint32 account = sConfigMgr->GetOption("AuctionHouseBot.Account", 0); + // + // Insert the bot in the list used for auction house iterations + // + + gBots.clear(); + for (uint32 id: gBotsId) { AuctionHouseBot* bot = new AuctionHouseBot(account, id); diff --git a/src/AuctionHouseBotWorldScript.h b/src/AuctionHouseBotWorldScript.h index e455595..7634c10 100644 --- a/src/AuctionHouseBotWorldScript.h +++ b/src/AuctionHouseBotWorldScript.h @@ -13,6 +13,10 @@ class AHBot_WorldScript : public WorldScript { +private: + void DeleteBots(); + void PopulateBots(); + public: AHBot_WorldScript(); From dd6163a26aa01d4c775a237ebbb276448e887ead Mon Sep 17 00:00:00 2001 From: Kewin Rausch Date: Sun, 25 Aug 2024 08:32:51 +0200 Subject: [PATCH 3/7] Improved the help text and descriptions --- README.md | 40 +++++++++++++++++++++++++++++++++------- conf/mod_ahbot.conf.dist | 2 ++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 810b8e7..9c0c917 100644 --- a/README.md +++ b/README.md @@ -16,29 +16,55 @@ ALTER TABLE `auctionhousebot` RENAME TO `mod_auctionhousebot`; ## Description An auction house bot for the best core: AzerothCore. +This mod works by selling and bidding auctions in the factions auction house. It can be instructed to do both the operations independently. ## Installation ``` -1. Simply place the module under the `modules` directory of your AzerothCore source. -1. Import the SQL manually to the right Database (auth, world or characters) or with the `db_assembler.sh` (if `include.sh` provided). +1. Simply place the module under the `modules` directory of your AzerothCore source. +1. Import the SQL manually to the right Database (auth, world or characters). 1. Re-run cmake and launch a clean build of AzerothCore. ``` -## Edit module configuration (optional) - -If you need to change the module configuration, go to your server configuration folder (where your `worldserver` or `worldserver.exe` is) -rename the file mod_ahbot.conf.dist to mod_ahbot.conf and edit it. - ## Usage Edit the module configuration and add a player account ID and a character ID. This character will sell and buy items in the auction house so give him a good name. +If you only specify the account ID, all the characters created within that account will be involved in selling and bidding on the markets. + +Specify what operation must be performed (`EnableSeller`, `EnableBuyer` or both). Notes: - The account used does not need any security level and can be a player account. - The character used by the ahbot is not meant to be used ingame. If you use it to browse the auction house, you might have issues like "Searching for items..." displaying forever. +## Edit module configuration (optional) + +If you need to change the module configuration, go to your server configuration folder (where your `worldserver` or `worldserver.exe` is) +rename the file mod_ahbot.conf.dist to mod_ahbot.conf and edit it. This will change the overall behavior of the bot. + +If you need to change a more specific value (for example the quotas of item sold), you will need to update values int the `mod_auctionhousebot` table or use the command line. + +The default quotas of all the auction houses for trade goods are: +- Gray = 0 +- White = 27 +- Green = 12 +- Blue = 10 +- Purple = 1 +- Orange = 0 +- Yellow = 0 + +The default quotas of all the auction houses for non trade goods items are: +- Gray = 0 +- White = 10 +- Green = 30 +- Blue = 8 +- Purple = 2 +- Orange = 0 +- Yellow = 0 + +The sum of the percentage for these categories must always be 100, or otherwise the defaults values will be used and the modifications will not be accepted. + ## Credits - Ayase: ported the bot to AzerothCore diff --git a/conf/mod_ahbot.conf.dist b/conf/mod_ahbot.conf.dist index f4e3762..0985d72 100644 --- a/conf/mod_ahbot.conf.dist +++ b/conf/mod_ahbot.conf.dist @@ -62,6 +62,8 @@ # AuctionHouseBot.ConsiderOnlyBotAuctions # Ignore player auctions and consider only bot ones when keeping track of the numer of auctions in place. # This allow to keep a background noise in the market even when lot of players are in. +# If this is not set, players acutions are counted in the valid auctions and you will need to greatly increase the maxitems SQL values to +# allow the bot to operate on the market. If this is set the players auctions will not be considered. # Default 0 (False) # # AuctionHouseBot.DuplicatesCount From 80c72de92a22e1723569e87f4afc8b505966561f Mon Sep 17 00:00:00 2001 From: Kewin Rausch Date: Sat, 7 Sep 2024 09:27:57 +0200 Subject: [PATCH 4/7] Introduced a mechanism that allows the bot to adapt to the market prices (right now is a plain average which resets to allow quick convergence with the markets sentiments) --- conf/mod_ahbot.conf.dist | 6 +- data/sql/db-world/mod_auctionhousebot.sql | 28 +++- src/AuctionHouseBot.cpp | 171 ++++++++++++++-------- src/AuctionHouseBotAuctionHouseScript.cpp | 62 +++++++- src/AuctionHouseBotAuctionHouseScript.h | 8 +- src/AuctionHouseBotCommon.h | 1 + src/AuctionHouseBotConfig.cpp | 69 +++++++++ src/AuctionHouseBotConfig.h | 13 ++ src/cs_ah_bot.cpp | 143 ++++++++++-------- 9 files changed, 363 insertions(+), 138 deletions(-) diff --git a/conf/mod_ahbot.conf.dist b/conf/mod_ahbot.conf.dist index 0985d72..f3fbd0b 100644 --- a/conf/mod_ahbot.conf.dist +++ b/conf/mod_ahbot.conf.dist @@ -47,6 +47,10 @@ # Should the Buyer use BuyPrice or SellPrice to determine Bid Prices # Default 0 (use SellPrice) # +# AuctionHouseBot.UseMarketPriceForSeller +# Should the Seller use the market price for its auctions? +# Default 0 (disabled) +# # Auction House Bot character data # AuctionHouseBot.Account is the account number # (in realmd->account table) of the player you want to run @@ -83,7 +87,6 @@ # 2 = shorts, auctions lasts within an hour # Default 1 # -# ############################################################################### AuctionHouseBot.DEBUG = 0 @@ -98,6 +101,7 @@ AuctionHouseBot.EnableSeller = 0 AuctionHouseBot.EnableBuyer = 0 AuctionHouseBot.UseBuyPriceForSeller = 0 AuctionHouseBot.UseBuyPriceForBuyer = 0 +AuctionHouseBot.UseMarketPriceForSeller = 0 AuctionHouseBot.Account = 0 AuctionHouseBot.GUID = 0 AuctionHouseBot.ItemsPerCycle = 200 diff --git a/data/sql/db-world/mod_auctionhousebot.sql b/data/sql/db-world/mod_auctionhousebot.sql index 12aaa00..ead151d 100644 --- a/data/sql/db-world/mod_auctionhousebot.sql +++ b/data/sql/db-world/mod_auctionhousebot.sql @@ -1,3 +1,7 @@ +-- +-- Main configuration for the auction houses +-- + DROP TABLE IF EXISTS `mod_auctionhousebot`; CREATE TABLE `mod_auctionhousebot` ( `auctionhouse` int(11) NOT NULL DEFAULT '0' COMMENT 'mapID of the auctionhouse.', @@ -65,20 +69,30 @@ CREATE TABLE `mod_auctionhousebot` ( PRIMARY KEY (`auctionhouse`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -DROP TABLE IF EXISTS `mod_auctionhousebot_disabled_items`; -CREATE TABLE `mod_auctionhousebot_disabled_items` ( - `item` mediumint(8) unsigned NOT NULL, - PRIMARY KEY (`item`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- +-- AHBot auction houses default configuration values +-- --- AHBot auctionhouse configuration INSERT INTO `mod_auctionhousebot` (`auctionhouse`, `name`, `minitems`, `maxitems`, `percentgreytradegoods`, `percentwhitetradegoods`, `percentgreentradegoods`, `percentbluetradegoods`, `percentpurpletradegoods`, `percentorangetradegoods`, `percentyellowtradegoods`, `percentgreyitems`, `percentwhiteitems`, `percentgreenitems`, `percentblueitems`, `percentpurpleitems`, `percentorangeitems`, `percentyellowitems`, `minpricegrey`, `maxpricegrey`, `minpricewhite`, `maxpricewhite`, `minpricegreen`, `maxpricegreen`, `minpriceblue`, `maxpriceblue`, `minpricepurple`, `maxpricepurple`, `minpriceorange`, `maxpriceorange`, `minpriceyellow`, `maxpriceyellow`, `minbidpricegrey`, `maxbidpricegrey`, `minbidpricewhite`, `maxbidpricewhite`, `minbidpricegreen`, `maxbidpricegreen`, `minbidpriceblue`, `maxbidpriceblue`, `minbidpricepurple`, `maxbidpricepurple`, `minbidpriceorange`, `maxbidpriceorange`, `minbidpriceyellow`, `maxbidpriceyellow`, `maxstackgrey`, `maxstackwhite`, `maxstackgreen`, `maxstackblue`, `maxstackpurple`, `maxstackorange`, `maxstackyellow`, `buyerpricegrey`, `buyerpricewhite`, `buyerpricegreen`, `buyerpriceblue`, `buyerpricepurple`, `buyerpriceorange`, `buyerpriceyellow`, `buyerbiddinginterval`, `buyerbidsperinterval`) VALUES (2,'Alliance',250,250,0,27,12,10,1,0,0,0,10,30,8,2,0,0,100,150,150,250,800,1400,1250,1750,2250,4550,3250,5550,5250,6550,70,100,70,100,80,100,75,100,80,100,80,100,80,100,0,0,3,2,1,1,1,1,3,5,12,15,20,22,1,1), (6,'Horde',250,250,0,27,12,10,1,0,0,0,10,30,8,2,0,0,100,150,150,250,800,1400,1250,1750,2250,4550,3250,5550,5250,6550,70,100,70,100,80,100,75,100,80,100,80,100,80,100,0,0,3,2,1,1,1,1,3,5,12,15,20,22,1,1), (7,'Neutral',250,250,0,27,12,10,1,0,0,0,10,30,8,2,0,0,100,150,150,250,800,1400,1250,1750,2250,4550,3250,5550,5250,6550,70,100,70,100,80,100,75,100,80,100,80,100,80,100,0,0,3,2,1,1,1,1,3,5,12,15,20,22,1,1); --- Items unavailable to players +-- +-- Items blacklist +-- + +DROP TABLE IF EXISTS `mod_auctionhousebot_disabled_items`; +CREATE TABLE `mod_auctionhousebot_disabled_items` ( + `item` mediumint(8) unsigned NOT NULL, + PRIMARY KEY (`item`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Blacklist default values +-- + INSERT INTO `mod_auctionhousebot_disabled_items` VALUES (17), (3895), (1700), (862), (4196), (3934), (2275), (4213), (4988), (4989), (4990), (4110), (4111), (4116), (3463), (3068), diff --git a/src/AuctionHouseBot.cpp b/src/AuctionHouseBot.cpp index 65a6646..dc14815 100644 --- a/src/AuctionHouseBot.cpp +++ b/src/AuctionHouseBot.cpp @@ -82,7 +82,7 @@ uint32 AuctionHouseBot::getStackCount(AHBConfig* config, uint32 max) ret = urand(1, 4) * 4; } - if (max % 3 == 0) // 3, 6, 9 + if (max % 3 == 0) // 3, 6, 9, 18 { ret = urand(1, 3) * 3; } @@ -413,7 +413,7 @@ void AuctionHouseBot::Buy(Player* AHBplayer, AHBConfig* config, WorldSession* se // // Perform a new bid on the auction // - + if (auction->bidder) { if (auction->bidder != AHBplayer->GetGUID()) @@ -421,21 +421,21 @@ void AuctionHouseBot::Buy(Player* AHBplayer, AHBConfig* config, WorldSession* se // // Mail to last bidder and return their money // - + auto trans = CharacterDatabase.BeginTransaction(); - + sAuctionMgr->SendAuctionOutbiddedMail(auction, bidprice, session->GetPlayer(), trans); CharacterDatabase.CommitTransaction (trans); } } - + auction->bidder = AHBplayer->GetGUID(); auction->bid = bidprice; - + // // Save the auction into database // - + CharacterDatabase.Execute("UPDATE auctionhouse SET buyguid = '{}', lastbid = '{}' WHERE id = '{}'", auction->bidder.GetCounter(), auction->bid, auction->Id); } else @@ -487,11 +487,11 @@ void AuctionHouseBot::Buy(Player* AHBplayer, AHBConfig* config, WorldSession* se { if (bought) { - LOG_INFO("module", "AHBot [{}]: Bought , id={}, ah={}, item={}, start={}, current={}, buyout={}", _id, auction->Id, auction->GetHouseId(), auction->item_template, auction->startbid, currentprice, auction->buyout); + LOG_INFO("module", "AHBot [{}]: Bought , id={}, ah={}, item={}, start={}, current={}, buyout={}", _id, prototype->ItemId, auction->GetHouseId(), auction->item_template, auction->startbid, currentprice, auction->buyout); } else { - LOG_INFO("module", "AHBot [{}]: New bid, id={}, ah={}, item={}, start={}, current={}, buyout={}", _id, auction->Id, auction->GetHouseId(), auction->item_template, auction->startbid, currentprice, auction->buyout); + LOG_INFO("module", "AHBot [{}]: New bid, id={}, ah={}, item={}, start={}, current={}, buyout={}", _id, prototype->ItemId, auction->GetHouseId(), auction->item_template, auction->startbid, currentprice, auction->buyout); } } } @@ -938,54 +938,65 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) item->SetItemRandomProperties(randomPropertyId); } + if (prototype->Quality > AHB_MAX_QUALITY) + { + err++; + + if (config->DebugOutSeller) + { + LOG_ERROR("module", "AHBot [{}]: Quality {} TOO HIGH for item {}", _id, prototype->Quality, itemID); + } + + item->RemoveFromUpdateQueueOf(AHBplayer); + continue; + } + // - // Determine the price and stack size + // Determine the price // uint64 buyoutPrice = 0; uint64 bidPrice = 0; uint32 stackCount = 1; - if (config->SellMethod) + if (config->SellAtMarketPrice) { - buyoutPrice = prototype->BuyPrice; - } - else - { - buyoutPrice = prototype->SellPrice; + buyoutPrice = config->GetItemPrice(itemID); } - if (prototype->Quality <= AHB_MAX_QUALITY) + if (buyoutPrice == 0) { - if (config->GetMaxStack(prototype->Quality) > 1 && item->GetMaxStackCount() > 1) + if (config->SellMethod) { - stackCount = minValue(getStackCount(config, item->GetMaxStackCount()), config->GetMaxStack(prototype->Quality)); - } - else if (config->GetMaxStack(prototype->Quality) == 0 && item->GetMaxStackCount() > 1) - { - stackCount = getStackCount(config, item->GetMaxStackCount()); + buyoutPrice = prototype->BuyPrice; } else { - stackCount = 1; + buyoutPrice = prototype->SellPrice; } + } + + buyoutPrice = buyoutPrice * urand(config->GetMinPrice(prototype->Quality), config->GetMaxPrice(prototype->Quality)); + buyoutPrice = buyoutPrice / 100; + + bidPrice = buyoutPrice * urand(config->GetMinBidPrice(prototype->Quality), config->GetMaxBidPrice(prototype->Quality)); + bidPrice = bidPrice / 100; - buyoutPrice *= urand(config->GetMinPrice(prototype->Quality), config->GetMaxPrice(prototype->Quality)); - buyoutPrice /= 100; - bidPrice = buyoutPrice * urand(config->GetMinBidPrice(prototype->Quality), config->GetMaxBidPrice(prototype->Quality)); - bidPrice /= 100; + // + // Determine the stack size + // + + if (config->GetMaxStack(prototype->Quality) > 1 && item->GetMaxStackCount() > 1) + { + stackCount = minValue(getStackCount(config, item->GetMaxStackCount()), config->GetMaxStack(prototype->Quality)); + } + else if (config->GetMaxStack(prototype->Quality) == 0 && item->GetMaxStackCount() > 1) + { + stackCount = getStackCount(config, item->GetMaxStackCount()); } else { - err++; - - if (config->DebugOutSeller) - { - LOG_ERROR("module", "AHBot [{}]: Quality {} TOO HIGH for item {}", _id, prototype->Quality, itemID); - } - - item->RemoveFromUpdateQueueOf(AHBplayer); - continue; + stackCount = 1; } item->SetCount(stackCount); @@ -1222,7 +1233,7 @@ void AuctionHouseBot::Commands(AHBotCommand command, uint32 ahMapID, uint32 col, case 6: config = _hordeConfig; break; - case 7: + default: config = _neutralConfig; break; } @@ -1273,13 +1284,15 @@ void AuctionHouseBot::Commands(AHBotCommand command, uint32 ahMapID, uint32 col, if (state == 0) { - config->AHBBuyer = false; - LOG_ERROR("module", "AHBot: Buyer disabled from console"); + _allianceConfig->AHBBuyer = false; + _hordeConfig->AHBBuyer = false; + _neutralConfig->AHBBuyer = false; } else { - config->AHBBuyer = true; - LOG_ERROR("module", "AHBot: Buyer enabled from console"); + _allianceConfig->AHBBuyer = true; + _hordeConfig->AHBBuyer = true; + _neutralConfig->AHBBuyer = true; } break; @@ -1291,13 +1304,35 @@ void AuctionHouseBot::Commands(AHBotCommand command, uint32 ahMapID, uint32 col, if (state == 0) { - config->AHBSeller = false; - LOG_ERROR("module", "AHBot: Seller disabled from console"); + _allianceConfig->AHBSeller = false; + _hordeConfig->AHBSeller = false; + _neutralConfig->AHBSeller = false; + } + else + { + _allianceConfig->AHBSeller = true; + _hordeConfig->AHBSeller = true; + _neutralConfig->AHBSeller = true; + } + + break; + } + case AHBotCommand::useMarketPrice: + { + char* param1 = strtok(args, " "); + uint32 state = (uint32)strtoul(param1, NULL, 0); + + if (state == 0) + { + _allianceConfig->SellAtMarketPrice = false; + _hordeConfig->SellAtMarketPrice = false; + _neutralConfig->SellAtMarketPrice = false; } else { - config->AHBSeller = true; - LOG_ERROR("module", "AHBot: Seller enabled from console"); + _allianceConfig->SellAtMarketPrice = true; + _hordeConfig->SellAtMarketPrice = true; + _neutralConfig->SellAtMarketPrice = true; } break; @@ -1309,6 +1344,10 @@ void AuctionHouseBot::Commands(AHBotCommand command, uint32 ahMapID, uint32 col, AuctionHouseObject::AuctionEntryMap::iterator itr; itr = auctionHouse->GetAuctionsBegin(); + // + // Iterate through all the autions and if they belong to the bot, make them expired + // + while (itr != auctionHouse->GetAuctionsEnd()) { if (itr->second->owner.GetCounter() == _id) @@ -1381,27 +1420,35 @@ void AuctionHouseBot::Commands(AHBotCommand command, uint32 ahMapID, uint32 col, uint32 orangei = (uint32) strtoul(param13, NULL, 0); uint32 yellowi = (uint32) strtoul(param14, NULL, 0); + // + // Setup the percentage in the configuration first, so validity test can be performed + // + + config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi); + + // + // Save the results into the database (after the tests) + // + auto trans = WorldDatabase.BeginTransaction(); - trans->Append("UPDATE mod_auctionhousebot SET percentgreytradegoods = '{}' WHERE auctionhouse = '{}'", greytg, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentwhitetradegoods = '{}' WHERE auctionhouse = '{}'", whitetg, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentgreentradegoods = '{}' WHERE auctionhouse = '{}'", greentg, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentbluetradegoods = '{}' WHERE auctionhouse = '{}'", bluetg, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentpurpletradegoods = '{}' WHERE auctionhouse = '{}'", purpletg, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentorangetradegoods = '{}' WHERE auctionhouse = '{}'", orangetg, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentyellowtradegoods = '{}' WHERE auctionhouse = '{}'", yellowtg, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentgreyitems = '{}' WHERE auctionhouse = '{}'", greyi, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentwhiteitems = '{}' WHERE auctionhouse = '{}'", whitei, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentgreenitems = '{}' WHERE auctionhouse = '{}'", greeni, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentblueitems = '{}' WHERE auctionhouse = '{}'", bluei, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentpurpleitems = '{}' WHERE auctionhouse = '{}'", purplei, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentorangeitems = '{}' WHERE auctionhouse = '{}'", orangei, ahMapID); - trans->Append("UPDATE mod_auctionhousebot SET percentyellowitems = '{}' WHERE auctionhouse = '{}'", yellowi, ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentgreytradegoods = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_GREY_TG) , ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentwhitetradegoods = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_WHITE_TG) , ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentgreentradegoods = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_GREEN_TG) , ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentbluetradegoods = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_BLUE_TG) , ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentpurpletradegoods = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_PURPLE_TG), ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentorangetradegoods = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_ORANGE_TG), ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentyellowtradegoods = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_YELLOW_TG), ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentgreyitems = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_GREY_I) , ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentwhiteitems = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_WHITE_I) , ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentgreenitems = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_GREEN_I) , ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentblueitems = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_BLUE_I) , ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentpurpleitems = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_PURPLE_I) , ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentorangeitems = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_ORANGE_I) , ahMapID); + trans->Append("UPDATE mod_auctionhousebot SET percentyellowitems = '{}' WHERE auctionhouse = '{}'", config->GetPercentages(AHB_YELLOW_I) , ahMapID); WorldDatabase.CommitTransaction(trans); - config->SetPercentages(greytg, whitetg, greentg, bluetg, purpletg, orangetg, yellowtg, greyi, whitei, greeni, bluei, purplei, orangei, yellowi); - break; } case AHBotCommand::minprice: diff --git a/src/AuctionHouseBotAuctionHouseScript.cpp b/src/AuctionHouseBotAuctionHouseScript.cpp index 48efaf1..a7ebdf3 100644 --- a/src/AuctionHouseBotAuctionHouseScript.cpp +++ b/src/AuctionHouseBotAuctionHouseScript.cpp @@ -3,6 +3,7 @@ */ #include "AuctionHouseMgr.h" +#include "GameTime.h" #include "AuctionHouseBot.h" #include "AuctionHouseBotCommon.h" @@ -142,9 +143,8 @@ void AHBot_AuctionHouseScript::OnAuctionAdd(AuctionHouseObject* /*ah*/, AuctionE void AHBot_AuctionHouseScript::OnAuctionRemove(AuctionHouseObject* /*ah*/, AuctionEntry* auction) { - // - // The the configuration for the auction house + // Get the configuration for the auction house // AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(auction->GetHouseId()); @@ -204,6 +204,64 @@ void AHBot_AuctionHouseScript::OnAuctionRemove(AuctionHouseObject* /*ah*/, Aucti config->DecItemCounts(prototype->Class, prototype->Quality); } +void AHBot_AuctionHouseScript::OnAuctionSuccessful(AuctionHouseObject* /*ah*/, AuctionEntry* auction) +{ + // + // Get the configuration for the auction house + // + + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(auction->GetHouseId()); + AHBConfig* config = gNeutralConfig; + + if (ahEntry) + { + if (ahEntry->houseId == AUCTIONHOUSE_ALLIANCE) + { + config = gAllianceConfig; + } + else if (ahEntry->houseId == AUCTIONHOUSE_HORDE) + { + config = gHordeConfig; + } + } + + // + // If the auction has been won, it means that it has been accepted by the market. + // Use the buyout as a reference since the price for the bid is downgraded during selling. + // + + config->UpdateItemStats(auction->item_template, auction->itemCount, auction->buyout); +} + +void AHBot_AuctionHouseScript::OnAuctionExpire(AuctionHouseObject* /*ah*/, AuctionEntry* auction) +{ + // + // Get the configuration for the auction house + // + + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(auction->GetHouseId()); + AHBConfig* config = gNeutralConfig; + + if (ahEntry) + { + if (ahEntry->houseId == AUCTIONHOUSE_ALLIANCE) + { + config = gAllianceConfig; + } + else if (ahEntry->houseId == AUCTIONHOUSE_HORDE) + { + config = gHordeConfig; + } + } + + // + // If the auction expired, then it means that the bid was unwanted by the market. + // Bid price is usually less or equal to the buyout, so this likely will bring the price down. + // + + config->UpdateItemStats(auction->item_template, auction->itemCount, auction->bid); +} + void AHBot_AuctionHouseScript::OnBeforeAuctionHouseMgrUpdate() { // diff --git a/src/AuctionHouseBotAuctionHouseScript.h b/src/AuctionHouseBotAuctionHouseScript.h index 16ba1b5..b5380ee 100644 --- a/src/AuctionHouseBotAuctionHouseScript.h +++ b/src/AuctionHouseBotAuctionHouseScript.h @@ -21,10 +21,12 @@ class AHBot_AuctionHouseScript : public AuctionHouseScript void OnBeforeAuctionHouseMgrSendAuctionExpiredMail (AuctionHouseMgr* auctionHouseMgr, AuctionEntry* auction, Player* owner, uint32& owner_accId, bool& sendNotification, bool& sendMail) override; void OnBeforeAuctionHouseMgrSendAuctionOutbiddedMail (AuctionHouseMgr* auctionHouseMgr, AuctionEntry* auction, Player* oldBidder, uint32& oldBidder_accId, Player* newBidder, uint32& newPrice, bool& sendNotification, bool& sendMail) override; - void OnAuctionAdd (AuctionHouseObject* ah, AuctionEntry* auction) override; - void OnAuctionRemove(AuctionHouseObject* ah, AuctionEntry* auction) override; + void OnAuctionAdd (AuctionHouseObject* ah, AuctionEntry* auction) override; + void OnAuctionRemove (AuctionHouseObject* ah, AuctionEntry* auction) override; + void OnAuctionSuccessful(AuctionHouseObject* ah, AuctionEntry* auction) override; + void OnAuctionExpire (AuctionHouseObject* ah, AuctionEntry* auction) override; void OnBeforeAuctionHouseMgrUpdate() override; }; -#endif /* AUCTION_HOUSE_BOT_AUCTION_HOUSE_SCRIPT_H */ \ No newline at end of file +#endif /* AUCTION_HOUSE_BOT_AUCTION_HOUSE_SCRIPT_H */ diff --git a/src/AuctionHouseBotCommon.h b/src/AuctionHouseBotCommon.h index 1e32cd6..3031485 100644 --- a/src/AuctionHouseBotCommon.h +++ b/src/AuctionHouseBotCommon.h @@ -79,6 +79,7 @@ enum class AHBotCommand : uint32 { buyer, seller, + useMarketPrice, ahexpire, minitems, diff --git a/src/AuctionHouseBotConfig.cpp b/src/AuctionHouseBotConfig.cpp index 66bb447..2bd5836 100644 --- a/src/AuctionHouseBotConfig.cpp +++ b/src/AuctionHouseBotConfig.cpp @@ -508,6 +508,7 @@ void AHBConfig::Reset() BuyMethod = false; SellMethod = false; + SellAtMarketPrice = false; ConsiderOnlyBotAuctions = false; ItemsPerCycle = 200; @@ -591,6 +592,10 @@ void AHBConfig::Reset() PurpleItemsBin.clear(); OrangeItemsBin.clear(); YellowItemsBin.clear(); + + itemsCount.clear(); + itemsSum.clear(); + itemsPrice.clear(); } uint32 AHBConfig::GetAHID() @@ -1945,6 +1950,69 @@ uint32 AHBConfig::GetBidsPerInterval() return buyerBidsPerInterval; } +void AHBConfig::UpdateItemStats(uint32 id, uint32 stackSize, uint64 buyout) +{ + if (!stackSize) + { + return; + } + + // + // Collects information about the item bought + // + + uint32 perUnit = buyout / stackSize; + + if (itemsCount.count(id) == 0) + { + itemsCount[id] = 1; + itemsSum[id] = perUnit; + itemsPrice[id] = perUnit; + } + else + { + itemsCount[id]++; + + // + // Reset the statistics at about every 100 buyout to force adapt to the market price + // This can cause spikes if this auction in particular is unbalanced, but adds + // some movement into the market that can make it an interesting opportunity. + // + + if (itemsCount[id] > 100 + (urand(1, 19) - 10)) + { + itemsCount[id] = 1; + itemsSum[id] = perUnit; + itemsPrice[id] = perUnit; + } + else + { + // + // Here is decided the price for single unit: + // right now is a plain, boring average of the ~100 previous auctions. + // + + itemsSum[id] = (itemsSum[id] + perUnit); + itemsPrice[id] = itemsSum[id] / itemsCount[id]; + } + } + + if (DebugOutConfig) + { + LOG_INFO("module", "Updating market price item={}, price={}", id, itemsPrice[id]); + } +} + +uint64 AHBConfig::GetItemPrice(uint32 id) +{ + if (itemsCount.count(id) != 0) + { + return itemsPrice[id]; + } + + return 0; +} + void AHBConfig::Initialize(std::set botsIds) { InitializeFromFile(); @@ -1971,6 +2039,7 @@ void AHBConfig::InitializeFromFile() AHBBuyer = sConfigMgr->GetOption ("AuctionHouseBot.EnableBuyer" , false); SellMethod = sConfigMgr->GetOption ("AuctionHouseBot.UseBuyPriceForSeller" , false); BuyMethod = sConfigMgr->GetOption ("AuctionHouseBot.UseBuyPriceForBuyer" , false); + SellAtMarketPrice = sConfigMgr->GetOption ("AuctionHouseBot.UseMarketPriceForSeller", false); DuplicatesCount = sConfigMgr->GetOption("AuctionHouseBot.DuplicatesCount" , 0); DivisibleStacks = sConfigMgr->GetOption ("AuctionHouseBot.DivisibleStacks" , false); ElapsingTimeClass = sConfigMgr->GetOption("AuctionHouseBot.DuplicatesCount" , 1); diff --git a/src/AuctionHouseBotConfig.h b/src/AuctionHouseBotConfig.h index 13601c7..9da9cdf 100644 --- a/src/AuctionHouseBotConfig.h +++ b/src/AuctionHouseBotConfig.h @@ -20,6 +20,7 @@ #ifndef AUCTION_HOUSE_BOT_CONFIG_H #define AUCTION_HOUSE_BOT_CONFIG_H +#include #include #include @@ -142,6 +143,14 @@ class AHBConfig uint32 orangeItems; uint32 yellowItems; + // + // Per-item statistics + // + + std::map itemsCount; + std::map itemsSum; + std::map itemsPrice; + void InitializeFromFile(); void InitializeFromSql(std::set botsIds); @@ -173,6 +182,7 @@ class AHBConfig bool AHBBuyer; bool BuyMethod; bool SellMethod; + bool SellAtMarketPrice; bool ConsiderOnlyBotAuctions; uint32 ItemsPerCycle; @@ -343,6 +353,9 @@ class AHBConfig uint32 TotalItemCounts (); uint32 GetItemCounts (uint32 color); + + void UpdateItemStats (uint32 id, uint32 stackSize, uint64 buyout); + uint64 GetItemPrice (uint32 id); }; // diff --git a/src/cs_ah_bot.cpp b/src/cs_ah_bot.cpp index d2941e4..5826d6c 100644 --- a/src/cs_ah_bot.cpp +++ b/src/cs_ah_bot.cpp @@ -35,6 +35,51 @@ using namespace Acore::ChatCommands; class ah_bot_commandscript : public CommandScript { +private: + static ItemQualities stringToItemQualities(const char* name, int length) + { + // + // Translates a string into ItemQualities enum + // + + if (strncmp(name, "grey", length) == 0) + { + return ITEM_QUALITY_POOR; + } + + if (strncmp(name, "white", length) == 0) + { + return ITEM_QUALITY_NORMAL; + } + + if (strncmp(name, "green", length) == 0) + { + return ITEM_QUALITY_UNCOMMON; + } + + if (strncmp(name, "blue", length) == 0) + { + return ITEM_QUALITY_RARE; + } + + if (strncmp(name, "purple", length) == 0) + { + return ITEM_QUALITY_EPIC; + } + + if (strncmp(name, "orange", length) == 0) + { + return ITEM_QUALITY_LEGENDARY; + } + + if (strncmp(name, "yellow", length) == 0) + { + return ITEM_QUALITY_ARTIFACT; + } + + return static_cast(-1); // Invalid + } + public: ah_bot_commandscript() : CommandScript("ah_bot_commandscript") { @@ -64,50 +109,6 @@ class ah_bot_commandscript : public CommandScript return false; } - // - // Support function the item quality - // - - auto qualityStringToEnum = [](const char* qualityName, int maxCount) - { - if (strncmp(qualityName, "grey", maxCount) == 0) - { - return ITEM_QUALITY_POOR; - } - - if (strncmp(qualityName, "white", maxCount) == 0) - { - return ITEM_QUALITY_NORMAL; - } - - if (strncmp(qualityName, "green", maxCount) == 0) - { - return ITEM_QUALITY_UNCOMMON; - } - - if (strncmp(qualityName, "blue", maxCount) == 0) - { - return ITEM_QUALITY_RARE; - } - - if (strncmp(qualityName, "purple", maxCount) == 0) - { - return ITEM_QUALITY_EPIC; - } - - if (strncmp(qualityName, "orange", maxCount) == 0) - { - return ITEM_QUALITY_LEGENDARY; - } - - if (strncmp(qualityName, "yellow", maxCount) == 0) - { - return ITEM_QUALITY_ARTIFACT; - } - - return static_cast(-1); // Invalid - }; - // // Commands which does not requires an AH // @@ -148,6 +149,23 @@ class ah_bot_commandscript : public CommandScript return true; } + else if (strncmp(opt, "usemarketprice", l) == 0) + { + char* param1 = strtok(NULL, " "); + + if (!param1) + { + handler->PSendSysMessage("Syntax is: ahbotoptions useMarketPrice $state (0 off 1 on)"); + return false; + } + + for (AuctionHouseBot* bot : gBots) + { + bot->Commands(AHBotCommand::useMarketPrice, 0, 0, param1); + } + + return true; + } // // Retrieve the auction house type @@ -177,9 +195,7 @@ class ah_bot_commandscript : public CommandScript if (!opt) { - handler->PSendSysMessage("Invalid syntax"); - handler->PSendSysMessage("Try ahbotoptions help to see a list of options."); - + handler->PSendSysMessage("Invalid syntax; the auction house id must be 2, 6 or 7"); return false; } @@ -192,6 +208,7 @@ class ah_bot_commandscript : public CommandScript handler->PSendSysMessage("AHBot commands:"); handler->PSendSysMessage("buyer - enable/disable buyer"); handler->PSendSysMessage("seller - enable/disabler seller"); + handler->PSendSysMessage("usemarketprice - enable/disabler selling at market price"); handler->PSendSysMessage("ahexpire - remove all bot auctions"); handler->PSendSysMessage("minitems - set min auctions"); handler->PSendSysMessage("maxitems - set max auctions"); @@ -230,7 +247,7 @@ class ah_bot_commandscript : public CommandScript return false; } - for (AuctionHouseBot* bot: gBots) + for (AuctionHouseBot* bot : gBots) { bot->Commands(AHBotCommand::minitems, ahMapID, 0, param1); } @@ -277,15 +294,15 @@ class ah_bot_commandscript : public CommandScript return false; } - uint32 greytg = uint32(strtoul(param1, NULL, 0)); - uint32 whitetg = uint32(strtoul(param2, NULL, 0)); - uint32 greentg = uint32(strtoul(param3, NULL, 0)); - uint32 bluetg = uint32(strtoul(param4, NULL, 0)); - uint32 purpletg = uint32(strtoul(param5, NULL, 0)); - uint32 orangetg = uint32(strtoul(param6, NULL, 0)); - uint32 yellowtg = uint32(strtoul(param7, NULL, 0)); - uint32 greyi = uint32(strtoul(param8, NULL, 0)); - uint32 whitei = uint32(strtoul(param9, NULL, 0)); + uint32 greytg = uint32(strtoul(param1 , NULL, 0)); + uint32 whitetg = uint32(strtoul(param2 , NULL, 0)); + uint32 greentg = uint32(strtoul(param3 , NULL, 0)); + uint32 bluetg = uint32(strtoul(param4 , NULL, 0)); + uint32 purpletg = uint32(strtoul(param5 , NULL, 0)); + uint32 orangetg = uint32(strtoul(param6 , NULL, 0)); + uint32 yellowtg = uint32(strtoul(param7 , NULL, 0)); + uint32 greyi = uint32(strtoul(param8 , NULL, 0)); + uint32 whitei = uint32(strtoul(param9 , NULL, 0)); uint32 greeni = uint32(strtoul(param10, NULL, 0)); uint32 bluei = uint32(strtoul(param11, NULL, 0)); uint32 purplei = uint32(strtoul(param12, NULL, 0)); @@ -347,7 +364,7 @@ class ah_bot_commandscript : public CommandScript return false; } - auto quality = qualityStringToEnum(param1, l); + auto quality = stringToItemQualities(param1, l); if (quality != static_cast(-1)) { @@ -373,7 +390,7 @@ class ah_bot_commandscript : public CommandScript return false; } - auto quality = qualityStringToEnum(param1, l); + auto quality = stringToItemQualities(param1, l); if (quality != static_cast(-1)) { @@ -407,7 +424,7 @@ class ah_bot_commandscript : public CommandScript return false; } - auto quality = qualityStringToEnum(param1, l); + auto quality = stringToItemQualities(param1, l); if (quality != static_cast(-1)) { @@ -441,7 +458,7 @@ class ah_bot_commandscript : public CommandScript return false; } - auto quality = qualityStringToEnum(param1, l); + auto quality = stringToItemQualities(param1, l); if (quality != static_cast(-1)) { @@ -474,7 +491,7 @@ class ah_bot_commandscript : public CommandScript // return false; // } - auto quality = qualityStringToEnum(param1, l); + auto quality = stringToItemQualities(param1, l); if (quality != static_cast(-1)) { @@ -500,7 +517,7 @@ class ah_bot_commandscript : public CommandScript return false; } - auto quality = qualityStringToEnum(param1, l); + auto quality = stringToItemQualities(param1, l); if (quality != static_cast(-1)) { From 2a1c672eff0768c4ebdb1b60dc4900d3b11d9552 Mon Sep 17 00:00:00 2001 From: Kewin Rausch Date: Sat, 7 Sep 2024 10:35:43 +0200 Subject: [PATCH 5/7] Threshold for market per-item price reset now implemented as a configurable value --- conf/mod_ahbot.conf.dist | 8 ++++++++ src/AuctionHouseBotConfig.cpp | 8 ++++---- src/AuctionHouseBotConfig.h | 1 + 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/conf/mod_ahbot.conf.dist b/conf/mod_ahbot.conf.dist index f3fbd0b..293b0f0 100644 --- a/conf/mod_ahbot.conf.dist +++ b/conf/mod_ahbot.conf.dist @@ -51,6 +51,13 @@ # Should the Seller use the market price for its auctions? # Default 0 (disabled) # +# AuctionHouseBot.MarketResetThreshold +# How many auctions of the same item are necessary before the plain priceis adopted. +# Before reaching this threshold, the price increase/decrease according to an heuristic. +# Set this variable to a lower value to have a fast reacting market price, +# to an high value to smooth the oscillations in prices. +# Default 25 +# # Auction House Bot character data # AuctionHouseBot.Account is the account number # (in realmd->account table) of the player you want to run @@ -102,6 +109,7 @@ AuctionHouseBot.EnableBuyer = 0 AuctionHouseBot.UseBuyPriceForSeller = 0 AuctionHouseBot.UseBuyPriceForBuyer = 0 AuctionHouseBot.UseMarketPriceForSeller = 0 +AuctionHouseBot.MarketResetThreshold = 25 AuctionHouseBot.Account = 0 AuctionHouseBot.GUID = 0 AuctionHouseBot.ItemsPerCycle = 200 diff --git a/src/AuctionHouseBotConfig.cpp b/src/AuctionHouseBotConfig.cpp index 596d994..0cb742a 100644 --- a/src/AuctionHouseBotConfig.cpp +++ b/src/AuctionHouseBotConfig.cpp @@ -1974,12 +1974,11 @@ void AHBConfig::UpdateItemStats(uint32 id, uint32 stackSize, uint64 buyout) itemsCount[id]++; // - // Reset the statistics at about every 100 buyout to force adapt to the market price - // This can cause spikes if this auction in particular is unbalanced, but adds - // some movement into the market that can make it an interesting opportunity. + // Reset the statistics to force adapt to the market price. + // Adds a little of randomness by adding/removing a range of 9 to the threshold. // - if (itemsCount[id] > 100 + (urand(1, 19) - 10)) + if (itemsCount[id] > MarketResetThreshold + (urand(1, 19) - 10)) { itemsCount[id] = 1; itemsSum[id] = perUnit; @@ -2040,6 +2039,7 @@ void AHBConfig::InitializeFromFile() SellMethod = sConfigMgr->GetOption ("AuctionHouseBot.UseBuyPriceForSeller" , false); BuyMethod = sConfigMgr->GetOption ("AuctionHouseBot.UseBuyPriceForBuyer" , false); SellAtMarketPrice = sConfigMgr->GetOption ("AuctionHouseBot.UseMarketPriceForSeller", false); + MarketResetThreshold = sConfigMgr->GetOption("AuctionHouseBot.MarketResetThreshold" , 25); DuplicatesCount = sConfigMgr->GetOption("AuctionHouseBot.DuplicatesCount" , 0); DivisibleStacks = sConfigMgr->GetOption ("AuctionHouseBot.DivisibleStacks" , false); ElapsingTimeClass = sConfigMgr->GetOption("AuctionHouseBot.DuplicatesCount" , 1); diff --git a/src/AuctionHouseBotConfig.h b/src/AuctionHouseBotConfig.h index 9da9cdf..f649037 100644 --- a/src/AuctionHouseBotConfig.h +++ b/src/AuctionHouseBotConfig.h @@ -183,6 +183,7 @@ class AHBConfig bool BuyMethod; bool SellMethod; bool SellAtMarketPrice; + uint32 MarketResetThreshold; bool ConsiderOnlyBotAuctions; uint32 ItemsPerCycle; From a5d5757dd7b6e094a6aa2e2d2faf52b74bf1949c Mon Sep 17 00:00:00 2001 From: Kewin Rausch Date: Sat, 7 Sep 2024 19:45:05 +0200 Subject: [PATCH 6/7] Adjusted the license on the source files --- src/AuctionHouseBotAuctionHouseScript.cpp | 2 +- src/AuctionHouseBotAuctionHouseScript.h | 2 +- src/AuctionHouseBotCommon.cpp | 4 ++-- src/AuctionHouseBotMailScript.cpp | 2 +- src/AuctionHouseBotMailScript.h | 4 ++-- src/AuctionHouseBotScript.cpp | 2 +- src/AuctionHouseBotWorldScript.cpp | 2 +- src/AuctionHouseBotWorldScript.h | 4 ++-- src/ah_bot_loader.cpp | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/AuctionHouseBotAuctionHouseScript.cpp b/src/AuctionHouseBotAuctionHouseScript.cpp index a7ebdf3..bab478f 100644 --- a/src/AuctionHouseBotAuctionHouseScript.cpp +++ b/src/AuctionHouseBotAuctionHouseScript.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE */ #include "AuctionHouseMgr.h" diff --git a/src/AuctionHouseBotAuctionHouseScript.h b/src/AuctionHouseBotAuctionHouseScript.h index b5380ee..1ff5468 100644 --- a/src/AuctionHouseBotAuctionHouseScript.h +++ b/src/AuctionHouseBotAuctionHouseScript.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE */ #ifndef AUCTION_HOUSE_BOT_AUCTION_HOUSE_SCRIPT_H diff --git a/src/AuctionHouseBotCommon.cpp b/src/AuctionHouseBotCommon.cpp index e71507e..640c775 100644 --- a/src/AuctionHouseBotCommon.cpp +++ b/src/AuctionHouseBotCommon.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE */ #include "AuctionHouseBot.h" @@ -19,4 +19,4 @@ AHBConfig* gNeutralConfig = new AHBConfig(7); // std::set gBotsId; -std::set gBots; \ No newline at end of file +std::set gBots; diff --git a/src/AuctionHouseBotMailScript.cpp b/src/AuctionHouseBotMailScript.cpp index c636943..56cbb9c 100644 --- a/src/AuctionHouseBotMailScript.cpp +++ b/src/AuctionHouseBotMailScript.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE */ #include "AuctionHouseBot.h" diff --git a/src/AuctionHouseBotMailScript.h b/src/AuctionHouseBotMailScript.h index dbd0b8d..bc90694 100644 --- a/src/AuctionHouseBotMailScript.h +++ b/src/AuctionHouseBotMailScript.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE */ #ifndef AUCTION_HOUSE_BOT_MAIL_SCRIPT_H @@ -20,4 +20,4 @@ class AHBot_MailScript : public MailScript void OnBeforeMailDraftSendMailTo(MailDraft* mailDraft, MailReceiver const& receiver, MailSender const& sender, MailCheckMask& checked, uint32& deliver_delay, uint32& custom_expiration, bool& deleteMailItemsFromDB, bool& sendMail) override; }; -#endif /* AUCTION_HOUSE_BOT_MAIL_SCRIPT_H */ \ No newline at end of file +#endif /* AUCTION_HOUSE_BOT_MAIL_SCRIPT_H */ diff --git a/src/AuctionHouseBotScript.cpp b/src/AuctionHouseBotScript.cpp index bf05c54..46bcbea 100644 --- a/src/AuctionHouseBotScript.cpp +++ b/src/AuctionHouseBotScript.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE */ #include "AuctionHouseBot.h" diff --git a/src/AuctionHouseBotWorldScript.cpp b/src/AuctionHouseBotWorldScript.cpp index bb49361..2a36e17 100644 --- a/src/AuctionHouseBotWorldScript.cpp +++ b/src/AuctionHouseBotWorldScript.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE */ #include "Config.h" diff --git a/src/AuctionHouseBotWorldScript.h b/src/AuctionHouseBotWorldScript.h index 7634c10..069b049 100644 --- a/src/AuctionHouseBotWorldScript.h +++ b/src/AuctionHouseBotWorldScript.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE */ #ifndef AUCTION_HOUSE_BOT_WORLD_SCRIPT_H @@ -24,4 +24,4 @@ class AHBot_WorldScript : public WorldScript void OnStartup() override; }; -#endif /* AUCTION_HOUSE_BOT_WORLD_SCRIPT_H */ \ No newline at end of file +#endif /* AUCTION_HOUSE_BOT_WORLD_SCRIPT_H */ diff --git a/src/ah_bot_loader.cpp b/src/ah_bot_loader.cpp index 1344243..08c40df 100644 --- a/src/ah_bot_loader.cpp +++ b/src/ah_bot_loader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 + * Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE * Copyright (C) 2021+ WarheadCore */ From b7c6352bbc09ff71e168228c65dad76d055bc895 Mon Sep 17 00:00:00 2001 From: Kewin Rausch Date: Sat, 14 Sep 2024 08:52:43 +0200 Subject: [PATCH 7/7] Change in item selection for the selling operations; instead of using a random pickup, which can always result in bad rolls and waste of cycles, the selling priority now follows the items rarity. First the bot will try to fill up poor items, and then when quotas are reached it will move to more rare ones --- src/AuctionHouseBot.cpp | 674 +++++++++++++++++----------------------- src/AuctionHouseBot.h | 7 +- 2 files changed, 284 insertions(+), 397 deletions(-) diff --git a/src/AuctionHouseBot.cpp b/src/AuctionHouseBot.cpp index dc14815..e74d674 100644 --- a/src/AuctionHouseBot.cpp +++ b/src/AuctionHouseBot.cpp @@ -49,11 +49,34 @@ AuctionHouseBot::~AuctionHouseBot() // Nothing } -uint32 AuctionHouseBot::getElement(std::set set, int index) +uint32 AuctionHouseBot::getElement(std::set set, int index, uint32 botId, uint32 maxDup, AuctionHouseObject* auctionHouse) { std::set::iterator it = set.begin(); std::advance(it, index); + if (maxDup > 0) + { + uint32 noStacks = 0; + + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin(); itr != auctionHouse->GetAuctionsEnd(); ++itr) + { + AuctionEntry* Aentry = itr->second; + + if (Aentry->owner.GetCounter() == botId) + { + if (*it == Aentry->item_template) + { + noStacks++; + } + } + } + + if (noStacks >= maxDup) + { + return 0; + } + } + return *it; } @@ -623,501 +646,366 @@ void AuctionHouseBot::Sell(Player* AHBplayer, AHBConfig* config) uint32 yellowItems = config->GetItemCounts(AHB_YELLOW_I); // - // Only insert a few at a time, so they dont appear all at once + // Loop variables // - uint32 noSold = 0; // Tracing counter - uint32 binEmpty = 0; // Tracing counter - uint32 noNeed = 0; // Tracing counter - uint32 tooMany = 0; // Tracing counter - uint32 loopBrk = 0; // Tracing counter - uint32 err = 0; // Tracing counter + uint32 noSold = 0; // Tracing counter + uint32 binEmpty = 0; // Tracing counter + uint32 noNeed = 0; // Tracing counter + uint32 tooMany = 0; // Tracing counter + uint32 loopBrk = 0; // Tracing counter + uint32 err = 0; // Tracing counter for (uint32 cnt = 1; cnt <= items; cnt++) { + uint32 choice = 0; uint32 itemID = 0; uint32 loopbreaker = 0; - // - // Attempts for some times to insert a single item stack as an auction. - // The attempt can be stopped by several internal checks. + // + // Select, in rarity order, a new random item // - while (itemID == 0 && loopbreaker <= 32) + while (itemID == 0 && loopbreaker <= AUCTION_HOUSE_BOT_LOOP_BREAKER) { - ++loopbreaker; + loopbreaker++; - // - // Get a random item from the bins - // + // Poor - uint32 choice = urand(0, 13); - - switch (choice) + if ((config->GreyItemsBin.size() > 0) && (greyItems < greyIcount)) { - case AHB_GREY_I: - if ((config->GreyItemsBin.size() > 0) && (greyItems < greyIcount)) - { - itemID = getElement(config->GreyItemsBin, urand(0, config->GreyItemsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } - - break; - - case AHB_WHITE_I: - if ((config->WhiteItemsBin.size() > 0) && (whiteItems < whiteIcount)) - { - itemID = getElement(config->WhiteItemsBin, urand(0, config->WhiteItemsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } - - break; - - case AHB_GREEN_I: - if ((config->GreenItemsBin.size() > 0) && (greenItems < greenIcount)) - { - itemID = getElement(config->GreenItemsBin, urand(0, config->GreenItemsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } - - break; - - case AHB_BLUE_I: - if ((config->BlueItemsBin.size() > 0) && (blueItems < blueIcount)) - { - itemID = getElement(config->BlueItemsBin, urand(0, config->BlueItemsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } - - break; - - case AHB_PURPLE_I: - if ((config->PurpleItemsBin.size() > 0) && (purpleItems < purpleIcount)) - { - itemID = getElement(config->PurpleItemsBin, urand(0, config->PurpleItemsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } - - break; - - case AHB_ORANGE_I: - if ((config->OrangeItemsBin.size() > 0) && (orangeItems < orangeIcount)) - { - itemID = getElement(config->OrangeItemsBin, urand(0, config->OrangeItemsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } - - break; - - case AHB_YELLOW_I: - if ((config->YellowItemsBin.size() > 0) && (yellowItems < yellowIcount)) - { - itemID = getElement(config->YellowItemsBin, urand(0, config->YellowItemsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } - - break; - - case AHB_GREY_TG: - if ((config->GreyTradeGoodsBin.size() > 0) && (greyTGoods < greyTGcount)) - { - itemID = getElement(config->GreyTradeGoodsBin, urand(0, config->GreyTradeGoodsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } - - break; - - case AHB_WHITE_TG: - if ((config->WhiteTradeGoodsBin.size() > 0) && (whiteTGoods < whiteTGcount)) - { - itemID = getElement(config->WhiteTradeGoodsBin, urand(0, config->WhiteTradeGoodsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } - - break; - - case AHB_GREEN_TG: - if ((config->GreenTradeGoodsBin.size() > 0) && (greenTGoods < greenTGcount)) - { - itemID = getElement(config->GreenTradeGoodsBin, urand(0, config->GreenTradeGoodsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } - - break; + choice = 0; + itemID = getElement(config->GreyItemsBin, urand(0, config->GreyItemsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); + } - case AHB_BLUE_TG: - if ((config->BlueTradeGoodsBin.size() > 0) && (blueTGoods < blueTGcount)) - { - itemID = getElement(config->BlueTradeGoodsBin, urand(0, config->BlueTradeGoodsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } + if (itemID == 0 && (config->GreyTradeGoodsBin.size() > 0) && (greyTGoods < greyTGcount)) + { + choice = 7; + itemID = getElement(config->GreyTradeGoodsBin, urand(0, config->GreyTradeGoodsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); + } - break; + // Normal - case AHB_PURPLE_TG: - if ((config->PurpleTradeGoodsBin.size() > 0) && (purpleTGoods < purpleTGcount)) - { - itemID = getElement(config->PurpleTradeGoodsBin, urand(0, config->PurpleTradeGoodsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } - - break; + if (itemID == 0 && (config->WhiteItemsBin.size() > 0) && (whiteItems < whiteIcount)) + { + choice = 1; + itemID = getElement(config->WhiteItemsBin, urand(0, config->WhiteItemsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); + } - case AHB_ORANGE_TG: - if ((config->OrangeTradeGoodsBin.size() > 0) && (orangeTGoods < orangeTGcount)) - { - itemID = getElement(config->OrangeTradeGoodsBin, urand(0, config->OrangeTradeGoodsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } + if (itemID == 0 && (config->WhiteTradeGoodsBin.size() > 0) && (whiteTGoods < whiteTGcount)) + { + choice = 8; + itemID = getElement(config->WhiteTradeGoodsBin, urand(0, config->WhiteTradeGoodsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); + } - break; + // Uncommon - case AHB_YELLOW_TG: - if ((config->YellowTradeGoodsBin.size() > 0) && (yellowTGoods < yellowTGcount)) - { - itemID = getElement(config->YellowTradeGoodsBin, urand(0, config->YellowTradeGoodsBin.size() - 1)); - } - else - { - noNeed++; - continue; - } + if (itemID == 0 && (config->GreenItemsBin.size() > 0) && (greenItems < greenIcount)) + { + choice = 2; + itemID = getElement(config->GreenItemsBin, urand(0, config->GreenItemsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); + } - break; + if (itemID == 0 && (config->GreenTradeGoodsBin.size() > 0) && (greenTGoods < greenTGcount)) + { + choice = 9; + itemID = getElement(config->GreenTradeGoodsBin, urand(0, config->GreenTradeGoodsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); + } - default: - err++; + // Rare - if (config->DebugOutSeller) - { - LOG_ERROR("module", "AHBot [{}]: itemID Switch - Default Reached", _id); - } + if (itemID == 0 && (config->BlueItemsBin.size() > 0) && (blueItems < blueIcount)) + { + choice = 3; + itemID = getElement(config->BlueItemsBin, urand(0, config->BlueItemsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); + } - break; + if (itemID == 0 && (config->BlueTradeGoodsBin.size() > 0) && (blueTGoods < blueTGcount)) + { + choice = 10; + itemID = getElement(config->BlueTradeGoodsBin, urand(0, config->BlueTradeGoodsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); } - // - // Check if it's a valid selection - // + // Epic - if (itemID == 0) + if (itemID == 0 && (config->PurpleItemsBin.size() > 0) && (purpleItems < purpleIcount)) { - binEmpty++; - - if (config->DebugOutSeller) - { - LOG_ERROR("module", "AHBot [{}]: No item could be selected in the bin {}", _id, choice); - } + choice = 4; + itemID = getElement(config->PurpleItemsBin, urand(0, config->PurpleItemsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); + } - continue; + if (itemID == 0 && (config->PurpleTradeGoodsBin.size() > 0) && (purpleTGoods < purpleTGcount)) + { + choice = 11; + itemID = getElement(config->PurpleTradeGoodsBin, urand(0, config->PurpleTradeGoodsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); } - // - // Check how many stacks of this items are sold by the bot. - // This avoid unfortunate rolls to overwhelm the market with the same products on low population, especially with whitelists. - // + // Legendary - if (config->DuplicatesCount > 0) + if (itemID == 0 && (config->OrangeItemsBin.size() > 0) && (orangeItems < orangeIcount)) { - uint32 noStacks = 0; - - for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin(); itr != auctionHouse->GetAuctionsEnd(); ++itr) - { - AuctionEntry* Aentry = itr->second; - - if (AHBplayer->GetGUID() == Aentry->owner) - { - if (itemID == Aentry->item_template) - { - noStacks++; - } - } - } + choice = 5; + itemID = getElement(config->OrangeItemsBin, urand(0, config->OrangeItemsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); + } - if (noStacks >= config->DuplicatesCount) - { - tooMany++; - continue; - } + if (itemID == 0 && (config->OrangeTradeGoodsBin.size() > 0) && (orangeTGoods < orangeTGcount)) + { + choice = 12; + itemID = getElement(config->OrangeTradeGoodsBin, urand(0, config->OrangeTradeGoodsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); } - // - // Retrieve information about the selected item - // + // Artifact - ItemTemplate const* prototype = sObjectMgr->GetItemTemplate(itemID); + if (itemID == 0 && (config->YellowItemsBin.size() > 0) && (yellowItems < yellowIcount)) + { + choice = 6; + itemID = getElement(config->YellowItemsBin, urand(0, config->YellowItemsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); + } - if (prototype == NULL) + if (itemID == 0 && (config->YellowTradeGoodsBin.size() > 0) && (yellowTGoods < yellowTGcount)) { - err++; + choice = 13; + itemID = getElement(config->YellowTradeGoodsBin, urand(0, config->YellowTradeGoodsBin.size() - 1), _id, config->DuplicatesCount, auctionHouse); + } + if (itemID == 0) + { + binEmpty++; + if (config->DebugOutSeller) { - LOG_ERROR("module", "AHBot [{}]: could not get prototype of item {}", _id, itemID); + LOG_ERROR("module", "AHBot [{}]: No item could be selected from the bins", _id); } - - continue; + + break; } + } - Item* item = Item::CreateItem(itemID, 1, AHBplayer); + if (itemID == 0 || loopbreaker > AUCTION_HOUSE_BOT_LOOP_BREAKER) + { + loopBrk++; + continue; + } - if (item == NULL) - { - err++; + // + // Retrieve information about the selected item + // - if (config->DebugOutSeller) - { - LOG_ERROR("module", "AHBot [{}]: could not create item from prototype {}", _id, itemID); - } + ItemTemplate const* prototype = sObjectMgr->GetItemTemplate(itemID); - break; + if (prototype == NULL) + { + err++; + + if (config->DebugOutSeller) + { + LOG_ERROR("module", "AHBot [{}]: could not get prototype of item {}", _id, itemID); } - // - // Start interacting with the item by adding a random property - // + continue; + } - item->AddToUpdateQueueOf(AHBplayer); + Item* item = Item::CreateItem(itemID, 1, AHBplayer); - uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemID); + if (item == NULL) + { + err++; - if (randomPropertyId != 0) + if (config->DebugOutSeller) { - item->SetItemRandomProperties(randomPropertyId); + LOG_ERROR("module", "AHBot [{}]: could not create item from prototype {}", _id, itemID); } - if (prototype->Quality > AHB_MAX_QUALITY) - { - err++; + continue; + } - if (config->DebugOutSeller) - { - LOG_ERROR("module", "AHBot [{}]: Quality {} TOO HIGH for item {}", _id, prototype->Quality, itemID); - } + // + // Start interacting with the item by adding a random property + // - item->RemoveFromUpdateQueueOf(AHBplayer); - continue; - } + item->AddToUpdateQueueOf(AHBplayer); - // - // Determine the price - // + uint32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemID); - uint64 buyoutPrice = 0; - uint64 bidPrice = 0; - uint32 stackCount = 1; + if (randomPropertyId != 0) + { + item->SetItemRandomProperties(randomPropertyId); + } - if (config->SellAtMarketPrice) - { - buyoutPrice = config->GetItemPrice(itemID); - } + if (prototype->Quality > AHB_MAX_QUALITY) + { + err++; - if (buyoutPrice == 0) + if (config->DebugOutSeller) { - if (config->SellMethod) - { - buyoutPrice = prototype->BuyPrice; - } - else - { - buyoutPrice = prototype->SellPrice; - } + LOG_ERROR("module", "AHBot [{}]: Quality {} TOO HIGH for item {}", _id, prototype->Quality, itemID); } - buyoutPrice = buyoutPrice * urand(config->GetMinPrice(prototype->Quality), config->GetMaxPrice(prototype->Quality)); - buyoutPrice = buyoutPrice / 100; + item->RemoveFromUpdateQueueOf(AHBplayer); + continue; + } - bidPrice = buyoutPrice * urand(config->GetMinBidPrice(prototype->Quality), config->GetMaxBidPrice(prototype->Quality)); - bidPrice = bidPrice / 100; + // + // Determine the price + // - // - // Determine the stack size - // + uint64 buyoutPrice = 0; + uint64 bidPrice = 0; + uint32 stackCount = 1; - if (config->GetMaxStack(prototype->Quality) > 1 && item->GetMaxStackCount() > 1) - { - stackCount = minValue(getStackCount(config, item->GetMaxStackCount()), config->GetMaxStack(prototype->Quality)); - } - else if (config->GetMaxStack(prototype->Quality) == 0 && item->GetMaxStackCount() > 1) + if (config->SellAtMarketPrice) + { + buyoutPrice = config->GetItemPrice(itemID); + } + + if (buyoutPrice == 0) + { + if (config->SellMethod) { - stackCount = getStackCount(config, item->GetMaxStackCount()); + buyoutPrice = prototype->BuyPrice; } else { - stackCount = 1; + buyoutPrice = prototype->SellPrice; } + } - item->SetCount(stackCount); + buyoutPrice = buyoutPrice * urand(config->GetMinPrice(prototype->Quality), config->GetMaxPrice(prototype->Quality)); + buyoutPrice = buyoutPrice / 100; - // - // Determine the auction time - // + bidPrice = buyoutPrice * urand(config->GetMinBidPrice(prototype->Quality), config->GetMaxBidPrice(prototype->Quality)); + bidPrice = bidPrice / 100; - uint32 etime = getElapsedTime(config->ElapsingTimeClass); + // + // Determine the stack size + // - // - // Determine the deposit - // + if (config->GetMaxStack(prototype->Quality) > 1 && item->GetMaxStackCount() > 1) + { + stackCount = minValue(getStackCount(config, item->GetMaxStackCount()), config->GetMaxStack(prototype->Quality)); + } + else if (config->GetMaxStack(prototype->Quality) == 0 && item->GetMaxStackCount() > 1) + { + stackCount = getStackCount(config, item->GetMaxStackCount()); + } + else + { + stackCount = 1; + } - uint32 dep = sAuctionMgr->GetAuctionDeposit(ahEntry, etime, item, stackCount); + item->SetCount(stackCount); - // - // Perform the auction - // + // + // Determine the auction time + // - auto trans = CharacterDatabase.BeginTransaction(); + uint32 etime = getElapsedTime(config->ElapsingTimeClass); - AuctionEntry* auctionEntry = new AuctionEntry(); - auctionEntry->Id = sObjectMgr->GenerateAuctionID(); - auctionEntry->houseId = config->GetAHID(); - auctionEntry->item_guid = item->GetGUID(); - auctionEntry->item_template = item->GetEntry(); - auctionEntry->itemCount = item->GetCount(); - auctionEntry->owner = AHBplayer->GetGUID(); - auctionEntry->startbid = bidPrice * stackCount; - auctionEntry->buyout = buyoutPrice * stackCount; - auctionEntry->bid = 0; - auctionEntry->deposit = dep; - auctionEntry->expire_time = (time_t)etime + time(NULL); - auctionEntry->auctionHouseEntry = ahEntry; - - item->SaveToDB(trans); - item->RemoveFromUpdateQueueOf(AHBplayer); - sAuctionMgr->AddAItem(item); - auctionHouse->AddAuction(auctionEntry); - auctionEntry->SaveToDB(trans); + // + // Determine the deposit + // - CharacterDatabase.CommitTransaction(trans); + uint32 dep = sAuctionMgr->GetAuctionDeposit(ahEntry, etime, item, stackCount); - // - // Increments the number of items presents in the auction - // + // + // Perform the auction + // - switch (choice) - { - case 0: - ++greyItems; - break; + auto trans = CharacterDatabase.BeginTransaction(); + + AuctionEntry* auctionEntry = new AuctionEntry(); + auctionEntry->Id = sObjectMgr->GenerateAuctionID(); + auctionEntry->houseId = config->GetAHID(); + auctionEntry->item_guid = item->GetGUID(); + auctionEntry->item_template = item->GetEntry(); + auctionEntry->itemCount = item->GetCount(); + auctionEntry->owner = AHBplayer->GetGUID(); + auctionEntry->startbid = bidPrice * stackCount; + auctionEntry->buyout = buyoutPrice * stackCount; + auctionEntry->bid = 0; + auctionEntry->deposit = dep; + auctionEntry->expire_time = (time_t)etime + time(NULL); + auctionEntry->auctionHouseEntry = ahEntry; + + item->SaveToDB(trans); + item->RemoveFromUpdateQueueOf(AHBplayer); + sAuctionMgr->AddAItem(item); + auctionHouse->AddAuction(auctionEntry); + auctionEntry->SaveToDB(trans); + + CharacterDatabase.CommitTransaction(trans); - case 1: - ++whiteItems; - break; + // + // Increments the number of items presents in the auction + // - case 2: - ++greenItems; - break; + switch (choice) + { + case 0: + ++greyItems; + break; - case 3: - ++blueItems; - break; + case 1: + ++whiteItems; + break; - case 4: - ++purpleItems; - break; + case 2: + ++greenItems; + break; - case 5: - ++orangeItems; - break; + case 3: + ++blueItems; + break; - case 6: - ++yellowItems; - break; + case 4: + ++purpleItems; + break; - case 7: - ++greyTGoods; - break; + case 5: + ++orangeItems; + break; - case 8: - ++whiteTGoods; - break; + case 6: + ++yellowItems; + break; - case 9: - ++greenTGoods; - break; + case 7: + ++greyTGoods; + break; - case 10: - ++blueTGoods; - break; + case 8: + ++whiteTGoods; + break; - case 11: - ++purpleTGoods; - break; + case 9: + ++greenTGoods; + break; - case 12: - ++orangeTGoods; - break; + case 10: + ++blueTGoods; + break; - case 13: - ++yellowTGoods; - break; + case 11: + ++purpleTGoods; + break; - default: - break; - } + case 12: + ++orangeTGoods; + break; - noSold++; + case 13: + ++yellowTGoods; + break; - if (config->TraceSeller) - { - LOG_INFO("module", "AHBot [{}]: New stack ah={}, id={}, stack={}, bid={}, buyout={}", _id, config->GetAHID(), itemID, stackCount, auctionEntry->startbid, auctionEntry->buyout); - } + default: + break; } - if (itemID == 0 || loopbreaker > 50) + noSold++; + + if (config->TraceSeller) { - loopBrk++; + LOG_INFO("module", "AHBot [{}]: New stack ah={}, id={}, stack={}, bid={}, buyout={}", _id, config->GetAHID(), itemID, stackCount, auctionEntry->startbid, auctionEntry->buyout); } } diff --git a/src/AuctionHouseBot.h b/src/AuctionHouseBot.h index 9f6b38d..fffbe1d 100644 --- a/src/AuctionHouseBot.h +++ b/src/AuctionHouseBot.h @@ -31,6 +31,8 @@ struct AuctionEntry; class Player; class WorldSession; +#define AUCTION_HOUSE_BOT_LOOP_BREAKER 32 + class AuctionHouseBot { private: @@ -61,7 +63,7 @@ class AuctionHouseBot uint32 getNofAuctions(AHBConfig* config, AuctionHouseObject* auctionHouse, ObjectGuid guid); uint32 getStackCount(AHBConfig* config, uint32 max); uint32 getElapsedTime(uint32 timeClass); - uint32 getElement(std::set set, int index); + uint32 getElement(std::set set, int index, uint32 botId, uint32 maxDup, AuctionHouseObject* auctionHouse); public: AuctionHouseBot(uint32 account, uint32 id); @@ -70,9 +72,6 @@ class AuctionHouseBot void Initialize(AHBConfig* allianceConfig, AHBConfig* hordeConfig, AHBConfig* neutralConfig); void Update(); - void DecrementItemCounts(AuctionEntry* ah); - void IncrementItemCounts(AuctionEntry* ah); - void Commands(AHBotCommand command, uint32 ahMapID, uint32 col, char* args); ObjectGuid::LowType GetAHBplayerGUID() { return _id; };