mirror of
https://github.com/araxiaonline/TrinityCore.git
synced 2026-06-13 03:32:28 -04:00
feat(ahbot): Add item level scaling for AH equipment
- Add 5 new config options for item level scaling: - AuctionHouseBot.Items.Scaling.Enabled (default: 0) - AuctionHouseBot.Items.Scaling.MinItemLevel (default: 200) - AuctionHouseBot.Items.Scaling.MaxItemLevel (default: 500) - AuctionHouseBot.Items.Scaling.Chance (default: 75) - AuctionHouseBot.Items.Scaling.EquipmentOnly (default: 1) - Implement scaling logic in AuctionHouseBotSeller::AddNewAuctions() - Uses ItemBonusMgr::GetItemBonusListForItemLevelDelta() for scaling - Random target ilvl within configured range - Respects chance and equipment-only filters - Update SetPricesOfItem() to use scaled item level for pricing - 2% price increase per item level gained - Add .ahbot stats [equipment] GM command for item level analysis - Shows distribution, avg/min/max ilvl, scaling config status - Add MCP console_command support for ahbot commands - ahbot status, rebuild, reload, stats Tested: Avg equipment ilvl increased from ~35 to 367.9 with default config
This commit is contained in:
@@ -25,7 +25,11 @@
|
||||
#include "DatabaseEnv.h"
|
||||
#include "GameTime.h"
|
||||
#include "DB2Stores.h"
|
||||
#include "AuctionHouseBot.h"
|
||||
#include "AuctionHouseMgr.h"
|
||||
#include "Item.h"
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
|
||||
namespace Araxia
|
||||
{
|
||||
@@ -440,6 +444,168 @@ void RegisterSpawnTools()
|
||||
};
|
||||
}
|
||||
}
|
||||
// AHBot commands - useful for managing auction house bot without a player
|
||||
// These mirror the .ahbot GM commands but work from MCP console
|
||||
else if (cmd == "ahbot")
|
||||
{
|
||||
std::string subcmd;
|
||||
iss >> subcmd;
|
||||
|
||||
if (subcmd == "status")
|
||||
{
|
||||
// Get AHBot status info
|
||||
std::unordered_map<AuctionHouseType, AuctionHouseBotStatusInfoPerType> statusInfo;
|
||||
sAuctionBot->PrepareStatusInfos(statusInfo);
|
||||
|
||||
return {
|
||||
{"success", true},
|
||||
{"command", "ahbot status"},
|
||||
{"alliance", {
|
||||
{"itemCount", statusInfo[AUCTION_HOUSE_ALLIANCE].ItemsCount}
|
||||
}},
|
||||
{"horde", {
|
||||
{"itemCount", statusInfo[AUCTION_HOUSE_HORDE].ItemsCount}
|
||||
}},
|
||||
{"neutral", {
|
||||
{"itemCount", statusInfo[AUCTION_HOUSE_NEUTRAL].ItemsCount}
|
||||
}},
|
||||
{"total", statusInfo[AUCTION_HOUSE_ALLIANCE].ItemsCount +
|
||||
statusInfo[AUCTION_HOUSE_HORDE].ItemsCount +
|
||||
statusInfo[AUCTION_HOUSE_NEUTRAL].ItemsCount}
|
||||
};
|
||||
}
|
||||
else if (subcmd == "rebuild")
|
||||
{
|
||||
std::string arg;
|
||||
iss >> arg;
|
||||
bool all = (arg == "all");
|
||||
|
||||
sAuctionBot->Rebuild(all);
|
||||
|
||||
return {
|
||||
{"success", true},
|
||||
{"command", "ahbot rebuild"},
|
||||
{"all", all},
|
||||
{"message", all ? "Rebuilding all auction house items" : "Rebuilding auction house items"}
|
||||
};
|
||||
}
|
||||
else if (subcmd == "reload")
|
||||
{
|
||||
sAuctionBot->ReloadAllConfig();
|
||||
return {
|
||||
{"success", true},
|
||||
{"command", "ahbot reload"},
|
||||
{"message", "AHBot configuration reloaded"}
|
||||
};
|
||||
}
|
||||
else if (subcmd == "stats")
|
||||
{
|
||||
// Item level statistics - mirrors the new .ahbot stats command
|
||||
std::string arg;
|
||||
iss >> arg;
|
||||
bool equipmentOnly = (arg == "equipment");
|
||||
|
||||
std::map<uint32, uint32> itemLevelBuckets;
|
||||
uint32 totalItems = 0;
|
||||
uint32 equipmentItems = 0;
|
||||
uint32 minItemLevel = UINT32_MAX;
|
||||
uint32 maxItemLevel = 0;
|
||||
uint64 totalItemLevel = 0;
|
||||
|
||||
std::vector<uint32> auctionHouseIds = { 1, 2, 6, 7 };
|
||||
|
||||
for (uint32 ahId : auctionHouseIds)
|
||||
{
|
||||
AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsById(ahId);
|
||||
if (!auctionHouse)
|
||||
continue;
|
||||
|
||||
for (auto itr = auctionHouse->GetAuctionsBegin(); itr != auctionHouse->GetAuctionsEnd(); ++itr)
|
||||
{
|
||||
AuctionPosting& auction = itr->second;
|
||||
for (Item* item : auction.Items)
|
||||
{
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
ItemTemplate const* proto = item->GetTemplate();
|
||||
if (!proto)
|
||||
continue;
|
||||
|
||||
bool isEquipment = (proto->GetClass() == ITEM_CLASS_WEAPON || proto->GetClass() == ITEM_CLASS_ARMOR);
|
||||
|
||||
if (equipmentOnly && !isEquipment)
|
||||
continue;
|
||||
|
||||
if (isEquipment)
|
||||
++equipmentItems;
|
||||
|
||||
uint32 itemLevel = Item::GetItemLevel(proto, *item->GetBonus(), 90, 0, 0, 0, 0, false, 0);
|
||||
|
||||
++totalItems;
|
||||
totalItemLevel += itemLevel;
|
||||
|
||||
if (itemLevel < minItemLevel)
|
||||
minItemLevel = itemLevel;
|
||||
if (itemLevel > maxItemLevel)
|
||||
maxItemLevel = itemLevel;
|
||||
|
||||
uint32 bucket = (itemLevel / 50) * 50;
|
||||
itemLevelBuckets[bucket]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (totalItems == 0)
|
||||
{
|
||||
return {
|
||||
{"success", true},
|
||||
{"command", "ahbot stats"},
|
||||
{"message", "No items found in auction house"},
|
||||
{"totalItems", 0}
|
||||
};
|
||||
}
|
||||
|
||||
json distribution = json::array();
|
||||
for (auto const& [bucket, count] : itemLevelBuckets)
|
||||
{
|
||||
distribution.push_back({
|
||||
{"minLevel", bucket},
|
||||
{"maxLevel", bucket + 49},
|
||||
{"count", count},
|
||||
{"percentage", (static_cast<float>(count) / totalItems) * 100.0f}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
{"success", true},
|
||||
{"command", "ahbot stats"},
|
||||
{"equipmentOnly", equipmentOnly},
|
||||
{"totalItems", totalItems},
|
||||
{"equipmentItems", equipmentItems},
|
||||
{"minItemLevel", minItemLevel},
|
||||
{"maxItemLevel", maxItemLevel},
|
||||
{"avgItemLevel", static_cast<float>(totalItemLevel) / totalItems},
|
||||
{"distribution", distribution},
|
||||
{"scalingConfig", {
|
||||
{"enabled", sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_ENABLED)},
|
||||
{"minTargetLevel", sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_MIN_ITEM_LEVEL)},
|
||||
{"maxTargetLevel", sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_MAX_ITEM_LEVEL)},
|
||||
{"chance", sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_CHANCE)},
|
||||
{"equipmentOnly", sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_EQUIPMENT_ONLY)}
|
||||
}}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return {
|
||||
{"success", false},
|
||||
{"error", "Unknown ahbot subcommand"},
|
||||
{"subcommand", subcmd},
|
||||
{"supported", {"status", "rebuild [all]", "reload", "stats [equipment]"}}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
{"success", false},
|
||||
@@ -448,7 +614,11 @@ void RegisterSpawnTools()
|
||||
{"supported", {
|
||||
"server info",
|
||||
"reload creature [entry]",
|
||||
"reload creature_spawns (requires restart)"
|
||||
"reload creature_spawns (requires restart)",
|
||||
"ahbot status",
|
||||
"ahbot rebuild [all]",
|
||||
"ahbot reload",
|
||||
"ahbot stats [equipment]"
|
||||
}}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -167,6 +167,11 @@ void AuctionBotConfig::GetConfigFromFile()
|
||||
SetConfig(CONFIG_AHBOT_ITEMS_LOOT, "AuctionHouseBot.Items.Loot", true);
|
||||
SetConfig(CONFIG_AHBOT_ITEMS_MISC, "AuctionHouseBot.Items.Misc", false);
|
||||
|
||||
// AHBot Item Level Scaling - applies random item level bonuses to equipment
|
||||
// Uses ItemBonusMgr::GetItemBonusListForItemLevelDelta() (same system as Timewalking/Remix)
|
||||
SetConfig(CONFIG_AHBOT_ITEM_SCALING_ENABLED, "AuctionHouseBot.Items.Scaling.Enabled", false);
|
||||
SetConfig(CONFIG_AHBOT_ITEM_SCALING_EQUIPMENT_ONLY, "AuctionHouseBot.Items.Scaling.EquipmentOnly", true);
|
||||
|
||||
SetConfig(CONFIG_AHBOT_BIND_NO, "AuctionHouseBot.Bind.No", true);
|
||||
SetConfig(CONFIG_AHBOT_BIND_PICKUP, "AuctionHouseBot.Bind.Pickup", false);
|
||||
SetConfig(CONFIG_AHBOT_BIND_EQUIP, "AuctionHouseBot.Bind.Equip", true);
|
||||
@@ -181,6 +186,10 @@ void AuctionBotConfig::GetConfigFromFile()
|
||||
|
||||
SetConfig(CONFIG_AHBOT_ITEM_MIN_ITEM_LEVEL, "AuctionHouseBot.Items.ItemLevel.Min", 0);
|
||||
SetConfig(CONFIG_AHBOT_ITEM_MAX_ITEM_LEVEL, "AuctionHouseBot.Items.ItemLevel.Max", 0);
|
||||
// Item level scaling range and chance (only used when scaling is enabled)
|
||||
SetConfig(CONFIG_AHBOT_ITEM_SCALING_MIN_ITEM_LEVEL, "AuctionHouseBot.Items.Scaling.MinItemLevel", 0);
|
||||
SetConfig(CONFIG_AHBOT_ITEM_SCALING_MAX_ITEM_LEVEL, "AuctionHouseBot.Items.Scaling.MaxItemLevel", 550);
|
||||
SetConfigMax(CONFIG_AHBOT_ITEM_SCALING_CHANCE, "AuctionHouseBot.Items.Scaling.Chance", 50, 100);
|
||||
SetConfig(CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL, "AuctionHouseBot.Items.ReqLevel.Min", 0);
|
||||
SetConfig(CONFIG_AHBOT_ITEM_MAX_REQ_LEVEL, "AuctionHouseBot.Items.ReqLevel.Max", 0);
|
||||
SetConfig(CONFIG_AHBOT_ITEM_MIN_SKILL_RANK, "AuctionHouseBot.Items.ReqSkill.Min", 0);
|
||||
|
||||
@@ -64,6 +64,9 @@ enum AuctionBotConfigUInt32Values
|
||||
CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO,
|
||||
CONFIG_AHBOT_ITEM_MIN_ITEM_LEVEL,
|
||||
CONFIG_AHBOT_ITEM_MAX_ITEM_LEVEL,
|
||||
CONFIG_AHBOT_ITEM_SCALING_MIN_ITEM_LEVEL,
|
||||
CONFIG_AHBOT_ITEM_SCALING_MAX_ITEM_LEVEL,
|
||||
CONFIG_AHBOT_ITEM_SCALING_CHANCE,
|
||||
CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL,
|
||||
CONFIG_AHBOT_ITEM_MAX_REQ_LEVEL,
|
||||
CONFIG_AHBOT_ITEM_MIN_SKILL_RANK,
|
||||
@@ -171,6 +174,7 @@ enum AuctionBotConfigBoolValues
|
||||
CONFIG_AHBOT_ITEMS_VENDOR,
|
||||
CONFIG_AHBOT_ITEMS_LOOT,
|
||||
CONFIG_AHBOT_ITEMS_MISC,
|
||||
CONFIG_AHBOT_ITEM_SCALING_ENABLED,
|
||||
CONFIG_AHBOT_BIND_NO,
|
||||
CONFIG_AHBOT_BIND_PICKUP,
|
||||
CONFIG_AHBOT_BIND_EQUIP,
|
||||
@@ -180,6 +184,7 @@ enum AuctionBotConfigBoolValues
|
||||
CONFIG_AHBOT_SELLER_ENABLED,
|
||||
CONFIG_AHBOT_BUYER_ENABLED,
|
||||
CONFIG_AHBOT_LOCKBOX_ENABLED,
|
||||
CONFIG_AHBOT_ITEM_SCALING_EQUIPMENT_ONLY,
|
||||
CONFIG_AHBOT_CLASS_CONSUMABLE_ALLOW_ZERO,
|
||||
CONFIG_AHBOT_CLASS_CONTAINER_ALLOW_ZERO,
|
||||
CONFIG_AHBOT_CLASS_WEAPON_ALLOW_ZERO,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "DB2Stores.h"
|
||||
#include "GameTime.h"
|
||||
#include "Item.h"
|
||||
#include "ItemBonusMgr.h"
|
||||
#include "Log.h"
|
||||
#include "Containers.h"
|
||||
#include "ObjectMgr.h"
|
||||
@@ -586,7 +587,9 @@ bool AuctionBotSeller::GetItemsToSell(SellerConfiguration& config, ItemsToSellAr
|
||||
}
|
||||
|
||||
// Set items price. All important value are passed by address.
|
||||
void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConfiguration& config, uint32& buyout, uint32& bid, uint32 stackCount)
|
||||
// scaledItemLevel: If non-zero, use this item level for price calculation instead of base level
|
||||
// This ensures scaled items are priced appropriately for their actual power level
|
||||
void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConfiguration& config, uint32& buyout, uint32& bid, uint32 stackCount, uint32 scaledItemLevel /*= 0*/)
|
||||
{
|
||||
uint32 classRatio = config.GetPriceRatioPerClass(ItemClass(itemProto->GetClass()));
|
||||
uint32 qualityRatio = config.GetPriceRatioPerQuality(AuctionQuality(itemProto->GetQuality()));
|
||||
@@ -595,6 +598,9 @@ void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConf
|
||||
float buyPrice = itemProto->GetBuyPrice();
|
||||
float sellPrice = itemProto->GetSellPrice();
|
||||
|
||||
// Use scaled item level if provided, otherwise use base item level
|
||||
float effectiveItemLevel = scaledItemLevel > 0 ? static_cast<float>(scaledItemLevel) : static_cast<float>(itemProto->GetBaseItemLevel());
|
||||
|
||||
if (buyPrice == 0)
|
||||
{
|
||||
if (sellPrice > 0)
|
||||
@@ -602,12 +608,21 @@ void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConf
|
||||
else
|
||||
{
|
||||
float divisor = ((itemProto->GetClass() == ITEM_CLASS_WEAPON || itemProto->GetClass() == ITEM_CLASS_ARMOR) ? 284.0f : 80.0f);
|
||||
float tempLevel = (itemProto->GetBaseItemLevel() == 0 ? 1.0f : itemProto->GetBaseItemLevel());
|
||||
float tempLevel = (effectiveItemLevel == 0 ? 1.0f : effectiveItemLevel);
|
||||
float tempQuality = (itemProto->GetQuality() == 0 ? 1.0f : itemProto->GetQuality());
|
||||
|
||||
buyPrice = tempLevel * tempQuality * static_cast<float>(GetBuyModifier(itemProto))* tempLevel / divisor;
|
||||
}
|
||||
}
|
||||
// If item has a buy price but was scaled, apply a multiplier based on item level increase
|
||||
else if (scaledItemLevel > 0 && scaledItemLevel > itemProto->GetBaseItemLevel())
|
||||
{
|
||||
// Scale price proportionally: higher ilvl = higher price
|
||||
// Formula: basePrice * (1 + (deltaLevel * 0.02)) - 2% increase per item level
|
||||
float deltaLevel = static_cast<float>(scaledItemLevel - itemProto->GetBaseItemLevel());
|
||||
float scalingFactor = 1.0f + (deltaLevel * 0.02f);
|
||||
buyPrice *= scalingFactor;
|
||||
}
|
||||
|
||||
if (sellPrice == 0)
|
||||
sellPrice = (buyPrice > 10 ? buyPrice / GetSellModifier(itemProto) : buyPrice);
|
||||
@@ -869,11 +884,47 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config)
|
||||
// Ex: Notched Shortsword of Stamina will only generate as a Notched Shortsword without this.
|
||||
item->SetItemRandomBonusList(GenerateItemRandomBonusListId(itemId));
|
||||
|
||||
// AHBot Item Level Scaling: Apply random item level bonus to equipment items
|
||||
// Uses the same ItemBonusMgr system as Timewalking/Remix for item level deltas
|
||||
// This allows AH to stock gear at varied item levels for players at all progression stages
|
||||
uint32 scaledItemLevel = prototype->GetBaseItemLevel();
|
||||
if (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_ENABLED))
|
||||
{
|
||||
// Check if we should scale this item (equipment-only filter and chance roll)
|
||||
bool isEquipment = (prototype->GetClass() == ITEM_CLASS_WEAPON || prototype->GetClass() == ITEM_CLASS_ARMOR);
|
||||
bool shouldScale = !sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_EQUIPMENT_ONLY) || isEquipment;
|
||||
|
||||
if (shouldScale && urand(0, 99) < sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_CHANCE))
|
||||
{
|
||||
uint32 minLevel = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_MIN_ITEM_LEVEL);
|
||||
uint32 maxLevel = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_MAX_ITEM_LEVEL);
|
||||
uint32 targetLevel = urand(minLevel, maxLevel);
|
||||
|
||||
// Only scale up, not down - if target is below base level, skip scaling
|
||||
if (targetLevel > prototype->GetBaseItemLevel())
|
||||
{
|
||||
int16 delta = static_cast<int16>(targetLevel - prototype->GetBaseItemLevel());
|
||||
if (uint32 bonusListId = ItemBonusMgr::GetItemBonusListForItemLevelDelta(delta))
|
||||
{
|
||||
item->AddBonuses(bonusListId);
|
||||
scaledItemLevel = targetLevel;
|
||||
TC_LOG_DEBUG("ahbot", "AHBot: Scaled item {} from ilvl {} to {} (delta: {}, bonus: {})",
|
||||
itemId, prototype->GetBaseItemLevel(), targetLevel, delta, bonusListId);
|
||||
}
|
||||
else
|
||||
{
|
||||
TC_LOG_DEBUG("ahbot", "AHBot: No bonus list found for item {} delta {} - keeping base ilvl {}",
|
||||
itemId, delta, prototype->GetBaseItemLevel());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 buyoutPrice;
|
||||
uint32 bidPrice = 0;
|
||||
|
||||
// Price of items are set here
|
||||
SetPricesOfItem(prototype, config, buyoutPrice, bidPrice, stackCount);
|
||||
// Price of items are set here - pass scaled item level for price calculation
|
||||
SetPricesOfItem(prototype, config, buyoutPrice, bidPrice, stackCount, scaledItemLevel);
|
||||
|
||||
// Deposit time
|
||||
uint32 etime = urand(1, 3);
|
||||
|
||||
@@ -142,7 +142,7 @@ private:
|
||||
void LoadSellerValues(SellerConfiguration& config);
|
||||
uint32 SetStat(SellerConfiguration& config);
|
||||
bool GetItemsToSell(SellerConfiguration& config, ItemsToSellArray& itemsToSellArray, AllItemsArray const& addedItem);
|
||||
void SetPricesOfItem(ItemTemplate const* itemProto, SellerConfiguration& config, uint32& buyout, uint32& bid, uint32 stackcnt);
|
||||
void SetPricesOfItem(ItemTemplate const* itemProto, SellerConfiguration& config, uint32& buyout, uint32& bid, uint32 stackcnt, uint32 scaledItemLevel = 0);
|
||||
uint32 GetStackSizeForItem(ItemTemplate const* itemProto, SellerConfiguration& config) const;
|
||||
void LoadItemsQuantity(SellerConfiguration& config);
|
||||
static uint32 GetBuyModifier(ItemTemplate const* prototype);
|
||||
|
||||
@@ -17,10 +17,13 @@
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "AuctionHouseBot.h"
|
||||
#include "AuctionHouseMgr.h"
|
||||
#include "Chat.h"
|
||||
#include "ChatCommand.h"
|
||||
#include "Item.h"
|
||||
#include "Language.h"
|
||||
#include "RBAC.h"
|
||||
#include <map>
|
||||
|
||||
using namespace Trinity::ChatCommands;
|
||||
|
||||
@@ -69,6 +72,7 @@ public:
|
||||
{ "rebuild", HandleAHBotRebuildCommand, rbac::RBAC_PERM_COMMAND_AHBOT_REBUILD, Console::Yes },
|
||||
{ "reload", HandleAHBotReloadCommand, rbac::RBAC_PERM_COMMAND_AHBOT_RELOAD, Console::Yes },
|
||||
{ "status", HandleAHBotStatusCommand, rbac::RBAC_PERM_COMMAND_AHBOT_STATUS, Console::Yes },
|
||||
{ "stats", HandleAHBotStatsCommand, rbac::RBAC_PERM_COMMAND_AHBOT_STATUS, Console::Yes },
|
||||
};
|
||||
|
||||
static ChatCommandTable commandTable =
|
||||
@@ -188,6 +192,105 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
// AHBot Stats Command - Reports item level distribution for auction house items
|
||||
// This is useful for analyzing the effectiveness of item level scaling
|
||||
// Usage: .ahbot stats [equipment] - shows item level distribution
|
||||
// equipment flag filters to only weapons/armor
|
||||
static bool HandleAHBotStatsCommand(ChatHandler* handler, Optional<EXACT_SEQUENCE("equipment")> equipmentOnly)
|
||||
{
|
||||
// Item level buckets for distribution analysis
|
||||
std::map<uint32, uint32> itemLevelBuckets; // bucket -> count
|
||||
uint32 totalItems = 0;
|
||||
uint32 equipmentItems = 0;
|
||||
uint32 minItemLevel = UINT32_MAX;
|
||||
uint32 maxItemLevel = 0;
|
||||
uint64 totalItemLevel = 0;
|
||||
|
||||
// Iterate through all three auction houses
|
||||
// AuctionHouseIds: 1=Alliance, 2=Neutral (Goblin), 6=Horde, 7=Neutral (Blackwater)
|
||||
std::vector<uint32> auctionHouseIds = { 1, 2, 6, 7 };
|
||||
|
||||
for (uint32 ahId : auctionHouseIds)
|
||||
{
|
||||
AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsById(ahId);
|
||||
if (!auctionHouse)
|
||||
continue;
|
||||
|
||||
for (auto itr = auctionHouse->GetAuctionsBegin(); itr != auctionHouse->GetAuctionsEnd(); ++itr)
|
||||
{
|
||||
AuctionPosting& auction = itr->second;
|
||||
for (Item* item : auction.Items)
|
||||
{
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
ItemTemplate const* proto = item->GetTemplate();
|
||||
if (!proto)
|
||||
continue;
|
||||
|
||||
bool isEquipment = (proto->GetClass() == ITEM_CLASS_WEAPON || proto->GetClass() == ITEM_CLASS_ARMOR);
|
||||
|
||||
// Skip non-equipment if filter is active
|
||||
if (equipmentOnly.has_value() && !isEquipment)
|
||||
continue;
|
||||
|
||||
if (isEquipment)
|
||||
++equipmentItems;
|
||||
|
||||
// Get item level from bonus data (includes any scaling bonuses)
|
||||
// Use static GetItemLevel with minimal parameters since AHBot items have no owner
|
||||
uint32 itemLevel = Item::GetItemLevel(proto, *item->GetBonus(), 90, 0, 0, 0, 0, false, 0);
|
||||
|
||||
++totalItems;
|
||||
totalItemLevel += itemLevel;
|
||||
|
||||
if (itemLevel < minItemLevel)
|
||||
minItemLevel = itemLevel;
|
||||
if (itemLevel > maxItemLevel)
|
||||
maxItemLevel = itemLevel;
|
||||
|
||||
// Bucket by 50 item levels for readable output
|
||||
uint32 bucket = (itemLevel / 50) * 50;
|
||||
itemLevelBuckets[bucket]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (totalItems == 0)
|
||||
{
|
||||
handler->SendSysMessage("AHBot Stats: No items found in auction house.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Output results
|
||||
handler->PSendSysMessage("=== AHBot Item Level Statistics ===");
|
||||
handler->PSendSysMessage("Total items analyzed: %u", totalItems);
|
||||
if (!equipmentOnly.has_value())
|
||||
handler->PSendSysMessage("Equipment items (weapons/armor): %u", equipmentItems);
|
||||
handler->PSendSysMessage("Item level range: %u - %u", minItemLevel, maxItemLevel);
|
||||
handler->PSendSysMessage("Average item level: %.1f", static_cast<float>(totalItemLevel) / totalItems);
|
||||
handler->SendSysMessage("--- Distribution by Item Level ---");
|
||||
|
||||
for (auto const& [bucket, count] : itemLevelBuckets)
|
||||
{
|
||||
float percentage = (static_cast<float>(count) / totalItems) * 100.0f;
|
||||
handler->PSendSysMessage(" ilvl %u-%u: %u items (%.1f%%)", bucket, bucket + 49, count, percentage);
|
||||
}
|
||||
|
||||
// Show scaling config status
|
||||
handler->SendSysMessage("--- Scaling Configuration ---");
|
||||
handler->PSendSysMessage("Scaling Enabled: %s", sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_ENABLED) ? "Yes" : "No");
|
||||
if (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_ENABLED))
|
||||
{
|
||||
handler->PSendSysMessage(" Min Target ilvl: %u", sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_MIN_ITEM_LEVEL));
|
||||
handler->PSendSysMessage(" Max Target ilvl: %u", sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_MAX_ITEM_LEVEL));
|
||||
handler->PSendSysMessage(" Scaling Chance: %u%%", sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_CHANCE));
|
||||
handler->PSendSysMessage(" Equipment Only: %s", sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_SCALING_EQUIPMENT_ONLY) ? "Yes" : "No");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template bool ahbot_commandscript::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_GRAY>(ChatHandler* handler, uint32 amount);
|
||||
|
||||
@@ -3779,6 +3779,41 @@ AuctionHouseBot.Class.Glyph.Price.Ratio = 100
|
||||
AuctionHouseBot.Items.ItemLevel.Min = 0
|
||||
AuctionHouseBot.Items.ItemLevel.Max = 0
|
||||
|
||||
#
|
||||
# AuctionHouseBot.Items.Scaling.*
|
||||
# Description: Item level scaling for AHBot items. When enabled, equipment items
|
||||
# posted by AHBot can receive random item level bonuses, allowing
|
||||
# the AH to stock gear suitable for all player progression levels.
|
||||
# Uses the same ItemBonusMgr system as Timewalking/Remix scaling.
|
||||
#
|
||||
# AuctionHouseBot.Items.Scaling.Enabled
|
||||
# Description: Enable item level scaling for AHBot items
|
||||
# Default: 0 - (Disabled, items use base item level)
|
||||
# 1 - (Enabled, items may receive random item level bonuses)
|
||||
#
|
||||
# AuctionHouseBot.Items.Scaling.MinItemLevel
|
||||
# Description: Minimum target item level for scaled items
|
||||
# Default: 0 - (Use item's base level as minimum)
|
||||
#
|
||||
# AuctionHouseBot.Items.Scaling.MaxItemLevel
|
||||
# Description: Maximum target item level for scaled items
|
||||
# Default: 550 - (MoP raid gear level)
|
||||
#
|
||||
# AuctionHouseBot.Items.Scaling.Chance
|
||||
# Description: Percentage chance (0-100) for each item to be scaled
|
||||
# Default: 50 - (50% of eligible items get scaled)
|
||||
#
|
||||
# AuctionHouseBot.Items.Scaling.EquipmentOnly
|
||||
# Description: Only scale equipment (weapons/armor), not consumables/materials
|
||||
# Default: 1 - (Only equipment is scaled)
|
||||
# 0 - (All item types can be scaled)
|
||||
|
||||
AuctionHouseBot.Items.Scaling.Enabled = 0
|
||||
AuctionHouseBot.Items.Scaling.MinItemLevel = 0
|
||||
AuctionHouseBot.Items.Scaling.MaxItemLevel = 550
|
||||
AuctionHouseBot.Items.Scaling.Chance = 50
|
||||
AuctionHouseBot.Items.Scaling.EquipmentOnly = 1
|
||||
|
||||
#
|
||||
# AuctionHouseBot.Items.ReqLevel.*
|
||||
# Description: Prevent seller from listing items below/above this required level
|
||||
|
||||
Reference in New Issue
Block a user