diff --git a/README.md b/README.md
index 7e0c981..4c8bf93 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,18 @@ Notes:
- Important! By default, most player crafted items (except glyphs, bolts, maybe a few other things) are disabled from showing up in the auction house in order to encourage player crafting on lower pop servers. If you want different behavior, alter the config variable "AuctionHouseBot.DisabledCraftedItemIDs" by deleting IDs you wish to show up. Note that fish are also disabled to encourage fishing, and that's also managed by disabled lists.
- It takes a few hours for the auction house to fully populate, as only 75 items gets added by default every 'tick'. You can change this in the config with the AuctionHouseBot.ItemsPerCycle variable.
- All price multpliers (along with the advanced pricing, see config) are applied multiplicative. Example: A Category of 1.5x, Quality of 2x, and CategoryQuality of 1.4x would make the multiplier 4.2 (1.5 x 2 x 1.4). The advanced pricing would then multiply that value further. Using item level price multpliers, which create a multiplier of itemlevel x value, is also multiplicitive along with the others. You cannot use item level price multipliers and advanced pricing, as advanced pricing will take priority between the two.
-- Bot-listed prices will not exceed 100k gold buyout
+- Bot-listed prices will not exceed 100k gold buyout
+
+### In-Game Commands
+
+The AuctionHouseBot module adds the following in-game commands (for GMs only):
+
+| Command | Description |
+|----------|--------------|
+| `.ahbot reload` | Reloads the AuctionHouseBot configuration file and updates settings. |
+| `.ahbot empty` | Removes all AuctionHouseBot auctions from all auction houses.
Player auctions are unaffected. Bids on affected items are returned to players.
Use with caution! |
+| `.ahbot update` | Forces the bot to refresh or repopulate auction listings immediately.
Note: If you have multiple minutes configured between Buy/Sell cycles, you may have to run this additional times before you see results. |
+
## Buying Bot Behavior
diff --git a/conf/mod_ahbot.conf.dist b/conf/mod_ahbot.conf.dist
index 591f820..be9fd08 100644
--- a/conf/mod_ahbot.conf.dist
+++ b/conf/mod_ahbot.conf.dist
@@ -1,5 +1,14 @@
[worldserver]
+###################################################################################################
+# AUCTION HOUSE BOT IN-GAME COMMANDS
+#
+# Available GM commands:
+# .ahbot reload - Reloads AuctionHouseBot configuration
+# .ahbot empty - Clears all AuctionHouseBot auctions from all auction houses
+# .ahbot update - Forces an immediate update cycle
+###################################################################################################
+
###############################################################################
# AUCTION HOUSE BOT SETTINGS
# AuctionHouseBot.DEBUG
diff --git a/src/AuctionHouseBot.cpp b/src/AuctionHouseBot.cpp
index dceef71..83c2f8c 100644
--- a/src/AuctionHouseBot.cpp
+++ b/src/AuctionHouseBot.cpp
@@ -1584,6 +1584,70 @@ void AuctionHouseBot::InitializeConfiguration()
NeutralConfig.SetMaxItems(sConfigMgr->GetOption("AuctionHouseBot.Neutral.MaxItems", 15000));
}
+void AuctionHouseBot::EmptyAuctionHouses()
+{
+ struct AuctionInfo {
+ uint32 itemID {0};
+ uint32 characterGUID {0};
+ uint32 houseID {0};
+ };
+ vector ahBotActiveAuctions;
+ auto trans = CharacterDatabase.BeginTransaction();
+
+ // Get all auctions owned by AHBots
+ std::string queryString = "SELECT id, buyguid, houseid FROM auctionhouse WHERE itemowner IN ({})";
+ QueryResult result = CharacterDatabase.Query(queryString, AHCharactersGUIDsForQuery);
+ if (!result)
+ return;
+
+ if (result->GetRowCount() > 0)
+ {
+ // Load results into vector for lookups later
+ do
+ {
+ Field* fields = result->Fetch();
+ AuctionInfo ai = {
+ fields[0].Get(),
+ fields[1].Get(),
+ fields[2].Get()
+ };
+ ahBotActiveAuctions.push_back(ai);
+ } while (result->NextRow());
+
+ // For each auction, refund bidder where possible, delete entry from AH
+ AuctionHouseObject* auctionHouse;
+ for (auto iter = ahBotActiveAuctions.begin(); iter != ahBotActiveAuctions.end(); ++iter)
+ {
+ AuctionInfo& ai = *iter;
+
+ // Get Auction House and Auction references
+ auctionHouse = nullptr;
+ switch (ai.houseID) {
+ case 2: auctionHouse = sAuctionMgr->GetAuctionsMap(AllianceConfig.GetAHFID()); break;
+ case 6: auctionHouse = sAuctionMgr->GetAuctionsMap(HordeConfig.GetAHFID()); break;
+ case 7: auctionHouse = sAuctionMgr->GetAuctionsMap(NeutralConfig.GetAHFID()); break;
+ }
+ if (auctionHouse == nullptr)
+ continue;
+
+ AuctionEntry* auction = auctionHouse->GetAuction(ai.itemID);
+ if (!auction)
+ continue;
+
+ // If auction has a bidder, refund that character
+ if (ai.characterGUID != 0)
+ sAuctionMgr->SendAuctionCancelledToBidderMail(auction, trans);
+
+ // Remove item from AH
+ auction->DeleteFromDB(trans);
+ sAuctionMgr->RemoveAItem(auction->item_guid);
+ auctionHouse->RemoveAuction(auction);
+ }
+ }
+
+ CharacterDatabase.CommitTransaction(trans);
+}
+
uint32 AuctionHouseBot::GetRandomStackValue(std::string configKeyString, uint32 defaultValue)
{
uint32 stackValue = sConfigMgr->GetOption(configKeyString, defaultValue);
diff --git a/src/AuctionHouseBot.h b/src/AuctionHouseBot.h
index bd4d2fa..f5d6569 100644
--- a/src/AuctionHouseBot.h
+++ b/src/AuctionHouseBot.h
@@ -298,6 +298,7 @@ public:
void Update();
void InitializeConfiguration();
+ void EmptyAuctionHouses();
uint32 GetRandomStackValue(std::string configKeyString, uint32 defaultValue);
uint32 GetRandomStackIncrementValue(std::string configKeyString, uint32 defaultValue);
void SetCyclesBetweenBuyOrSell();
diff --git a/src/AuctionHouseBotScript.cpp b/src/AuctionHouseBotScript.cpp
index 1abe11c..02297f7 100644
--- a/src/AuctionHouseBotScript.cpp
+++ b/src/AuctionHouseBotScript.cpp
@@ -2,6 +2,7 @@
* Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
*/
+#include "Chat.h"
#include "ScriptMgr.h"
#include "AuctionHouseBot.h"
#include "Log.h"
@@ -118,9 +119,69 @@ public:
}
};
+class AHBot_CommandScript : public CommandScript
+{
+public:
+ AHBot_CommandScript() : CommandScript("AHBot_CommandScript") { }
+
+ Acore::ChatCommands::ChatCommandTable GetCommands() const override
+ {
+ static Acore::ChatCommands::ChatCommandTable AHBotCommandTable = {
+ {"update", HandleAHBotUpdateCommand, SEC_GAMEMASTER, Acore::ChatCommands::Console::Yes},
+ {"reload", HandleAHBotReloadCommand, SEC_GAMEMASTER, Acore::ChatCommands::Console::Yes},
+ {"empty", HandleAHBotEmptyCommand, SEC_GAMEMASTER, Acore::ChatCommands::Console::Yes},
+ {"help", HandleAHBotHelpCommand, SEC_GAMEMASTER, Acore::ChatCommands::Console::Yes}
+ };
+
+ static Acore::ChatCommands::ChatCommandTable commandTable = {
+ {"ahbot", AHBotCommandTable},
+ };
+
+ return commandTable;
+ }
+
+ static bool HandleAHBotUpdateCommand(ChatHandler* handler, const char* /*args*/)
+ {
+ LOG_INFO("module", "AuctionHouseBot: Updating Auction House...");
+ handler->PSendSysMessage("AuctionHouseBot: Updating Auction House...");
+ AuctionHouseBot::instance()->Update();
+ return true;
+ }
+
+ static bool HandleAHBotReloadCommand(ChatHandler* handler, char const* /*args*/)
+ {
+ LOG_INFO("module", "AuctionHouseBot: Reloading Config...");
+ handler->PSendSysMessage("AuctionHouseBot: Reloading Config...");
+
+ // Reload config file with isReload = true
+ sConfigMgr->LoadModulesConfigs(true, false);
+ AuctionHouseBot::instance()->InitializeConfiguration();
+ AuctionHouseBot::instance()->PopulateItemCandidatesAndProportions();
+ return true;
+ }
+
+ static bool HandleAHBotEmptyCommand(ChatHandler* handler, char const* /*args*/)
+ {
+ LOG_INFO("module", "AuctionHouseBot: Emptying Auction House...");
+ handler->PSendSysMessage("AuctionHouseBot: Emptying Auction House...");
+ AuctionHouseBot::instance()->EmptyAuctionHouses();
+ return true;
+ }
+
+ static bool HandleAHBotHelpCommand(ChatHandler* handler, char const* /*args*/)
+ {
+ handler->PSendSysMessage("AuctionHouseBot commands:");
+ handler->PSendSysMessage(" .ahbot reload - Reloads configuration");
+ handler->PSendSysMessage(" .ahbot empty - Removes all AuctionHouseBot auctions");
+ handler->PSendSysMessage(" .ahbot update - Runs an update cycle");
+ return true;
+ }
+};
+
void AddAHBotScripts()
{
new AHBot_WorldScript();
new AHBot_AuctionHouseScript();
new AHBot_MailScript();
+ new AHBot_CommandScript();
}