Compare commits

...

21 Commits

Author SHA1 Message Date
Nathan Handley
5561885b8b Merge pull request #49 from zeb139/issue-47
Fixed handling of null UseDropRates.<Category>.AffectedQualities configs. Improved module disablement
2025-11-11 22:01:32 -06:00
zeb
41fd346a6e improved module disablement when AuctionHouseBot.GUIDs is not configured 2025-11-11 22:33:33 -05:00
zeb
8038fec2db fixed handling of null UseDropRates.<Category>.AffectedQualities configs 2025-11-11 22:22:29 -05:00
Nathan Handley
7db32506d2 Update README.md 2025-11-11 18:09:35 -06:00
Nathan Handley
a2f55d3df0 Merge pull request #48 from zeb139/issue-46
Added mod-ah-bot backwards compatible script loader
2025-11-11 18:07:05 -06:00
zeb
c2e3be9e57 added mod-ah-bot backwards compatible script loader 2025-11-11 19:03:31 -05:00
Nathan Handley
a3385f09be Update README.md 2025-11-11 17:19:04 -06:00
Nathan Handley
d5ad1f9020 Add note about repository rename 2025-11-09 15:33:26 -06:00
Nathan Handley
d197c00963 Merge pull request #45 from zeb139/master
Fix build error: undefined reference to `Addmod_ah_bot_plusScripts()'
2025-11-09 15:10:07 -06:00
zeb
4863229bb6 fixed new name build error 2025-11-09 15:26:48 -05:00
Nathan Handley
c35954cc21 Update README.md 2025-11-09 07:18:48 -06:00
Nathan Handley
6fd491277a Remove old text block about professions 2025-11-09 07:13:16 -06:00
Nathan Handley
43e82355b4 Clarify comments on exclusion 2025-11-08 23:44:04 -06:00
Nathan Handley
1df870435a Merge pull request #44 from zeb139/issue-43
Improved logging for some cases of ParseNumberListToSet, Fixed erroneous duplicate entries error logging
2025-11-07 19:47:45 -06:00
zeb
cd2d0146bb improved logging for some cases of ParseNumberListToSet, fixed erroneous duplicate entries error logging 2025-11-07 14:23:54 -05:00
Nathan Handley
f326bee515 Merge pull request #41 from zeb139/development
Add Advanced_Pricing_Calculator spreadsheet tool
2025-10-25 15:10:31 -05:00
zeb
8079160ef5 added Advanced_Pricing_Calculator spreadsheet tool 2025-10-24 14:00:23 -04:00
Nathan Handley
b6a7c651c5 Merge pull request #40 from zeb139/development
Improved UseDropRates item selection logic, Removed duplicates from ItemTiersByClassAndQuality
2025-10-17 19:29:13 -05:00
zeb
f935be7b88 improved UseDropRates item selection logic, removed duplicates from ItemTiersByClassAndQuality 2025-10-15 11:53:45 -04:00
Nathan Handley
6c4195b102 Merge pull request #39 from zeb139/add-usedroprates-minrate
Added UseDropRates.MinDropRate + other fixes
2025-10-14 08:53:26 -05:00
zeb
00e1fe1988 Added UseDropRates.MinDropRate 2025-10-14 08:28:43 -04:00
8 changed files with 128 additions and 38 deletions

View File

@@ -1,4 +1,4 @@
## Description
## Auction Bot Plus
This is a fork of the auction house bot for AzerothCore. This fork gives a much more blizzlike experience in the offerings on the auction house, and it is built with the following ethos: "Maximum understandable customization in the hands of admins via non-SQL configurations". Here are some of the feature highlights:
- All configuration is done via config files, with no SQL configuration needed
@@ -27,7 +27,6 @@ Requires an AzerothCore version that is caught up to at least change set 3f46e05
Notes:
- These accounts do not need any security level and can be a player accounts.
- The characters used by the ahbot are 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.
- 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. This can be reduced via the configuration if you want.
@@ -51,6 +50,12 @@ The AuctionHouseBot module adds the following in-game commands (for GMs only):
The above behavior is replicated on each enabled auction house. If left to default settings, 1 item in each auction house will attempt to be bought from, if the price calculation seems favorable. Note that any item buy attempt, even items above buying price, consumes a buy candidate. That means that too many overpriced items can drown out potential sales.
## Additional Resources
[Advanced Pricing Calculator](tools/AdvancedPricingCalculator/Advanced_Pricing_Calculator.xlsx) - If `AuctionHouseBot.AdvancedPricing.<Category>.<Subclass>.Enabled` is enabled, this spreadsheet can help quickly visualize how config settings affect in-game prices.
## Credits
- NathanHandley: Created this rewrite of the one that was ported to AzerothCore

View File

@@ -94,7 +94,7 @@ AuctionHouseBot.ListingExpireTimeInSecondsMax = 86400
# Crafted items may also appear more often since their drop rate is effectively 100%.
# Default: false (disabled)
#
# AuctionHouseBot.Seller.AdvancedListingRules.UseDropRates.<Category>
# AuctionHouseBot.AdvancedListingRules.UseDropRates.<Category>
# Toggle AdvancedListingRules.UseDropRates behavior for individual category.
# Only applied if AdvancedListingRules.UseDropRates.Enabled is true.
# Default: true (enabled)
@@ -107,6 +107,12 @@ AuctionHouseBot.ListingExpireTimeInSecondsMax = 86400
# (0) Poor, (1) Common, (2) Uncommon, (3) Rare, (4) Epic, (5) Legendary, (6) Heirloom
# Default: 2,3,4,5
#
# AuctionHouseBot.AdvancedListingRules.UseDropRates.MinDropRate
# The minimum drop rate any affected item can have.
# Some items can have extremely low drop rates in the DB (e.g. 0.00006), so
# this setting will raise those items' drop rate to this value.
# Default: 0.005
#
# 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.
@@ -135,6 +141,7 @@ AuctionHouseBot.AdvancedListingRules.UseDropRates.Weapon.AffectedQualities = 2,3
AuctionHouseBot.AdvancedListingRules.UseDropRates.Armor.AffectedQualities = 2,3,4,5
AuctionHouseBot.AdvancedListingRules.UseDropRates.Recipe.AffectedQualities = 2,3,4,5
AuctionHouseBot.AdvancedListingRules.UseDropRates.MinDropRate = 0.005
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 =
@@ -187,6 +194,9 @@ AuctionHouseBot.BuyoutBelowVendorVariationAddPercent = 0.25
# AuctionHouseBot.<faction>.MinItems
# AuctionHouseBot.<faction>.MaxItems
# The minimum and maximum number of items to post on that auction house
# Note: If you have AllowTwoSide.Interaction.Auction enabled in your AzerothCore's
# worldserver.conf, then only the Neutral AH will appear to fill in the
# database. Auctions will still appear in non-Neutral AH.
# Default: 15000 for both
###############################################################################
@@ -497,8 +507,11 @@ AuctionHouseBot.PriceMinimumCenterBase.OverrideItems =
# model their prices alongside more predictable items - their prices
# may be considered "low".
#
# Note that the AdvancedPricing logic also relies on values
# set by AuctionHouseBot.PriceMultiplier.Category*.Quality*
# Consider using the Advanced_Pricing_Calculator spreadsheet included
# in the "tools" folder of this module for help with changing config settings.
#
# Note that the AdvancedPricing logic also relies on values
# set by AuctionHouseBot.PriceMultiplier.Category*.Quality*
# Defaults: true (Enabled)
#
# Note that all price multpliers (along with the advanced pricing) are applied
@@ -869,8 +882,9 @@ AuctionHouseBot.ListingStack.RandomStackIncrement.Glyph = 1
# Comma separated list of itemIDs to exclude from any item level restriction logic
# Ranges using a dash (-) can also be used
# NOTE: Other filtering will still be honored even if it's listed here
# Example: "100,150-200" would cause item level 100, and all item levels
# between 150 and 200 (inclusively) to not be subjected to this restriction.
# Example: "2589,3200-3202" would cause Linen Cloth (2589), Burnt Leather Bracers (3200),
# Barbarian War Axe (3201), and Forest Leather Bracers (3202) to not
# be subjected to this restriction
###############################################################################
AuctionHouseBot.ListedItemLevelRestrict.Enabled = false

View File

@@ -161,6 +161,7 @@ AuctionHouseBot::AuctionHouseBot() :
AdvancedListingRuleUseDropRatesWeaponEnabled(true),
AdvancedListingRuleUseDropRatesArmorEnabled(true),
AdvancedListingRuleUseDropRatesRecipeEnabled(true),
AdvancedListingRuleUseDropRatesMinDropRate(0.005),
LastBuyCycleCount(0),
LastSellCycleCount(0),
ActiveListMultipleItemID(0),
@@ -1100,10 +1101,10 @@ bool AuctionHouseBot::HandleAdvancedListingRuleUseDropRates(ItemTemplate const*&
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
// If chosen tier is empty, search more common tiers until not empty
auto& tierBuckets = ItemTiersByClassAndQuality[proto->Class][proto->Quality];
while (tierBuckets[tier].empty() && tier < 10) {
tier++;
while (tierBuckets[tier].empty() && tier > 0) {
tier--;
}
// Pull a random item from selected rarity tier
@@ -1196,11 +1197,11 @@ void AuctionHouseBot::PopulateItemDropChances()
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)
if (i == ITEM_CLASS_WEAPON)
LOG_INFO("module", "Weapon Count: {} Tier {} has {} items", GetQualityName((ItemQualities)j), k, items.size());
if (i == 9)
if (i == ITEM_CLASS_ARMOR)
LOG_INFO("module", "Armor Count: {} Tier {} has {} items", GetQualityName((ItemQualities)j), k, items.size());
if (i == ITEM_CLASS_RECIPE)
LOG_INFO("module", "Recipe Count: {} Tier {} has {} items", GetQualityName((ItemQualities)j), k, items.size());
}
}
@@ -1210,6 +1211,14 @@ void AuctionHouseBot::PopulateItemDropChances()
void AuctionHouseBot::PopulateItemDropChancesForCategoryAndQuality(ItemClass category, std::string qualities)
{
if (qualities.empty())
{
LOG_ERROR("module", "AuctionHouseBot: PopulateItemDropChancesForCategoryAndQuality() qualities are not set. "
"Verify that mod_ahbot.conf has values for AdvancedListingRules.UseDropRates.<Category>.AffectedQualities. "
"Defaulting to '2,3,4,5' to prevent crash.");
qualities = "2,3,4,5";
}
// Search creature loot templates, referenced loot_loot_template, group_loot tables, and object_loot tables for items' drop rates
std::string directDropString = R"SQL(
with chances AS (
@@ -1292,7 +1301,7 @@ void AuctionHouseBot::PopulateItemDropChancesForCategoryAndQuality(ItemClass cat
SELECT itemID,
0 AS direct_chance,
AVG(reference_chance) AS reference_chance
MIN(reference_chance) AS reference_chance
FROM chances
GROUP BY itemID
)SQL";
@@ -1347,7 +1356,7 @@ void AuctionHouseBot::PopulateItemDropChancesForCategoryAndQuality(ItemClass cat
}
// Add drop rate of all results to CachedItemDropRates
auto parseResults = [this](QueryResult result)
auto parseResults = [this](QueryResult result, bool overwriteDropRate)
{
do {
Field* fields = result->Fetch();
@@ -1359,12 +1368,17 @@ void AuctionHouseBot::PopulateItemDropChancesForCategoryAndQuality(ItemClass cat
if (IsItemQuestReward(itemID) || IsItemCrafted(itemID))
continue;
if (CachedItemDropRates.contains(itemID) && !overwriteDropRate)
continue;
if (!fields[1].IsNull())
directDropChance = fields[1].Get<double>();
if (!fields[2].IsNull())
referenceDropChance = fields[2].Get<double>();
// Choose higher of two rates (one is normally 0), then raise to MinDropRate if less than
double higherDropChance = (directDropChance > referenceDropChance) ? directDropChance : referenceDropChance;
higherDropChance = (higherDropChance < AdvancedListingRuleUseDropRatesMinDropRate) ? AdvancedListingRuleUseDropRatesMinDropRate : higherDropChance;
if (CachedItemDropRates[itemID] < higherDropChance)
CachedItemDropRates[itemID] = higherDropChance;
@@ -1372,11 +1386,11 @@ void AuctionHouseBot::PopulateItemDropChancesForCategoryAndQuality(ItemClass cat
} while (result->NextRow());
};
parseResults(directResult);
parseResults(referenceResult);
parseResults(danglingReferenceResult);
parseResults(groupResult);
parseResults(objectsDropResult);
parseResults(directResult, true);
parseResults(referenceResult, true);
parseResults(danglingReferenceResult, false);
parseResults(groupResult, true);
parseResults(objectsDropResult, true);
// Populate drop rates Tiers
for (auto& [classID, qualityGroups] : ItemCandidatesByItemClassAndQuality)
@@ -1399,6 +1413,14 @@ void AuctionHouseBot::PopulateItemDropChancesForCategoryAndQuality(ItemClass cat
}
}
}
// Remove duplicates
for (auto& byClass : ItemTiersByClassAndQuality)
for (auto& byQuality : byClass)
for (auto& byTier : byQuality) {
std::sort(byTier.begin(), byTier.end());
byTier.erase(std::unique(byTier.begin(), byTier.end()), byTier.end());
}
}
void AuctionHouseBot::InitializeAdvancedListingRuleUseDropRatesTiers()
@@ -1706,8 +1728,6 @@ void AuctionHouseBot::Update()
if (AHCharacters.empty() == true)
return;
CleanupExpiredAuctionItems();
if ((SellingBotEnabled == false) && (BuyingBotEnabled == false))
return;
@@ -1787,24 +1807,30 @@ void AuctionHouseBot::Update()
ObjectAccessor::RemoveObject(player.get());
}
bool AuctionHouseBot::IsModuleEnabled()
{
bool sellerEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.EnableSeller", false);
bool buyerEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.Buyer.Enabled", false);
if (sellerEnabled == false && buyerEnabled == false)
return false;
string charString = sConfigMgr->GetOption<std::string>("AuctionHouseBot.GUIDs", "0");
if (charString == "0" || charString.empty())
{
LOG_INFO("module", "AuctionHouseBot: AuctionHouseBot.GUIDs is not configured so this module will be disabled");
return false;
}
return true;
}
void AuctionHouseBot::InitializeConfiguration()
{
debug_Out = sConfigMgr->GetOption<bool>("AuctionHouseBot.DEBUG", false);
debug_Out_Filters = sConfigMgr->GetOption<bool>("AuctionHouseBot.DEBUG_FILTERS", false);
// Bot enablement
SellingBotEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.EnableSeller", false);
BuyingBotEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.Buyer.Enabled", false);
if (SellingBotEnabled == false && BuyingBotEnabled == false)
return;
string charString = sConfigMgr->GetOption<std::string>("AuctionHouseBot.GUIDs", "0");
if (charString == "0")
{
BuyingBotEnabled = false;
SellingBotEnabled = false;
LOG_INFO("module", "AuctionHouseBot: AuctionHouseBot.GUIDs is '0' so this module will be disabled");
return;
}
AddCharacters(charString);
// Buyer & Seller core properties
@@ -1815,9 +1841,14 @@ void AuctionHouseBot::InitializeConfiguration()
AdvancedListingRuleUseDropRatesWeaponEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Weapon", true);
AdvancedListingRuleUseDropRatesArmorEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Armor", true);
AdvancedListingRuleUseDropRatesRecipeEnabled = sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Recipe", true);
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"), "");
AdvancedListingRuleUseDropRatesMinDropRate = sConfigMgr->GetOption<float>("AuctionHouseBot.AdvancedListingRules.UseDropRates.MinDropRate", 0.005);
if (AdvancedListingRuleUseDropRatesMinDropRate < 0 || AdvancedListingRuleUseDropRatesMinDropRate > 100) AdvancedListingRuleUseDropRatesMinDropRate = 0.005;
AdvancedListingRuleUseDropRatesWeaponAffectedQualities.clear();
AdvancedListingRuleUseDropRatesArmorAffectedQualities.clear();
AdvancedListingRuleUseDropRatesRecipeAffectedQualities.clear();
ParseNumberListToSet(AdvancedListingRuleUseDropRatesWeaponAffectedQualities, sConfigMgr->GetOption<std::string>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Weapon.AffectedQualities", "2,3,4,5"), "AdvancedListingRules.UseDropRates.Weapon.AffectedQualities");
ParseNumberListToSet(AdvancedListingRuleUseDropRatesArmorAffectedQualities, sConfigMgr->GetOption<std::string>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Armor.AffectedQualities", "2,3,4,5"), "AdvancedListingRules.UseDropRates.Armor.AffectedQualities");
ParseNumberListToSet(AdvancedListingRuleUseDropRatesRecipeAffectedQualities, sConfigMgr->GetOption<std::string>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Recipe.AffectedQualities", "2,3,4,5"), "AdvancedListingRules.UseDropRates.Recipe.AffectedQualities");
AdvancedListingRuleUseDropRatesExceptionItems.clear();
ParseNumberListToSet(AdvancedListingRuleUseDropRatesExceptionItems, sConfigMgr->GetOption<std::string>("AuctionHouseBot.AdvancedListingRules.UseDropRates.DisabledItemIDs", ""), "AdvancedListingRules.UseDropRates.DisabledItemIDs");
MaxBuyoutPriceInCopper = sConfigMgr->GetOption<uint32>("AuctionHouseBot.MaxBuyoutPriceInCopper", 1000000000);

View File

@@ -289,6 +289,7 @@ private:
std::set<uint32> AdvancedListingRuleUseDropRatesWeaponAffectedQualities;
std::set<uint32> AdvancedListingRuleUseDropRatesArmorAffectedQualities;
std::set<uint32> AdvancedListingRuleUseDropRatesRecipeAffectedQualities;
float AdvancedListingRuleUseDropRatesMinDropRate;
std::unordered_set<uint32> QuestRewardItemIDs;
FactionSpecificAuctionHouseConfig AllianceConfig;
@@ -312,6 +313,7 @@ public:
~AuctionHouseBot();
void Update();
bool IsModuleEnabled();
void InitializeConfiguration();
void EmptyAuctionHouses();
uint32 GetRandomStackValue(std::string configKeyString, uint32 defaultValue);

View File

@@ -20,13 +20,16 @@ public:
void OnAfterConfigLoad(bool /*reload*/) override
{
if (!auctionbot->IsModuleEnabled())
return;
auctionbot->InitializeConfiguration();
if (HasPerformedStartup == true)
{
LOG_INFO("server.loading", "AuctionHouseBot: (Re)populating item candidate lists ...");
auctionbot->PopulateItemCandidatesAndProportions();
if (sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Enabled", true))
if (sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Enabled", false))
{
auctionbot->PopulateQuestRewardItemIDs();
auctionbot->PopulateItemDropChances();
@@ -36,9 +39,12 @@ public:
void OnStartup() override
{
if (!auctionbot->IsModuleEnabled())
return;
LOG_INFO("server.loading", "AuctionHouseBot: (Re)populating item candidate lists ...");
auctionbot->PopulateItemCandidatesAndProportions();
if (sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Enabled", true))
if (sConfigMgr->GetOption<bool>("AuctionHouseBot.AdvancedListingRules.UseDropRates.Enabled", false))
{
auctionbot->PopulateQuestRewardItemIDs();
auctionbot->PopulateItemDropChances();
@@ -169,6 +175,8 @@ public:
LOG_INFO("module", "AuctionHouseBot: Updating Auction House...");
handler->PSendSysMessage("AuctionHouseBot: Updating Auction House...");
AuctionHouseBot::instance()->Update();
LOG_INFO("module", "AuctionHouseBot: Auction House Updated.");
handler->PSendSysMessage("AuctionHouseBot: Auction House Updated.");
return true;
}
@@ -198,6 +206,9 @@ public:
LOG_INFO("module", "AuctionHouseBot: Emptying Auction House...");
handler->PSendSysMessage("AuctionHouseBot: Emptying Auction House...");
AuctionHouseBot::instance()->EmptyAuctionHouses();
AuctionHouseBot::instance()->CleanupExpiredAuctionItems(); // Must go after EmptyAuctionHouses()
LOG_INFO("module", "AuctionHouseBot: Auction Houses Emptied.");
handler->PSendSysMessage("AuctionHouseBot: Auction Houses Emptied.");
return true;
}

View File

@@ -8,6 +8,11 @@
void AddAHBotScripts();
// Add all
void Addmod_ah_bot_plusScripts()
{
AddAHBotScripts();
}
void Addmod_ah_botScripts()
{
AddAHBotScripts();

View File

@@ -0,0 +1,22 @@
## mod-ah-bot Advanced Pricing Calculator
This spreadsheet helps show the buy and sell prices that the Bot(s) will use based on your configuration when `AuctionHouseBot.AdvancedPricing.<Category>.<Subclass>.Enabled` is `true` .
### How to Use
**Edit only the “Config” tab**
- This tab contains many adjustable settings from the modules config file
- Change these values to match your servers setup
- Items in other tabs reference the `Config` tab, so values will update immediately
<br>
**You shouldnt need to modify anything outside the Config sheet unless you know what you're doing.**
*There are hidden columns in each tab that can show items' Quality, Vendor Price, and Item Level (according to the database).
If you make custom changes to your database info, consider updating these as well for accurate pricing.*
### Notes
- The spreadsheet does not consider the following settings:
- AuctionHouseBot.Buyer.AcceptablePriceModifier
- AuctionHouseBot.BidVariationHighReducePercent
- AuctionHouseBot.BidVariationLowReducePercent
- AuctionHouseBot.BuyoutBelowVendorVariationAddPercentEnabled
- AuctionHouseBot.BuyoutBelowVendorVariationAddPercent