mirror of
https://github.com/NathanHandley/mod-ah-bot-plus.git
synced 2026-01-13 01:08:37 +00:00
Added additional AdvancedListingRules.UseDropRates config
This commit is contained in:
@@ -85,33 +85,59 @@ AuctionHouseBot.ListingExpireTimeInSecondsMax = 86400
|
|||||||
# AuctionHouseBot.AdvancedListingRules.UseDropRates.Enabled
|
# AuctionHouseBot.AdvancedListingRules.UseDropRates.Enabled
|
||||||
# Enable/Disable the Seller using items' in-game drop rates from Enemies
|
# Enable/Disable the Seller using items' in-game drop rates from Enemies
|
||||||
# and GameObjects to determine the probability of listing them on the AH.
|
# and GameObjects to determine the probability of listing them on the AH.
|
||||||
# Attempts to simulate "live" AHs by making very powerful items appear less often.
|
# This makes rare items appear less frequently on the AH.
|
||||||
|
# How it works: Each time an enabled item Category/Quality is selected to post an auction,
|
||||||
|
# a number is rolled between 0-100. Based on this roll, a Tier is chosen based on
|
||||||
|
# UseDropRates.TiersConfig, then a random item from that rarity tier is listed on the AH.
|
||||||
# This setting respects ListProportion config. It can also result in more duplicate
|
# This setting respects ListProportion config. It can also result in more duplicate
|
||||||
# items appearing on the AH due to higher-drop-rate items being selected more often.
|
# items appearing on the AH due to higher-drop-rate items being selected more often.
|
||||||
# Crafted items may also appear more often since their drop rate is effectively 100%.
|
# Crafted items may also appear more often since their drop rate is effectively 100%.
|
||||||
# Default: false (disabled)
|
# Default: false (disabled)
|
||||||
#
|
#
|
||||||
# AuctionHouseBot.AdvancedListingRules.UseDropRates.MinQuality
|
|
||||||
# The minimum quality that should be included by AdvancedListingRules.UseDropRates.
|
|
||||||
# Value should be the integer corresponding to the desired minimum rarity.
|
|
||||||
# Examples: Setting to 3 will apply to Rare, Epic, Legendary, and Heirloom.
|
|
||||||
# Setting to 1 will apply to Common, Uncommon, Rare, Epic, Legendary, and Heirloom.
|
|
||||||
# (0) Poor, (1) Common, (2) Uncommon, (3) Rare, (4) Epic, (5) Legendary, (6) Heirloom
|
|
||||||
# Default: 3
|
|
||||||
#
|
|
||||||
# AuctionHouseBot.Seller.AdvancedListingRules.UseDropRates.<Category>
|
# AuctionHouseBot.Seller.AdvancedListingRules.UseDropRates.<Category>
|
||||||
# Toggle AdvancedListingRules.UseDropRates behavior for individual category.
|
# Toggle AdvancedListingRules.UseDropRates behavior for individual category.
|
||||||
# Only applied if AdvancedListingRules.UseDropRates.Enabled is true.
|
# Only applied if AdvancedListingRules.UseDropRates.Enabled is true.
|
||||||
# Default: true (enabled)
|
# Default: true (enabled)
|
||||||
|
#
|
||||||
|
# AuctionHouseBot.AdvancedListingRules.UseDropRates.<Category>.AffectedQualities
|
||||||
|
# The qualities that should be affected by AdvancedListingRules.UseDropRates.
|
||||||
|
# Value should be a string of comma separated numbers corresponding to the desired qualities.
|
||||||
|
# Examples: Setting to 2,3,5 will apply to Uncommon, Rare, and Legendary.
|
||||||
|
# Setting to 4 will apply only to Epic.
|
||||||
|
# (0) Poor, (1) Common, (2) Uncommon, (3) Rare, (4) Epic, (5) Legendary, (6) Heirloom
|
||||||
|
# Default: 2,3,4,5
|
||||||
|
#
|
||||||
|
# AuctionHouseBot.AdvancedListingRules.UseDropRates.TiersConfig
|
||||||
|
# The thresholds that define item drop rate tiers.
|
||||||
|
# Value should be a string of comma-separated numbers between 0 and 100.
|
||||||
|
# Each number creates a tier for items whose drop rate falls within that range.
|
||||||
|
# The order of numbers in the string does not need to be sorted; they will be
|
||||||
|
# interpreted in descending order. However, you may find it easier to read when sorted.
|
||||||
|
# Whitespace is also ignored.
|
||||||
|
# Example: Setting to 50,10,5 will create 3 tiers:
|
||||||
|
# - 50–100%: items with drop rate 50% or higher
|
||||||
|
# - 10–50%: items with drop rate between 10% and 50%
|
||||||
|
# - 0–5%: items with drop rate 0–5%
|
||||||
|
# Default: 50, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01, 0.005
|
||||||
|
#
|
||||||
|
# AuctionHouseBot.AdvancedListingRules.UseDropRates.DisabledItemIDs
|
||||||
|
# Comma separated list of itemIDs to exclude from having its drop rate influence its AH availability
|
||||||
|
# Ranges using a dash (-) can also be used.
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
AuctionHouseBot.AdvancedListingRules.UseDropRates.Enabled = false
|
AuctionHouseBot.AdvancedListingRules.UseDropRates.Enabled = false
|
||||||
AuctionHouseBot.AdvancedListingRules.UseDropRates.MinQuality = 2
|
|
||||||
|
|
||||||
AuctionHouseBot.AdvancedListingRules.UseDropRates.Weapon = true
|
AuctionHouseBot.AdvancedListingRules.UseDropRates.Weapon = true
|
||||||
AuctionHouseBot.AdvancedListingRules.UseDropRates.Armor = true
|
AuctionHouseBot.AdvancedListingRules.UseDropRates.Armor = true
|
||||||
AuctionHouseBot.AdvancedListingRules.UseDropRates.Recipe = true
|
AuctionHouseBot.AdvancedListingRules.UseDropRates.Recipe = true
|
||||||
|
|
||||||
|
AuctionHouseBot.AdvancedListingRules.UseDropRates.Weapon.AffectedQualities = 2,3,4,5
|
||||||
|
AuctionHouseBot.AdvancedListingRules.UseDropRates.Armor.AffectedQualities = 2,3,4,5
|
||||||
|
AuctionHouseBot.AdvancedListingRules.UseDropRates.Recipe.AffectedQualities = 2,3,4,5
|
||||||
|
|
||||||
|
AuctionHouseBot.AdvancedListingRules.UseDropRates.TiersConfig = 50, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05, 0.02, 0.01, 0.005
|
||||||
|
AuctionHouseBot.AdvancedListingRules.UseDropRates.DisabledItemIDs =
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# AuctionHouseBot.MaxBuyoutPriceInCopper
|
# AuctionHouseBot.MaxBuyoutPriceInCopper
|
||||||
# Maximum amount that a buyout on a listing can be in copper. Prevents
|
# Maximum amount that a buyout on a listing can be in copper. Prevents
|
||||||
|
|||||||
@@ -1016,40 +1016,11 @@ void AuctionHouseBot::AddNewAuctions(std::vector<Player*> AHBPlayers, FactionSpe
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If current item is crafted, ineligible, or quest reward, ignore drop rates and continue to list it
|
if (IsItemEligibleForDBDropRates(prototype))
|
||||||
if (AdvancedListingRuleUseDropRatesEnabled &&
|
|
||||||
IsItemEligibleForDBDropRates(prototype) &&
|
|
||||||
!IsItemCrafted(itemID) &&
|
|
||||||
!IsItemQuestReward(itemID))
|
|
||||||
{
|
{
|
||||||
// The AHBot has chosen a rare/epic armor/weapon/recipe, so select another item
|
bool foundDBDropRatesItem = HandleAdvancedListingRuleUseDropRates(prototype);
|
||||||
// of that type based on drop rates. This way ListProportions are respected.
|
if (foundDBDropRatesItem)
|
||||||
|
itemID = prototype->ItemId;
|
||||||
// Roll for rarity tier
|
|
||||||
double r = 100.0 * (urand(0, INT32_MAX) / static_cast<double>(INT32_MAX));
|
|
||||||
int tier = GetItemDropChanceTier(r);
|
|
||||||
|
|
||||||
// If chosen tier is empty, search rarer tiers until not empty
|
|
||||||
auto& tierBuckets = ItemTiersByClassAndQuality[prototype->Class][prototype->Quality];
|
|
||||||
while (tierBuckets[tier].empty() && tier < 10) {
|
|
||||||
if (debug_Out)
|
|
||||||
LOG_INFO("module", "Bucket is empty for class {} quality {} tier {}", prototype->Class, prototype->Quality, tier);
|
|
||||||
tier++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pull a random item from selected rarity tier
|
|
||||||
auto& bucket = tierBuckets[tier];
|
|
||||||
if (!bucket.empty())
|
|
||||||
{
|
|
||||||
itemID = bucket[rand() % bucket.size()];
|
|
||||||
prototype = sObjectMgr->GetItemTemplate(itemID);
|
|
||||||
if (!prototype)
|
|
||||||
{
|
|
||||||
if (debug_Out)
|
|
||||||
LOG_ERROR("module", "AHSeller: prototype == NULL");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else continue;
|
else continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1120,76 +1091,174 @@ void AuctionHouseBot::AddNewAuctions(std::vector<Player*> AHBPlayers, FactionSpe
|
|||||||
LOG_INFO("module", "AHSeller: Added {} items", itemsGenerated);
|
LOG_INFO("module", "AHSeller: Added {} items", itemsGenerated);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AuctionHouseBot::GetAdvancedListingRuleUseDropRatesEnabledCategoriesString()
|
bool AuctionHouseBot::HandleAdvancedListingRuleUseDropRates(ItemTemplate const*& proto)
|
||||||
{
|
{
|
||||||
std::vector<uint32> enabledCategories;
|
// The AHBot has chosen a rare/epic armor/weapon/recipe, so select another item
|
||||||
|
// of that type based on drop rates. This way ListProportions are respected.
|
||||||
|
|
||||||
if (AdvancedListingRuleUseDropRatesWeaponEnabled)
|
// Roll for rarity tier
|
||||||
enabledCategories.push_back(ITEM_CLASS_WEAPON);
|
double r = 100.0 * (urand(0, INT32_MAX) / static_cast<double>(INT32_MAX));
|
||||||
if (AdvancedListingRuleUseDropRatesArmorEnabled)
|
int tier = GetItemDropChanceTier(r);
|
||||||
enabledCategories.push_back(ITEM_CLASS_ARMOR);
|
|
||||||
if (AdvancedListingRuleUseDropRatesRecipeEnabled)
|
|
||||||
enabledCategories.push_back(ITEM_CLASS_RECIPE);
|
|
||||||
|
|
||||||
std::ostringstream oss;
|
// If chosen tier is empty, search rarer tiers until not empty
|
||||||
for (size_t i = 0; i < enabledCategories.size(); ++i)
|
auto& tierBuckets = ItemTiersByClassAndQuality[proto->Class][proto->Quality];
|
||||||
{
|
while (tierBuckets[tier].empty() && tier < 10) {
|
||||||
if (i > 0)
|
tier++;
|
||||||
oss << ",";
|
|
||||||
oss << enabledCategories[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return oss.str();
|
// Pull a random item from selected rarity tier
|
||||||
|
uint32 itemID = proto->ItemId;
|
||||||
|
auto& bucket = tierBuckets[tier];
|
||||||
|
if (!bucket.empty())
|
||||||
|
{
|
||||||
|
itemID = bucket[rand() % bucket.size()];
|
||||||
|
proto = sObjectMgr->GetItemTemplate(itemID);
|
||||||
|
if (!proto)
|
||||||
|
{
|
||||||
|
if (debug_Out)
|
||||||
|
LOG_ERROR("module", "AHSeller: prototype == NULL");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuctionHouseBot::PopulateItemDropChances()
|
void AuctionHouseBot::PopulateItemDropChances()
|
||||||
|
{
|
||||||
|
InitializeAdvancedListingRuleUseDropRatesTiers();
|
||||||
|
|
||||||
|
if (!AdvancedListingRuleUseDropRatesWeaponEnabled &&
|
||||||
|
!AdvancedListingRuleUseDropRatesArmorEnabled &&
|
||||||
|
!AdvancedListingRuleUseDropRatesRecipeEnabled)
|
||||||
|
{
|
||||||
|
LOG_ERROR("module", "AuctionHouseBot: No categories are enabled for AuctionHouseBot.Seller.AdvancedListingRules.UseDropRates");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto handleDropChancesForCategoryAndQuality = [this](ItemClass category, std::set<uint32> affectedQualities) {
|
||||||
|
std::string qualities = "";
|
||||||
|
int i = 0;
|
||||||
|
for (uint32 q : affectedQualities)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
qualities += ",";
|
||||||
|
qualities += to_string(q);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
PopulateItemDropChancesForCategoryAndQuality(category, qualities);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (AdvancedListingRuleUseDropRatesWeaponEnabled)
|
||||||
|
handleDropChancesForCategoryAndQuality(ITEM_CLASS_WEAPON, AdvancedListingRuleUseDropRatesWeaponAffectedQualities);
|
||||||
|
if (AdvancedListingRuleUseDropRatesArmorEnabled)
|
||||||
|
handleDropChancesForCategoryAndQuality(ITEM_CLASS_ARMOR, AdvancedListingRuleUseDropRatesArmorAffectedQualities);
|
||||||
|
if (AdvancedListingRuleUseDropRatesRecipeEnabled)
|
||||||
|
handleDropChancesForCategoryAndQuality(ITEM_CLASS_RECIPE, AdvancedListingRuleUseDropRatesRecipeAffectedQualities);
|
||||||
|
|
||||||
|
// Erase item candidates that are not crafted, not quest rewards, and missing DB drop rate
|
||||||
|
for (auto& [classID, qualityGroups] : ItemCandidatesByItemClassAndQuality)
|
||||||
|
{
|
||||||
|
for (auto& [qualityID, candidates] : qualityGroups)
|
||||||
|
{
|
||||||
|
candidates.erase(
|
||||||
|
std::remove_if(
|
||||||
|
candidates.begin(),
|
||||||
|
candidates.end(),
|
||||||
|
[&](uint32 id)
|
||||||
|
{
|
||||||
|
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(id);
|
||||||
|
if (!IsItemCategoryQualityInDBDropRatesConfig(proto))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool shouldErase = !IsItemCrafted(id)
|
||||||
|
&& !IsItemQuestReward(id)
|
||||||
|
&& !CachedItemDropRates.contains(id);
|
||||||
|
|
||||||
|
return shouldErase;
|
||||||
|
}),
|
||||||
|
candidates.end()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug_Out)
|
||||||
|
{
|
||||||
|
// Show number of items in each tier
|
||||||
|
LOG_INFO("module", "AHBot AdvancedListingRule UseDropRates item counts by class and quality after appyling filters:");
|
||||||
|
for (size_t i = 0; i < ItemTiersByClassAndQuality.size(); ++i)
|
||||||
|
{
|
||||||
|
const auto& qualities = ItemTiersByClassAndQuality[i];
|
||||||
|
for (size_t j = 0; j < qualities.size(); ++j)
|
||||||
|
{
|
||||||
|
const auto& tiers = qualities[j];
|
||||||
|
for (size_t k = 0; k < tiers.size(); ++k)
|
||||||
|
{
|
||||||
|
const auto& items = tiers[k];
|
||||||
|
if (i == 2)
|
||||||
|
LOG_INFO("module", "Armor Count: {} Tier {} has {} items", GetQualityName((ItemQualities)j), k, items.size());
|
||||||
|
if (i == 4)
|
||||||
|
LOG_INFO("module", "Weapon Count: {} Tier {} has {} items", GetQualityName((ItemQualities)j), k, items.size());
|
||||||
|
if (i == 9)
|
||||||
|
LOG_INFO("module", "Recipe Count: {} Tier {} has {} items", GetQualityName((ItemQualities)j), k, items.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuctionHouseBot::PopulateItemDropChancesForCategoryAndQuality(ItemClass category, std::string qualities)
|
||||||
{
|
{
|
||||||
// Search creature loot templates, referenced loot_loot_template, group_loot tables, and object_loot tables for items' drop rates
|
// Search creature loot templates, referenced loot_loot_template, group_loot tables, and object_loot tables for items' drop rates
|
||||||
std::string directDropString = R"SQL(
|
std::string directDropString = R"SQL(
|
||||||
SELECT it.entry AS itemID,
|
with chances AS (
|
||||||
clt.Chance AS direct_chance,
|
SELECT it.entry AS itemID,
|
||||||
0 AS reference_chance
|
clt.Chance AS direct_chance,
|
||||||
|
0 AS reference_chance
|
||||||
FROM creature_template ct
|
FROM creature_template ct
|
||||||
JOIN creature_loot_template clt ON clt.Entry = ct.lootid
|
JOIN creature_loot_template clt ON clt.Entry = ct.lootid
|
||||||
JOIN item_template it ON it.entry = clt.Item
|
JOIN item_template it ON it.entry = clt.Item
|
||||||
WHERE clt.Reference = 0 AND clt.GroupId = 0 AND it.class IN ({}) AND it.quality >= {}
|
WHERE clt.Reference = 0 AND clt.GroupId = 0 AND it.class IN ({}) AND it.quality IN ({})
|
||||||
|
)
|
||||||
|
SELECT itemID,
|
||||||
|
MIN(direct_chance) AS direct_chance,
|
||||||
|
0 AS reference_chance
|
||||||
|
FROM chances
|
||||||
|
GROUP BY itemID
|
||||||
)SQL";
|
)SQL";
|
||||||
|
|
||||||
std::string referenceDropString = R"SQL(
|
std::string referenceDropString = R"SQL(
|
||||||
WITH reference_group_counts AS (
|
WITH chances AS (
|
||||||
SELECT entry AS referenceID, COUNT(*) AS groupCount
|
|
||||||
FROM reference_loot_template
|
|
||||||
GROUP BY entry
|
|
||||||
),
|
|
||||||
all_references AS (
|
|
||||||
SELECT
|
SELECT
|
||||||
rlt.Entry AS referenceID,
|
|
||||||
rlt.Item AS itemID,
|
rlt.Item AS itemID,
|
||||||
rlt.Chance AS referenceChance,
|
CASE
|
||||||
rgc.groupCount,
|
WHEN COUNT(clt.Entry) > 0 THEN
|
||||||
MIN(clt.Chance) AS creatureChance,
|
(1.0 / CASE WHEN rgc.groupCount < 6 THEN 6 ELSE rgc.groupCount END)
|
||||||
CASE WHEN COUNT(clt.Entry) > 0 THEN 1 ELSE 0 END AS hasCreature
|
* COALESCE(NULLIF(rlt.Chance,0),1)
|
||||||
|
* COALESCE(NULLIF(MIN(clt.Chance),0),1)
|
||||||
|
ELSE
|
||||||
|
(1.0 / rgc.groupCount) * COALESCE(NULLIF(rlt.Chance,0),1)
|
||||||
|
END AS reference_chance
|
||||||
FROM reference_loot_template rlt
|
FROM reference_loot_template rlt
|
||||||
JOIN reference_group_counts rgc ON rlt.Entry = rgc.referenceID
|
JOIN (
|
||||||
LEFT JOIN creature_loot_template clt ON clt.Reference = rlt.Entry
|
SELECT entry, COUNT(*) AS groupCount
|
||||||
WHERE clt.`Comment` NOT LIKE '%Placeholder%'
|
FROM reference_loot_template
|
||||||
|
GROUP BY entry
|
||||||
|
) rgc ON rlt.Entry = rgc.entry
|
||||||
|
LEFT JOIN creature_loot_template clt
|
||||||
|
ON clt.Reference = rlt.Entry
|
||||||
|
AND clt.Comment NOT LIKE '%Placeholder%'
|
||||||
|
JOIN item_template it ON it.entry = rlt.Item
|
||||||
|
WHERE it.class IN ({})
|
||||||
|
AND it.quality IN ({})
|
||||||
GROUP BY rlt.Entry, rlt.Item, rlt.Chance, rgc.groupCount
|
GROUP BY rlt.Entry, rlt.Item, rlt.Chance, rgc.groupCount
|
||||||
)
|
)
|
||||||
SELECT
|
SELECT itemID,
|
||||||
ar.itemID AS itemID,
|
0 AS direct_chance,
|
||||||
0 AS direct_chance,
|
MIN(reference_chance) AS reference_chance
|
||||||
CASE
|
FROM chances
|
||||||
WHEN ar.hasCreature = 1
|
GROUP BY itemID
|
||||||
THEN (1.0 / case when ar.groupCount < 6 then 6 ELSE ar.groupCount end) *
|
|
||||||
COALESCE(NULLIF(ar.referenceChance,0),1) *
|
|
||||||
COALESCE(NULLIF(ar.creatureChance,0),1)
|
|
||||||
ELSE
|
|
||||||
(1.0 / ar.groupCount) *
|
|
||||||
COALESCE(NULLIF(ar.referenceChance,0),1)
|
|
||||||
END AS reference_chance
|
|
||||||
FROM all_references ar
|
|
||||||
JOIN item_template it ON it.entry = ar.itemID
|
|
||||||
WHERE it.class IN ({}) AND it.quality >= {}
|
|
||||||
)SQL";
|
)SQL";
|
||||||
|
|
||||||
// This will lookup items in referenced_loot_template whose Reference entry is not associated with a creature_loot_template
|
// This will lookup items in referenced_loot_template whose Reference entry is not associated with a creature_loot_template
|
||||||
@@ -1204,21 +1273,28 @@ void AuctionHouseBot::PopulateItemDropChances()
|
|||||||
),
|
),
|
||||||
reference_data AS (
|
reference_data AS (
|
||||||
SELECT
|
SELECT
|
||||||
rlt.Entry AS referenceID,
|
rlt.Entry AS referenceID,
|
||||||
rlt.Item AS itemID,
|
rlt.Item AS itemID,
|
||||||
rlt.Chance AS referenceChance,
|
rlt.Chance AS referenceChance,
|
||||||
rgc.groupCount
|
rgc.groupCount
|
||||||
FROM reference_loot_template rlt
|
FROM reference_loot_template rlt
|
||||||
JOIN reference_group_counts rgc ON rlt.Entry = rgc.referenceID
|
JOIN reference_group_counts rgc ON rlt.Entry = rgc.referenceID
|
||||||
)
|
),
|
||||||
SELECT
|
chances AS (
|
||||||
rd.itemID AS itemID,
|
SELECT rd.itemID AS itemID,
|
||||||
0 AS direct_chance,
|
0 AS direct_chance,
|
||||||
(1.0 / rd.groupCount) * COALESCE(NULLIF(rd.referenceChance, 0), 1) AS reference_chance
|
(1.0 / rd.groupCount) * COALESCE(NULLIF(rd.referenceChance, 0), 1) AS reference_chance
|
||||||
FROM reference_data rd
|
FROM reference_data rd
|
||||||
JOIN item_template it ON it.entry = rd.itemID
|
JOIN item_template it ON it.entry = rd.itemID
|
||||||
WHERE it.class IN ({})
|
WHERE it.class IN ({})
|
||||||
AND it.quality >= {}
|
AND it.quality IN ({})
|
||||||
|
)
|
||||||
|
|
||||||
|
SELECT itemID,
|
||||||
|
0 AS direct_chance,
|
||||||
|
AVG(reference_chance) AS reference_chance
|
||||||
|
FROM chances
|
||||||
|
GROUP BY itemID
|
||||||
)SQL";
|
)SQL";
|
||||||
|
|
||||||
std::string groupDropString = R"SQL(
|
std::string groupDropString = R"SQL(
|
||||||
@@ -1238,7 +1314,7 @@ void AuctionHouseBot::PopulateItemDropChances()
|
|||||||
SELECT group_tables.*, COUNT(*) OVER (PARTITION BY loot_entry, group_id) AS item_count
|
SELECT group_tables.*, COUNT(*) OVER (PARTITION BY loot_entry, group_id) AS item_count
|
||||||
FROM group_tables
|
FROM group_tables
|
||||||
) compute_item_count
|
) compute_item_count
|
||||||
WHERE itemClass IN ({}) AND itemQuality >= {}
|
WHERE itemClass IN ({}) AND itemQuality IN ({})
|
||||||
)SQL";
|
)SQL";
|
||||||
|
|
||||||
std::string objectsDropString = R"SQL(
|
std::string objectsDropString = R"SQL(
|
||||||
@@ -1247,30 +1323,23 @@ void AuctionHouseBot::PopulateItemDropChances()
|
|||||||
0 AS reference_chance
|
0 AS reference_chance
|
||||||
FROM item_loot_template ilt
|
FROM item_loot_template ilt
|
||||||
JOIN item_template it ON it.entry = ilt.Item
|
JOIN item_template it ON it.entry = ilt.Item
|
||||||
WHERE it.class IN ({}) AND it.quality >= {} AND chance != 0
|
WHERE it.class IN ({}) AND it.quality IN ({}) AND chance != 0
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT it.entry AS itemID,
|
SELECT it.entry AS itemID,
|
||||||
golt.Chance AS direct_chance,
|
golt.Chance AS direct_chance,
|
||||||
0 AS reference_chance
|
0 AS reference_chance
|
||||||
FROM gameobject_loot_template golt
|
FROM gameobject_loot_template golt
|
||||||
JOIN item_template it ON it.entry = golt.Item
|
JOIN item_template it ON it.entry = golt.Item
|
||||||
WHERE it.class IN ({}) AND it.quality >= {} AND chance != 0
|
WHERE it.class IN ({}) AND it.quality IN ({}) AND chance != 0
|
||||||
)SQL";
|
)SQL";
|
||||||
|
|
||||||
std::string enabledCategories = GetAdvancedListingRuleUseDropRatesEnabledCategoriesString();
|
QueryResult directResult = WorldDatabase.Query(directDropString, category, qualities);
|
||||||
if (enabledCategories.empty())
|
QueryResult referenceResult = WorldDatabase.Query(referenceDropString, category, qualities);
|
||||||
{
|
QueryResult danglingReferenceResult = WorldDatabase.Query(danglingReferenceDropString, category, qualities);
|
||||||
LOG_ERROR("module", "AuctionHouseBot: No categories are enabled for AuctionHouseBot.Seller.AdvancedListingRules.UseDropRates");
|
QueryResult groupResult = WorldDatabase.Query(groupDropString, category, qualities);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QueryResult directResult = WorldDatabase.Query(directDropString, enabledCategories, AdvancedListingRuleUseDropRatesMinQuality);
|
|
||||||
QueryResult referenceResult = WorldDatabase.Query(referenceDropString, enabledCategories, AdvancedListingRuleUseDropRatesMinQuality);
|
|
||||||
QueryResult danglingReferenceResult = WorldDatabase.Query(danglingReferenceDropString, enabledCategories, AdvancedListingRuleUseDropRatesMinQuality);
|
|
||||||
QueryResult groupResult = WorldDatabase.Query(groupDropString, enabledCategories, AdvancedListingRuleUseDropRatesMinQuality);
|
|
||||||
QueryResult objectsDropResult = WorldDatabase.Query(objectsDropString,
|
QueryResult objectsDropResult = WorldDatabase.Query(objectsDropString,
|
||||||
enabledCategories, AdvancedListingRuleUseDropRatesMinQuality,
|
category, qualities,
|
||||||
enabledCategories, AdvancedListingRuleUseDropRatesMinQuality);
|
category, qualities);
|
||||||
if (!directResult || !referenceResult || !danglingReferenceResult || !groupResult || !objectsDropResult)
|
if (!directResult || !referenceResult || !danglingReferenceResult || !groupResult || !objectsDropResult)
|
||||||
{
|
{
|
||||||
LOG_ERROR("module", "AuctionHouseBot: PopulateItemDropChances() failed to query items' drop rates.");
|
LOG_ERROR("module", "AuctionHouseBot: PopulateItemDropChances() failed to query items' drop rates.");
|
||||||
@@ -1309,36 +1378,19 @@ void AuctionHouseBot::PopulateItemDropChances()
|
|||||||
parseResults(groupResult);
|
parseResults(groupResult);
|
||||||
parseResults(objectsDropResult);
|
parseResults(objectsDropResult);
|
||||||
|
|
||||||
// Process item candidates: filter invalid entries and group by drop rate tier
|
// Populate drop rates Tiers
|
||||||
for (auto& [classID, qualityGroups] : ItemCandidatesByItemClassAndQuality)
|
for (auto& [classID, qualityGroups] : ItemCandidatesByItemClassAndQuality)
|
||||||
{
|
{
|
||||||
for (auto& [qualityID, candidates] : qualityGroups)
|
for (auto& [qualityID, candidates] : qualityGroups)
|
||||||
{
|
{
|
||||||
// Erase items that are not crafted, not quest rewards, and missing DB drop rate
|
|
||||||
candidates.erase(
|
|
||||||
std::remove_if(
|
|
||||||
candidates.begin(),
|
|
||||||
candidates.end(),
|
|
||||||
[&](uint32 id)
|
|
||||||
{
|
|
||||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(id);
|
|
||||||
if (!IsItemEligibleForDBDropRates(proto))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
bool shouldErase = !IsItemCrafted(id)
|
|
||||||
&& !IsItemQuestReward(id)
|
|
||||||
&& !CachedItemDropRates.contains(id);
|
|
||||||
|
|
||||||
return shouldErase;
|
|
||||||
}),
|
|
||||||
candidates.end()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Now process the remaining valid items
|
|
||||||
for (uint32 id : candidates)
|
for (uint32 id : candidates)
|
||||||
{
|
{
|
||||||
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(id);
|
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(id);
|
||||||
if (!IsItemEligibleForDBDropRates(proto))
|
if (!IsItemCategoryQualityInDBDropRatesConfig(proto))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Skip items that haven't been populated yet.
|
||||||
|
if (!CachedItemDropRates.contains(id))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
double rate = CachedItemDropRates[id];
|
double rate = CachedItemDropRates[id];
|
||||||
@@ -1347,21 +1399,59 @@ void AuctionHouseBot::PopulateItemDropChances()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (debug_Out)
|
void AuctionHouseBot::InitializeAdvancedListingRuleUseDropRatesTiers()
|
||||||
|
{
|
||||||
|
// Re-initialize to reset
|
||||||
|
DropRatesToTierMap = std::map<double, int, std::greater<double>>();
|
||||||
|
ItemTiersByClassAndQuality = std::vector<std::vector<std::vector<std::vector<uint32>>>>(17); // 17 Categories
|
||||||
|
std::string tiersConfigString = sConfigMgr->GetOption<std::string>("AuctionHouseBot.AdvancedListingRules.UseDropRates.TiersConfig", "50,10,5,2,1,0.5,0.2,0.1,0.05,0.02,0.01,0.005");
|
||||||
|
|
||||||
|
// Parse tiers config, populate DropRate -> Tier map for later lookups
|
||||||
|
int curTier = 0;
|
||||||
|
std::string delimitedValue;
|
||||||
|
std::stringstream tiersConfigStream;
|
||||||
|
tiersConfigStream.str(tiersConfigString);
|
||||||
|
while (std::getline(tiersConfigStream, delimitedValue, ',')) // Process each tier in the string, delimited by the comma ","
|
||||||
{
|
{
|
||||||
// Show number of items in each tier
|
// Trim whitespace
|
||||||
for (int i = 0; i < 17; i++)
|
delimitedValue.erase(0, delimitedValue.find_first_not_of(" \t"));
|
||||||
for (int j = 0; j < 7; j++)
|
delimitedValue.erase(delimitedValue.find_last_not_of(" \t") + 1);
|
||||||
for (int k = 0; k < 10; k++)
|
|
||||||
{
|
if (delimitedValue.empty())
|
||||||
if (i == 2)
|
{
|
||||||
LOG_INFO("module", "Armor Count: Rarity {} Tier {} has {} items", j, k, ItemTiersByClassAndQuality[i][j][k].size());
|
LOG_ERROR("module", "AuctionHouseBot: Empty entry found in AuctionHouseBot.AdvancedListingRules.UseDropRates.TiersConfig: '{}'", tiersConfigString);
|
||||||
if (i == 4)
|
continue;
|
||||||
LOG_INFO("module", "Weapon Count: Rarity {} Tier {} has {} items", j, k, ItemTiersByClassAndQuality[i][j][k].size());
|
}
|
||||||
if (i == 9)
|
|
||||||
LOG_INFO("module", "Recipe Count: Rarity {} Tier {} has {} items", j, k, ItemTiersByClassAndQuality[i][j][k].size());
|
double rate = std::stod(delimitedValue);
|
||||||
}
|
if (rate <= 0.0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("module", "AuctionHouseBot: Invalid (non-positive) drop rate '{}' in AuctionHouseBot.AdvancedListingRules.UseDropRates.TiersConfig: '{}'", delimitedValue, tiersConfigString);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for duplicates
|
||||||
|
if (DropRatesToTierMap.contains(rate))
|
||||||
|
{
|
||||||
|
LOG_ERROR("module", "AuctionHouseBot: Duplicate drop rate '{}' found in AuctionHouseBot.AdvancedListingRules.UseDropRates.TiersConfig: '{}'", rate, tiersConfigString);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DropRatesToTierMap[rate] = curTier;
|
||||||
|
curTier++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DropRatesToTierMap.empty())
|
||||||
|
LOG_ERROR("module", "AuctionHouseBot: Failed to parse any valid drop rates from AuctionHouseBot.AdvancedListingRules.UseDropRates.TiersConfig: '{}'", tiersConfigString);
|
||||||
|
|
||||||
|
// Resize ItemTiersByClassAndQuality by tier count
|
||||||
|
for (auto& qualities : ItemTiersByClassAndQuality)
|
||||||
|
{
|
||||||
|
qualities.resize(7); // 7 Qualities
|
||||||
|
for (auto& tiers : qualities)
|
||||||
|
tiers.resize(DropRatesToTierMap.size() + 1); // Create an extra "catch-all" bucket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1404,17 +1494,16 @@ void AuctionHouseBot::PopulateQuestRewardItemIDs()
|
|||||||
|
|
||||||
int AuctionHouseBot::GetItemDropChanceTier(double dropRate)
|
int AuctionHouseBot::GetItemDropChanceTier(double dropRate)
|
||||||
{
|
{
|
||||||
if (dropRate > 10) return 0;
|
for(const auto& pair : DropRatesToTierMap)
|
||||||
else if (dropRate > 5) return 1;
|
{
|
||||||
else if (dropRate > 2) return 2;
|
double mapDropRate = pair.first;
|
||||||
else if (dropRate > 1) return 3;
|
int mapTier = pair.second;
|
||||||
else if (dropRate > 0.5) return 4;
|
if (dropRate >= mapDropRate)
|
||||||
else if (dropRate > 0.2) return 5;
|
return mapTier;
|
||||||
else if (dropRate > 0.1) return 6;
|
}
|
||||||
else if (dropRate > 0.05) return 7;
|
|
||||||
else if (dropRate > 0.02) return 8;
|
// If dropRate is lower than smallest configured tier, return "catch-all" bucket index
|
||||||
else if (dropRate > 0.01) return 9;
|
return DropRatesToTierMap.size();
|
||||||
else return 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuctionHouseBot::AddNewAuctionBuyerBotBid(std::vector<Player*> AHBPlayers, FactionSpecificAuctionHouseConfig *config)
|
void AuctionHouseBot::AddNewAuctionBuyerBotBid(std::vector<Player*> AHBPlayers, FactionSpecificAuctionHouseConfig *config)
|
||||||
@@ -1726,7 +1815,11 @@ void AuctionHouseBot::InitializeConfiguration()
|
|||||||
AdvancedListingRuleUseDropRatesWeaponEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Weapon", true);
|
AdvancedListingRuleUseDropRatesWeaponEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Weapon", true);
|
||||||
AdvancedListingRuleUseDropRatesArmorEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Armor", true);
|
AdvancedListingRuleUseDropRatesArmorEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Armor", true);
|
||||||
AdvancedListingRuleUseDropRatesRecipeEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Recipe", true);
|
AdvancedListingRuleUseDropRatesRecipeEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Recipe", true);
|
||||||
AdvancedListingRuleUseDropRatesMinQuality = sConfigMgr->GetOption<int>("AuctionHouseBot.AdvancedListingRules.UseDropRates.MinQuality", 3);
|
ParseNumberListToSet(AdvancedListingRuleUseDropRatesWeaponAffectedQualities, sConfigMgr->GetOption<std::string>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Weapon.AffectedQualities", "2,3,4,5"), "");
|
||||||
|
ParseNumberListToSet(AdvancedListingRuleUseDropRatesArmorAffectedQualities, sConfigMgr->GetOption<std::string>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Armor.AffectedQualities", "2,3,4,5"), "");
|
||||||
|
ParseNumberListToSet(AdvancedListingRuleUseDropRatesRecipeAffectedQualities, sConfigMgr->GetOption<std::string>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Recipe.AffectedQualities", "2,3,4,5"), "");
|
||||||
|
AdvancedListingRuleUseDropRatesExceptionItems.clear();
|
||||||
|
ParseNumberListToSet(AdvancedListingRuleUseDropRatesExceptionItems, sConfigMgr->GetOption<std::string>("AuctionHouseBot.AdvancedListingRules.UseDropRates.DisabledItemIDs", ""), "AdvancedListingRules.UseDropRates.DisabledItemIDs");
|
||||||
MaxBuyoutPriceInCopper = sConfigMgr->GetOption<uint32>("AuctionHouseBot.MaxBuyoutPriceInCopper", 1000000000);
|
MaxBuyoutPriceInCopper = sConfigMgr->GetOption<uint32>("AuctionHouseBot.MaxBuyoutPriceInCopper", 1000000000);
|
||||||
BuyoutVariationReducePercent = sConfigMgr->GetOption<float>("AuctionHouseBot.BuyoutVariationReducePercent", 0.15f);
|
BuyoutVariationReducePercent = sConfigMgr->GetOption<float>("AuctionHouseBot.BuyoutVariationReducePercent", 0.15f);
|
||||||
BuyoutVariationAddPercent = sConfigMgr->GetOption<float>("AuctionHouseBot.BuyoutVariationAddPercent", 0.25f);
|
BuyoutVariationAddPercent = sConfigMgr->GetOption<float>("AuctionHouseBot.BuyoutVariationAddPercent", 0.25f);
|
||||||
@@ -1915,21 +2008,21 @@ void AuctionHouseBot::InitializeConfiguration()
|
|||||||
ListedItemLevelMin = sConfigMgr->GetOption("AuctionHouseBot.ListedItemLevelRestrict.MinItemLevel", 0);
|
ListedItemLevelMin = sConfigMgr->GetOption("AuctionHouseBot.ListedItemLevelRestrict.MinItemLevel", 0);
|
||||||
ListedItemLevelMax = sConfigMgr->GetOption("AuctionHouseBot.ListedItemLevelRestrict.MaxItemLevel", 999);
|
ListedItemLevelMax = sConfigMgr->GetOption("AuctionHouseBot.ListedItemLevelRestrict.MaxItemLevel", 999);
|
||||||
ListedItemLevelExceptionItems.clear();
|
ListedItemLevelExceptionItems.clear();
|
||||||
AddItemIDsFromString(ListedItemLevelExceptionItems, sConfigMgr->GetOption<std::string>("AuctionHouseBot.ListedItemLevelRestrict.ExceptionItemIDs", ""), "ListedItemLevelRestrict.ExceptionItemIDs");
|
ParseNumberListToSet(ListedItemLevelExceptionItems, sConfigMgr->GetOption<std::string>("AuctionHouseBot.ListedItemLevelRestrict.ExceptionItemIDs", ""), "ListedItemLevelRestrict.ExceptionItemIDs");
|
||||||
|
|
||||||
// Item ID Restrictions
|
// Item ID Restrictions
|
||||||
ListedItemIDRestrictedEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.ListedItemIDRestrict.Enabled", false);
|
ListedItemIDRestrictedEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.ListedItemIDRestrict.Enabled", false);
|
||||||
ListedItemIDMin = sConfigMgr->GetOption("AuctionHouseBot.ListedItemIDRestrict.MinItemID", 0);
|
ListedItemIDMin = sConfigMgr->GetOption("AuctionHouseBot.ListedItemIDRestrict.MinItemID", 0);
|
||||||
ListedItemIDMax = sConfigMgr->GetOption("AuctionHouseBot.ListedItemIDRestrict.MaxItemID", 200000);
|
ListedItemIDMax = sConfigMgr->GetOption("AuctionHouseBot.ListedItemIDRestrict.MaxItemID", 200000);
|
||||||
ListedItemIDExceptionItems.clear();
|
ListedItemIDExceptionItems.clear();
|
||||||
AddItemIDsFromString(ListedItemIDExceptionItems, sConfigMgr->GetOption<std::string>("AuctionHouseBot.ListedItemIDRestrict.ExceptionItemIDs", ""), "ListedItemIDRestrict.ExceptionItemIDs");
|
ParseNumberListToSet(ListedItemIDExceptionItems, sConfigMgr->GetOption<std::string>("AuctionHouseBot.ListedItemIDRestrict.ExceptionItemIDs", ""), "ListedItemIDRestrict.ExceptionItemIDs");
|
||||||
|
|
||||||
// Disabled Items
|
// Disabled Items
|
||||||
DisabledItemTextFilter = sConfigMgr->GetOption<bool>("AuctionHouseBot.DisabledItemTextFilter", true);
|
DisabledItemTextFilter = sConfigMgr->GetOption<bool>("AuctionHouseBot.DisabledItemTextFilter", true);
|
||||||
DisabledRecipeProducedItemFilterEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.DisabledRecipeProducedItemFilterEnabled", false);
|
DisabledRecipeProducedItemFilterEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.DisabledRecipeProducedItemFilterEnabled", false);
|
||||||
DisabledItems.clear();
|
DisabledItems.clear();
|
||||||
AddItemIDsFromString(DisabledItems, sConfigMgr->GetOption<std::string>("AuctionHouseBot.DisabledInvalidItemIDs", ""), "AuctionHouseBot.DisabledInvalidItemIDs");
|
ParseNumberListToSet(DisabledItems, sConfigMgr->GetOption<std::string>("AuctionHouseBot.DisabledInvalidItemIDs", ""), "AuctionHouseBot.DisabledInvalidItemIDs");
|
||||||
AddItemIDsFromString(DisabledItems, sConfigMgr->GetOption<std::string>("AuctionHouseBot.DisabledCustomItemIDs", ""), "AuctionHouseBot.DisabledCustomItemIDs");
|
ParseNumberListToSet(DisabledItems, sConfigMgr->GetOption<std::string>("AuctionHouseBot.DisabledCustomItemIDs", ""), "AuctionHouseBot.DisabledCustomItemIDs");
|
||||||
AddValuesToSetByKeyMap(DisabledRecipeProducedItemClassSubClasses, sConfigMgr->GetOption<std::string>("AuctionHouseBot.DisabledRecipeProducedItemClassSubClasses", ""), 0, 20);
|
AddValuesToSetByKeyMap(DisabledRecipeProducedItemClassSubClasses, sConfigMgr->GetOption<std::string>("AuctionHouseBot.DisabledRecipeProducedItemClassSubClasses", ""), 0, 20);
|
||||||
|
|
||||||
if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
|
if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_AUCTION))
|
||||||
@@ -2193,7 +2286,7 @@ void AuctionHouseBot::AddValuesToSetByKeyMap(std::map<uint32, std::unordered_set
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuctionHouseBot::AddItemIDsFromString(std::set<uint32>& workingItemIDSet, std::string itemString, const char* parentOperationName)
|
void AuctionHouseBot::ParseNumberListToSet(std::set<uint32>& workingItemIDSet, std::string itemString, const char* parentOperationName)
|
||||||
{
|
{
|
||||||
std::string delimitedValue;
|
std::string delimitedValue;
|
||||||
std::stringstream itemIdStream;
|
std::stringstream itemIdStream;
|
||||||
@@ -2201,6 +2294,10 @@ void AuctionHouseBot::AddItemIDsFromString(std::set<uint32>& workingItemIDSet, s
|
|||||||
itemIdStream.str(itemString);
|
itemIdStream.str(itemString);
|
||||||
while (std::getline(itemIdStream, delimitedValue, ',')) // Process each item ID in the string, delimited by the comma ","
|
while (std::getline(itemIdStream, delimitedValue, ',')) // Process each item ID in the string, delimited by the comma ","
|
||||||
{
|
{
|
||||||
|
// Trim whitespace
|
||||||
|
delimitedValue.erase(0, delimitedValue.find_first_not_of(" \t"));
|
||||||
|
delimitedValue.erase(delimitedValue.find_last_not_of(" \t") + 1);
|
||||||
|
|
||||||
std::string valueOne;
|
std::string valueOne;
|
||||||
std::stringstream itemPairStream(delimitedValue);
|
std::stringstream itemPairStream(delimitedValue);
|
||||||
itemPairStream >> valueOne;
|
itemPairStream >> valueOne;
|
||||||
@@ -2221,18 +2318,18 @@ void AuctionHouseBot::AddItemIDsFromString(std::set<uint32>& workingItemIDSet, s
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int32 i = leftId; i <= rightId; ++i)
|
for (int32 i = leftId; i <= rightId; ++i)
|
||||||
AddToItemIDSet(workingItemIDSet, i, parentOperationName);
|
AddToNumberListSet(workingItemIDSet, i, parentOperationName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto itemId = atoi(valueOne.c_str());
|
auto itemId = atoi(valueOne.c_str());
|
||||||
AddToItemIDSet(workingItemIDSet, itemId, parentOperationName);
|
AddToNumberListSet(workingItemIDSet, itemId, parentOperationName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuctionHouseBot::AddToItemIDSet(std::set<uint32>& workingItemIDSet, uint32 itemID, const char* parentOperationName)
|
void AuctionHouseBot::AddToNumberListSet(std::set<uint32>& workingItemIDSet, uint32 itemID, const char* parentOperationName)
|
||||||
{
|
{
|
||||||
if (workingItemIDSet.find(itemID) != workingItemIDSet.end())
|
if (workingItemIDSet.find(itemID) != workingItemIDSet.end())
|
||||||
{
|
{
|
||||||
@@ -2347,23 +2444,41 @@ bool AuctionHouseBot::IsItemCrafted(uint32 itemID)
|
|||||||
return (ItemIDsProducedByRecipes.find(itemID) != ItemIDsProducedByRecipes.end());
|
return (ItemIDsProducedByRecipes.find(itemID) != ItemIDsProducedByRecipes.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AuctionHouseBot::IsItemEligibleForDBDropRates(ItemTemplate const* proto)
|
bool AuctionHouseBot::IsItemCategoryQualityInDBDropRatesConfig(ItemTemplate const* proto)
|
||||||
{
|
{
|
||||||
if (!AdvancedListingRuleUseDropRatesEnabled)
|
if (!proto)
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!proto || proto->Quality < AdvancedListingRuleUseDropRatesMinQuality)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch (proto->Class)
|
switch (proto->Class)
|
||||||
{
|
{
|
||||||
case ITEM_CLASS_WEAPON:
|
case ITEM_CLASS_WEAPON:
|
||||||
return AdvancedListingRuleUseDropRatesWeaponEnabled;
|
return (AdvancedListingRuleUseDropRatesWeaponEnabled &&
|
||||||
|
AdvancedListingRuleUseDropRatesWeaponAffectedQualities.contains(proto->Quality));
|
||||||
case ITEM_CLASS_ARMOR:
|
case ITEM_CLASS_ARMOR:
|
||||||
return AdvancedListingRuleUseDropRatesArmorEnabled;
|
return (AdvancedListingRuleUseDropRatesArmorEnabled &&
|
||||||
|
AdvancedListingRuleUseDropRatesArmorAffectedQualities.contains(proto->Quality));
|
||||||
case ITEM_CLASS_RECIPE:
|
case ITEM_CLASS_RECIPE:
|
||||||
return AdvancedListingRuleUseDropRatesRecipeEnabled;
|
return (AdvancedListingRuleUseDropRatesRecipeEnabled &&
|
||||||
|
AdvancedListingRuleUseDropRatesRecipeAffectedQualities.contains(proto->Quality));
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AuctionHouseBot::IsItemEligibleForDBDropRates(ItemTemplate const* proto)
|
||||||
|
{
|
||||||
|
if (!proto || !AdvancedListingRuleUseDropRatesEnabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Only continue if the itemID isn't an exception
|
||||||
|
if (AdvancedListingRuleUseDropRatesExceptionItems.find(proto->ItemId) != AdvancedListingRuleUseDropRatesExceptionItems.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If feature enabled, && item category/quality enabled
|
||||||
|
// && is not crafted, && is not a quest reward
|
||||||
|
return (AdvancedListingRuleUseDropRatesEnabled &&
|
||||||
|
IsItemCategoryQualityInDBDropRatesConfig(proto) &&
|
||||||
|
!IsItemCrafted(proto->ItemId) &&
|
||||||
|
!IsItemQuestReward(proto->ItemId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -279,12 +279,16 @@ private:
|
|||||||
std::set<uint32> ListedItemIDExceptionItems;
|
std::set<uint32> ListedItemIDExceptionItems;
|
||||||
bool PreventOverpayingForVendorItems;
|
bool PreventOverpayingForVendorItems;
|
||||||
std::unordered_map<uint32, double> CachedItemDropRates;
|
std::unordered_map<uint32, double> CachedItemDropRates;
|
||||||
std::vector<uint32> ItemTiersByClassAndQuality[17][7][11]; // [Classes][Qualities][Tiers]
|
std::vector<std::vector<std::vector<std::vector<uint32>>>> ItemTiersByClassAndQuality; // [Classes][Qualities][Tiers] .. [17][7][configurable]
|
||||||
|
std::map<double, int, std::greater<double>> DropRatesToTierMap;
|
||||||
|
std::set<uint32> AdvancedListingRuleUseDropRatesExceptionItems;
|
||||||
bool AdvancedListingRuleUseDropRatesEnabled;
|
bool AdvancedListingRuleUseDropRatesEnabled;
|
||||||
bool AdvancedListingRuleUseDropRatesWeaponEnabled;
|
bool AdvancedListingRuleUseDropRatesWeaponEnabled;
|
||||||
bool AdvancedListingRuleUseDropRatesArmorEnabled;
|
bool AdvancedListingRuleUseDropRatesArmorEnabled;
|
||||||
bool AdvancedListingRuleUseDropRatesRecipeEnabled;
|
bool AdvancedListingRuleUseDropRatesRecipeEnabled;
|
||||||
int AdvancedListingRuleUseDropRatesMinQuality;
|
std::set<uint32> AdvancedListingRuleUseDropRatesWeaponAffectedQualities;
|
||||||
|
std::set<uint32> AdvancedListingRuleUseDropRatesArmorAffectedQualities;
|
||||||
|
std::set<uint32> AdvancedListingRuleUseDropRatesRecipeAffectedQualities;
|
||||||
std::unordered_set<uint32> QuestRewardItemIDs;
|
std::unordered_set<uint32> QuestRewardItemIDs;
|
||||||
|
|
||||||
FactionSpecificAuctionHouseConfig AllianceConfig;
|
FactionSpecificAuctionHouseConfig AllianceConfig;
|
||||||
@@ -316,18 +320,21 @@ public:
|
|||||||
void SetBuyingBotBuyCandidatesPerBuyCycle();
|
void SetBuyingBotBuyCandidatesPerBuyCycle();
|
||||||
void GetConfigMinAndMax(std::string config, uint32& min, uint32& max);
|
void GetConfigMinAndMax(std::string config, uint32& min, uint32& max);
|
||||||
void AddCharacters(std::string characterGUIDString);
|
void AddCharacters(std::string characterGUIDString);
|
||||||
void AddItemIDsFromString(std::set<uint32>& workingItemIDSet, std::string itemString, const char* parentOperationName);
|
void ParseNumberListToSet(std::set<uint32>& workingItemIDSet, std::string itemString, const char* parentOperationName);
|
||||||
void AddToItemIDSet(std::set<uint32>& workingItemIDSet, uint32 itemID, const char* parentOperationName);
|
void AddToNumberListSet(std::set<uint32>& workingItemIDSet, uint32 itemID, const char* parentOperationName);
|
||||||
const char* GetQualityName(ItemQualities quality);
|
const char* GetQualityName(ItemQualities quality);
|
||||||
const char* GetCategoryName(ItemClass category);
|
const char* GetCategoryName(ItemClass category);
|
||||||
uint32 GetStackSizeForItem(ItemTemplate const* itemProto) const;
|
uint32 GetStackSizeForItem(ItemTemplate const* itemProto) const;
|
||||||
void CalculateItemValue(ItemTemplate const* itemProto, uint64& outBidPrice, uint64& outBuyoutPrice);
|
void CalculateItemValue(ItemTemplate const* itemProto, uint64& outBidPrice, uint64& outBuyoutPrice);
|
||||||
void PopulateItemDropChances();
|
void PopulateItemDropChances();
|
||||||
std::string GetAdvancedListingRuleUseDropRatesEnabledCategoriesString();
|
void PopulateItemDropChancesForCategoryAndQuality(ItemClass category, std::string qualities);
|
||||||
|
void InitializeAdvancedListingRuleUseDropRatesTiers();
|
||||||
void PopulateQuestRewardItemIDs();
|
void PopulateQuestRewardItemIDs();
|
||||||
bool IsItemQuestReward(uint32 itemID);
|
bool IsItemQuestReward(uint32 itemID);
|
||||||
bool IsItemCrafted(uint32 itemID);
|
bool IsItemCrafted(uint32 itemID);
|
||||||
|
bool IsItemCategoryQualityInDBDropRatesConfig(ItemTemplate const* proto);
|
||||||
bool IsItemEligibleForDBDropRates(ItemTemplate const* proto);
|
bool IsItemEligibleForDBDropRates(ItemTemplate const* proto);
|
||||||
|
bool HandleAdvancedListingRuleUseDropRates(ItemTemplate const*& proto);
|
||||||
int GetItemDropChanceTier(double dropRate);
|
int GetItemDropChanceTier(double dropRate);
|
||||||
float GetAdvancedPricingMultiplier(ItemTemplate const* itemProto);
|
float GetAdvancedPricingMultiplier(ItemTemplate const* itemProto);
|
||||||
ItemTemplate const* GetProducedItemFromRecipe(ItemTemplate const* recipeItemTemplate);
|
ItemTemplate const* GetProducedItemFromRecipe(ItemTemplate const* recipeItemTemplate);
|
||||||
|
|||||||
@@ -181,6 +181,15 @@ public:
|
|||||||
sConfigMgr->LoadModulesConfigs(true, false);
|
sConfigMgr->LoadModulesConfigs(true, false);
|
||||||
AuctionHouseBot::instance()->InitializeConfiguration();
|
AuctionHouseBot::instance()->InitializeConfiguration();
|
||||||
AuctionHouseBot::instance()->PopulateItemCandidatesAndProportions();
|
AuctionHouseBot::instance()->PopulateItemCandidatesAndProportions();
|
||||||
|
|
||||||
|
if (sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Enabled", true))
|
||||||
|
{
|
||||||
|
auctionbot->PopulateQuestRewardItemIDs();
|
||||||
|
auctionbot->PopulateItemDropChances();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("module", "AuctionHouseBot: Config reloaded.");
|
||||||
|
handler->PSendSysMessage("AuctionHouseBot: Config reloaded.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user