diff options
Diffstat (limited to 'src')
97 files changed, 5040 insertions, 276 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index fbcffb47b7c..c79deb5d960 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -466,7 +466,7 @@ enum SMART_ACTION SMART_ACTION_SET_VISIBILITY = 47, // on/off SMART_ACTION_SET_ACTIVE = 48, // on/off SMART_ACTION_ATTACK_START = 49, // - SMART_ACTION_SUMMON_GO = 50, // GameObjectID, DespawnTime in ms, + SMART_ACTION_SUMMON_GO = 50, // GameObjectID, DespawnTime in s SMART_ACTION_KILL_UNIT = 51, // SMART_ACTION_ACTIVATE_TAXI = 52, // TaxiID SMART_ACTION_WP_START = 53, // run/walk, pathID, canRepeat, quest, despawntime, reactState diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 855ffd51bb8..020ed1a686a 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -681,6 +681,23 @@ enum RBACPermissions RBAC_PERM_COMMAND_MODIFY_CURRENCY = 775, // only 4.3.4 RBAC_PERM_COMMAND_DEBUG_PHASE = 776, // only 4.3.4 RBAC_PERM_COMMAND_MAILBOX = 777, + RBAC_PERM_COMMAND_AHBOT = 778, + RBAC_PERM_COMMAND_AHBOT_ITEMS = 779, + RBAC_PERM_COMMAND_AHBOT_ITEMS_GRAY = 780, + RBAC_PERM_COMMAND_AHBOT_ITEMS_WHITE = 781, + RBAC_PERM_COMMAND_AHBOT_ITEMS_GREEN = 782, + RBAC_PERM_COMMAND_AHBOT_ITEMS_BLUE = 783, + RBAC_PERM_COMMAND_AHBOT_ITEMS_PURPLE = 784, + RBAC_PERM_COMMAND_AHBOT_ITEMS_ORANGE = 785, + RBAC_PERM_COMMAND_AHBOT_ITEMS_YELLOW = 786, + RBAC_PERM_COMMAND_AHBOT_RATIO = 787, + RBAC_PERM_COMMAND_AHBOT_RATIO_ALLIANCE = 788, + RBAC_PERM_COMMAND_AHBOT_RATIO_HORDE = 789, + RBAC_PERM_COMMAND_AHBOT_RATIO_NEUTRAL = 790, + RBAC_PERM_COMMAND_AHBOT_REBUILD = 791, + RBAC_PERM_COMMAND_AHBOT_RELOAD = 792, + RBAC_PERM_COMMAND_AHBOT_STATUS = 793, + RBAC_PERM_COMMAND_GUILD_INFO = 794, // custom permissions 1000+ RBAC_PERM_MAX diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp new file mode 100644 index 00000000000..6bf5fa0aaa5 --- /dev/null +++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Log.h" +#include "Item.h" +#include "World.h" +#include "Config.h" +#include "AuctionHouseMgr.h" +#include "AuctionHouseBot.h" +#include "AuctionHouseBotBuyer.h" +#include "AuctionHouseBotSeller.h" + +bool AuctionBotConfig::Initialize() +{ + GetConfigFromFile(); + + if (!GetConfig(CONFIG_AHBOT_BUYER_ENABLED) && !GetConfig(CONFIG_AHBOT_SELLER_ENABLED)) + { + TC_LOG_INFO("ahbot", "AHBOT is Disabled."); + return false; + } + + if (GetConfig(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO) == 0 && GetConfig(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO) == 0 && GetConfig(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO) == 0 && + !GetConfig(CONFIG_AHBOT_BUYER_ALLIANCE_ENABLED) && !GetConfig(CONFIG_AHBOT_BUYER_HORDE_ENABLED) && !GetConfig(CONFIG_AHBOT_BUYER_NEUTRAL_ENABLED)) + { + TC_LOG_INFO("ahbot", "All feature of AuctionHouseBot are disabled!"); + return false; + } + + if (GetConfig(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO) == 0 && GetConfig(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO) == 0 && GetConfig(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO) == 0) + TC_LOG_INFO("ahbot", "AuctionHouseBot SELLER is disabled!"); + + if (!GetConfig(CONFIG_AHBOT_BUYER_ALLIANCE_ENABLED) && !GetConfig(CONFIG_AHBOT_BUYER_HORDE_ENABLED) && !GetConfig(CONFIG_AHBOT_BUYER_NEUTRAL_ENABLED)) + TC_LOG_INFO("ahbot", "AuctionHouseBot BUYER is disabled!"); + + _itemsPerCycleBoost = GetConfig(CONFIG_AHBOT_ITEMS_PER_CYCLE_BOOST); + _itemsPerCycleNormal = GetConfig(CONFIG_AHBOT_ITEMS_PER_CYCLE_NORMAL); + + return true; +} + +void AuctionBotConfig::SetConfig(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue) +{ + SetConfig(index, sConfigMgr->GetIntDefault(fieldname, defvalue)); + + if (int32(GetConfig(index)) < 0) + { + TC_LOG_ERROR("ahbot", "AHBot: %s (%i) can't be negative. Using %u instead.", fieldname, int32(GetConfig(index)), defvalue); + SetConfig(index, defvalue); + } +} + +void AuctionBotConfig::SetConfigMax(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 maxvalue) +{ + SetConfig(index, sConfigMgr->GetIntDefault(fieldname, defvalue)); + + if (GetConfig(index) > maxvalue) + { + TC_LOG_ERROR("ahbot", "AHBot: %s (%u) must be in range 0...%u. Using %u instead.", fieldname, GetConfig(index), maxvalue, maxvalue); + SetConfig(index, maxvalue); + } +} + +void AuctionBotConfig::SetConfigMinMax(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 minvalue, uint32 maxvalue) +{ + SetConfig(index, sConfigMgr->GetIntDefault(fieldname, defvalue)); + + if (GetConfig(index) > maxvalue) + { + TC_LOG_ERROR("ahbot", "AHBot: %s (%u) must be in range %u...%u. Using %u instead.", fieldname, GetConfig(index), minvalue, maxvalue, maxvalue); + SetConfig(index, maxvalue); + } + + if (GetConfig(index) < minvalue) + { + TC_LOG_ERROR("ahbot", "AHBot: %s (%u) must be in range %u...%u. Using %u instead.", fieldname, GetConfig(index), minvalue, maxvalue, minvalue); + SetConfig(index, minvalue); + } +} + +void AuctionBotConfig::SetConfig(AuctionBotConfigBoolValues index, char const* fieldname, bool defvalue) +{ + SetConfig(index, sConfigMgr->GetBoolDefault(fieldname, defvalue)); +} + +//Get AuctionHousebot configuration file +void AuctionBotConfig::GetConfigFromFile() +{ + SetConfigMax(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO, "AuctionHouseBot.Alliance.Items.Amount.Ratio", 100, 10000); + SetConfigMax(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO, "AuctionHouseBot.Horde.Items.Amount.Ratio", 100, 10000); + SetConfigMax(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO, "AuctionHouseBot.Neutral.Items.Amount.Ratio", 100, 10000); + + SetAHBotIncludes(sConfigMgr->GetStringDefault("AuctionHouseBot.forceIncludeItems", "")); + SetAHBotExcludes(sConfigMgr->GetStringDefault("AuctionHouseBot.forceExcludeItems", "")); + + SetConfig(CONFIG_AHBOT_BUYER_ALLIANCE_ENABLED, "AuctionHouseBot.Buyer.Alliance.Enabled", false); + SetConfig(CONFIG_AHBOT_BUYER_HORDE_ENABLED, "AuctionHouseBot.Buyer.Horde.Enabled", false); + SetConfig(CONFIG_AHBOT_BUYER_NEUTRAL_ENABLED, "AuctionHouseBot.Buyer.Neutral.Enabled", false); + + SetConfig(CONFIG_AHBOT_ITEMS_VENDOR, "AuctionHouseBot.Items.Vendor", false); + SetConfig(CONFIG_AHBOT_ITEMS_LOOT, "AuctionHouseBot.Items.Loot", true); + SetConfig(CONFIG_AHBOT_ITEMS_MISC, "AuctionHouseBot.Items.Misc", false); + + 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); + SetConfig(CONFIG_AHBOT_BIND_USE, "AuctionHouseBot.Bind.Use", true); + SetConfig(CONFIG_AHBOT_BIND_QUEST, "AuctionHouseBot.Bind.Quest", false); + SetConfig(CONFIG_AHBOT_LOCKBOX_ENABLED, "AuctionHouseBot.LockBox.Enabled", false); + + SetConfig(CONFIG_AHBOT_BUYPRICE_SELLER, "AuctionHouseBot.BuyPrice.Seller", true); + + SetConfig(CONFIG_AHBOT_ITEMS_PER_CYCLE_BOOST, "AuctionHouseBot.ItemsPerCycle.Boost", 1000); + SetConfig(CONFIG_AHBOT_ITEMS_PER_CYCLE_NORMAL, "AuctionHouseBot.ItemsPerCycle.Normal", 20); + + SetConfig(CONFIG_AHBOT_ITEM_MIN_ITEM_LEVEL, "AuctionHouseBot.Items.ItemLevel.Min", 0); + SetConfig(CONFIG_AHBOT_ITEM_MAX_ITEM_LEVEL, "AuctionHouseBot.Items.ItemLevel.Max", 0); + 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); + SetConfig(CONFIG_AHBOT_ITEM_MAX_SKILL_RANK, "AuctionHouseBot.Items.ReqSkill.Max", 0); + + SetConfig(CONFIG_AHBOT_ITEM_GRAY_AMOUNT, "AuctionHouseBot.Items.Amount.Gray", 0); + SetConfig(CONFIG_AHBOT_ITEM_WHITE_AMOUNT, "AuctionHouseBot.Items.Amount.White", 2000); + SetConfig(CONFIG_AHBOT_ITEM_GREEN_AMOUNT, "AuctionHouseBot.Items.Amount.Green", 2500); + SetConfig(CONFIG_AHBOT_ITEM_BLUE_AMOUNT, "AuctionHouseBot.Items.Amount.Blue", 1500); + SetConfig(CONFIG_AHBOT_ITEM_PURPLE_AMOUNT, "AuctionHouseBot.Items.Amount.Purple", 500); + SetConfig(CONFIG_AHBOT_ITEM_ORANGE_AMOUNT, "AuctionHouseBot.Items.Amount.Orange", 0); + SetConfig(CONFIG_AHBOT_ITEM_YELLOW_AMOUNT, "AuctionHouseBot.Items.Amount.Yellow", 0); + + SetConfigMax(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT, "AuctionHouseBot.Class.Consumable", 6, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT, "AuctionHouseBot.Class.Container", 4, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT, "AuctionHouseBot.Class.Weapon", 8, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_GEM_AMOUNT, "AuctionHouseBot.Class.Gem", 3, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT, "AuctionHouseBot.Class.Armor", 8, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_REAGENT_AMOUNT, "AuctionHouseBot.Class.Reagent", 1, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT, "AuctionHouseBot.Class.Projectile", 2, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT, "AuctionHouseBot.Class.TradeGood", 10, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_GENERIC_AMOUNT, "AuctionHouseBot.Class.Generic", 1, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT, "AuctionHouseBot.Class.Recipe", 6, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_QUIVER_AMOUNT, "AuctionHouseBot.Class.Quiver", 1, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_QUEST_AMOUNT, "AuctionHouseBot.Class.Quest", 1, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_KEY_AMOUNT, "AuctionHouseBot.Class.Key", 1, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_MISC_AMOUNT, "AuctionHouseBot.Class.Misc", 5, 10); + SetConfigMax(CONFIG_AHBOT_CLASS_GLYPH_AMOUNT, "AuctionHouseBot.Class.Glyph", 3, 10); + + SetConfig(CONFIG_AHBOT_ALLIANCE_PRICE_RATIO, "AuctionHouseBot.Alliance.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_HORDE_PRICE_RATIO, "AuctionHouseBot.Horde.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_NEUTRAL_PRICE_RATIO, "AuctionHouseBot.Neutral.Price.Ratio", 100); + + SetConfig(CONFIG_AHBOT_ITEM_GRAY_PRICE_RATIO, "AuctionHouseBot.Items.Gray.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_ITEM_WHITE_PRICE_RATIO, "AuctionHouseBot.Items.White.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_ITEM_GREEN_PRICE_RATIO, "AuctionHouseBot.Items.Green.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_ITEM_BLUE_PRICE_RATIO, "AuctionHouseBot.Items.Blue.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_ITEM_PURPLE_PRICE_RATIO, "AuctionHouseBot.Items.Purple.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_ITEM_ORANGE_PRICE_RATIO, "AuctionHouseBot.Items.Orange.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_ITEM_YELLOW_PRICE_RATIO, "AuctionHouseBot.Items.Yellow.Price.Ratio", 100); + + SetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_PRICE_RATIO, "AuctionHouseBot.Class.Consumable.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_CONTAINER_PRICE_RATIO, "AuctionHouseBot.Class.Container.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_WEAPON_PRICE_RATIO, "AuctionHouseBot.Class.Weapon.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_GEM_PRICE_RATIO, "AuctionHouseBot.Class.Gem.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_ARMOR_PRICE_RATIO, "AuctionHouseBot.Class.Armor.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_REAGENT_PRICE_RATIO, "AuctionHouseBot.Class.Reagent.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_PRICE_RATIO, "AuctionHouseBot.Class.Projectile.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_PRICE_RATIO, "AuctionHouseBot.Class.TradeGood.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_GENERIC_PRICE_RATIO, "AuctionHouseBot.Class.Generic.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_RECIPE_PRICE_RATIO, "AuctionHouseBot.Class.Recipe.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_QUIVER_PRICE_RATIO, "AuctionHouseBot.Class.Quiver.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_QUEST_PRICE_RATIO, "AuctionHouseBot.Class.Quest.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_KEY_PRICE_RATIO, "AuctionHouseBot.Class.Key.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_MISC_PRICE_RATIO, "AuctionHouseBot.Class.Misc.Price.Ratio", 100); + SetConfig(CONFIG_AHBOT_CLASS_GLYPH_PRICE_RATIO, "AuctionHouseBot.Class.Glyph.Price.Ratio", 100); + + SetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_ALLOW_ZERO, "AuctionHouseBot.Class.Consumable.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_CONTAINER_ALLOW_ZERO, "AuctionHouseBot.Class.Container.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_WEAPON_ALLOW_ZERO, "AuctionHouseBot.Class.Weapon.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_GEM_ALLOW_ZERO, "AuctionHouseBot.Class.Gem.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_ARMOR_ALLOW_ZERO, "AuctionHouseBot.Class.Armor.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_REAGENT_ALLOW_ZERO, "AuctionHouseBot.Class.Reagent.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_ALLOW_ZERO, "AuctionHouseBot.Class.Projectile.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_ALLOW_ZERO, "AuctionHouseBot.Class.TradeGood.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_RECIPE_ALLOW_ZERO, "AuctionHouseBot.Class.Recipe.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_QUIVER_ALLOW_ZERO, "AuctionHouseBot.Class.Quiver.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_QUEST_ALLOW_ZERO, "AuctionHouseBot.Class.Quest.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_KEY_ALLOW_ZERO, "AuctionHouseBot.Class.Key.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_MISC_ALLOW_ZERO, "AuctionHouseBot.Class.Misc.Allow.Zero", false); + SetConfig(CONFIG_AHBOT_CLASS_GLYPH_ALLOW_ZERO, "AuctionHouseBot.Class.Glyph.Allow.Zero", false); + + SetConfig(CONFIG_AHBOT_MINTIME, "AuctionHouseBot.MinTime", 1); + SetConfig(CONFIG_AHBOT_MAXTIME, "AuctionHouseBot.MaxTime", 72); + + SetConfigMinMax(CONFIG_AHBOT_BUYER_CHANCE_RATIO_ALLIANCE, "AuctionHouseBot.Buyer.Alliance.Chance.Ratio", 3, 1, 100); + SetConfigMinMax(CONFIG_AHBOT_BUYER_CHANCE_RATIO_HORDE, "AuctionHouseBot.Buyer.Horde.Chance.Ratio", 3, 1, 100); + SetConfigMinMax(CONFIG_AHBOT_BUYER_CHANCE_RATIO_NEUTRAL, "AuctionHouseBot.Buyer.Neutral.Chance.Ratio", 3, 1, 100); + SetConfigMinMax(CONFIG_AHBOT_BUYER_RECHECK_INTERVAL, "AuctionHouseBot.Buyer.Recheck.Interval", 20, 1, DAY / MINUTE); + + SetConfig(CONFIG_AHBOT_SELLER_ENABLED, "AuctionHouseBot.Seller.Enabled", false); + SetConfig(CONFIG_AHBOT_BUYER_ENABLED, "AuctionHouseBot.Buyer.Enabled", false); + SetConfig(CONFIG_AHBOT_BUYPRICE_BUYER, "AuctionHouseBot.Buyer.Buyprice", true); + + SetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_REQ_LEVEL, "AuctionHouseBot.Class.Misc.Mount.ReqLevel.Min", 0); + SetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_REQ_LEVEL, "AuctionHouseBot.Class.Misc.Mount.ReqLevel.Max", 0); + SetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_SKILL_RANK, "AuctionHouseBot.Class.Misc.Mount.ReqSkill.Min", 0); + SetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_SKILL_RANK, "AuctionHouseBot.Class.Misc.Mount.ReqSkill.Max", 0); + SetConfig(CONFIG_AHBOT_CLASS_GLYPH_MIN_REQ_LEVEL, "AuctionHouseBot.Class.Glyph.ReqLevel.Min", 0); + SetConfig(CONFIG_AHBOT_CLASS_GLYPH_MAX_REQ_LEVEL, "AuctionHouseBot.Class.Glyph.ReqLevel.Max", 0); + SetConfig(CONFIG_AHBOT_CLASS_GLYPH_MIN_ITEM_LEVEL, "AuctionHouseBot.Class.Glyph.ItemLevel.Min", 0); + SetConfig(CONFIG_AHBOT_CLASS_GLYPH_MAX_ITEM_LEVEL, "AuctionHouseBot.Class.Glyph.ItemLevel.Max", 0); + SetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_MIN_ITEM_LEVEL, "AuctionHouseBot.Class.TradeGood.ItemLevel.Min", 0); + SetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_MAX_ITEM_LEVEL, "AuctionHouseBot.Class.TradeGood.ItemLevel.Max", 0); + SetConfig(CONFIG_AHBOT_CLASS_CONTAINER_MIN_ITEM_LEVEL, "AuctionHouseBot.Class.Container.ItemLevel.Min", 0); + SetConfig(CONFIG_AHBOT_CLASS_CONTAINER_MAX_ITEM_LEVEL, "AuctionHouseBot.Class.Container.ItemLevel.Max", 0); +} + +char const* AuctionBotConfig::GetHouseTypeName(AuctionHouseType houseType) +{ + static char const* names[MAX_AUCTION_HOUSE_TYPE] = { "Alliance", "Horde", "Neutral" }; + return names[houseType]; +} + +uint32 AuctionBotConfig::GetConfigItemAmountRatio(AuctionHouseType houseType) const +{ + switch (houseType) + { + case AUCTION_HOUSE_ALLIANCE: + return GetConfig(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO); + case AUCTION_HOUSE_HORDE: + return GetConfig(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO); + default: + return GetConfig(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO); + } +} + +bool AuctionBotConfig::GetConfigBuyerEnabled(AuctionHouseType houseType) const +{ + switch (houseType) + { + case AUCTION_HOUSE_ALLIANCE: + return GetConfig(CONFIG_AHBOT_BUYER_ALLIANCE_ENABLED); + case AUCTION_HOUSE_HORDE: + return GetConfig(CONFIG_AHBOT_BUYER_HORDE_ENABLED); + default: + return GetConfig(CONFIG_AHBOT_BUYER_NEUTRAL_ENABLED); + } +} + +uint32 AuctionBotConfig::GetConfigItemQualityAmount(AuctionQuality quality) const +{ + switch (quality) + { + case AUCTION_QUALITY_GRAY: + return GetConfig(CONFIG_AHBOT_ITEM_GRAY_AMOUNT); + case AUCTION_QUALITY_WHITE: + return GetConfig(CONFIG_AHBOT_ITEM_WHITE_AMOUNT); + case AUCTION_QUALITY_GREEN: + return GetConfig(CONFIG_AHBOT_ITEM_GREEN_AMOUNT); + case AUCTION_QUALITY_BLUE: + return GetConfig(CONFIG_AHBOT_ITEM_BLUE_AMOUNT); + case AUCTION_QUALITY_PURPLE: + return GetConfig(CONFIG_AHBOT_ITEM_PURPLE_AMOUNT); + case AUCTION_QUALITY_ORANGE: + return GetConfig(CONFIG_AHBOT_ITEM_ORANGE_AMOUNT); + default: + return GetConfig(CONFIG_AHBOT_ITEM_YELLOW_AMOUNT); + } +} + +AuctionHouseBot::AuctionHouseBot(): _buyer(nullptr), _seller(nullptr), _operationSelector(0) +{ +} + +AuctionHouseBot::~AuctionHouseBot() +{ + delete _buyer; + delete _seller; +} + +void AuctionHouseBot::InitializeAgents() +{ + if (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_SELLER_ENABLED)) + { + delete _seller; + + _seller = new AuctionBotSeller(); + if (!_seller->Initialize()) + { + delete _seller; + _seller = nullptr; + } + } + + if (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_ENABLED)) + { + delete _buyer; + + _buyer = new AuctionBotBuyer(); + if (!_buyer->Initialize()) + { + delete _buyer; + _buyer = nullptr; + } + } +} + +void AuctionHouseBot::Initialize() +{ + if (sAuctionBotConfig->Initialize()) + InitializeAgents(); +} + +void AuctionHouseBot::SetItemsRatio(uint32 al, uint32 ho, uint32 ne) +{ + if (_seller) + _seller->SetItemsRatio(al, ho, ne); +} + +void AuctionHouseBot::SetItemsRatioForHouse(AuctionHouseType house, uint32 val) +{ + if (_seller) + _seller->SetItemsRatioForHouse(house, val); +} + +void AuctionHouseBot::SetItemsAmount(uint32(&vals)[MAX_AUCTION_QUALITY]) +{ + if (_seller) + _seller->SetItemsAmount(vals); +} + +void AuctionHouseBot::SetItemsAmountForQuality(AuctionQuality quality, uint32 val) +{ + if (_seller) + _seller->SetItemsAmountForQuality(quality, val); +} + +void AuctionHouseBot::ReloadAllConfig() +{ + sAuctionBotConfig->Reload(); + InitializeAgents(); +} + +void AuctionHouseBot::PrepareStatusInfos(AuctionHouseBotStatusInfo& statusInfo) +{ + for (uint32 i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + { + statusInfo[i].ItemsCount = 0; + + for (int j = 0; j < MAX_AUCTION_QUALITY; ++j) + statusInfo[i].QualityInfo[j] = 0; + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(AuctionHouseType(i)); + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin(); itr != auctionHouse->GetAuctionsEnd(); ++itr) + { + AuctionEntry* auctionEntry = itr->second; + if (Item* item = sAuctionMgr->GetAItem(auctionEntry->itemGUIDLow)) + { + ItemTemplate const* prototype = item->GetTemplate(); + if (!auctionEntry->owner) // Add only ahbot items + { + if (prototype->Quality < MAX_AUCTION_QUALITY) + ++statusInfo[i].QualityInfo[prototype->Quality]; + + ++statusInfo[i].ItemsCount; + } + } + } + } +} + +void AuctionHouseBot::Rebuild(bool all) +{ + for (uint32 i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + { + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(AuctionHouseType(i)); + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin(); itr != auctionHouse->GetAuctionsEnd(); ++itr) + if (!itr->second->owner) // ahbot auction + if (all || itr->second->bid == 0) // expire now auction if no bid or forced + itr->second->expire_time = sWorld->GetGameTime(); + } +} + +void AuctionHouseBot::Update() +{ + // nothing do... + if (!_buyer && !_seller) + return; + + // scan all possible update cases until first success + for (uint32 count = 0; count < 2 * MAX_AUCTION_HOUSE_TYPE; ++count) + { + bool successStep = false; + + if (_operationSelector < MAX_AUCTION_HOUSE_TYPE) + { + if (_seller) + successStep = _seller->Update(AuctionHouseType(_operationSelector)); + } + else + { + if (_buyer) + successStep = _buyer->Update(AuctionHouseType(_operationSelector - MAX_AUCTION_HOUSE_TYPE)); + } + + ++_operationSelector; + if (_operationSelector >= 2 * MAX_AUCTION_HOUSE_TYPE) + _operationSelector = 0; + + // one success update per call + if (successStep) + break; + } +} diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.h b/src/server/game/AuctionHouseBot/AuctionHouseBot.h new file mode 100644 index 00000000000..04ca96dfdd9 --- /dev/null +++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.h @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef AUCTION_HOUSE_BOT_H +#define AUCTION_HOUSE_BOT_H + +#include "Define.h" + +class AuctionBotSeller; +class AuctionBotBuyer; + +// shadow of ItemQualities with skipped ITEM_QUALITY_HEIRLOOM, anything after ITEM_QUALITY_ARTIFACT(6) in fact +enum AuctionQuality +{ + AUCTION_QUALITY_GRAY = ITEM_QUALITY_POOR, + AUCTION_QUALITY_WHITE = ITEM_QUALITY_NORMAL, + AUCTION_QUALITY_GREEN = ITEM_QUALITY_UNCOMMON, + AUCTION_QUALITY_BLUE = ITEM_QUALITY_RARE, + AUCTION_QUALITY_PURPLE = ITEM_QUALITY_EPIC, + AUCTION_QUALITY_ORANGE = ITEM_QUALITY_LEGENDARY, + AUCTION_QUALITY_YELLOW = ITEM_QUALITY_ARTIFACT, +}; + +#define MAX_AUCTION_QUALITY 7 + +enum AuctionHouseType +{ + AUCTION_HOUSE_ALLIANCE = 0, + AUCTION_HOUSE_HORDE = 1, + AUCTION_HOUSE_NEUTRAL = 2 +}; + +#define MAX_AUCTION_HOUSE_TYPE 3 + +enum AuctionBotConfigUInt32Values +{ + CONFIG_AHBOT_MAXTIME, + CONFIG_AHBOT_MINTIME, + CONFIG_AHBOT_ITEMS_PER_CYCLE_BOOST, + CONFIG_AHBOT_ITEMS_PER_CYCLE_NORMAL, + CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO, + CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO, + CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO, + CONFIG_AHBOT_ITEM_MIN_ITEM_LEVEL, + CONFIG_AHBOT_ITEM_MAX_ITEM_LEVEL, + CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL, + CONFIG_AHBOT_ITEM_MAX_REQ_LEVEL, + CONFIG_AHBOT_ITEM_MIN_SKILL_RANK, + CONFIG_AHBOT_ITEM_MAX_SKILL_RANK, + CONFIG_AHBOT_ITEM_GRAY_AMOUNT, + CONFIG_AHBOT_ITEM_WHITE_AMOUNT, + CONFIG_AHBOT_ITEM_GREEN_AMOUNT, + CONFIG_AHBOT_ITEM_BLUE_AMOUNT, + CONFIG_AHBOT_ITEM_PURPLE_AMOUNT, + CONFIG_AHBOT_ITEM_ORANGE_AMOUNT, + CONFIG_AHBOT_ITEM_YELLOW_AMOUNT, + CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT, + CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT, + CONFIG_AHBOT_CLASS_WEAPON_AMOUNT, + CONFIG_AHBOT_CLASS_GEM_AMOUNT, + CONFIG_AHBOT_CLASS_ARMOR_AMOUNT, + CONFIG_AHBOT_CLASS_REAGENT_AMOUNT, + CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT, + CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT, + CONFIG_AHBOT_CLASS_GENERIC_AMOUNT, + CONFIG_AHBOT_CLASS_RECIPE_AMOUNT, + CONFIG_AHBOT_CLASS_QUIVER_AMOUNT, + CONFIG_AHBOT_CLASS_QUEST_AMOUNT, + CONFIG_AHBOT_CLASS_KEY_AMOUNT, + CONFIG_AHBOT_CLASS_MISC_AMOUNT, + CONFIG_AHBOT_CLASS_GLYPH_AMOUNT, + CONFIG_AHBOT_ALLIANCE_PRICE_RATIO, + CONFIG_AHBOT_HORDE_PRICE_RATIO, + CONFIG_AHBOT_NEUTRAL_PRICE_RATIO, + CONFIG_AHBOT_ITEM_GRAY_PRICE_RATIO, + CONFIG_AHBOT_ITEM_WHITE_PRICE_RATIO, + CONFIG_AHBOT_ITEM_GREEN_PRICE_RATIO, + CONFIG_AHBOT_ITEM_BLUE_PRICE_RATIO, + CONFIG_AHBOT_ITEM_PURPLE_PRICE_RATIO, + CONFIG_AHBOT_ITEM_ORANGE_PRICE_RATIO, + CONFIG_AHBOT_ITEM_YELLOW_PRICE_RATIO, + CONFIG_AHBOT_CLASS_CONSUMABLE_PRICE_RATIO, + CONFIG_AHBOT_CLASS_CONTAINER_PRICE_RATIO, + CONFIG_AHBOT_CLASS_WEAPON_PRICE_RATIO, + CONFIG_AHBOT_CLASS_GEM_PRICE_RATIO, + CONFIG_AHBOT_CLASS_ARMOR_PRICE_RATIO, + CONFIG_AHBOT_CLASS_REAGENT_PRICE_RATIO, + CONFIG_AHBOT_CLASS_PROJECTILE_PRICE_RATIO, + CONFIG_AHBOT_CLASS_TRADEGOOD_PRICE_RATIO, + CONFIG_AHBOT_CLASS_GENERIC_PRICE_RATIO, + CONFIG_AHBOT_CLASS_RECIPE_PRICE_RATIO, + CONFIG_AHBOT_CLASS_MONEY_PRICE_RATIO, + CONFIG_AHBOT_CLASS_QUIVER_PRICE_RATIO, + CONFIG_AHBOT_CLASS_QUEST_PRICE_RATIO, + CONFIG_AHBOT_CLASS_KEY_PRICE_RATIO, + CONFIG_AHBOT_CLASS_PERMANENT_PRICE_RATIO, + CONFIG_AHBOT_CLASS_MISC_PRICE_RATIO, + CONFIG_AHBOT_CLASS_GLYPH_PRICE_RATIO, + CONFIG_AHBOT_BUYER_CHANCE_RATIO_ALLIANCE, + CONFIG_AHBOT_BUYER_CHANCE_RATIO_HORDE, + CONFIG_AHBOT_BUYER_CHANCE_RATIO_NEUTRAL, + CONFIG_AHBOT_BUYER_RECHECK_INTERVAL, + CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_REQ_LEVEL, + CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_REQ_LEVEL, + CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_SKILL_RANK, + CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_SKILL_RANK, + CONFIG_AHBOT_CLASS_GLYPH_MIN_REQ_LEVEL, + CONFIG_AHBOT_CLASS_GLYPH_MAX_REQ_LEVEL, + CONFIG_AHBOT_CLASS_GLYPH_MIN_ITEM_LEVEL, + CONFIG_AHBOT_CLASS_GLYPH_MAX_ITEM_LEVEL, + CONFIG_AHBOT_CLASS_TRADEGOOD_MIN_ITEM_LEVEL, + CONFIG_AHBOT_CLASS_TRADEGOOD_MAX_ITEM_LEVEL, + CONFIG_AHBOT_CLASS_CONTAINER_MIN_ITEM_LEVEL, + CONFIG_AHBOT_CLASS_CONTAINER_MAX_ITEM_LEVEL, + CONFIG_UINT32_AHBOT_UINT32_COUNT +}; + +enum AuctionBotConfigBoolValues +{ + CONFIG_AHBOT_BUYER_ALLIANCE_ENABLED, + CONFIG_AHBOT_BUYER_HORDE_ENABLED, + CONFIG_AHBOT_BUYER_NEUTRAL_ENABLED, + CONFIG_AHBOT_ITEMS_VENDOR, + CONFIG_AHBOT_ITEMS_LOOT, + CONFIG_AHBOT_ITEMS_MISC, + CONFIG_AHBOT_BIND_NO, + CONFIG_AHBOT_BIND_PICKUP, + CONFIG_AHBOT_BIND_EQUIP, + CONFIG_AHBOT_BIND_USE, + CONFIG_AHBOT_BIND_QUEST, + CONFIG_AHBOT_BUYPRICE_SELLER, + CONFIG_AHBOT_BUYPRICE_BUYER, + CONFIG_AHBOT_SELLER_ENABLED, + CONFIG_AHBOT_BUYER_ENABLED, + CONFIG_AHBOT_LOCKBOX_ENABLED, + CONFIG_AHBOT_CLASS_CONSUMABLE_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_CONTAINER_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_WEAPON_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_GEM_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_ARMOR_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_REAGENT_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_PROJECTILE_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_TRADEGOOD_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_RECIPE_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_QUIVER_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_QUEST_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_KEY_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_MISC_ALLOW_ZERO, + CONFIG_AHBOT_CLASS_GLYPH_ALLOW_ZERO, + CONFIG_UINT32_AHBOT_BOOL_COUNT +}; + +// All basic config data used by other AHBot classes for self-configure. +class AuctionBotConfig +{ +private: + AuctionBotConfig(): _itemsPerCycleBoost(1000), _itemsPerCycleNormal(20) {} + ~AuctionBotConfig() {} + AuctionBotConfig(const AuctionBotConfig&); + AuctionBotConfig& operator=(const AuctionBotConfig&); + +public: + static AuctionBotConfig* instance() + { + static AuctionBotConfig instance; + return &instance; + } + + bool Initialize(); + const std::string& GetAHBotIncludes() const { return _AHBotIncludes; } + const std::string& GetAHBotExcludes() const { return _AHBotExcludes; } + + uint32 GetConfig(AuctionBotConfigUInt32Values index) const { return _configUint32Values[index]; } + bool GetConfig(AuctionBotConfigBoolValues index) const { return _configBoolValues[index]; } + void SetConfig(AuctionBotConfigBoolValues index, bool value) { _configBoolValues[index] = value; } + void SetConfig(AuctionBotConfigUInt32Values index, uint32 value) { _configUint32Values[index] = value; } + + uint32 GetConfigItemAmountRatio(AuctionHouseType houseType) const; + bool GetConfigBuyerEnabled(AuctionHouseType houseType) const; + uint32 GetConfigItemQualityAmount(AuctionQuality quality) const; + + uint32 GetItemPerCycleBoost() const { return _itemsPerCycleBoost; } + uint32 GetItemPerCycleNormal() const { return _itemsPerCycleNormal; } + void Reload() { GetConfigFromFile(); } + + static char const* GetHouseTypeName(AuctionHouseType houseType); + +private: + std::string _AHBotIncludes; + std::string _AHBotExcludes; + uint32 _itemsPerCycleBoost; + uint32 _itemsPerCycleNormal; + + uint32 _configUint32Values[CONFIG_UINT32_AHBOT_UINT32_COUNT]; + bool _configBoolValues[CONFIG_UINT32_AHBOT_BOOL_COUNT]; + + void SetAHBotIncludes(const std::string& AHBotIncludes) { _AHBotIncludes = AHBotIncludes; } + void SetAHBotExcludes(const std::string& AHBotExcludes) { _AHBotExcludes = AHBotExcludes; } + + void SetConfig(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue); + void SetConfigMax(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 maxvalue); + void SetConfigMinMax(AuctionBotConfigUInt32Values index, char const* fieldname, uint32 defvalue, uint32 minvalue, uint32 maxvalue); + void SetConfig(AuctionBotConfigBoolValues index, char const* fieldname, bool defvalue); + void GetConfigFromFile(); +}; + +#define sAuctionBotConfig AuctionBotConfig::instance() + +class AuctionBotAgent +{ +public: + AuctionBotAgent() {} + virtual ~AuctionBotAgent() {} + virtual bool Initialize() = 0; + virtual bool Update(AuctionHouseType houseType) = 0; +}; + +struct AuctionHouseBotStatusInfoPerType +{ + uint32 ItemsCount; + uint32 QualityInfo[MAX_AUCTION_QUALITY]; +}; + +typedef AuctionHouseBotStatusInfoPerType AuctionHouseBotStatusInfo[MAX_AUCTION_HOUSE_TYPE]; + +// This class handle both Selling and Buying method +// (holder of AuctionBotBuyer and AuctionBotSeller objects) +class AuctionHouseBot +{ +private: + AuctionHouseBot(); + ~AuctionHouseBot(); + AuctionHouseBot(const AuctionHouseBot&); + AuctionHouseBot& operator=(const AuctionHouseBot&); + +public: + static AuctionHouseBot* instance() + { + static AuctionHouseBot instance; + return &instance; + } + + void Update(); + void Initialize(); + + // Followed method is mainly used by cs_ahbot.cpp for in-game/console command + void SetItemsRatio(uint32 al, uint32 ho, uint32 ne); + void SetItemsRatioForHouse(AuctionHouseType house, uint32 val); + void SetItemsAmount(uint32(&vals)[MAX_AUCTION_QUALITY]); + void SetItemsAmountForQuality(AuctionQuality quality, uint32 val); + void ReloadAllConfig(); + void Rebuild(bool all); + + void PrepareStatusInfos(AuctionHouseBotStatusInfo& statusInfo); +private: + void InitializeAgents(); + + AuctionBotBuyer* _buyer; + AuctionBotSeller* _seller; + + uint32 _operationSelector; // 0..2*MAX_AUCTION_HOUSE_TYPE-1 +}; + +#define sAuctionBot AuctionHouseBot::instance() + +#endif diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp new file mode 100644 index 00000000000..0043482c77f --- /dev/null +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Log.h" +#include "Item.h" +#include "ItemPrototype.h" +#include "AuctionHouseBotBuyer.h" + +AuctionBotBuyer::AuctionBotBuyer(): _checkInterval(20) +{ + // Define faction for our main data class. + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + _houseConfig[i].Initialize(AuctionHouseType(i)); +} + +AuctionBotBuyer::~AuctionBotBuyer() +{ +} + +bool AuctionBotBuyer::Initialize() +{ + LoadConfig(); + + bool activeHouse = false; + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + { + if (_houseConfig[i].BuyerEnabled) + { + activeHouse = true; + break; + } + } + + if (!activeHouse) + return false; + + //load Check interval + _checkInterval = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_RECHECK_INTERVAL) * MINUTE; + TC_LOG_DEBUG("ahbot", "AHBot buyer interval between 2 check = %u", _checkInterval); + return true; +} + +void AuctionBotBuyer::LoadBuyerValues(BuyerConfiguration& config) +{ + uint32 factionChance; + + switch (config.GetHouseType()) + { + case AUCTION_HOUSE_ALLIANCE: + config.BuyerPriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ALLIANCE_PRICE_RATIO) + 50; + factionChance = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCE_RATIO_ALLIANCE); + break; + case AUCTION_HOUSE_HORDE: + config.BuyerPriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_HORDE_PRICE_RATIO) + 50; + factionChance = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCE_RATIO_HORDE); + break; + default: + config.BuyerPriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_NEUTRAL_PRICE_RATIO) + 50; + factionChance = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_CHANCE_RATIO_NEUTRAL); + break; + } + + config.FactionChance = 5000 * factionChance; +} + +void AuctionBotBuyer::LoadConfig() +{ + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + { + _houseConfig[i].BuyerEnabled = sAuctionBotConfig->GetConfigBuyerEnabled(AuctionHouseType(i)); + if (_houseConfig[i].BuyerEnabled) + LoadBuyerValues(_houseConfig[i]); + } +} + +uint32 AuctionBotBuyer::GetBuyableEntry(BuyerConfiguration& config) +{ + config.SameItemInfo.clear(); + uint32 count = 0; + time_t now = time(nullptr); + + AuctionHouseObject* house = sAuctionMgr->GetAuctionsMap(config.GetHouseType()); + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = house->GetAuctionsBegin(); itr != house->GetAuctionsEnd(); ++itr) + { + AuctionEntry* entry = itr->second; + Item* item = sAuctionMgr->GetAItem(entry->itemGUIDLow); + if (item) + { + ItemTemplate const * prototype = item->GetTemplate(); + if (prototype) + { + ++config.SameItemInfo[item->GetEntry()].ItemCount; // Structure constructor will make sure Element are correctly initialized if entry is created here. + config.SameItemInfo[item->GetEntry()].BuyPrice = config.SameItemInfo[item->GetEntry()].BuyPrice + (itr->second->buyout / item->GetCount()); + config.SameItemInfo[item->GetEntry()].BidPrice = config.SameItemInfo[item->GetEntry()].BidPrice + (itr->second->startbid / item->GetCount()); + if (itr->second->buyout != 0) + { + if (itr->second->buyout / item->GetCount() < config.SameItemInfo[item->GetEntry()].MinBuyPrice) + config.SameItemInfo[item->GetEntry()].MinBuyPrice = itr->second->buyout / item->GetCount(); + else if (config.SameItemInfo[item->GetEntry()].MinBuyPrice == 0) + config.SameItemInfo[item->GetEntry()].MinBuyPrice = itr->second->buyout / item->GetCount(); + } + if (itr->second->startbid / item->GetCount() < config.SameItemInfo[item->GetEntry()].MinBidPrice) + config.SameItemInfo[item->GetEntry()].MinBidPrice = itr->second->startbid / item->GetCount(); + else if (config.SameItemInfo[item->GetEntry()].MinBidPrice == 0) + config.SameItemInfo[item->GetEntry()].MinBidPrice = itr->second->startbid / item->GetCount(); + + if (!entry->owner) + { + + if (entry->bid != 0 && entry->bidder) // Add bid by player + { + config.CheckedEntry[entry->Id].LastExist = now; + config.CheckedEntry[entry->Id].AuctionId = entry->Id; + ++count; + } + } + else + { + if (entry->bid != 0) + { + if (entry->bidder) + { + config.CheckedEntry[entry->Id].LastExist = now; + config.CheckedEntry[entry->Id].AuctionId = entry->Id; + ++count; + } + } + else + { + config.CheckedEntry[entry->Id].LastExist = now; + config.CheckedEntry[entry->Id].AuctionId = entry->Id; + ++count; + } + } + } + } + } + + TC_LOG_DEBUG("ahbot", "AHBot: %u items added to buyable vector for ah type: %u", count, config.GetHouseType()); + TC_LOG_DEBUG("ahbot", "AHBot: SameItemInfo size = %u", (uint32)config.SameItemInfo.size()); + return count; +} + +void AuctionBotBuyer::PrepareListOfEntry(BuyerConfiguration& config) +{ + time_t now = time(nullptr) - 5; + + for (CheckEntryMap::iterator itr = config.CheckedEntry.begin(); itr != config.CheckedEntry.end();) + { + if (itr->second.LastExist < (now - 5)) + config.CheckedEntry.erase(itr++); + else + ++itr; + } + + TC_LOG_DEBUG("ahbot", "AHBot: CheckedEntry size = %u", (uint32)config.CheckedEntry.size()); +} + +bool AuctionBotBuyer::IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, double maxBuyablePrice, uint32 minBuyPrice, uint32 maxChance, uint32 chanceRatio) +{ + double ratio = 0; + uint32 chance = 0; + + if (buyoutPrice <= minBuyPrice) + { + if (buyoutPrice <= maxBuyablePrice) + chance = maxChance; + else + { + + if (buyoutPrice > 0 && maxBuyablePrice > 0) + { + ratio = buyoutPrice / maxBuyablePrice; + if (ratio < 10) + chance = maxChance - (ratio * maxChance / 10); + else + chance = 1; + } + } + } + else if (buyoutPrice <= inGameBuyPrice) + { + if (buyoutPrice <= maxBuyablePrice) + chance = maxChance / 5; + else + { + + if (buyoutPrice > 0 && maxBuyablePrice > 0) + { + ratio = buyoutPrice / maxBuyablePrice; + if (ratio < 10) + chance = (maxChance / 5) - (ratio * maxChance / 50); + else + chance = 1; + } + } + } + else if (buyoutPrice <= maxBuyablePrice) + chance = maxChance / 10; + else + { + if (buyoutPrice > 0 && maxBuyablePrice > 0) + { + ratio = buyoutPrice / maxBuyablePrice; + if (ratio < 10) + chance = (maxChance / 5) - (ratio* maxChance / 50); + else + chance = 0; + } + else + chance = 0; + } + + if (urand(1, chanceRatio) <= chance) + { + TC_LOG_DEBUG("ahbot", "AHBot: WIN BUY! Chance = %u, num = %u.", chance, chanceRatio); + return true; + } + else + { + TC_LOG_DEBUG("ahbot", "AHBot: LOOSE BUY! Chance = %u, num = %u.", chance, chanceRatio); + return false; + } +} + +bool AuctionBotBuyer::IsBidableEntry(uint32 bidPrice, double inGameBuyPrice, double maxBidablePrice, uint32 minBidPrice, uint32 maxChance, uint32 chanceRatio) +{ + double ratio = 0; + uint32 chance = 0; + + if (bidPrice <= minBidPrice) + { + if (inGameBuyPrice != 0 && bidPrice < inGameBuyPrice - (inGameBuyPrice / 30)) + chance = maxChance; + else + { + if (bidPrice < maxBidablePrice) + { + ratio = maxBidablePrice / bidPrice; + if (ratio < 3) + chance = maxChance / 500 * ratio; + else + chance = maxChance / 500; + } + } + } + else if (bidPrice < (inGameBuyPrice - (inGameBuyPrice / 30))) + chance = (maxChance / 10); + else + { + if (bidPrice < maxBidablePrice) + { + ratio = maxBidablePrice / bidPrice; + if (ratio < 4) + chance = maxChance / 1000 * ratio; + else + chance = maxChance / 1000; + } + } + + if (urand(1, chanceRatio) <= chance) + { + TC_LOG_DEBUG("ahbot", "AHBot: WIN BID! Chance = %u, num = %u.", chance, chanceRatio); + return true; + } + else + { + TC_LOG_DEBUG("ahbot", "AHBot: LOOSE BID! Chance = %u, num = %u.", chance, chanceRatio); + return false; + } +} + +void AuctionBotBuyer::PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice) +{ + TC_LOG_DEBUG("ahbot", "AHBot: Bid placed to entry %u, %.2fg", auction->Id, float(bidPrice) / 10000.0f); + auction->bid = bidPrice; +} + +void AuctionBotBuyer::BuyEntry(AuctionEntry* auction) +{ + TC_LOG_DEBUG("ahbot", "AHBot: Entry %u bought at %.2fg", auction->Id, float(auction->buyout) / 10000.0f); + auction->bid = auction->buyout; +} + +void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config) +{ + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config.GetHouseType()); + + PrepareListOfEntry(config); + + time_t now = time(nullptr); + uint32 buyCycles; + if (config.CheckedEntry.size() > sAuctionBotConfig->GetItemPerCycleBoost()) + { + buyCycles = sAuctionBotConfig->GetItemPerCycleBoost(); + TC_LOG_DEBUG("ahbot", "AHBot: Boost value used for Buyer! (if this happens often adjust both ItemsPerCycle in worldserver.conf)"); + } + else + buyCycles = sAuctionBotConfig->GetItemPerCycleNormal(); + + for (CheckEntryMap::iterator itr = config.CheckedEntry.begin(); itr != config.CheckedEntry.end();) + { + AuctionEntry* auction = auctionHouse->GetAuction(itr->second.AuctionId); + if (!auction) // is auction not active now + { + TC_LOG_DEBUG("ahbot", "AHBot: Entry %u doesn't exists, perhaps bought already?", + itr->second.AuctionId); + + config.CheckedEntry.erase(itr++); + continue; + } + + if (itr->second.LastChecked != 0 && (now - itr->second.LastChecked) <= _checkInterval) + { + TC_LOG_DEBUG("ahbot", "AHBot: In time interval wait for entry %u!", auction->Id); + ++itr; + continue; + } + + if (buyCycles == 0) + break; + + uint32 maxChance = 5000; + + Item* item = sAuctionMgr->GetAItem(auction->itemGUIDLow); + if (!item) // auction item not accessible, possible auction in payment pending mode + { + config.CheckedEntry.erase(itr++); + continue; + } + + ItemTemplate const* prototype = item->GetTemplate(); + + uint32 basePrice = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYPRICE_BUYER) ? prototype->BuyPrice : prototype->SellPrice; + basePrice *= item->GetCount(); + + double maxBuyablePrice = (basePrice * config.BuyerPriceRatio) / 100; + BuyerItemInfoMap::iterator sameItemItr = config.SameItemInfo.find(item->GetEntry()); + uint32 buyoutPrice = auction->buyout / item->GetCount(); + + uint32 bidPrice; + uint32 bidPriceByItem; + if (auction->bid >= auction->startbid) + { + bidPrice = auction->GetAuctionOutBid(); + bidPriceByItem = auction->bid / item->GetCount(); + } + else + { + bidPrice = auction->startbid; + bidPriceByItem = auction->startbid / item->GetCount(); + } + + double inGameBuyPrice; + double inGameBidPrice; + if (sameItemItr == config.SameItemInfo.end()) + { + inGameBuyPrice = 0; + inGameBidPrice = 0; + } + else + { + if (sameItemItr->second.ItemCount == 1) + maxBuyablePrice = maxBuyablePrice * 5; // if only one item exist can be bought if the price is high too. + inGameBuyPrice = sameItemItr->second.BuyPrice / sameItemItr->second.ItemCount; + inGameBidPrice = sameItemItr->second.BidPrice / sameItemItr->second.ItemCount; + } + + double maxBidablePrice = maxBuyablePrice - (maxBuyablePrice / 30); // Max Bidable price defined to 70% of max buyable price + + TC_LOG_DEBUG("ahbot", "AHBot: Auction added with data:"); + TC_LOG_DEBUG("ahbot", "AHBot: MaxPrice of Entry %u is %.1fg.", itr->second.AuctionId, maxBuyablePrice / 10000); + TC_LOG_DEBUG("ahbot", "AHBot: GamePrice buy=%.1fg, bid=%.1fg.", inGameBuyPrice / 10000, inGameBidPrice / 10000); + TC_LOG_DEBUG("ahbot", "AHBot: Minimal price see in AH Buy=%ug, Bid=%ug.", + sameItemItr->second.MinBuyPrice / 10000, sameItemItr->second.MinBidPrice / 10000); + TC_LOG_DEBUG("ahbot", "AHBot: Actual Entry price, Buy=%ug, Bid=%ug.", buyoutPrice / 10000, bidPrice / 10000); + + if (!auction->owner) // Original auction owner + maxChance = maxChance / 5; // if Owner is AHBot this mean player placed bid on this auction. We divide by 5 chance for AhBuyer to place bid on it. (This make more challenge than ignore entry) + if (auction->buyout != 0) // Is the item directly buyable? + { + if (IsBuyableEntry(buyoutPrice, inGameBuyPrice, maxBuyablePrice, sameItemItr->second.MinBuyPrice, maxChance, config.FactionChance)) + { + if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, sameItemItr->second.MinBidPrice, maxChance / 2, config.FactionChance)) + { + if (urand(0, 5) == 0) + PlaceBidToEntry(auction, bidPrice); + else + BuyEntry(auction); + } + else + BuyEntry(auction); + } + else if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, sameItemItr->second.MinBidPrice, maxChance / 2, config.FactionChance)) + PlaceBidToEntry(auction, bidPrice); + } + else if (IsBidableEntry(bidPriceByItem, inGameBuyPrice, maxBidablePrice, sameItemItr->second.MinBidPrice, maxChance, config.FactionChance)) + PlaceBidToEntry(auction, bidPrice); + + itr->second.LastChecked = now; + --buyCycles; + + ++itr; + } +} + +bool AuctionBotBuyer::Update(AuctionHouseType houseType) +{ + if (sAuctionBotConfig->GetConfigBuyerEnabled(houseType)) + { + TC_LOG_DEBUG("ahbot", "AHBot: %s buying ...", AuctionBotConfig::GetHouseTypeName(houseType)); + if (GetBuyableEntry(_houseConfig[houseType]) > 0) + AddNewAuctionBuyerBotBid(_houseConfig[houseType]); + return true; + } + + return false; +} diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h new file mode 100644 index 00000000000..1148435f1c1 --- /dev/null +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef AUCTION_HOUSE_BOT_BUYER_H +#define AUCTION_HOUSE_BOT_BUYER_H + +#include "Define.h" +#include "AuctionHouseMgr.h" +#include "AuctionHouseBot.h" + +struct BuyerAuctionEval +{ + BuyerAuctionEval(): AuctionId(0), LastChecked(0), LastExist(0) {} + + uint32 AuctionId; + time_t LastChecked; + time_t LastExist; +}; + +struct BuyerItemInfo +{ + BuyerItemInfo(): ItemCount(0), BuyPrice(0), BidPrice(0), MinBuyPrice(0), MinBidPrice(0) {} + + uint32 ItemCount; + double BuyPrice; + double BidPrice; + uint32 MinBuyPrice; + uint32 MinBidPrice; +}; + +typedef std::map<uint32, BuyerItemInfo> BuyerItemInfoMap; +typedef std::map<uint32, BuyerAuctionEval> CheckEntryMap; + +struct BuyerConfiguration +{ + BuyerConfiguration(): FactionChance(3), BuyerEnabled(false), BuyerPriceRatio(100), _houseType(AUCTION_HOUSE_NEUTRAL) {} + + void Initialize(AuctionHouseType houseType) + { + _houseType = houseType; + } + + AuctionHouseType GetHouseType() const { return _houseType; } + + BuyerItemInfoMap SameItemInfo; + CheckEntryMap CheckedEntry; + uint32 FactionChance; + bool BuyerEnabled; + uint32 BuyerPriceRatio; + +private: + AuctionHouseType _houseType; +}; + +// This class handle all Buyer method +// (holder of AuctionBotConfig for each auction house type) +class AuctionBotBuyer : public AuctionBotAgent +{ +public: + AuctionBotBuyer(); + ~AuctionBotBuyer() override; + + bool Initialize() override; + bool Update(AuctionHouseType houseType) override; + + void LoadConfig(); + void AddNewAuctionBuyerBotBid(BuyerConfiguration& config); + +private: + uint32 _checkInterval; + BuyerConfiguration _houseConfig[MAX_AUCTION_HOUSE_TYPE]; + + void LoadBuyerValues(BuyerConfiguration& config); + bool IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, double maxBuyablePrice, uint32 minBuyPrice, uint32 maxChance, uint32 chanceRatio); + bool IsBidableEntry(uint32 bidPrice, double inGameBuyPrice, double maxBidablePrice, uint32 minBidPrice, uint32 maxChance, uint32 chanceRatio); + void PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice); + void BuyEntry(AuctionEntry* auction); + void PrepareListOfEntry(BuyerConfiguration& config); + uint32 GetBuyableEntry(BuyerConfiguration& config); +}; + +#endif diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp new file mode 100644 index 00000000000..13aa1f22fa3 --- /dev/null +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp @@ -0,0 +1,1029 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Log.h" +#include "DBCStores.h" +#include "ObjectMgr.h" +#include "AuctionHouseMgr.h" +#include "AuctionHouseBotSeller.h" + +AuctionBotSeller::AuctionBotSeller() +{ + // Define faction for our main data class. + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + _houseConfig[i].Initialize(AuctionHouseType(i)); +} + +AuctionBotSeller::~AuctionBotSeller() +{ +} + +bool AuctionBotSeller::Initialize() +{ + std::vector<uint32> npcItems; + std::vector<uint32> lootItems; + std::vector<uint32> includeItems; + std::vector<uint32> excludeItems; + + TC_LOG_DEBUG("ahbot", "AHBot seller filters:"); + + { + std::stringstream includeStream(sAuctionBotConfig->GetAHBotIncludes()); + std::string temp; + while (getline(includeStream, temp, ',')) + includeItems.push_back(atoi(temp.c_str())); + } + + { + std::stringstream excludeStream(sAuctionBotConfig->GetAHBotExcludes()); + std::string temp; + while (getline(excludeStream, temp, ',')) + excludeItems.push_back(atoi(temp.c_str())); + } + + TC_LOG_DEBUG("ahbot", "Forced Inclusion %u items", (uint32)includeItems.size()); + TC_LOG_DEBUG("ahbot", "Forced Exclusion %u items", (uint32)excludeItems.size()); + + TC_LOG_DEBUG("ahbot", "Loading npc vendor items for filter.."); + const CreatureTemplateContainer* creatures = sObjectMgr->GetCreatureTemplates(); + std::set<uint32> tempItems; + for (CreatureTemplateContainer::const_iterator it = creatures->begin(); it != creatures->end(); ++it) + { + if (const VendorItemData* data = sObjectMgr->GetNpcVendorItemList(it->first)) + { + for (VendorItemList::const_iterator it2 = data->m_items.begin(); it2 != data->m_items.end(); ++it2) + tempItems.insert((*it2)->item); + } + } + for (std::set<uint32>::const_iterator it = tempItems.begin(); it != tempItems.end(); ++it) + npcItems.push_back(*it); + + TC_LOG_DEBUG("ahbot", "Npc vendor filter has %u items", (uint32)npcItems.size()); + + TC_LOG_DEBUG("ahbot", "Loading loot items for filter.."); + QueryResult result = WorldDatabase.PQuery( + "SELECT `item` FROM `creature_loot_template` UNION " + "SELECT `item` FROM `disenchant_loot_template` UNION " + "SELECT `item` FROM `fishing_loot_template` UNION " + "SELECT `item` FROM `gameobject_loot_template` UNION " + "SELECT `item` FROM `item_loot_template` UNION " + "SELECT `item` FROM `milling_loot_template` UNION " + "SELECT `item` FROM `pickpocketing_loot_template` UNION " + "SELECT `item` FROM `prospecting_loot_template` UNION " + "SELECT `item` FROM `skinning_loot_template` UNION " + "SELECT `item` FROM `spell_loot_template`"); + + if (result) + { + do + { + Field* fields = result->Fetch(); + + uint32 entry = fields[0].GetUInt32(); + if (!entry) + continue; + + lootItems.push_back(entry); + } while (result->NextRow()); + } + + TC_LOG_DEBUG("ahbot", "Loot filter has %u items", (uint32)lootItems.size()); + TC_LOG_DEBUG("ahbot", "Sorting and cleaning items for AHBot seller..."); + + uint32 itemsAdded = 0; + + for (uint32 itemId = 0; itemId < sItemStore.GetNumRows(); ++itemId) + { + ItemTemplate const* prototype = sObjectMgr->GetItemTemplate(itemId); + + if (!prototype) + continue; + + // skip items with too high quality (code can't properly work with its) + if (prototype->Quality >= MAX_AUCTION_QUALITY) + continue; + + // forced exclude filter + bool isExcludeItem = false; + for (size_t i = 0; i < excludeItems.size() && !isExcludeItem; ++i) + if (itemId == excludeItems[i]) + isExcludeItem = true; + + if (isExcludeItem) + continue; + + // forced include filter + bool isForcedIncludeItem = false; + for (size_t i = 0; i < includeItems.size() && !isForcedIncludeItem; ++i) + if (itemId == includeItems[i]) + isForcedIncludeItem = true; + + if (isForcedIncludeItem) + { + _itemPool[prototype->Quality][prototype->Class].push_back(itemId); + ++itemsAdded; + continue; + } + + // bounding filters + switch (prototype->Bonding) + { + case NO_BIND: + if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BIND_NO)) + continue; + break; + case BIND_WHEN_PICKED_UP: + if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BIND_PICKUP)) + continue; + break; + case BIND_WHEN_EQUIPED: + if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BIND_EQUIP)) + continue; + break; + case BIND_WHEN_USE: + if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BIND_USE)) + continue; + break; + case BIND_QUEST_ITEM: + if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BIND_QUEST)) + continue; + break; + default: + continue; + } + + bool allowZero = false; + switch (prototype->Class) + { + case ITEM_CLASS_CONSUMABLE: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_ALLOW_ZERO); break; + case ITEM_CLASS_CONTAINER: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_ALLOW_ZERO); break; + case ITEM_CLASS_WEAPON: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_ALLOW_ZERO); break; + case ITEM_CLASS_GEM: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_ALLOW_ZERO); break; + case ITEM_CLASS_ARMOR: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_ALLOW_ZERO); break; + case ITEM_CLASS_REAGENT: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_REAGENT_ALLOW_ZERO); break; + case ITEM_CLASS_PROJECTILE: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_ALLOW_ZERO); break; + case ITEM_CLASS_TRADE_GOODS: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_ALLOW_ZERO); break; + case ITEM_CLASS_RECIPE: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_ALLOW_ZERO); break; + case ITEM_CLASS_QUIVER: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUIVER_ALLOW_ZERO); break; + case ITEM_CLASS_QUEST: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_ALLOW_ZERO); break; + case ITEM_CLASS_KEY: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_KEY_ALLOW_ZERO); break; + case ITEM_CLASS_MISC: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_ALLOW_ZERO); break; + case ITEM_CLASS_GLYPH: + allowZero = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_ALLOW_ZERO); break; + default: + allowZero = false; + } + + // Filter out items with no buy/sell price unless otherwise flagged in the config. + if (!allowZero) + { + if (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYPRICE_SELLER)) + { + if (prototype->BuyPrice == 0) + continue; + } + else + { + if (prototype->SellPrice == 0) + continue; + } + } + + // vendor filter + if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEMS_VENDOR)) + { + bool isVendorItem = false; + for (size_t i = 0; i < npcItems.size() && !isVendorItem; ++i) + if (itemId == npcItems[i]) + isVendorItem = true; + + if (isVendorItem) + continue; + } + + // loot filter + if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEMS_LOOT)) + { + bool isLootItem = false; + for (size_t i = 0; i < lootItems.size() && !isLootItem; ++i) + if (itemId == lootItems[i]) + isLootItem = true; + + if (isLootItem) + continue; + } + + // not vendor/loot filter + if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEMS_MISC)) + { + bool isVendorItem = false; + bool isLootItem = false; + + for (size_t i = 0; i < npcItems.size() && !isVendorItem; ++i) + if (itemId == npcItems[i]) + isVendorItem = true; + + for (size_t i = 0; i < lootItems.size() && !isLootItem; ++i) + if (itemId == lootItems[i]) + isLootItem = true; + + if (!isLootItem && !isVendorItem) + continue; + } + + // item class/subclass specific filters + switch (prototype->Class) + { + case ITEM_CLASS_ARMOR: + case ITEM_CLASS_WEAPON: + { + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_ITEM_LEVEL)) + if (prototype->ItemLevel < value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_ITEM_LEVEL)) + if (prototype->ItemLevel > value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL)) + if (prototype->RequiredLevel < value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_REQ_LEVEL)) + if (prototype->RequiredLevel > value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_SKILL_RANK)) + if (prototype->RequiredSkillRank < value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_SKILL_RANK)) + if (prototype->RequiredSkillRank > value) + continue; + break; + } + case ITEM_CLASS_RECIPE: + case ITEM_CLASS_CONSUMABLE: + case ITEM_CLASS_PROJECTILE: + { + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_REQ_LEVEL)) + if (prototype->RequiredLevel < value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_REQ_LEVEL)) + if (prototype->RequiredLevel > value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MIN_SKILL_RANK)) + if (prototype->RequiredSkillRank < value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_MAX_SKILL_RANK)) + if (prototype->RequiredSkillRank > value) + continue; + break; + } + case ITEM_CLASS_MISC: + if (prototype->SubClass == ITEM_SUBCLASS_JUNK_MOUNT) + { + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_REQ_LEVEL)) + if (prototype->RequiredLevel < value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_REQ_LEVEL)) + if (prototype->RequiredLevel > value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MIN_SKILL_RANK)) + if (prototype->RequiredSkillRank < value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_MOUNT_MAX_SKILL_RANK)) + if (prototype->RequiredSkillRank > value) + continue; + } + + if (prototype->Flags & ITEM_FLAG_UNLOCKED) + { + // skip any not locked lootable items (mostly quest specific or reward cases) + if (!prototype->LockID) + continue; + + if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_LOCKBOX_ENABLED)) + continue; + } + + break; + case ITEM_CLASS_GLYPH: + { + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MIN_REQ_LEVEL)) + if (prototype->RequiredLevel < value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MAX_REQ_LEVEL)) + if (prototype->RequiredLevel > value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MIN_ITEM_LEVEL)) + if (prototype->RequiredLevel < value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_MAX_ITEM_LEVEL)) + if (prototype->RequiredLevel > value) + continue; + break; + } + case ITEM_CLASS_TRADE_GOODS: + { + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_MIN_ITEM_LEVEL)) + if (prototype->ItemLevel < value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_MAX_ITEM_LEVEL)) + if (prototype->ItemLevel > value) + continue; + break; + } + case ITEM_CLASS_CONTAINER: + case ITEM_CLASS_QUIVER: + { + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_MIN_ITEM_LEVEL)) + if (prototype->ItemLevel < value) + continue; + if (uint32 value = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_MAX_ITEM_LEVEL)) + if (prototype->ItemLevel > value) + continue; + break; + } + } + + _itemPool[prototype->Quality][prototype->Class].push_back(itemId); + ++itemsAdded; + } + + if (!itemsAdded) + { + TC_LOG_ERROR("ahbot", "AuctionHouseBot seller not have items, disabled."); + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO, 0); + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO, 0); + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO, 0); + return false; + } + + TC_LOG_DEBUG("ahbot", "AuctionHouseBot seller will use %u items to fill auction house (according your config choices)", itemsAdded); + + LoadConfig(); + + TC_LOG_DEBUG("ahbot", "Items loaded \tGray\tWhite\tGreen\tBlue\tPurple\tOrange\tYellow"); + for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i) + TC_LOG_DEBUG("ahbot", "\t\t%u\t%u\t%u\t%u\t%u\t%u\t%u", + (uint32)_itemPool[0][i].size(), (uint32)_itemPool[1][i].size(), (uint32)_itemPool[2][i].size(), + (uint32)_itemPool[3][i].size(), (uint32)_itemPool[4][i].size(), (uint32)_itemPool[5][i].size(), + (uint32)_itemPool[6][i].size()); + + TC_LOG_DEBUG("ahbot", "AHBot seller configuration data loaded and initialized"); + return true; +} + +void AuctionBotSeller::LoadConfig() +{ + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + if (sAuctionBotConfig->GetConfigItemAmountRatio(AuctionHouseType(i))) + LoadSellerValues(_houseConfig[i]); +} + +void AuctionBotSeller::LoadItemsQuantity(SellerConfiguration& config) +{ + uint32 ratio = sAuctionBotConfig->GetConfigItemAmountRatio(config.GetHouseType()); + + config.SetItemsAmountPerQuality(AUCTION_QUALITY_GRAY, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GRAY_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_WHITE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_WHITE_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_GREEN, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GREEN_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_BLUE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_BLUE_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_PURPLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_PURPLE_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_ORANGE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_ORANGE_AMOUNT) * ratio / 100); + config.SetItemsAmountPerQuality(AUCTION_QUALITY_YELLOW, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_YELLOW_AMOUNT) * ratio / 100); + + // Set quantity wanted but only on possible item color + // This avoid any no-exist class-color items selection by random items create function + // ============================================================================================ + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_CONSUMABLE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_CONTAINER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_GEM, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_PROJECTILE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_RECIPE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_QUIVER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_KEY, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_MISC, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GRAY, ITEM_CLASS_GLYPH, 0); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_GEM, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_REAGENT, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_REAGENT_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_PROJECTILE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_GENERIC, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GENERIC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_RECIPE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_QUIVER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUIVER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_KEY, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_KEY_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_MISC, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_WHITE, ITEM_CLASS_GLYPH, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_AMOUNT)); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_GEM, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_PROJECTILE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_RECIPE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_QUIVER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUIVER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_KEY, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_KEY_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_MISC, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_GREEN, ITEM_CLASS_GLYPH, 0); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_GEM, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_PROJECTILE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_RECIPE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_QUIVER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUIVER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_KEY, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_MISC, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_BLUE, ITEM_CLASS_GLYPH, 0); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_GEM, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_PROJECTILE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_RECIPE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_QUIVER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_KEY, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_MISC, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_PURPLE, ITEM_CLASS_GLYPH, 0); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_CONSUMABLE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_CONTAINER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_GEM, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_PROJECTILE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_RECIPE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_QUIVER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_QUEST, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_KEY, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_MISC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_ORANGE, ITEM_CLASS_GLYPH, 0); + + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_CONSUMABLE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_CONTAINER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_GEM, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT)); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_REAGENT, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_PROJECTILE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_TRADE_GOODS, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_GENERIC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_RECIPE, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_QUIVER, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_QUEST, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_KEY, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_MISC, 0); + config.SetItemsQuantityPerClass(AUCTION_QUALITY_YELLOW, ITEM_CLASS_GLYPH, 0); + // ============================================================================================ + + // Set the best value to get nearest amount of items wanted + for (uint32 j = 0; j < MAX_AUCTION_QUALITY; ++j) + { + uint32 index = config.GetItemsAmountPerQuality(AuctionQuality(j)) / + (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_AMOUNT) + + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_REAGENT_AMOUNT) + + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GENERIC_AMOUNT) + + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUIVER_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_AMOUNT) + + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_KEY_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_AMOUNT) + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_AMOUNT)); + + for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i) + config.SetItemsAmountPerClass(AuctionQuality(j), ItemClass(i), index); + } +} + +void AuctionBotSeller::LoadSellerValues(SellerConfiguration& config) +{ + LoadItemsQuantity(config); + uint32 PriceRatio; + switch (config.GetHouseType()) + { + case AUCTION_HOUSE_ALLIANCE: + PriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ALLIANCE_PRICE_RATIO); + break; + case AUCTION_HOUSE_HORDE: + PriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_HORDE_PRICE_RATIO); + break; + default: + PriceRatio = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_NEUTRAL_PRICE_RATIO); + break; + } + + config.SetPriceRatioPerQuality(AUCTION_QUALITY_GRAY, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GRAY_PRICE_RATIO) / 100); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_WHITE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_WHITE_PRICE_RATIO) / 100); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_GREEN, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_GREEN_PRICE_RATIO) / 100); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_BLUE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_BLUE_PRICE_RATIO) / 100); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_PURPLE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_PURPLE_PRICE_RATIO) / 100); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_ORANGE, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_ORANGE_PRICE_RATIO) / 100); + config.SetPriceRatioPerQuality(AUCTION_QUALITY_YELLOW, PriceRatio * sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ITEM_YELLOW_PRICE_RATIO) / 100); + + config.SetPriceRatioPerClass(ITEM_CLASS_CONSUMABLE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONSUMABLE_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_CONTAINER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_CONTAINER_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_WEAPON, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_WEAPON_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_GEM, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GEM_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_ARMOR, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_ARMOR_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_REAGENT, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_REAGENT_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_PROJECTILE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PROJECTILE_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_TRADE_GOODS, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_TRADEGOOD_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_GENERIC, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GENERIC_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_RECIPE, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_RECIPE_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_MONEY, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MONEY_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_QUIVER, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUIVER_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_QUEST, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_QUEST_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_KEY, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_KEY_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_PERMANENT, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_PERMANENT_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_MISC, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_MISC_PRICE_RATIO)); + config.SetPriceRatioPerClass(ITEM_CLASS_GLYPH, sAuctionBotConfig->GetConfig(CONFIG_AHBOT_CLASS_GLYPH_PRICE_RATIO)); + + //load min and max auction times + config.SetMinTime(sAuctionBotConfig->GetConfig(CONFIG_AHBOT_MINTIME)); + config.SetMaxTime(sAuctionBotConfig->GetConfig(CONFIG_AHBOT_MAXTIME)); + + TC_LOG_DEBUG("ahbot", "AHBot: minTime = %u", config.GetMinTime()); + TC_LOG_DEBUG("ahbot", "AHBot: maxTime = %u", config.GetMaxTime()); + + TC_LOG_DEBUG("ahbot", "AHBot: For AH type %u", config.GetHouseType()); + TC_LOG_DEBUG("ahbot", "AHBot: GrayItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_GRAY)); + TC_LOG_DEBUG("ahbot", "AHBot: WhiteItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_WHITE)); + TC_LOG_DEBUG("ahbot", "AHBot: GreenItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_GREEN)); + TC_LOG_DEBUG("ahbot", "AHBot: BlueItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_BLUE)); + TC_LOG_DEBUG("ahbot", "AHBot: PurpleItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_PURPLE)); + TC_LOG_DEBUG("ahbot", "AHBot: OrangeItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_ORANGE)); + TC_LOG_DEBUG("ahbot", "AHBot: YellowItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_YELLOW)); +} + +// Set static of items on one AH faction. +// Fill ItemInfos object with real content of AH. +uint32 AuctionBotSeller::SetStat(SellerConfiguration& config) +{ + AllItemsArray itemsSaved(MAX_AUCTION_QUALITY, std::vector<uint32>(MAX_ITEM_CLASS)); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config.GetHouseType()); + for (AuctionHouseObject::AuctionEntryMap::const_iterator itr = auctionHouse->GetAuctionsBegin(); itr != auctionHouse->GetAuctionsEnd(); ++itr) + { + AuctionEntry* auctionEntry = itr->second; + Item* item = sAuctionMgr->GetAItem(auctionEntry->itemGUIDLow); + if (item) + { + ItemTemplate const* prototype = item->GetTemplate(); + if (prototype) + if (!auctionEntry->owner) // Add only ahbot items + ++itemsSaved[prototype->Quality][prototype->Class]; + } + } + + uint32 count = 0; + for (uint32 j = 0; j < MAX_AUCTION_QUALITY; ++j) + { + for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i) + { + config.SetMissedItemsPerClass((AuctionQuality)j, (ItemClass)i, itemsSaved[j][i]); + count += config.GetMissedItemsPerClass((AuctionQuality)j, (ItemClass)i); + } + } + + TC_LOG_DEBUG("ahbot", "AHBot: Missed Item \tGray\tWhite\tGreen\tBlue\tPurple\tOrange\tYellow"); + for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i) + { + TC_LOG_DEBUG("ahbot", "AHBot: \t\t%u\t%u\t%u\t%u\t%u\t%u\t%u", + config.GetMissedItemsPerClass(AUCTION_QUALITY_GRAY, (ItemClass)i), + config.GetMissedItemsPerClass(AUCTION_QUALITY_WHITE, (ItemClass)i), + config.GetMissedItemsPerClass(AUCTION_QUALITY_GREEN, (ItemClass)i), + config.GetMissedItemsPerClass(AUCTION_QUALITY_BLUE, (ItemClass)i), + config.GetMissedItemsPerClass(AUCTION_QUALITY_PURPLE, (ItemClass)i), + config.GetMissedItemsPerClass(AUCTION_QUALITY_ORANGE, (ItemClass)i), + config.GetMissedItemsPerClass(AUCTION_QUALITY_YELLOW, (ItemClass)i)); + } + config.LastMissedItem = count; + + return count; +} + +// getRandomArray is used to make viable the possibility to add any of missed item in place of first one to last one. +bool AuctionBotSeller::GetItemsToSell(SellerConfiguration& config, ItemsToSellArray& itemsToSellArray, AllItemsArray const& addedItem) +{ + itemsToSellArray.clear(); + bool found = false; + + for (uint32 j = 0; j < MAX_AUCTION_QUALITY; ++j) + { + for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i) + { + if (config.GetMissedItemsPerClass(AuctionQuality(j), ItemClass(i)) > addedItem[j][i] && !_itemPool[j][i].empty()) + { + ItemToSell miss_item; + miss_item.Color = j; + miss_item.Itemclass = i; + itemsToSellArray.push_back(miss_item); + found = true; + } + } + } + + return found; +} + +// Set items price. All important value are passed by address. +void AuctionBotSeller::SetPricesOfItem(ItemTemplate const* itemProto, SellerConfiguration& config, uint32& buyp, uint32& bidp, uint32 stackCount) +{ + uint32 classRatio = config.GetPriceRatioPerClass(ItemClass(itemProto->Class)); + uint32 qualityRatio = config.GetPriceRatioPerQuality(AuctionQuality(itemProto->Quality)); + uint32 priceRatio = (classRatio * qualityRatio) / 100; + + uint32 buyPrice = itemProto->BuyPrice; + uint32 sellPrice = itemProto->SellPrice; + + if (buyPrice == 0) + { + if (sellPrice > 0) + buyPrice = sellPrice * GetSellModifier(itemProto); + else + { + uint32 divisor = ((itemProto->Class == 2 || itemProto->Class == 4) ? 284 : 80); + uint32 tempLevel = (itemProto->ItemLevel == 0 ? 1 : itemProto->ItemLevel); + uint32 tempQuality = (itemProto->Quality == 0 ? 1 : itemProto->Quality); + + buyPrice = tempLevel * tempQuality * GetBuyModifier(itemProto)* tempLevel / divisor; + } + } + + if (sellPrice == 0) + sellPrice = (buyPrice > 10 ? buyPrice / GetSellModifier(itemProto) : buyPrice); + + if (!sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYPRICE_SELLER)) + buyPrice = sellPrice; + + uint32 basePrice = (buyPrice * stackCount * priceRatio) / (itemProto->Class == 6 ? 200 : itemProto->BuyCount) / 100; + uint32 range = basePrice * 0.04; + + buyp = urand(basePrice - range, basePrice + range) + 1; + + basePrice = buyp * .5; + range = buyp * .4; + bidp = urand(basePrice - range, basePrice + range) + 1; +} + +// Determine the multiplier for the sell price of any weapon without a buy price. +uint32 AuctionBotSeller::GetSellModifier(ItemTemplate const* prototype) +{ + switch (prototype->Class) + { + case ITEM_CLASS_WEAPON: + case ITEM_CLASS_ARMOR: + case ITEM_CLASS_REAGENT: + case ITEM_CLASS_PROJECTILE: + return 5; + default: + return 4; + } +} + +// Return the modifier by which the item's level and quality will be modified by to derive a relatively accurate price. +uint32 AuctionBotSeller::GetBuyModifier(ItemTemplate const* prototype) +{ + switch (prototype->Class) + { + case ITEM_CLASS_CONSUMABLE: + { + switch (prototype->SubClass) + { + case ITEM_SUBCLASS_CONSUMABLE: + return 100; + case ITEM_SUBCLASS_FLASK: + return 400; + case ITEM_SUBCLASS_SCROLL: + return 15; + case ITEM_SUBCLASS_ITEM_ENHANCEMENT: + return 250; + case ITEM_SUBCLASS_BANDAGE: + return 125; + default: + return 300; + } + } + case ITEM_CLASS_WEAPON: + { + switch (prototype->SubClass) + { + case ITEM_SUBCLASS_WEAPON_AXE: + case ITEM_SUBCLASS_WEAPON_MACE: + case ITEM_SUBCLASS_WEAPON_SWORD: + case ITEM_SUBCLASS_WEAPON_FIST: + case ITEM_SUBCLASS_WEAPON_DAGGER: + return 1200; + case ITEM_SUBCLASS_WEAPON_AXE2: + case ITEM_SUBCLASS_WEAPON_MACE2: + case ITEM_SUBCLASS_WEAPON_POLEARM: + case ITEM_SUBCLASS_WEAPON_SWORD2: + case ITEM_SUBCLASS_WEAPON_STAFF: + return 1500; + case ITEM_SUBCLASS_WEAPON_THROWN: + return 350; + default: + return 1000; + } + } + case ITEM_CLASS_ARMOR: + { + switch (prototype->SubClass) + { + case ITEM_SUBCLASS_ARMOR_MISC: + case ITEM_SUBCLASS_ARMOR_CLOTH: + return 500; + case ITEM_SUBCLASS_ARMOR_LEATHER: + return 600; + case ITEM_SUBCLASS_ARMOR_MAIL: + return 700; + case ITEM_SUBCLASS_ARMOR_PLATE: + case ITEM_SUBCLASS_ARMOR_SHIELD: + return 800; + default: + return 400; + } + } + case ITEM_CLASS_REAGENT: + case ITEM_CLASS_PROJECTILE: + return 50; + case ITEM_CLASS_TRADE_GOODS: + { + switch (prototype->SubClass) + { + case ITEM_SUBCLASS_TRADE_GOODS: + case ITEM_SUBCLASS_PARTS: + case ITEM_SUBCLASS_MEAT: + return 50; + case ITEM_SUBCLASS_EXPLOSIVES: + return 250; + case ITEM_SUBCLASS_DEVICES: + return 500; + case ITEM_SUBCLASS_ELEMENTAL: + case ITEM_SUBCLASS_TRADE_GOODS_OTHER: + case ITEM_SUBCLASS_ENCHANTING: + return 300; + default: + return 100; + } + } + case ITEM_CLASS_QUEST: return 1000; + case ITEM_CLASS_KEY: return 3000; + default: + return 500; + } +} + +void AuctionBotSeller::SetItemsRatio(uint32 al, uint32 ho, uint32 ne) +{ + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO, std::max(al, 100000u)); + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO, std::max(ho, 100000u)); + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO, std::max(ne, 100000u)); + + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + LoadItemsQuantity(_houseConfig[i]); +} + +void AuctionBotSeller::SetItemsRatioForHouse(AuctionHouseType house, uint32 val) +{ + val = std::max(val, 10000u); // apply same upper limit as used for config load + + switch (house) + { + case AUCTION_HOUSE_ALLIANCE: sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO, val); break; + case AUCTION_HOUSE_HORDE: sAuctionBotConfig->SetConfig(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO, val); break; + default: sAuctionBotConfig->SetConfig(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO, val); break; + } + + LoadItemsQuantity(_houseConfig[house]); +} + +void AuctionBotSeller::SetItemsAmount(uint32(&vals)[MAX_AUCTION_QUALITY]) +{ + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_GRAY_AMOUNT, vals[AUCTION_QUALITY_GRAY]); + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_WHITE_AMOUNT, vals[AUCTION_QUALITY_WHITE]); + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_GREEN_AMOUNT, vals[AUCTION_QUALITY_GREEN]); + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_BLUE_AMOUNT, vals[AUCTION_QUALITY_BLUE]); + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_PURPLE_AMOUNT, vals[AUCTION_QUALITY_PURPLE]); + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_ORANGE_AMOUNT, vals[AUCTION_QUALITY_ORANGE]); + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_YELLOW_AMOUNT, vals[AUCTION_QUALITY_YELLOW]); + + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + LoadItemsQuantity(_houseConfig[i]); +} + +void AuctionBotSeller::SetItemsAmountForQuality(AuctionQuality quality, uint32 val) +{ + switch (quality) + { + case AUCTION_QUALITY_GRAY: + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_GRAY_AMOUNT, val); break; + case AUCTION_QUALITY_WHITE: + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_WHITE_AMOUNT, val); break; + case AUCTION_QUALITY_GREEN: + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_GREEN_AMOUNT, val); break; + case AUCTION_QUALITY_BLUE: + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_BLUE_AMOUNT, val); break; + case AUCTION_QUALITY_PURPLE: + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_PURPLE_AMOUNT, val); break; + case AUCTION_QUALITY_ORANGE: + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_ORANGE_AMOUNT, val); break; + default: + sAuctionBotConfig->SetConfig(CONFIG_AHBOT_ITEM_YELLOW_AMOUNT, val); break; + } + + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + LoadItemsQuantity(_houseConfig[i]); +} + +// Add new auction to one of the factions. +// Faction and setting associated is defined passed argument ( config ) +void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config) +{ + uint32 count = 0; + uint32 items = 0; + + // If there is large amount of items missed we can use boost value to get fast filled AH + if (config.LastMissedItem > sAuctionBotConfig->GetItemPerCycleBoost()) + { + items = sAuctionBotConfig->GetItemPerCycleBoost(); + TC_LOG_DEBUG("ahbot", "AHBot: Boost value used to fill AH! (if this happens often adjust both ItemsPerCycle in worldserver.conf)"); + } + else + items = sAuctionBotConfig->GetItemPerCycleNormal(); + + uint32 houseid = 0; + uint32 auctioneer = 0; + switch (config.GetHouseType()) + { + case AUCTION_HOUSE_ALLIANCE: + houseid = 1; auctioneer = 79707; break; + case AUCTION_HOUSE_HORDE: + houseid = 6; auctioneer = 4656; break; + default: + houseid = 7; auctioneer = 23442; break; + } + + AuctionHouseEntry const* ahEntry = sAuctionHouseStore.LookupEntry(houseid); + + AuctionHouseObject* auctionHouse = sAuctionMgr->GetAuctionsMap(config.GetHouseType()); + + ItemsToSellArray itemsToSell; + AllItemsArray allItems(MAX_AUCTION_QUALITY, std::vector<uint32>(MAX_ITEM_CLASS)); + // Main loop + // getRandomArray will give what categories of items should be added (return true if there is at least 1 items missed) + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + while (GetItemsToSell(config, itemsToSell, allItems) && items > 0) + { + --items; + + // Select random position from missed items table + uint32 pos = urand(0, itemsToSell.size() - 1); + + // Set itemId with random item ID for selected categories and color, from _itemPool table + uint32 itemId = _itemPool[itemsToSell[pos].Color][itemsToSell[pos].Itemclass][urand(0, _itemPool[itemsToSell[pos].Color][itemsToSell[pos].Itemclass].size() - 1)]; + ++allItems[itemsToSell[pos].Color][itemsToSell[pos].Itemclass]; // Helper table to avoid rescan from DB in this loop. (has we add item in random orders) + + if (!itemId) + { + TC_LOG_DEBUG("ahbot", "AHBot: Item entry 0 auction creating attempt."); + continue; + } + + ItemTemplate const* prototype = sObjectMgr->GetItemTemplate(itemId); + if (!prototype) + { + TC_LOG_DEBUG("ahbot", "AHBot: Unknown item %u auction creating attempt.", itemId); + continue; + } + + uint32 stackCount = urand(1, prototype->GetMaxStackSize()); + + Item* item = Item::CreateItem(itemId, stackCount); + if (!item) + { + TC_LOG_ERROR("ahbot", "AHBot: Item::CreateItem() returned NULL for item %u (stack: %u)", itemId, stackCount); + return; + } + + // Update the just created item so that if it needs random properties it has them. + // Ex: Notched Shortsword of Stamina will only generate as a Notched Shortsword without this. + if (int32 randomPropertyId = Item::GenerateItemRandomPropertyId(itemId)) + item->SetItemRandomProperties(randomPropertyId); + + uint32 buyoutPrice; + uint32 bidPrice = 0; + + // Price of items are set here + SetPricesOfItem(prototype, config, buyoutPrice, bidPrice, stackCount); + + // Deposit time + uint32 etime = urand(1, 3); + switch (etime) + { + case 1: + etime = 43200; + break; + case 2: + etime = 86400; + break; + case 3: + etime = 172800; + break; + default: + etime = 86400; + break; + } + + AuctionEntry* auctionEntry = new AuctionEntry(); + auctionEntry->Id = sObjectMgr->GenerateAuctionID(); + auctionEntry->owner = 0; + auctionEntry->itemGUIDLow = item->GetGUIDLow(); + auctionEntry->itemEntry = item->GetEntry(); + auctionEntry->startbid = bidPrice; + auctionEntry->buyout = buyoutPrice; + auctionEntry->auctioneer = auctioneer; + auctionEntry->bidder = 0; + auctionEntry->bid = 0; + auctionEntry->deposit = sAuctionMgr->GetAuctionDeposit(ahEntry, etime, item, stackCount); + auctionEntry->auctionHouseEntry = ahEntry; + auctionEntry->expire_time = time(NULL) + urand(config.GetMinTime(), config.GetMaxTime()) * HOUR; + + item->SaveToDB(trans); + sAuctionMgr->AddAItem(item); + auctionHouse->AddAuction(auctionEntry); + auctionEntry->SaveToDB(trans); + + auctionHouse->AddAuction(auctionEntry); + + ++count; + } + CharacterDatabase.CommitTransaction(trans); + + TC_LOG_DEBUG("ahbot", "AHBot: Added %u items to auction", count); +} + +bool AuctionBotSeller::Update(AuctionHouseType houseType) +{ + if (sAuctionBotConfig->GetConfigItemAmountRatio(houseType) > 0) + { + TC_LOG_DEBUG("ahbot", "AHBot: %s selling ...", AuctionBotConfig::GetHouseTypeName(houseType)); + if (SetStat(_houseConfig[houseType])) + AddNewAuctions(_houseConfig[houseType]); + return true; + } + else + return false; +} diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h new file mode 100644 index 00000000000..014fe23f71a --- /dev/null +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef AUCTION_HOUSE_BOT_SELLER_H +#define AUCTION_HOUSE_BOT_SELLER_H + +#include "Define.h" +#include "ItemPrototype.h" +#include "AuctionHouseBot.h" + +struct ItemToSell +{ + uint32 Color; + uint32 Itemclass; +}; + +typedef std::vector<ItemToSell> ItemsToSellArray; +typedef std::vector<std::vector<uint32>> AllItemsArray; + +struct SellerItemClassInfo +{ + SellerItemClassInfo(): AmountOfItems(0), MissItems(0), Quantity(0), PriceRatio(0) {} + + uint32 AmountOfItems; + uint32 MissItems; + uint32 Quantity; + uint32 PriceRatio; +}; + +struct SellerItemInfo +{ + SellerItemInfo(): AmountOfItems(0), MissItems(0), PriceRatio(0) {} + + uint32 AmountOfItems; + uint32 MissItems; + uint32 PriceRatio; + + SellerItemClassInfo ItemClassInfos[MAX_ITEM_CLASS]; +}; + +class SellerConfiguration +{ +public: + SellerConfiguration(): LastMissedItem(0), _houseType(AUCTION_HOUSE_NEUTRAL), _minTime(1), _maxTime(72) + { + } + + ~SellerConfiguration() {} + + void Initialize(AuctionHouseType houseType) + { + _houseType = houseType; + } + + AuctionHouseType GetHouseType() const { return _houseType; } + + uint32 LastMissedItem; + + void SetMinTime(uint32 value) + { + _minTime = value; + } + uint32 GetMinTime() const + { + return std::min(1u, std::min(_minTime, _maxTime)); + } + + void SetMaxTime(uint32 value) { _maxTime = value; } + uint32 GetMaxTime() const { return _maxTime; } + // Data access classified by item class and item quality + void SetItemsAmountPerClass(AuctionQuality quality, ItemClass itemclass, uint32 amount) { _ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems = amount * _ItemInfo[quality].ItemClassInfos[itemclass].Quantity; } + uint32 GetItemsAmountPerClass(AuctionQuality quality, ItemClass itemclass) const { return _ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems; } + void SetItemsQuantityPerClass(AuctionQuality quality, ItemClass itemclass, uint32 qty) { _ItemInfo[quality].ItemClassInfos[itemclass].Quantity = qty; } + uint32 GetItemsQuantityPerClass(AuctionQuality quality, ItemClass itemclass) const { return _ItemInfo[quality].ItemClassInfos[itemclass].Quantity; } + void SetMissedItemsPerClass(AuctionQuality quality, ItemClass itemclass, uint32 found) + { + if (_ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems > found) + _ItemInfo[quality].ItemClassInfos[itemclass].MissItems = _ItemInfo[quality].ItemClassInfos[itemclass].AmountOfItems - found; + else + _ItemInfo[quality].ItemClassInfos[itemclass].MissItems = 0; + } + uint32 GetMissedItemsPerClass(AuctionQuality quality, ItemClass itemclass) const { return _ItemInfo[quality].ItemClassInfos[itemclass].MissItems; } + + // Data for every quality of item + void SetItemsAmountPerQuality(AuctionQuality quality, uint32 cnt) { _ItemInfo[quality].AmountOfItems = cnt; } + uint32 GetItemsAmountPerQuality(AuctionQuality quality) const { return _ItemInfo[quality].AmountOfItems; } + void SetPriceRatioPerQuality(AuctionQuality quality, uint32 value) { _ItemInfo[quality].PriceRatio = value; } + uint32 GetPriceRatioPerQuality(AuctionQuality quality) const { return _ItemInfo[quality].PriceRatio; } + void SetPriceRatioPerClass(ItemClass item, uint32 value) { _ItemInfo[0].ItemClassInfos[item].PriceRatio = value; } + uint32 GetPriceRatioPerClass(ItemClass item) const { return _ItemInfo[0].ItemClassInfos[item].PriceRatio; } + +private: + AuctionHouseType _houseType; + uint32 _minTime; + uint32 _maxTime; + SellerItemInfo _ItemInfo[MAX_AUCTION_QUALITY]; +}; + +// This class handle all Selling method +// (holder of AHB_Seller_Config data for each auction house type) +class AuctionBotSeller : public AuctionBotAgent +{ +public: + typedef std::vector<uint32> ItemPool; + + AuctionBotSeller(); + ~AuctionBotSeller() override; + + bool Initialize() override; + bool Update(AuctionHouseType houseType) override; + + void AddNewAuctions(SellerConfiguration& config); + void SetItemsRatio(uint32 al, uint32 ho, uint32 ne); + void SetItemsRatioForHouse(AuctionHouseType house, uint32 val); + void SetItemsAmount(uint32(&vals)[MAX_AUCTION_QUALITY]); + void SetItemsAmountForQuality(AuctionQuality quality, uint32 val); + void LoadConfig(); + +private: + SellerConfiguration _houseConfig[MAX_AUCTION_HOUSE_TYPE]; + + ItemPool _itemPool[MAX_AUCTION_QUALITY][MAX_ITEM_CLASS]; + + 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& buyp, uint32& bidp, uint32 stackcnt); + void LoadItemsQuantity(SellerConfiguration& config); + static uint32 GetBuyModifier(ItemTemplate const* prototype); + static uint32 GetSellModifier(ItemTemplate const* itemProto); +}; + +#endif diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp index 1bc83cccaa0..e58c09251ba 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.cpp +++ b/src/server/game/Battlegrounds/ArenaTeam.cpp @@ -240,7 +240,7 @@ bool ArenaTeam::LoadMembersFromDB(QueryResult result) newMember.Name = fields[6].GetString(); newMember.Class = fields[7].GetUInt8(); newMember.PersonalRating = fields[8].GetUInt16(); - newMember.MatchMakerRating = fields[9].GetUInt16() > 0 ? fields[9].GetUInt16() : 1500; + newMember.MatchMakerRating = fields[9].GetUInt16() > 0 ? fields[9].GetUInt16() : sWorld->getIntConfig(CONFIG_ARENA_START_MATCHMAKER_RATING); // Delete member if character information is missing if (newMember.Name.empty()) diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 3a59ffa8cf9..e95e135d8ce 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -733,6 +733,27 @@ void Battleground::EndBattleground(uint32 winner) SetWinner(BG_TEAM_NEUTRAL); } + PreparedStatement* stmt = nullptr; + uint64 battlegroundId = 1; + if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PVPSTATS_MAXID); + PreparedQueryResult result = CharacterDatabase.Query(stmt); + + if (result) + { + Field* fields = result->Fetch(); + battlegroundId = fields[0].GetUInt64() + 1; + } + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_BATTLEGROUND); + stmt->setUInt64(0, battlegroundId); + stmt->setUInt8(1, GetWinner()); + stmt->setUInt8(2, m_BracketId + 1); + stmt->setUInt8(3, GetTypeID(true)); + CharacterDatabase.Execute(stmt); + } + SetStatus(STATUS_WAIT_LEAVE); //we must set it this way, because end time is sent in packet! m_EndTime = TIME_TO_AUTOREMOVE; @@ -770,6 +791,28 @@ void Battleground::EndBattleground(uint32 winner) uint32 loser_kills = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_LOSER_HONOR_FIRST); uint32 winner_arena = player->GetRandomWinner() ? sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_LAST) : sWorld->getIntConfig(CONFIG_BG_REWARD_WINNER_ARENA_FIRST); + if (isBattleground() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE)) + { + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PVPSTATS_PLAYER); + BattlegroundScoreMap::const_iterator score = PlayerScores.find(player->GetGUIDLow()); + + stmt->setUInt32(0, battlegroundId); + stmt->setUInt32(1, player->GetGUIDLow()); + stmt->setUInt32(2, score->second->GetKillingBlows()); + stmt->setUInt32(3, score->second->GetDeaths()); + stmt->setUInt32(4, score->second->GetHonorableKills()); + stmt->setUInt32(5, score->second->GetBonusHonor()); + stmt->setUInt32(6, score->second->GetDamageDone()); + stmt->setUInt32(7, score->second->GetHealingDone()); + stmt->setUInt32(8, score->second->GetAttr1()); + stmt->setUInt32(9, score->second->GetAttr2()); + stmt->setUInt32(10, score->second->GetAttr3()); + stmt->setUInt32(11, score->second->GetAttr4()); + stmt->setUInt32(12, score->second->GetAttr5()); + + CharacterDatabase.Execute(stmt); + } + // Reward winner team if (team == winner) { diff --git a/src/server/game/Battlegrounds/BattlegroundScore.h b/src/server/game/Battlegrounds/BattlegroundScore.h index 81aca355be8..f91c2aae579 100644 --- a/src/server/game/Battlegrounds/BattlegroundScore.h +++ b/src/server/game/Battlegrounds/BattlegroundScore.h @@ -107,6 +107,19 @@ struct BattlegroundScore // For Logging purpose virtual std::string ToString() const { return ""; } + uint32 GetKillingBlows() const { return KillingBlows; } + uint32 GetDeaths() const { return Deaths; } + uint32 GetHonorableKills() const { return HonorableKills; } + uint32 GetBonusHonor() const { return BonusHonor; } + uint32 GetDamageDone() const { return DamageDone; } + uint32 GetHealingDone() const { return HealingDone; } + + virtual uint32 GetAttr1() const { return 0; } + virtual uint32 GetAttr2() const { return 0; } + virtual uint32 GetAttr3() const { return 0; } + virtual uint32 GetAttr4() const { return 0; } + virtual uint32 GetAttr5() const { return 0; } + uint64 PlayerGuid; // Default score, present in every type diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h index 7655880117f..aed82efd5cb 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAB.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAB.h @@ -267,6 +267,9 @@ struct BattlegroundABScore final : public BattlegroundScore data << uint32(BasesDefended); } + uint32 GetAttr1() const final override { return BasesAssaulted; } + uint32 GetAttr2() const final override { return BasesDefended; } + uint32 BasesAssaulted; uint32 BasesDefended; }; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h index 882d729c1e8..b56ec2ca489 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundAV.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundAV.h @@ -1568,6 +1568,12 @@ struct BattlegroundAVScore final : public BattlegroundScore data << uint32(MinesCaptured); } + uint32 GetAttr1() const final override { return GraveyardsAssaulted; } + uint32 GetAttr2() const final override { return GraveyardsDefended; } + uint32 GetAttr3() const final override { return TowersAssaulted; } + uint32 GetAttr4() const final override { return TowersDefended; } + uint32 GetAttr5() const final override { return MinesCaptured; } + uint32 GraveyardsAssaulted; uint32 GraveyardsDefended; uint32 TowersAssaulted; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h index 4a146a17917..408037b254e 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.h @@ -349,6 +349,8 @@ struct BattlegroundEYScore final : public BattlegroundScore data << uint32(FlagCaptures); } + uint32 GetAttr1() const final override { return FlagCaptures; } + uint32 FlagCaptures; }; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h index 5a9b47ec9b5..c772078a647 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.h @@ -878,6 +878,9 @@ struct BattlegroundICScore final : public BattlegroundScore data << uint32(BasesDefended); } + uint32 GetAttr1() const final override { return BasesAssaulted; } + uint32 GetAttr2() const final override { return BasesDefended; } + uint32 BasesAssaulted; uint32 BasesDefended; }; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h index 627c23850d2..eae9e02ba9e 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.h @@ -538,6 +538,9 @@ struct BattlegroundSAScore final : public BattlegroundScore data << uint32(GatesDestroyed); } + uint32 GetAttr1() const final override { return DemolishersDestroyed; } + uint32 GetAttr2() const final override { return GatesDestroyed; } + uint32 DemolishersDestroyed; uint32 GatesDestroyed; }; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h index d29715c982b..71bd5d53047 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundWS.h +++ b/src/server/game/Battlegrounds/Zones/BattlegroundWS.h @@ -177,6 +177,9 @@ struct BattlegroundWGScore final : public BattlegroundScore data << uint32(FlagReturns); } + uint32 GetAttr1() const final override { return FlagCaptures; } + uint32 GetAttr2() const final override { return FlagReturns; } + uint32 FlagCaptures; uint32 FlagReturns; }; diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 532900c0438..d7d14e7bda4 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -13,6 +13,7 @@ file(GLOB_RECURSE sources_Achievements Achievements/*.cpp Achievements/*.h) file(GLOB_RECURSE sources_Addons Addons/*.cpp Addons/*.h) file(GLOB_RECURSE sources_AI AI/*.cpp AI/*.h) file(GLOB_RECURSE sources_AuctionHouse AuctionHouse/*.cpp AuctionHouse/*.h) +file(GLOB_RECURSE sources_AuctionHouseBot AuctionHouseBot/*.cpp AuctionHouseBot/*.h) file(GLOB_RECURSE sources_Battlefield Battlefield/*.cpp Battlefield/*.h) file(GLOB_RECURSE sources_Battlegrounds Battlegrounds/*.cpp Battlegrounds/*.h) file(GLOB_RECURSE sources_Calendar Calendar/*.cpp Calendar/*.h) @@ -63,6 +64,7 @@ set(game_STAT_SRCS ${sources_Addons} ${sources_AI} ${sources_AuctionHouse} + ${sources_AuctionHouseBot} ${sources_Battlefield} ${sources_Battlegrounds} ${sources_Calendar} @@ -136,6 +138,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/AI/ScriptedAI ${CMAKE_CURRENT_SOURCE_DIR}/AI/SmartScripts ${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouse + ${CMAKE_CURRENT_SOURCE_DIR}/AuctionHouseBot ${CMAKE_CURRENT_SOURCE_DIR}/Battlefield ${CMAKE_CURRENT_SOURCE_DIR}/Battlefield/Zones ${CMAKE_CURRENT_SOURCE_DIR}/Battlegrounds diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 50f67d4f920..265197e9c3b 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -1148,7 +1148,7 @@ bool ChatHandler::extractPlayerTarget(char* args, Player** player, uint64* playe } else { - Player* pl = getSelectedPlayer(); + Player* pl = getSelectedPlayerOrSelf(); // if allowed player pointer if (player) *player = pl; diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index 32820de0fc2..c0e3da32b3f 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -112,7 +112,7 @@ class ChatHandler GameTele const* extractGameTeleFromLink(char* text); bool GetPlayerGroupAndGUIDByName(const char* cname, Player* &player, Group* &group, uint64 &guid, bool offline = false); std::string extractPlayerNameFromLink(char* text); - // select by arg (name/link) or in-game selection online/offline player + // select by arg (name/link) or in-game selection online/offline player or self if a creature is selected bool extractPlayerTarget(char* args, Player** player, uint64* player_guid = NULL, std::string* player_name = NULL); std::string playerLink(std::string const& name) const { return m_session ? "|cffffffff|Hplayer:"+name+"|h["+name+"]|h|r" : name; } diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 6894dd86493..5a4ef765a6e 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -690,8 +690,11 @@ void Item::SetState(ItemUpdateState state, Player* forplayer) if (uState == ITEM_NEW && state == ITEM_REMOVED) { // pretend the item never existed - RemoveFromUpdateQueueOf(forplayer); - forplayer->DeleteRefundReference(GetGUIDLow()); + if (forplayer) + { + RemoveFromUpdateQueueOf(forplayer); + forplayer->DeleteRefundReference(GetGUIDLow()); + } delete this; return; } @@ -701,7 +704,8 @@ void Item::SetState(ItemUpdateState state, Player* forplayer) if (uState != ITEM_NEW) uState = state; - AddToUpdateQueueOf(forplayer); + if (forplayer) + AddToUpdateQueueOf(forplayer); } else { diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index cdc61f8b2ff..85381c1dfd9 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -700,7 +700,7 @@ class WorldObject : public Object, public WorldLocation TempSummon* SummonCreature(uint32 id, Position const &pos, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0, uint32 vehId = 0) const; TempSummon* SummonCreature(uint32 id, float x, float y, float z, float ang = 0, TempSummonType spwtype = TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime = 0) const; - GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime); + GameObject* SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime /* s */); Creature* SummonTrigger(float x, float y, float z, float ang, uint32 dur, CreatureAI* (*GetAI)(Creature*) = NULL); void SummonCreatureGroup(uint8 group, std::list<TempSummon*>* list = NULL); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 1fc1cd9f7b8..71a7f4b160e 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -15296,6 +15296,19 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, Item* item = StoreNewItem(dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); SendNewItem(item, quest->RewardItemIdCount[i], true, false); } + else if (quest->IsDFQuest()) + { + MailSender sender(MAIL_CREATURE, 34337 /* The Postmaster */ ); + MailDraft draft("Recovered Item", "We recovered a lost item in the twisting nether and noted that it was yours.$B$BPlease find said object enclosed."); // This is the text used in Cataclysm, it probably wasn't changed. + SQLTransaction trans = CharacterDatabase.BeginTransaction(); + if (Item* item = Item::CreateItem(quest->RewardItemId[i], quest->RewardItemIdCount[i], 0)) + { + item->SaveToDB(trans); + draft.AddItem(item); + } + draft.SendMailTo(trans, MailReceiver(this, this->GetGUIDLow()), sender); + CharacterDatabase.CommitTransaction(trans); + } } } } @@ -15309,7 +15322,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool rewarded = (m_RewardedQuests.find(quest_id) != m_RewardedQuests.end()); // Not give XP in case already completed once repeatable quest - uint32 XP = rewarded ? 0 : uint32(quest->XPValue(this)*sWorld->getRate(RATE_XP_QUEST)); + uint32 XP = rewarded && !quest->IsDFQuest() ? 0 : uint32(quest->XPValue(this)*sWorld->getRate(RATE_XP_QUEST)); // handle SPELL_AURA_MOD_XP_QUEST_PCT auras Unit::AuraEffectList const& ModXPPctAuras = GetAuraEffectsByType(SPELL_AURA_MOD_XP_QUEST_PCT); @@ -15435,6 +15448,10 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, void Player::FailQuest(uint32 questId) { + // Already complete quests shouldn't turn failed. + if (GetQuestStatus(questId) == QUEST_STATUS_COMPLETE) + return; + if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId)) { SetQuestStatus(questId, QUEST_STATUS_FAILED); @@ -22684,6 +22701,8 @@ bool Player::ModifyMoney(int32 amount, bool sendError /*= true*/) SetMoney(GetMoney() + amount); else { + sScriptMgr->OnPlayerMoneyLimit(this, amount); + if (sendError) SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, NULL, NULL); return false; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d75e7db11fe..bfa57ef64b8 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -14333,7 +14333,18 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u // Remove charge (aura can be removed by triggers) if (prepare && useCharges && takeCharges) - i->aura->DropCharge(); + { + // Set charge drop delay (only for missiles) + if ((procExtra & PROC_EX_REFLECT) && target && procSpell && procSpell->Speed > 0.0f) + { + // Set up missile speed based delay (from Spell.cpp: Spell::AddUnitTarget()::L2237) + uint32 delay = uint32(std::floor(std::max<float>(target->GetDistance(this), 5.0f) / procSpell->Speed * 1000.0f)); + // Schedule charge drop + i->aura->DropChargeDelayed(delay); + } + else + i->aura->DropCharge(); + } i->aura->CallScriptAfterProcHandlers(aurApp, eventInfo); diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index 8c7b926a700..375d39cf232 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -657,6 +657,9 @@ public: std::string const& GetName() const { return m_name; } std::string const& GetMOTD() const { return m_motd; } std::string const& GetInfo() const { return m_info; } + uint32 GetMemberCount() const { return m_members.size(); } + time_t GetCreatedDate() const { return m_createdDate; } + uint64 GetBankMoney() const { return m_bankMoney; } bool SetName(std::string const& name); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 243a931d463..9e29fb01c3b 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -159,7 +159,7 @@ void Map::LoadMap(int gx, int gy, bool reload) // load grid map for base map if (!m_parentMap->GridMaps[gx][gy]) - m_parentMap->EnsureGridCreated_i(GridCoord(63-gx, 63-gy)); + m_parentMap->EnsureGridCreated(GridCoord(63-gx, 63-gy)); ((MapInstanced*)(m_parentMap))->AddGridMapReference(GridCoord(gx, gy)); GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy]; diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index f4d1bc03144..cb868097ac6 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -941,7 +941,34 @@ enum TrinityStrings LANG_LIST_MAIL_INFO_3 = 1154, LANG_LIST_MAIL_INFO_ITEM = 1155, LANG_LIST_MAIL_NOT_FOUND = 1156, - // Room for more level 3 1157-1199 not used + LANG_AHBOT_RELOAD_OK = 1157, + LANG_AHBOT_STATUS_BAR_CONSOLE = 1158, + LANG_AHBOT_STATUS_MIDBAR_CONSOLE = 1159, + LANG_AHBOT_STATUS_TITLE1_CONSOLE = 1160, + LANG_AHBOT_STATUS_TITLE1_CHAT = 1161, + LANG_AHBOT_STATUS_FORMAT_CONSOLE = 1162, + LANG_AHBOT_STATUS_FORMAT_CHAT = 1163, + LANG_AHBOT_STATUS_ITEM_COUNT = 1164, + LANG_AHBOT_STATUS_ITEM_RATIO = 1165, + LANG_AHBOT_STATUS_TITLE2_CONSOLE = 1166, + LANG_AHBOT_STATUS_TITLE2_CHAT = 1167, + LANG_AHBOT_QUALITY_GRAY = 1168, + LANG_AHBOT_QUALITY_WHITE = 1169, + LANG_AHBOT_QUALITY_GREEN = 1170, + LANG_AHBOT_QUALITY_BLUE = 1171, + LANG_AHBOT_QUALITY_PURPLE = 1172, + LANG_AHBOT_QUALITY_ORANGE = 1173, + LANG_AHBOT_QUALITY_YELLOW = 1174, + LANG_AHBOT_ITEMS_AMOUNT = 1175, + LANG_AHBOT_ITEMS_RATIO = 1176, + LANG_GUILD_INFO_NAME = 1177, + LANG_GUILD_INFO_GUILD_MASTER = 1178, + LANG_GUILD_INFO_CREATION_DATE = 1179, + LANG_GUILD_INFO_MEMBER_COUNT = 1180, + LANG_GUILD_INFO_BANK_GOLD = 1181, + LANG_GUILD_INFO_MOTD = 1182, + LANG_GUILD_INFO_EXTRA_INFO = 1183, + // Room for more level 3 1184-1199 not used // Debug commands LANG_CINEMATIC_NOT_EXIST = 1200, diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index d036d438926..ed6c5430674 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -47,6 +47,7 @@ void AddSC_SmartScripts(); //Commands void AddSC_account_commandscript(); void AddSC_achievement_commandscript(); +void AddSC_ahbot_commandscript(); void AddSC_arena_commandscript(); void AddSC_ban_commandscript(); void AddSC_bf_commandscript(); @@ -749,6 +750,7 @@ void AddCommandScripts() { AddSC_account_commandscript(); AddSC_achievement_commandscript(); + AddSC_ahbot_commandscript(); AddSC_arena_commandscript(); AddSC_ban_commandscript(); AddSC_bf_commandscript(); diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index daa4c36a442..d13c81ed059 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -1180,6 +1180,11 @@ void ScriptMgr::OnPlayerMoneyChanged(Player* player, int32& amount) FOREACH_SCRIPT(PlayerScript)->OnMoneyChanged(player, amount); } +void ScriptMgr::OnPlayerMoneyLimit(Player* player, int32 amount) +{ + FOREACH_SCRIPT(PlayerScript)->OnMoneyLimit(player, amount); +} + void ScriptMgr::OnGivePlayerXP(Player* player, uint32& amount, Unit* victim) { FOREACH_SCRIPT(PlayerScript)->OnGiveXP(player, amount, victim); diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index ea25d51dab2..499d7ff6c09 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -706,6 +706,9 @@ class PlayerScript : public UnitScript // Called when a player's money is modified (before the modification is done) virtual void OnMoneyChanged(Player* /*player*/, int32& /*amount*/) { } + // Called when a player's money is at limit (amount = money tried to add) + virtual void OnMoneyLimit(Player* /*player*/, int32 /*amount*/) { } + // Called when a player gains XP (before anything is given) virtual void OnGiveXP(Player* /*player*/, uint32& /*amount*/, Unit* /*victim*/) { } @@ -1053,6 +1056,7 @@ class ScriptMgr void OnPlayerFreeTalentPointsChanged(Player* player, uint32 newPoints); void OnPlayerTalentsReset(Player* player, bool noCost); void OnPlayerMoneyChanged(Player* player, int32& amount); + void OnPlayerMoneyLimit(Player* player, int32 amount); void OnGivePlayerXP(Player* player, uint32& amount, Unit* victim); void OnPlayerReputationChange(Player* player, uint32 factionID, int32& standing, bool incremental); void OnPlayerDuelRequest(Player* target, Player* challenger); diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 348869075ee..07cfa80f297 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -335,7 +335,7 @@ m_spellInfo(spellproto), m_casterGuid(casterGUID ? casterGUID : caster->GetGUID( m_castItemGuid(castItem ? castItem->GetGUID() : 0), m_applyTime(time(NULL)), m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0), m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1), -m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false) +m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr) { if (m_spellInfo->ManaPerSecond || m_spellInfo->ManaPerSecondPerLevel) m_timeCla = 1 * IN_MILLISECONDS; @@ -467,6 +467,12 @@ void Aura::_Remove(AuraRemoveMode removeMode) target->_UnapplyAura(aurApp, removeMode); appItr = m_applications.begin(); } + + if (m_dropEvent) + { + m_dropEvent->to_Abort = true; + m_dropEvent = nullptr; + } } void Aura::UpdateTargetMap(Unit* caster, bool apply) @@ -815,6 +821,26 @@ bool Aura::ModCharges(int32 num, AuraRemoveMode removeMode) return false; } +void Aura::ModChargesDelayed(int32 num, AuraRemoveMode removeMode) +{ + m_dropEvent = nullptr; + ModCharges(num, removeMode); +} + +void Aura::DropChargeDelayed(uint32 delay, AuraRemoveMode removeMode) +{ + // aura is already during delayed charge drop + if (m_dropEvent) + return; + // only units have events + Unit* owner = m_owner->ToUnit(); + if (!owner) + return; + + m_dropEvent = new ChargeDropEvent(this, removeMode); + owner->m_Events.AddEvent(m_dropEvent, owner->m_Events.CalculateTime(delay)); +} + void Aura::SetStackAmount(uint8 stackAmount) { m_stackAmount = stackAmount; @@ -2538,3 +2564,9 @@ void DynObjAura::FillTargetMap(std::map<Unit*, uint8> & targets, Unit* /*caster* } } +bool ChargeDropEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) +{ + // _base is always valid (look in Aura::_Remove()) + _base->ModChargesDelayed(-1, _mode); + return true; +} diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index e578c0ffc3a..1266bf5c6ec 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -34,6 +34,7 @@ class Aura; class DynamicObject; class AuraScript; class ProcInfo; +class ChargeDropEvent; // update aura target map every 500 ms instead of every update - reduce amount of grid searcher calls #define UPDATE_TARGET_MAP_INTERVAL 500 @@ -131,7 +132,7 @@ class Aura void SetDuration(int32 duration, bool withMods = false); void RefreshDuration(bool withMods = false); void RefreshTimers(); - bool IsExpired() const { return !GetDuration();} + bool IsExpired() const { return !GetDuration() && !m_dropEvent; } bool IsPermanent() const { return GetMaxDuration() == -1; } uint8 GetCharges() const { return m_procCharges; } @@ -140,6 +141,8 @@ class Aura uint8 CalcMaxCharges() const { return CalcMaxCharges(GetCaster()); } bool ModCharges(int32 num, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); bool DropCharge(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) { return ModCharges(-1, removeMode); } + void ModChargesDelayed(int32 num, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); + void DropChargeDelayed(uint32 delay, AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT); uint8 GetStackAmount() const { return m_stackAmount; } void SetStackAmount(uint8 num); @@ -264,6 +267,8 @@ class Aura bool m_isSingleTarget:1; // true if it's a single target spell and registered at caster - can change at spell steal for example bool m_isUsingCharges:1; + ChargeDropEvent* m_dropEvent; + private: Unit::AuraApplicationList m_removedApplications; }; @@ -299,4 +304,16 @@ class DynObjAura : public Aura void FillTargetMap(std::map<Unit*, uint8> & targets, Unit* caster) override; }; + +class ChargeDropEvent : public BasicEvent +{ + friend class Aura; + protected: + ChargeDropEvent(Aura* base, AuraRemoveMode mode) : _base(base), _mode(mode) { } + bool Execute(uint64 /*e_time*/, uint32 /*p_time*/); + + private: + Aura* _base; + AuraRemoveMode _mode; +}; #endif diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index bc97744fe32..8e0c8c8bd01 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3350,6 +3350,16 @@ void SpellMgr::LoadSpellInfoCorrections() // that will be clear if we get more spells with problem like this spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY; break; + case 63414: // Spinning Up (Mimiron) + spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_UNIT_CASTER); + spellInfo->ChannelInterruptFlags = 0; + break; + case 63036: // Rocket Strike (Mimiron) + spellInfo->Speed = 0; + break; + case 64668: // Magnetic Field (Mimiron) + spellInfo->Mechanic = MECHANIC_NONE; + break; case 64468: // Empowering Shadows (Yogg-Saron) case 64486: // Empowering Shadows (Yogg-Saron) spellInfo->MaxAffectedTargets = 3; // same for both modes? diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 4de9cb34df6..f9c8c800ca5 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -23,6 +23,7 @@ #include "World.h" #include "AchievementMgr.h" #include "ArenaTeamMgr.h" +#include "AuctionHouseBot.h" #include "AuctionHouseMgr.h" #include "BattlefieldMgr.h" #include "BattlegroundMgr.h" @@ -1021,6 +1022,7 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_BATTLEGROUND_CAST_DESERTER] = sConfigMgr->GetBoolDefault("Battleground.CastDeserter", true); m_bool_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE] = sConfigMgr->GetBoolDefault("Battleground.QueueAnnouncer.Enable", false); m_bool_configs[CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY] = sConfigMgr->GetBoolDefault("Battleground.QueueAnnouncer.PlayerOnly", false); + m_bool_configs[CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE] = sConfigMgr->GetBoolDefault("Battleground.StoreStatistics.Enable", false); m_int_configs[CONFIG_BATTLEGROUND_INVITATION_TYPE] = sConfigMgr->GetIntDefault ("Battleground.InvitationType", 0); m_int_configs[CONFIG_BATTLEGROUND_PREMATURE_FINISH_TIMER] = sConfigMgr->GetIntDefault ("Battleground.PrematureFinishTimer", 5 * MINUTE * IN_MILLISECONDS); m_int_configs[CONFIG_BATTLEGROUND_PREMADE_GROUP_WAIT_FOR_MATCH] = sConfigMgr->GetIntDefault ("Battleground.PremadeGroupWaitForMatch", 30 * MINUTE * IN_MILLISECONDS); @@ -1254,6 +1256,9 @@ void World::LoadConfigSettings(bool reload) m_bool_configs[CONFIG_IP_BASED_ACTION_LOGGING] = sConfigMgr->GetBoolDefault("Allow.IP.Based.Action.Logging", false); + // AHBot + m_int_configs[CONFIG_AHBOT_UPDATE_INTERVAL] = sConfigMgr->GetIntDefault("AuctionHouseBot.Update.Interval", 20); + // call ScriptMgr if we're reloading the configuration if (reload) sScriptMgr->OnConfigLoad(reload); @@ -1739,6 +1744,9 @@ void World::SetInitialWorldSettings() m_timers[WUPDATE_AUTOBROADCAST].SetInterval(getIntConfig(CONFIG_AUTOBROADCAST_INTERVAL)); m_timers[WUPDATE_DELETECHARS].SetInterval(DAY*IN_MILLISECONDS); // check for chars to delete every day + // for AhBot + m_timers[WUPDATE_AHBOT].SetInterval(getIntConfig(CONFIG_AHBOT_UPDATE_INTERVAL) * IN_MILLISECONDS); // every 20 sec + m_timers[WUPDATE_PINGDB].SetInterval(getIntConfig(CONFIG_DB_PING_INTERVAL)*MINUTE*IN_MILLISECONDS); // Mysql ping time in minutes //to set mailtimer to return mails every day between 4 and 5 am @@ -1766,6 +1774,9 @@ void World::SetInitialWorldSettings() // Delete all characters which have been deleted X days before Player::DeleteOldCharacters(); + TC_LOG_INFO("server.loading", "Initialize AuctionHouseBot..."); + sAuctionBot->Initialize(); + // Delete all custom channels which haven't been used for PreserveCustomChannelDuration days. Channel::CleanOldChannelsInDB(); @@ -1998,6 +2009,13 @@ void World::Update(uint32 diff) sAuctionMgr->Update(); } + /// <li> Handle AHBot operations + if (m_timers[WUPDATE_AHBOT].Passed()) + { + sAuctionBot->Update(); + m_timers[WUPDATE_AHBOT].Reset(); + } + /// <li> Handle session updates when the timer has passed RecordTimeDiff(NULL); UpdateSessions(diff); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index cb87e1739c2..b77f8777bdc 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -76,6 +76,7 @@ enum WorldTimers WUPDATE_AUTOBROADCAST, WUPDATE_MAILBOXQUEUE, WUPDATE_DELETECHARS, + WUPDATE_AHBOT, WUPDATE_PINGDB, WUPDATE_COUNT }; @@ -121,6 +122,7 @@ enum WorldBoolConfigs CONFIG_BATTLEGROUND_CAST_DESERTER, CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE, CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_PLAYERONLY, + CONFIG_BATTLEGROUND_STORE_STATISTICS_ENABLE, CONFIG_BG_XP_FOR_KILL, CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS, CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE, @@ -332,6 +334,7 @@ enum WorldIntConfigs CONFIG_BG_REWARD_LOSER_HONOR_LAST, CONFIG_BIRTHDAY_TIME, CONFIG_CREATURE_PICKPOCKET_REFILL, + CONFIG_AHBOT_UPDATE_INTERVAL, INT_CONFIG_VALUE_COUNT }; diff --git a/src/server/scripts/CMakeLists.txt b/src/server/scripts/CMakeLists.txt index ba2709f0a23..f193cf4aa6a 100644 --- a/src/server/scripts/CMakeLists.txt +++ b/src/server/scripts/CMakeLists.txt @@ -78,6 +78,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/game/AI/ScriptedAI ${CMAKE_SOURCE_DIR}/src/server/game/AI/SmartScripts ${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouse + ${CMAKE_SOURCE_DIR}/src/server/game/AuctionHouseBot ${CMAKE_SOURCE_DIR}/src/server/game/Battlefield ${CMAKE_SOURCE_DIR}/src/server/game/Battlefield/Zones ${CMAKE_SOURCE_DIR}/src/server/game/Battlegrounds diff --git a/src/server/scripts/Commands/cs_ahbot.cpp b/src/server/scripts/Commands/cs_ahbot.cpp new file mode 100644 index 00000000000..04647d51ff0 --- /dev/null +++ b/src/server/scripts/Commands/cs_ahbot.cpp @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "Chat.h" +#include "Language.h" +#include "AuctionHouseBot.h" + +static const uint32 ahbotQualityIds[MAX_AUCTION_QUALITY] = +{ + LANG_AHBOT_QUALITY_GRAY, LANG_AHBOT_QUALITY_WHITE, + LANG_AHBOT_QUALITY_GREEN, LANG_AHBOT_QUALITY_BLUE, + LANG_AHBOT_QUALITY_PURPLE, LANG_AHBOT_QUALITY_ORANGE, + LANG_AHBOT_QUALITY_YELLOW +}; + +class ahbot_commandscript : public CommandScript +{ +public: + ahbot_commandscript(): CommandScript("ahbot_commandscript") {} + + ChatCommand* GetCommands() const + { + static ChatCommand ahbotItemsAmountCommandTable[] = + { + { "gray", rbac::RBAC_PERM_COMMAND_AHBOT_ITEMS_GRAY, true, &HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_GRAY>, "", NULL }, + { "white", rbac::RBAC_PERM_COMMAND_AHBOT_ITEMS_WHITE, true, &HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_WHITE>, "", NULL }, + { "green", rbac::RBAC_PERM_COMMAND_AHBOT_ITEMS_GREEN, true, &HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_GREEN>, "", NULL }, + { "blue", rbac::RBAC_PERM_COMMAND_AHBOT_ITEMS_BLUE, true, &HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_BLUE>, "", NULL }, + { "purple", rbac::RBAC_PERM_COMMAND_AHBOT_ITEMS_PURPLE, true, &HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_PURPLE>, "", NULL }, + { "orange", rbac::RBAC_PERM_COMMAND_AHBOT_ITEMS_ORANGE, true, &HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_ORANGE>, "", NULL }, + { "yellow", rbac::RBAC_PERM_COMMAND_AHBOT_ITEMS_YELLOW, true, &HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_YELLOW>, "", NULL }, + { "", rbac::RBAC_PERM_COMMAND_AHBOT_ITEMS, true, &HandleAHBotItemsAmountCommand, "", NULL }, + { NULL, 0, true, NULL, "", NULL } + }; + + static ChatCommand ahbotItemsRatioCommandTable[] = + { + { "alliance", rbac::RBAC_PERM_COMMAND_AHBOT_RATIO_ALLIANCE, true, &HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_ALLIANCE>, "", NULL }, + { "horde", rbac::RBAC_PERM_COMMAND_AHBOT_RATIO_HORDE, true, &HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_HORDE>, "", NULL }, + { "neutral", rbac::RBAC_PERM_COMMAND_AHBOT_RATIO_NEUTRAL, true, &HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_NEUTRAL>, "", NULL }, + { "", rbac::RBAC_PERM_COMMAND_AHBOT_RATIO, true, &HandleAHBotItemsRatioCommand, "", NULL }, + { NULL, 0, true, NULL, "", NULL } + }; + + static ChatCommand ahbotCommandTable[] = + { + { "items", rbac::RBAC_PERM_COMMAND_AHBOT_ITEMS, true, NULL, "", ahbotItemsAmountCommandTable }, + { "ratio", rbac::RBAC_PERM_COMMAND_AHBOT_RATIO, true, NULL, "", ahbotItemsRatioCommandTable }, + { "rebuild", rbac::RBAC_PERM_COMMAND_AHBOT_REBUILD, true, &HandleAHBotRebuildCommand, "", NULL }, + { "reload", rbac::RBAC_PERM_COMMAND_AHBOT_RELOAD, true, &HandleAHBotReloadCommand, "", NULL }, + { "status", rbac::RBAC_PERM_COMMAND_AHBOT_STATUS, true, &HandleAHBotStatusCommand, "", NULL }, + { NULL, 0, true, NULL, "", NULL } + }; + + static ChatCommand commandTable[] = + { + { "ahbot", rbac::RBAC_PERM_COMMAND_AHBOT, false, NULL, "", ahbotCommandTable }, + { NULL, 0, false, NULL, "", NULL } + }; + + return commandTable; + } + + static bool HandleAHBotItemsAmountCommand(ChatHandler* handler, const char* args) + { + uint32 qVals[MAX_AUCTION_QUALITY]; + char* arg = strtok((char*)args, " "); + for (int i = 0; i < MAX_AUCTION_QUALITY; ++i) + { + if (!arg) + return false; + qVals[i] = atoi(arg); + arg = strtok(NULL, " "); + } + + sAuctionBot->SetItemsAmount(qVals); + + for (int i = 0; i < MAX_AUCTION_QUALITY; ++i) + handler->PSendSysMessage(LANG_AHBOT_ITEMS_AMOUNT, handler->GetTrinityString(ahbotQualityIds[i]), sAuctionBotConfig->GetConfigItemQualityAmount(AuctionQuality(i))); + + return true; + } + + template <AuctionQuality Q> + static bool HandleAHBotItemsAmountQualityCommand(ChatHandler* handler, const char* args) + { + char* arg = strtok((char*)args, " "); + if (!arg) + return false; + uint32 qualityVal = atoi(arg); + + sAuctionBot->SetItemsAmountForQuality(Q, qualityVal); + handler->PSendSysMessage(LANG_AHBOT_ITEMS_AMOUNT, handler->GetTrinityString(ahbotQualityIds[Q]), + sAuctionBotConfig->GetConfigItemQualityAmount(Q)); + + return true; + } + + static bool HandleAHBotItemsRatioCommand(ChatHandler* handler, const char* args) + { + uint32 rVal[MAX_AUCTION_QUALITY]; + char* arg = strtok((char*)args, " "); + for (int i = 0; i < MAX_AUCTION_QUALITY; ++i) + { + if (!arg) + return false; + rVal[i] = atoi(arg); + arg = strtok(NULL, " "); + } + + sAuctionBot->SetItemsRatio(rVal[0], rVal[1], rVal[2]); + + for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) + handler->PSendSysMessage(LANG_AHBOT_ITEMS_RATIO, AuctionBotConfig::GetHouseTypeName(AuctionHouseType(i)), sAuctionBotConfig->GetConfigItemAmountRatio(AuctionHouseType(i))); + return true; + } + + template<AuctionHouseType H> + static bool HandleAHBotItemsRatioHouseCommand(ChatHandler* handler, const char* args) + { + char* arg = strtok((char*)args, " "); + if (!arg) + return false; + uint32 ratioVal = atoi(arg); + + sAuctionBot->SetItemsRatioForHouse(H, ratioVal); + handler->PSendSysMessage(LANG_AHBOT_ITEMS_RATIO, AuctionBotConfig::GetHouseTypeName(H), sAuctionBotConfig->GetConfigItemAmountRatio(H)); + return true; + } + + static bool HandleAHBotRebuildCommand(ChatHandler* /*handler*/, const char* args) + { + char* arg = strtok((char*)args, " "); + if (!arg) + return false; + + bool all = false; + if (strcmp(arg, "all") == 0) + all = true; + + sAuctionBot->Rebuild(all); + return true; + } + + static bool HandleAHBotReloadCommand(ChatHandler* handler, const char* /*args*/) + { + sAuctionBot->ReloadAllConfig(); + handler->SendSysMessage(LANG_AHBOT_RELOAD_OK); + return true; + } + + static bool HandleAHBotStatusCommand(ChatHandler* handler, const char* args) + { + char* arg = strtok((char*)args, " "); + if (!arg) + return false; + + bool all = false; + if (strcmp(arg, "all") == 0) + all = true; + + AuctionHouseBotStatusInfo statusInfo; + sAuctionBot->PrepareStatusInfos(statusInfo); + + WorldSession* session = handler->GetSession(); + + if (!session) + { + handler->SendSysMessage(LANG_AHBOT_STATUS_BAR_CONSOLE); + handler->SendSysMessage(LANG_AHBOT_STATUS_TITLE1_CONSOLE); + handler->SendSysMessage(LANG_AHBOT_STATUS_MIDBAR_CONSOLE); + } + else + handler->SendSysMessage(LANG_AHBOT_STATUS_TITLE1_CHAT); + + uint32 fmtId = session ? LANG_AHBOT_STATUS_FORMAT_CHAT : LANG_AHBOT_STATUS_FORMAT_CONSOLE; + + handler->PSendSysMessage(fmtId, handler->GetTrinityString(LANG_AHBOT_STATUS_ITEM_COUNT), + statusInfo[AUCTION_HOUSE_ALLIANCE].ItemsCount, + statusInfo[AUCTION_HOUSE_HORDE].ItemsCount, + statusInfo[AUCTION_HOUSE_NEUTRAL].ItemsCount, + statusInfo[AUCTION_HOUSE_ALLIANCE].ItemsCount + + statusInfo[AUCTION_HOUSE_HORDE].ItemsCount + + statusInfo[AUCTION_HOUSE_NEUTRAL].ItemsCount); + + if (all) + { + handler->PSendSysMessage(fmtId, handler->GetTrinityString(LANG_AHBOT_STATUS_ITEM_RATIO), + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO), + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO), + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO), + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_ALLIANCE_ITEM_AMOUNT_RATIO) + + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_HORDE_ITEM_AMOUNT_RATIO) + + sAuctionBotConfig->GetConfig(CONFIG_AHBOT_NEUTRAL_ITEM_AMOUNT_RATIO)); + + if (!session) + { + handler->SendSysMessage(LANG_AHBOT_STATUS_BAR_CONSOLE); + handler->SendSysMessage(LANG_AHBOT_STATUS_TITLE2_CONSOLE); + handler->SendSysMessage(LANG_AHBOT_STATUS_MIDBAR_CONSOLE); + } + else + handler->SendSysMessage(LANG_AHBOT_STATUS_TITLE2_CHAT); + + for (int i = 0; i < MAX_AUCTION_QUALITY; ++i) + handler->PSendSysMessage(fmtId, handler->GetTrinityString(ahbotQualityIds[i]), + statusInfo[AUCTION_HOUSE_ALLIANCE].QualityInfo[i], + statusInfo[AUCTION_HOUSE_HORDE].QualityInfo[i], + statusInfo[AUCTION_HOUSE_NEUTRAL].QualityInfo[i], + sAuctionBotConfig->GetConfigItemQualityAmount(AuctionQuality(i))); + } + + if (!session) + handler->SendSysMessage(LANG_AHBOT_STATUS_BAR_CONSOLE); + + return true; + } + +}; + +template bool ahbot_commandscript::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_GRAY>(ChatHandler* handler, const char*); +template bool ahbot_commandscript::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_WHITE>(ChatHandler* handler, const char*); +template bool ahbot_commandscript::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_GREEN>(ChatHandler* handler, const char*); +template bool ahbot_commandscript::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_BLUE>(ChatHandler* handler, const char*); +template bool ahbot_commandscript::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_PURPLE>(ChatHandler* handler, const char*); +template bool ahbot_commandscript::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_ORANGE>(ChatHandler* handler, const char*); +template bool ahbot_commandscript::HandleAHBotItemsAmountQualityCommand<AUCTION_QUALITY_YELLOW>(ChatHandler* handler, const char*); + +template bool ahbot_commandscript::HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_ALLIANCE>(ChatHandler* handler, const char*); +template bool ahbot_commandscript::HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_HORDE>(ChatHandler* handler, const char*); +template bool ahbot_commandscript::HandleAHBotItemsRatioHouseCommand<AUCTION_HOUSE_NEUTRAL>(ChatHandler* handler, const char*); + +void AddSC_ahbot_commandscript() +{ + new ahbot_commandscript(); +} diff --git a/src/server/scripts/Commands/cs_guild.cpp b/src/server/scripts/Commands/cs_guild.cpp index 86213291367..7b074087c0f 100644 --- a/src/server/scripts/Commands/cs_guild.cpp +++ b/src/server/scripts/Commands/cs_guild.cpp @@ -44,6 +44,7 @@ public: { "uninvite", rbac::RBAC_PERM_COMMAND_GUILD_UNINVITE, true, &HandleGuildUninviteCommand, "", NULL }, { "rank", rbac::RBAC_PERM_COMMAND_GUILD_RANK, true, &HandleGuildRankCommand, "", NULL }, { "rename", rbac::RBAC_PERM_COMMAND_GUILD_RENAME, true, &HandleGuildRenameCommand, "", NULL }, + { "info", rbac::RBAC_PERM_COMMAND_GUILD_INFO, true, &HandleGuildInfoCommand, "", NULL }, { NULL, 0, false, NULL, "", NULL } }; static ChatCommand commandTable[] = @@ -243,6 +244,49 @@ public: handler->PSendSysMessage(LANG_GUILD_RENAME_DONE, oldGuildStr, newGuildStr); return true; } + + static bool HandleGuildInfoCommand(ChatHandler* handler, char const* args) + { + Guild* guild = nullptr; + + if (args && strlen(args) > 0) + { + if (isNumeric(args)) + { + uint32 guildId = uint32(atoi(args)); + guild = sGuildMgr->GetGuildById(guildId); + } + else + { + std::string guildName = args; + guild = sGuildMgr->GetGuildByName(guildName); + } + } + else if (Player* target = handler->getSelectedPlayerOrSelf()) + guild = target->GetGuild(); + + if (!guild) + return false; + + // Display Guild Information + handler->PSendSysMessage(LANG_GUILD_INFO_NAME, guild->GetName().c_str(), guild->GetId()); // Guild Id + Name + + std::string guildMasterName; + if (sObjectMgr->GetPlayerNameByGUID(guild->GetLeaderGUID(), guildMasterName)) + handler->PSendSysMessage(LANG_GUILD_INFO_GUILD_MASTER, guildMasterName.c_str(), guild->GetLeaderGUID()); // Guild Master + + // Format creation date + char createdDateStr[20]; + time_t createdDate = guild->GetCreatedDate(); + strftime(createdDateStr, 20, "%Y-%m-%d %H:%M:%S", localtime(&createdDate)); + + handler->PSendSysMessage(LANG_GUILD_INFO_CREATION_DATE, createdDateStr); // Creation Date + handler->PSendSysMessage(LANG_GUILD_INFO_MEMBER_COUNT, guild->GetMemberCount()); // Number of Members + handler->PSendSysMessage(LANG_GUILD_INFO_BANK_GOLD, guild->GetBankMoney() / 100 / 100); // Bank Gold (in gold coins) + handler->PSendSysMessage(LANG_GUILD_INFO_MOTD, guild->GetMOTD().c_str()); // Message of the Day + handler->PSendSysMessage(LANG_GUILD_INFO_EXTRA_INFO, guild->GetInfo().c_str()); // Extra Information + return true; + } }; void AddSC_guild_commandscript() diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index ee307a1d065..dc00ad047da 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -628,7 +628,7 @@ public: return false; // can be NULL at console call - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); std::string namePart = args; std::wstring wNamePart; diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index a3848c00877..9cb7173556a 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -662,7 +662,7 @@ public: static bool HandleCooldownCommand(ChatHandler* handler, char const* args) { - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { handler->SendSysMessage(LANG_PLAYER_NOT_FOUND); diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index 5dbe95b3e54..f70f17232eb 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -98,7 +98,7 @@ public: return false; } - Player* target = handler->getSelectedPlayer(); + Player* target = handler->getSelectedPlayerOrSelf(); if (!target) { handler->SendSysMessage(LANG_NO_CHAR_SELECTED); diff --git a/src/server/scripts/Commands/cs_quest.cpp b/src/server/scripts/Commands/cs_quest.cpp index 6004cd0bc89..08603279824 100644 --- a/src/server/scripts/Commands/cs_quest.cpp +++ b/src/server/scripts/Commands/cs_quest.cpp @@ -53,7 +53,7 @@ public: static bool HandleQuestAdd(ChatHandler* handler, const char* args) { - Player* player = handler->getSelectedPlayer(); + Player* player = handler->getSelectedPlayerOrSelf(); if (!player) { handler->SendSysMessage(LANG_NO_CHAR_SELECTED); @@ -151,7 +151,7 @@ public: static bool HandleQuestComplete(ChatHandler* handler, const char* args) { - Player* player = handler->getSelectedPlayer(); + Player* player = handler->getSelectedPlayerOrSelf(); if (!player) { handler->SendSysMessage(LANG_NO_CHAR_SELECTED); diff --git a/src/server/scripts/EasternKingdoms/Gnomeregan/gnomeregan.cpp b/src/server/scripts/EasternKingdoms/Gnomeregan/gnomeregan.cpp index b171bf014c7..220cf0c92b4 100644 --- a/src/server/scripts/EasternKingdoms/Gnomeregan/gnomeregan.cpp +++ b/src/server/scripts/EasternKingdoms/Gnomeregan/gnomeregan.cpp @@ -317,7 +317,7 @@ public: me->SummonCreature(NPC_CAVERNDEEP_AMBUSHER, SpawnPosition[9], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1800000); break; case 2: - if (GameObject* go = me->SummonGameObject(183410, -533.140f, -105.322f, -156.016f, 0, 0, 0, 0, 0, 1000)) + if (GameObject* go = me->SummonGameObject(183410, -533.140f, -105.322f, -156.016f, 0, 0, 0, 0, 0, 1)) { GoSummonList.push_back(go->GetGUID()); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); //We can't use it! @@ -332,7 +332,7 @@ public: Talk(SAY_BLASTMASTER_7); break; case 4: - if (GameObject* go = me->SummonGameObject(183410, -542.199f, -96.854f, -155.790f, 0, 0, 0, 0, 0, 1000)) + if (GameObject* go = me->SummonGameObject(183410, -542.199f, -96.854f, -155.790f, 0, 0, 0, 0, 0, 1)) { GoSummonList.push_back(go->GetGUID()); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); @@ -346,7 +346,7 @@ public: me->SummonCreature(NPC_CAVERNDEEP_AMBUSHER, SpawnPosition[14], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 1800000); break; case 6: - if (GameObject* go = me->SummonGameObject(183410, -507.820f, -103.333f, -151.353f, 0, 0, 0, 0, 0, 1000)) + if (GameObject* go = me->SummonGameObject(183410, -507.820f, -103.333f, -151.353f, 0, 0, 0, 0, 0, 1)) { GoSummonList.push_back(go->GetGUID()); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); //We can't use it! @@ -354,7 +354,7 @@ public: } break; case 7: - if (GameObject* go = me->SummonGameObject(183410, -511.829f, -86.249f, -151.431f, 0, 0, 0, 0, 0, 1000)) + if (GameObject* go = me->SummonGameObject(183410, -511.829f, -86.249f, -151.431f, 0, 0, 0, 0, 0, 1)) { GoSummonList.push_back(go->GetGUID()); go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); //We can't use it! diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp index ae6aaef9999..95990f18829 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter1.cpp @@ -26,6 +26,7 @@ #include "Player.h" #include "SpellInfo.h" #include "CreatureTextMgr.h" +#include "MoveSplineInit.h" /*###### ##Quest 12848 @@ -322,6 +323,117 @@ public: }; + /*###### +## npc_eye_of_acherus +######*/ + +enum EyeOfAcherus +{ + SPELL_EYE_VISUAL = 51892, + SPELL_EYE_FLIGHT_BOOST = 51923, + SPELL_EYE_FLIGHT = 51890, + + EVENT_MOVE_START = 1, + + TALK_MOVE_START = 0, + TALK_CONTROL = 1, + + POINT_EYE_FALL = 1, + POINT_EYE_MOVE_END = 3 +}; + +Position const EyeOFAcherusFallPoint = { 2361.21f, -5660.45f, 496.7444f, 0.0f }; + +class npc_eye_of_acherus : public CreatureScript +{ + public: + npc_eye_of_acherus() : CreatureScript("npc_eye_of_acherus") { } + + struct npc_eye_of_acherusAI : public ScriptedAI + { + npc_eye_of_acherusAI(Creature* creature) : ScriptedAI(creature) + { + me->SetDisplayId(me->GetCreatureTemplate()->Modelid1); + if (Player* owner = me->GetCharmerOrOwner()->ToPlayer()) + owner->SendAutoRepeatCancel(me); + + me->SetReactState(REACT_PASSIVE); + + me->GetMotionMaster()->MovePoint(POINT_EYE_FALL, EyeOFAcherusFallPoint, false); + + Movement::MoveSplineInit init(me); + init.MoveTo(EyeOFAcherusFallPoint.GetPositionX(), EyeOFAcherusFallPoint.GetPositionY(), EyeOFAcherusFallPoint.GetPositionZ(), false); + init.SetFall(); + init.Launch(); + } + + void OnCharmed(bool /*apply*/) override { } + + void UpdateAI(uint32 diff) override + { + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_MOVE_START: + { + DoCast(me, SPELL_EYE_FLIGHT_BOOST); + + me->SetControlled(false, UNIT_STATE_ROOT); + if (Player* owner = me->GetCharmerOrOwner()->ToPlayer()) + { + for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) + me->SetSpeed(UnitMoveType(i), owner->GetSpeedRate(UnitMoveType(i)), true); + Talk(TALK_MOVE_START, owner); + } + me->GetMotionMaster()->MovePath(me->GetEntry() * 100, false); + break; + } + default: + break; + } + } + } + + void MovementInform(uint32 movementType, uint32 pointId) override + { + if (movementType == WAYPOINT_MOTION_TYPE && pointId == POINT_EYE_MOVE_END - 1) + { + me->SetByteValue(UNIT_FIELD_BYTES_2, 0, SHEATH_STATE_MELEE); + me->RemoveAllAuras(); + + if (Player* owner = me->GetCharmerOrOwner()->ToPlayer()) + { + owner->RemoveAura(SPELL_EYE_FLIGHT_BOOST); + for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) + me->SetSpeed(UnitMoveType(i), owner->GetSpeedRate(UnitMoveType(i)), true); + + TalkToMap(TALK_CONTROL, owner); + } + me->SetDisableGravity(false); + DoCast(me, SPELL_EYE_FLIGHT); + } + + if (movementType == POINT_MOTION_TYPE && pointId == POINT_EYE_FALL) + { + me->SetDisableGravity(true); + me->SetControlled(true, UNIT_STATE_ROOT); + _events.ScheduleEvent(EVENT_MOVE_START, 5000); + } + } + + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_eye_of_acherusAI(creature); + } +}; + /*###### ## npc_death_knight_initiate ######*/ @@ -1079,6 +1191,7 @@ void AddSC_the_scarlet_enclave_c1() new npc_unworthy_initiate(); new npc_unworthy_initiate_anchor(); new go_acherus_soul_prison(); + new npc_eye_of_acherus(); new npc_death_knight_initiate(); new npc_salanar_the_horseman(); new npc_dark_rider_of_acherus(); diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp index 72757387b1c..e202e55e675 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/chapter5.cpp @@ -1138,7 +1138,7 @@ public: case 48: // Show the cleansing effect (dawn of light) //if (GameObject* go = me->GetMap()->GetGameObject(uiDawnofLightGUID)) // go->SetPhaseMask(128, true); - me->SummonGameObject(GO_LIGHT_OF_DAWN, 2283.896f, -5287.914f, 83.066f, 0, 0, 0, 0, 0, 30000); + me->SummonGameObject(GO_LIGHT_OF_DAWN, 2283.896f, -5287.914f, 83.066f, 0, 0, 0, 0, 0, 30); if (Creature* temp = ObjectAccessor::GetCreature(*me, uiTirionGUID)) { if (temp->HasAura(SPELL_REBIRTH_OF_THE_ASHBRINGER, 0)) diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp index 26937a83e63..cdfcede1c93 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp @@ -124,7 +124,7 @@ class boss_arcanist_doan : public CreatureScript CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_arcanist_doanAI>(creature); + return GetScarletMonasteryAI<boss_arcanist_doanAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp index 71a5343d160..c3c74e4c83d 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp @@ -15,13 +15,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Azshir_the_Sleepless -SD%Complete: 80 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "scarlet_monastery.h" @@ -70,9 +63,9 @@ class boss_azshir_the_sleepless : public CreatureScript _JustDied(); } - void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override + void DamageTaken(Unit* /*attacker*/, uint32& damage) override { - if (HealthBelowPct(50) && !_siphon) + if (!_siphon && me->HealthBelowPctDamaged(50, damage)) { DoCastVictim(SPELL_SOUL_SIPHON); events.ScheduleEvent(EVENT_SOUL_SIPHON, 20000); @@ -120,7 +113,7 @@ class boss_azshir_the_sleepless : public CreatureScript CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_azshir_the_sleeplessAI>(creature); + return GetScarletMonasteryAI<boss_azshir_the_sleeplessAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp index 18369c7adfc..14698faaa97 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp @@ -80,9 +80,9 @@ class boss_bloodmage_thalnos : public CreatureScript Talk(SAY_KILL); } - void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override + void DamageTaken(Unit* /*attacker*/, uint32& damage) override { - if (HealthBelowPct(35) && !_hpYell) + if (!_hpYell && me->HealthBelowPctDamaged(35, damage)) { Talk(SAY_HEALTH); _hpYell = true; @@ -114,18 +114,13 @@ class boss_bloodmage_thalnos : public CreatureScript } } - void UpdateAI(uint32 diff) override - { - BossAI::UpdateAI(diff); - } - private: bool _hpYell; }; CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_bloodmage_thalnosAI>(creature); + return GetScarletMonasteryAI<boss_bloodmage_thalnosAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp index d1d25dd2ba6..d77334785ef 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp @@ -100,9 +100,9 @@ class boss_herod : public CreatureScript me->SummonCreature(NPC_SCARLET_TRAINEE, ScarletTraineePos, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); } - void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override + void DamageTaken(Unit* /*attacker*/, uint32& damage) override { - if (HealthBelowPct(30) && !_enrage) + if (!_enrage && me->HealthBelowPctDamaged(30, damage)) { Talk(EMOTE_ENRAGE); Talk(SAY_ENRAGE); @@ -129,18 +129,13 @@ class boss_herod : public CreatureScript } } - void UpdateAI(uint32 diff) override - { - BossAI::UpdateAI(diff); - } - private: bool _enrage; }; CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_herodAI>(creature); + return GetScarletMonasteryAI<boss_herodAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp index 40c7667843b..0e1b51f9a83 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp @@ -73,16 +73,11 @@ class boss_houndmaster_loksey : public CreatureScript break; } } - - void UpdateAI(uint32 diff) override - { - BossAI::UpdateAI(diff); - } }; CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_houndmaster_lokseyAI>(creature); + return GetScarletMonasteryAI<boss_houndmaster_lokseyAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp index 24efd7017ec..d64e556c011 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -16,13 +15,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Scorn -SD%Complete: 100 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "scarlet_monastery.h" @@ -95,16 +87,11 @@ class boss_scorn : public CreatureScript break; } } - - void UpdateAI(uint32 diff) override - { - BossAI::UpdateAI(diff); - } }; CreatureAI* GetAI(Creature* creature) const override { - return GetInstanceAI<boss_scornAI>(creature); + return GetScarletMonasteryAI<boss_scornAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp index 78837912688..dc65bd42bf4 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp @@ -28,7 +28,7 @@ DoorData const doorData[] = class instance_scarlet_monastery : public InstanceMapScript { public: - instance_scarlet_monastery() : InstanceMapScript("instance_scarlet_monastery", 189) { } + instance_scarlet_monastery() : InstanceMapScript(SMScriptName, 189) { } struct instance_scarlet_monastery_InstanceMapScript : public InstanceScript { diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h index d4ce3f1614f..a74efba751f 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h @@ -18,6 +18,7 @@ #ifndef SCARLET_M_ #define SCARLET_M_ +#define SMScriptName "instance_scarlet_monastery" uint32 const EncounterCount = 10; enum DataTypes @@ -57,4 +58,10 @@ enum GameObjectIds GO_PUMPKIN_SHRINE = 186267 }; +template<class AI> +inline AI* GetScarletMonasteryAI(Creature* creature) +{ + return GetInstanceAI<AI>(creature, SMScriptName); +} + #endif // SCARLET_M_ diff --git a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp index 0f33103fc2c..789a5c3a874 100644 --- a/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp +++ b/src/server/scripts/EasternKingdoms/SunkenTemple/instance_sunken_temple.cpp @@ -183,13 +183,13 @@ public: /* void UseLastStatue(GameObject* go) { - AtalaiStatue1->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue1->GetPositionX(), AtalaiStatue1->GetPositionY(), AtalaiStatue1->GetPositionZ(), 0, 0, 0, 0, 0, 100000); - AtalaiStatue2->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue2->GetPositionX(), AtalaiStatue2->GetPositionY(), AtalaiStatue2->GetPositionZ(), 0, 0, 0, 0, 0, 100000); - AtalaiStatue3->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue3->GetPositionX(), AtalaiStatue3->GetPositionY(), AtalaiStatue3->GetPositionZ(), 0, 0, 0, 0, 0, 100000); - AtalaiStatue4->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue4->GetPositionX(), AtalaiStatue4->GetPositionY(), AtalaiStatue4->GetPositionZ(), 0, 0, 0, 0, 0, 100000); - AtalaiStatue5->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue5->GetPositionX(), AtalaiStatue5->GetPositionY(), AtalaiStatue5->GetPositionZ(), 0, 0, 0, 0, 0, 100000); - AtalaiStatue6->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue6->GetPositionX(), AtalaiStatue6->GetPositionY(), AtalaiStatue6->GetPositionZ(), 0, 0, 0, 0, 0, 100000); - go->SummonGameObject(148838, -488.997, 96.61, -189.019, -1.52, 0, 0, 0, 0, 100000); + AtalaiStatue1->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue1->GetPositionX(), AtalaiStatue1->GetPositionY(), AtalaiStatue1->GetPositionZ(), 0, 0, 0, 0, 0, 100); + AtalaiStatue2->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue2->GetPositionX(), AtalaiStatue2->GetPositionY(), AtalaiStatue2->GetPositionZ(), 0, 0, 0, 0, 0, 100); + AtalaiStatue3->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue3->GetPositionX(), AtalaiStatue3->GetPositionY(), AtalaiStatue3->GetPositionZ(), 0, 0, 0, 0, 0, 100); + AtalaiStatue4->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue4->GetPositionX(), AtalaiStatue4->GetPositionY(), AtalaiStatue4->GetPositionZ(), 0, 0, 0, 0, 0, 100); + AtalaiStatue5->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue5->GetPositionX(), AtalaiStatue5->GetPositionY(), AtalaiStatue5->GetPositionZ(), 0, 0, 0, 0, 0, 100); + AtalaiStatue6->SummonGameObject(GO_ATALAI_LIGHT2, AtalaiStatue6->GetPositionX(), AtalaiStatue6->GetPositionY(), AtalaiStatue6->GetPositionZ(), 0, 0, 0, 0, 0, 100); + go->SummonGameObject(148838, -488.997, 96.61, -189.019, -1.52, 0, 0, 0, 0, 100); } */ diff --git a/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp b/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp index ce9ed4f36c8..3e15a80fd74 100644 --- a/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp +++ b/src/server/scripts/Kalimdor/RazorfenDowns/razorfen_downs.cpp @@ -204,7 +204,7 @@ public: case EVENT_COMPLETE: { DoCast(me, SPELL_IDOM_ROOM_CAMERA_SHAKE); - me->SummonGameObject(GO_BELNISTRASZS_BRAZIER, 2577.196f, 947.0781f, 53.16757f, 2.356195f, 0, 0, 0.9238796f, 0.3826832f, 3600000); + me->SummonGameObject(GO_BELNISTRASZS_BRAZIER, 2577.196f, 947.0781f, 53.16757f, 2.356195f, 0, 0, 0.9238796f, 0.3826832f, 3600); std::list<WorldObject*> ClusterList; Trinity::AllWorldObjectsInRange objects(me, 50.0f); Trinity::WorldObjectListSearcher<Trinity::AllWorldObjectsInRange> searcher(me, ClusterList, objects); diff --git a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp index bc6807c54d9..905761ce359 100644 --- a/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp +++ b/src/server/scripts/Northrend/AzjolNerub/Ahnkahet/boss_jedoga_shadowseeker.cpp @@ -39,11 +39,8 @@ enum Spells SPELL_SPHERE_VISUAL = 56075, SPELL_GIFT_OF_THE_HERALD = 56219, SPELL_CYCLONE_STRIKE = 56855, // Self - SPELL_CYCLONE_STRIKE_H = 60030, SPELL_LIGHTNING_BOLT = 56891, // 40Y - SPELL_LIGHTNING_BOLT_H = 60032, // 40Y - SPELL_THUNDERSHOCK = 56926, // 30Y - SPELL_THUNDERSHOCK_H = 60029 // 30Y + SPELL_THUNDERSHOCK = 56926 // 30Y }; const Position JedogaPosition[2] = @@ -296,7 +293,7 @@ public: if (uiBoltTimer <= diff) { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - me->CastSpell(target, DUNGEON_MODE(SPELL_LIGHTNING_BOLT, SPELL_LIGHTNING_BOLT_H), false); + me->CastSpell(target, SPELL_LIGHTNING_BOLT, false); uiBoltTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); } else uiBoltTimer -= diff; @@ -304,7 +301,7 @@ public: if (uiThunderTimer <= diff) { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true)) - me->CastSpell(target, DUNGEON_MODE(SPELL_THUNDERSHOCK, SPELL_THUNDERSHOCK_H), false); + me->CastSpell(target, SPELL_THUNDERSHOCK, false); uiThunderTimer = urand(15*IN_MILLISECONDS, 30*IN_MILLISECONDS); } else uiThunderTimer -= diff; diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp index 81e124cf5bc..4c3ca322574 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/boss_sartharion.cpp @@ -41,9 +41,7 @@ enum Enums SPELL_BERSERK = 61632, // Increases the caster's attack speed by 150% and all damage it deals by 500% for 5 min. SPELL_CLEAVE = 56909, // Inflicts 35% weapon damage to an enemy and its nearest allies, affecting up to 10 targets. SPELL_FLAME_BREATH = 56908, // Inflicts 8750 to 11250 Fire damage to enemies in a cone in front of the caster. - SPELL_FLAME_BREATH_H = 58956, // Inflicts 10938 to 14062 Fire damage to enemies in a cone in front of the caster. SPELL_TAIL_LASH = 56910, // A sweeping tail strike hits all enemies behind the caster, inflicting 3063 to 3937 damage and stunning them for 2 sec. - SPELL_TAIL_LASH_H = 58957, // A sweeping tail strike hits all enemies behind the caster, inflicting 4375 to 5625 damage and stunning them for 2 sec. SPELL_WILL_OF_SARTHARION = 61254, // Sartharion's presence bolsters the resolve of the Twilight Drakes, increasing their total health by 25%. This effect also increases Sartharion's health by 25%. SPELL_LAVA_STRIKE = 57571, // (Real spell cast should be 57578) 57571 then trigger visual missile, then summon Lava Blaze on impact(spell 57572) SPELL_TWILIGHT_REVENGE = 60639, @@ -443,11 +441,11 @@ public: break; case EVENT_FLAME_BREATH: Talk(SAY_SARTHARION_BREATH); - DoCastVictim(RAID_MODE(SPELL_FLAME_BREATH, SPELL_FLAME_BREATH_H)); + DoCastVictim(SPELL_FLAME_BREATH); events.ScheduleEvent(EVENT_FLAME_BREATH, urand(25000, 35000)); break; case EVENT_TAIL_SWEEP: - DoCastVictim(RAID_MODE(SPELL_TAIL_LASH, SPELL_TAIL_LASH_H)); + DoCastVictim(SPELL_TAIL_LASH); events.ScheduleEvent(EVENT_TAIL_SWEEP, urand(15000, 20000)); break; case EVENT_CLEAVE_ATTACK: diff --git a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp index e332e7959ce..0a712b69771 100644 --- a/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp +++ b/src/server/scripts/Northrend/ChamberOfAspects/ObsidianSanctum/obsidian_sanctum.cpp @@ -29,10 +29,7 @@ enum Enums SPELL_TWILIGHT_RESIDUE = 61885, // makes immune to shadow damage, applied when leave phase //Miniboses (Vesperon, Shadron, Tenebron) - SPELL_SHADOW_BREATH_H = 59126, // Inflicts 8788 to 10212 Fire damage to enemies in a cone in front of the caster. SPELL_SHADOW_BREATH = 57570, // Inflicts 6938 to 8062 Fire damage to enemies in a cone in front of the caster. - - SPELL_SHADOW_FISSURE_H = 59127, // Deals 9488 to 13512 Shadow damage to any enemy within the Shadow fissure after 5 sec. SPELL_SHADOW_FISSURE = 57579, // Deals 6188 to 8812 Shadow damage to any enemy within the Shadow fissure after 5 sec. //Vesperon @@ -49,7 +46,6 @@ enum Enums SPELL_GIFT_OF_TWILIGTH_SHA = 57835, // TARGET_SCRIPT shadron SPELL_GIFT_OF_TWILIGTH_SAR = 58766, // TARGET_SCRIPT sartharion SPELL_VOID_BLAST = 57581, // Twilight Fissure - SPELL_VOID_BLAST_H = 59128, //Tenebron //in the portal spawns 6 eggs, if not killed in time (approx. 20s) they will hatch, whelps can cast 60708 @@ -382,12 +378,12 @@ struct dummy_dragonAI : public ScriptedAI { case EVENT_SHADOW_FISSURE: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) - DoCast(target, RAID_MODE(SPELL_SHADOW_FISSURE, SPELL_SHADOW_FISSURE)); + DoCast(target, SPELL_SHADOW_FISSURE); events.ScheduleEvent(eventId, urand(15000, 20000)); break; case EVENT_SHADOW_BREATH: Talk(SAY_BREATH); - DoCastVictim(RAID_MODE(SPELL_SHADOW_BREATH, SPELL_SHADOW_BREATH_H)); + DoCastVictim(SPELL_SHADOW_BREATH); events.ScheduleEvent(eventId, urand(20000, 25000)); break; default: @@ -949,7 +945,7 @@ public: if (events.ExecuteEvent() == EVENT_VOID_BLAST) { - DoCastAOE(RAID_MODE(SPELL_VOID_BLAST, SPELL_VOID_BLAST_H)); + DoCastAOE(SPELL_VOID_BLAST); ////twilight realm //DoCastVictim(57620, true); //DoCastVictim(57874, true); diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/instance_trial_of_the_champion.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/instance_trial_of_the_champion.cpp index ac8a7969c9d..5209e8b2f94 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/instance_trial_of_the_champion.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheChampion/instance_trial_of_the_champion.cpp @@ -194,7 +194,7 @@ public: { pAnnouncer->GetMotionMaster()->MovePoint(0, 748.309f, 619.487f, 411.171f); pAnnouncer->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - pAnnouncer->SummonGameObject(instance->IsHeroic()? GO_CHAMPIONS_LOOT_H : GO_CHAMPIONS_LOOT, 746.59f, 618.49f, 411.09f, 1.42f, 0, 0, 0, 0, 90000000); + pAnnouncer->SummonGameObject(instance->IsHeroic()? GO_CHAMPIONS_LOOT_H : GO_CHAMPIONS_LOOT, 746.59f, 618.49f, 411.09f, 1.42f, 0, 0, 0, 0, 90000); } } } @@ -217,7 +217,7 @@ public: { pAnnouncer->GetMotionMaster()->MovePoint(0, 748.309f, 619.487f, 411.171f); pAnnouncer->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - pAnnouncer->SummonGameObject(instance->IsHeroic()? GO_EADRIC_LOOT_H : GO_EADRIC_LOOT, 746.59f, 618.49f, 411.09f, 1.42f, 0, 0, 0, 0, 90000000); + pAnnouncer->SummonGameObject(instance->IsHeroic()? GO_EADRIC_LOOT_H : GO_EADRIC_LOOT, 746.59f, 618.49f, 411.09f, 1.42f, 0, 0, 0, 0, 90000); } break; case BOSS_ARGENT_CHALLENGE_P: @@ -226,7 +226,7 @@ public: { pAnnouncer->GetMotionMaster()->MovePoint(0, 748.309f, 619.487f, 411.171f); pAnnouncer->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - pAnnouncer->SummonGameObject(instance->IsHeroic()? GO_PALETRESS_LOOT_H : GO_PALETRESS_LOOT, 746.59f, 618.49f, 411.09f, 1.42f, 0, 0, 0, 0, 90000000); + pAnnouncer->SummonGameObject(instance->IsHeroic()? GO_PALETRESS_LOOT_H : GO_PALETRESS_LOOT, 746.59f, 618.49f, 411.09f, 1.42f, 0, 0, 0, 0, 90000); } break; } diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp index 6a664ec7f8d..7af55ec37ea 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/boss_anubarak_trial.cpp @@ -465,7 +465,7 @@ class npc_swarm_scarab : public CreatureScript void JustDied(Unit* killer) override { - DoCast(killer, RAID_MODE(SPELL_TRAITOR_KING_10, SPELL_TRAITOR_KING_25)); + DoCast(killer, SPELL_TRAITOR_KING); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h index 8a62453d7c1..dc0f390f8e0 100644 --- a/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h +++ b/src/server/scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/trial_of_the_crusader.h @@ -293,8 +293,7 @@ enum AchievementData SPELL_WORMS_KILLED_IN_10_SECONDS = 68523, SPELL_CHAMPIONS_KILLED_IN_MINUTE = 68620, SPELL_DEFEAT_FACTION_CHAMPIONS = 68184, - SPELL_TRAITOR_KING_10 = 68186, - SPELL_TRAITOR_KING_25 = 68515, + SPELL_TRAITOR_KING = 68186, // Timed events EVENT_START_TWINS_FIGHT = 21853 diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index 1ff7e1b1352..9d24ad062df 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -643,7 +643,7 @@ class spell_marrowgar_bone_spike_graveyard : public SpellScriptLoader for (std::list<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr, ++i) { Unit* target = *itr; - target->CastCustomSpell(BoneSpikeSummonId[i], SPELLVALUE_BASE_POINT0, 0, target, true); + target->CastSpell(target, BoneSpikeSummonId[i], true); } marrowgarAI->Talk(SAY_BONESPIKE); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index f60a7ba278b..11f20129b3e 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -1269,7 +1269,13 @@ class spell_putricide_mutated_plague : public SpellScriptLoader void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { uint32 healSpell = uint32(GetSpellInfo()->Effects[EFFECT_0].CalcValue()); - GetTarget()->CastSpell(GetTarget(), healSpell, true, NULL, NULL, GetCasterGUID()); + SpellInfo const* healSpellInfo = sSpellMgr->GetSpellInfo(healSpell); + + if (!healSpellInfo) + return; + + int32 heal = healSpellInfo->Effects[0].CalcValue() * GetStackAmount(); + GetTarget()->CastCustomSpell(healSpell, SPELLVALUE_BASE_POINT0, heal, GetTarget(), true, NULL, NULL, GetCasterGUID()); } void Register() override diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index 2a587e535a3..676e4134f11 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -38,10 +38,8 @@ enum Events enum Spells { - SPELL_IMPALE_10 = 28783, - SPELL_IMPALE_25 = 56090, - SPELL_LOCUST_SWARM_10 = 28785, - SPELL_LOCUST_SWARM_25 = 54021, + SPELL_IMPALE = 28783, + SPELL_LOCUST_SWARM = 28785, SPELL_SUMMON_CORPSE_SCARABS_PLR = 29105, // This spawns 5 corpse scarabs on top of player SPELL_SUMMON_CORPSE_SCARABS_MOB = 28864, // This spawns 10 corpse scarabs on top of dead guards SPELL_BERSERK = 27680 @@ -154,14 +152,14 @@ public: case EVENT_IMPALE: //Cast Impale on a random target //Do NOT cast it when we are afflicted by locust swarm - if (!me->HasAura(RAID_MODE(SPELL_LOCUST_SWARM_10, SPELL_LOCUST_SWARM_25))) + if (!me->HasAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_LOCUST_SWARM, me))) if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, RAID_MODE(SPELL_IMPALE_10, SPELL_IMPALE_25)); + DoCast(target, SPELL_IMPALE); events.ScheduleEvent(EVENT_IMPALE, urand(10000, 20000)); break; case EVENT_LOCUST: /// @todo Add Text - DoCast(me, RAID_MODE(SPELL_LOCUST_SWARM_10, SPELL_LOCUST_SWARM_25)); + DoCast(me, SPELL_LOCUST_SWARM); DoSummon(NPC_CRYPT_GUARD, GuardSummonPos, 0, TEMPSUMMON_CORPSE_DESPAWN); events.ScheduleEvent(EVENT_LOCUST, 90000); break; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp index 3d42827c0a8..ec273d5f6e8 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp @@ -31,16 +31,12 @@ enum Yells enum Spells { SPELL_POISON_BOLT_VOLLEY = 28796, - H_SPELL_POISON_BOLT_VOLLEY = 54098, SPELL_RAIN_OF_FIRE = 28794, - H_SPELL_RAIN_OF_FIRE = 54099, SPELL_FRENZY = 28798, - H_SPELL_FRENZY = 54100, - SPELL_WIDOWS_EMBRACE = 28732, - H_SPELL_WIDOWS_EMBRACE = 54097 + SPELL_WIDOWS_EMBRACE = 28732 }; -#define SPELL_WIDOWS_EMBRACE_HELPER RAID_MODE(SPELL_WIDOWS_EMBRACE, H_SPELL_WIDOWS_EMBRACE) +#define SPELL_WIDOWS_EMBRACE_HELPER RAID_MODE<uint32>(28732, 54097) enum Events { @@ -108,7 +104,7 @@ class boss_faerlina : public CreatureScript void SpellHit(Unit* caster, SpellInfo const* spell) override { - if (spell->Id == SPELL_WIDOWS_EMBRACE || spell->Id == H_SPELL_WIDOWS_EMBRACE) + if (spell->Id == SPELL_WIDOWS_EMBRACE_HELPER) { /// @todo Add Text ++_frenzyDispels; @@ -133,7 +129,7 @@ class boss_faerlina : public CreatureScript if (_delayFrenzy && !me->HasAura(SPELL_WIDOWS_EMBRACE_HELPER)) { _delayFrenzy = false; - DoCast(me, RAID_MODE(SPELL_FRENZY, H_SPELL_FRENZY), true); + DoCast(me, SPELL_FRENZY, true); } events.Update(diff); @@ -147,18 +143,18 @@ class boss_faerlina : public CreatureScript { case EVENT_POISON: if (!me->HasAura(SPELL_WIDOWS_EMBRACE_HELPER)) - DoCastAOE(RAID_MODE(SPELL_POISON_BOLT_VOLLEY, H_SPELL_POISON_BOLT_VOLLEY)); + DoCastAOE(SPELL_POISON_BOLT_VOLLEY); events.ScheduleEvent(EVENT_POISON, urand(8000, 15000)); break; case EVENT_FIRE: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, RAID_MODE(SPELL_RAIN_OF_FIRE, H_SPELL_RAIN_OF_FIRE)); + DoCast(target, SPELL_RAIN_OF_FIRE); events.ScheduleEvent(EVENT_FIRE, urand(6000, 18000)); break; case EVENT_FRENZY: /// @todo Add Text if (!me->HasAura(SPELL_WIDOWS_EMBRACE_HELPER)) - DoCast(me, RAID_MODE(SPELL_FRENZY, H_SPELL_FRENZY)); + DoCast(me, SPELL_FRENZY); else _delayFrenzy = true; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp index fa5a0c47808..648fc3c87d2 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp @@ -35,7 +35,6 @@ enum Spells { SPELL_HARVEST_SOUL = 28679, SPELL_SHADOW_BOLT = 29317, - H_SPELL_SHADOW_BOLT = 56405, SPELL_INFORM_LIVE_TRAINEE = 27892, SPELL_INFORM_LIVE_KNIGHT = 27928, SPELL_INFORM_LIVE_RIDER = 27935, @@ -459,7 +458,7 @@ class boss_gothik : public CreatureScript } break; case EVENT_BOLT: - DoCastVictim(RAID_MODE(SPELL_SHADOW_BOLT, H_SPELL_SHADOW_BOLT)); + DoCastVictim(SPELL_SHADOW_BOLT); events.ScheduleEvent(EVENT_BOLT, 1000); break; case EVENT_HARVEST: diff --git a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp index 5702987cc5a..9987802a165 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp @@ -27,9 +27,7 @@ enum Spells SPELL_WARN_NECROTIC_AURA = 59481, SPELL_SUMMON_SPORE = 29234, SPELL_DEATHBLOOM = 29865, - H_SPELL_DEATHBLOOM = 55053, - SPELL_INEVITABLE_DOOM = 29204, - H_SPELL_INEVITABLE_DOOM = 55052 + SPELL_INEVITABLE_DOOM = 29204 }; enum Texts @@ -111,12 +109,12 @@ class boss_loatheb : public CreatureScript events.ScheduleEvent(EVENT_NECROTIC_AURA_FADING, 14000); break; case EVENT_DEATHBLOOM: - DoCastAOE(RAID_MODE(SPELL_DEATHBLOOM, H_SPELL_DEATHBLOOM)); + DoCastAOE(SPELL_DEATHBLOOM); events.ScheduleEvent(EVENT_DEATHBLOOM, 30000); break; case EVENT_INEVITABLE_DOOM: _doomCounter++; - DoCastAOE(RAID_MODE(SPELL_INEVITABLE_DOOM, H_SPELL_INEVITABLE_DOOM)); + DoCastAOE(SPELL_INEVITABLE_DOOM); events.ScheduleEvent(EVENT_INEVITABLE_DOOM, std::max(120000 - _doomCounter * 15000, 15000)); // needs to be confirmed break; case EVENT_SPORE: diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp index 7f7adefc2fb..5b02b7a2009 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp @@ -23,14 +23,10 @@ enum Spells { SPELL_WEB_WRAP = 28622, - SPELL_WEB_SPRAY_10 = 29484, - SPELL_WEB_SPRAY_25 = 54125, - SPELL_POISON_SHOCK_10 = 28741, - SPELL_POISON_SHOCK_25 = 54122, - SPELL_NECROTIC_POISON_10 = 28776, - SPELL_NECROTIC_POISON_25 = 54121, - SPELL_FRENZY_10 = 54123, - SPELL_FRENZY_25 = 54124, + SPELL_WEB_SPRAY = 29484, + SPELL_POISON_SHOCK = 28741, + SPELL_NECROTIC_POISON = 28776, + SPELL_FRENZY = 54123 }; enum Creatures @@ -108,7 +104,7 @@ public: { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0, true, -SPELL_WEB_WRAP)) { - target->RemoveAura(RAID_MODE(SPELL_WEB_SPRAY_10, SPELL_WEB_SPRAY_25)); + target->RemoveAura(sSpellMgr->GetSpellIdForDifficulty(SPELL_WEB_SPRAY, me)); uint8 pos = rand32() % MAX_POS_WRAP; target->GetMotionMaster()->MoveJump(PosWrap[pos].GetPositionX(), PosWrap[pos].GetPositionY(), PosWrap[pos].GetPositionZ(), 20, 20); if (Creature* wrap = DoSummon(NPC_WEB_WRAP, PosWrap[pos], 0, TEMPSUMMON_CORPSE_DESPAWN)) @@ -118,19 +114,19 @@ public: events.ScheduleEvent(EVENT_WRAP, 40000); break; case EVENT_SPRAY: - DoCastAOE(RAID_MODE(SPELL_WEB_SPRAY_10, SPELL_WEB_SPRAY_25)); + DoCastAOE(SPELL_WEB_SPRAY); events.ScheduleEvent(EVENT_SPRAY, 40000); break; case EVENT_SHOCK: - DoCastAOE(RAID_MODE(SPELL_POISON_SHOCK_10, SPELL_POISON_SHOCK_25)); + DoCastAOE(SPELL_POISON_SHOCK); events.ScheduleEvent(EVENT_SHOCK, urand(10000, 20000)); break; case EVENT_POISON: - DoCastVictim(RAID_MODE(SPELL_NECROTIC_POISON_10, SPELL_NECROTIC_POISON_25)); + DoCastVictim(SPELL_NECROTIC_POISON); events.ScheduleEvent(EVENT_POISON, urand(10000, 20000)); break; case EVENT_FRENZY: - DoCast(me, RAID_MODE(SPELL_FRENZY_10, SPELL_FRENZY_25), true); + DoCast(me, SPELL_FRENZY, true); events.ScheduleEvent(EVENT_FRENZY, 600000); break; case EVENT_SUMMON: diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp index a47b75ec234..3e8a54f7cec 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp @@ -22,7 +22,6 @@ enum Spells { SPELL_HATEFUL_STRIKE = 41926, - H_SPELL_HATEFUL_STRIKE = 59192, SPELL_FRENZY = 28131, SPELL_BERSERK = 26662, SPELL_SLIME_BOLT = 32309 @@ -127,7 +126,7 @@ public: if (!pMostHPTarget) pMostHPTarget = me->GetVictim(); - DoCast(pMostHPTarget, RAID_MODE(SPELL_HATEFUL_STRIKE, H_SPELL_HATEFUL_STRIKE), true); + DoCast(pMostHPTarget, SPELL_HATEFUL_STRIKE, true); events.ScheduleEvent(EVENT_HATEFUL, 1000); break; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp index 6a3927d4aa0..ea345c0dee0 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp @@ -140,7 +140,7 @@ class boss_sapphiron : public CreatureScript IceBlockMap::iterator itr = _iceblocks.find(target->GetGUID()); if (itr != _iceblocks.end() && !itr->second) { - if (GameObject* iceblock = me->SummonGameObject(GO_ICEBLOCK, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, 0, 0, 0, 0, 25000)) + if (GameObject* iceblock = me->SummonGameObject(GO_ICEBLOCK, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, 0, 0, 0, 0, 25)) itr->second = iceblock->GetGUID(); } } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp index 34e21336547..0dfae16323b 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp @@ -32,7 +32,6 @@ enum StalaggYells enum StalagSpells { SPELL_POWERSURGE = 28134, - H_SPELL_POWERSURGE = 54529, SPELL_MAGNETIC_PULL = 28338, SPELL_STALAGG_TESLA = 28097 }; @@ -48,7 +47,6 @@ enum FeugenYells enum FeugenSpells { SPELL_STATICFIELD = 28135, - H_SPELL_STATICFIELD = 54528, SPELL_FEUGEN_TESLA = 28109 }; @@ -80,7 +78,6 @@ enum ThaddiusSpells SPELL_POLARITY_SHIFT = 28089, SPELL_BALL_LIGHTNING = 28299, SPELL_CHAIN_LIGHTNING = 28167, - H_SPELL_CHAIN_LIGHTNING = 54531, SPELL_BERSERK = 27680, SPELL_POSITIVE_CHARGE = 28062, SPELL_POSITIVE_CHARGE_STACK = 29659, @@ -258,7 +255,7 @@ public: events.ScheduleEvent(EVENT_SHIFT, 30000); return; case EVENT_CHAIN: - DoCastVictim(RAID_MODE(SPELL_CHAIN_LIGHTNING, H_SPELL_CHAIN_LIGHTNING)); + DoCastVictim(SPELL_CHAIN_LIGHTNING); events.ScheduleEvent(EVENT_CHAIN, urand(10000, 20000)); return; case EVENT_BERSERK: @@ -358,7 +355,7 @@ public: if (powerSurgeTimer <= uiDiff) { - DoCast(me, RAID_MODE(SPELL_POWERSURGE, H_SPELL_POWERSURGE)); + DoCast(me, SPELL_POWERSURGE); powerSurgeTimer = urand(15000, 20000); } else powerSurgeTimer -= uiDiff; @@ -424,7 +421,7 @@ public: if (staticFieldTimer <= uiDiff) { - DoCast(me, RAID_MODE(SPELL_STATICFIELD, H_SPELL_STATICFIELD)); + DoCast(me, SPELL_STATICFIELD); staticFieldTimer = 5000; } else staticFieldTimer -= uiDiff; diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp index 83082b18d73..ae48dd7aa9a 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp @@ -28,17 +28,14 @@ enum Spells { SPELL_BALL_LIGHTNING = 52780, - H_SPELL_BALL_LIGHTNING = 59800, SPELL_STATIC_OVERLOAD = 52658, - H_SPELL_STATIC_OVERLOAD = 59795, SPELL_DISPERSE = 52770, SPELL_SUMMON_SPARK = 52746, SPELL_SPARK_DESPAWN = 52776, - //Spark of Ionar - SPELL_SPARK_VISUAL_TRIGGER = 52667, - H_SPELL_SPARK_VISUAL_TRIGGER = 59833 + // Spark of Ionar + SPELL_SPARK_VISUAL_TRIGGER = 52667 }; enum Yells @@ -193,7 +190,7 @@ public: { lSparkList.Summon(summoned); - summoned->CastSpell(summoned, DUNGEON_MODE(SPELL_SPARK_VISUAL_TRIGGER, H_SPELL_SPARK_VISUAL_TRIGGER), true); + summoned->CastSpell(summoned, SPELL_SPARK_VISUAL_TRIGGER, true); if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp index 576fc4492f1..98d7d629756 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_loken.cpp @@ -45,11 +45,9 @@ enum Yells enum Spells { SPELL_ARC_LIGHTNING = 52921, - SPELL_LIGHTNING_NOVA_N = 52960, - SPELL_LIGHTNING_NOVA_H = 59835, + SPELL_LIGHTNING_NOVA = 52960, - SPELL_PULSING_SHOCKWAVE_N = 52961, - SPELL_PULSING_SHOCKWAVE_H = 59836, + SPELL_PULSING_SHOCKWAVE = 52961, SPELL_PULSING_SHOCKWAVE_AURA = 59414 }; @@ -134,7 +132,7 @@ public: DoCast(me, SPELL_PULSING_SHOCKWAVE_AURA, true); me->ClearUnitState(UNIT_STATE_CASTING); // this flag breaks movement - DoCast(me, SPELL_PULSING_SHOCKWAVE_N, true); + DoCast(me, SPELL_PULSING_SHOCKWAVE, true); m_uiResumePulsingShockwave_Timer = 0; } else @@ -155,9 +153,9 @@ public: { Talk(SAY_NOVA); Talk(EMOTE_NOVA); - DoCast(me, SPELL_LIGHTNING_NOVA_N); + DoCast(me, SPELL_LIGHTNING_NOVA); - me->RemoveAurasDueToSpell(DUNGEON_MODE<uint32>(SPELL_PULSING_SHOCKWAVE_N, SPELL_PULSING_SHOCKWAVE_H)); + me->RemoveAurasDueToSpell(sSpellMgr->GetSpellIdForDifficulty(SPELL_PULSING_SHOCKWAVE, me)); m_uiResumePulsingShockwave_Timer = DUNGEON_MODE(5000, 4000); // Pause Pulsing Shockwave aura m_uiLightningNova_Timer = urand(20000, 21000); } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp index b424ce01b06..31805d3404f 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_volkhan.cpp @@ -39,10 +39,8 @@ enum Enums EMOTE_TO_ANVIL = 5, EMOTE_SHATTER = 6, - SPELL_HEAT_N = 52387, - SPELL_HEAT_H = 59528, - SPELL_SHATTERING_STOMP_N = 52237, - SPELL_SHATTERING_STOMP_H = 59529, + SPELL_HEAT = 52387, + SPELL_SHATTERING_STOMP = 52237, SPELL_TEMPER = 52238, SPELL_TEMPER_DUMMY = 52654, @@ -51,10 +49,8 @@ enum Enums // Molten Golem SPELL_BLAST_WAVE = 23113, - SPELL_IMMOLATION_STRIKE_N = 52433, - SPELL_IMMOLATION_STRIKE_H = 59530, - SPELL_SHATTER_N = 52429, - SPELL_SHATTER_H = 59527, + SPELL_IMMOLATION_STRIKE = 52433, + SPELL_SHATTER = 52429, NPC_VOLKHAN_ANVIL = 28823, NPC_MOLTEN_GOLEM = 28695, @@ -184,7 +180,7 @@ public: // Only shatter brittle golems if (temp->IsAlive() && temp->GetEntry() == NPC_BRITTLE_GOLEM) { - temp->CastSpell(temp, DUNGEON_MODE(SPELL_SHATTER_N, SPELL_SHATTER_H), false); + temp->CastSpell(temp, SPELL_SHATTER, false); GolemsShattered += 1; } } @@ -201,7 +197,7 @@ public: summoned->GetMotionMaster()->MoveFollow(target, 0.0f, 0.0f); // Why healing when just summoned? - summoned->CastSpell(summoned, DUNGEON_MODE(SPELL_HEAT_N, SPELL_HEAT_H), false, NULL, NULL, me->GetGUID()); + summoned->CastSpell(summoned, SPELL_HEAT, false, NULL, NULL, me->GetGUID()); } } @@ -253,7 +249,7 @@ public: // Should he stomp even if he has no brittle golem to shatter? Talk(SAY_STOMP); - DoCast(me, SPELL_SHATTERING_STOMP_N); + DoCast(me, SPELL_SHATTERING_STOMP); Talk(EMOTE_SHATTER); @@ -418,7 +414,7 @@ public: void SpellHit(Unit* /*pCaster*/, const SpellInfo* pSpell) override { // This is the dummy effect of the spells - if (pSpell->Id == SPELL_SHATTER_N || pSpell->Id == SPELL_SHATTER_H) + if (pSpell->Id == sSpellMgr->GetSpellIdForDifficulty(SPELL_SHATTER, me)) if (me->GetEntry() == NPC_BRITTLE_GOLEM) me->DespawnOrUnsummon(); } @@ -439,7 +435,7 @@ public: if (m_uiImmolation_Timer <= uiDiff) { - DoCastVictim(SPELL_IMMOLATION_STRIKE_N); + DoCastVictim(SPELL_IMMOLATION_STRIKE); m_uiImmolation_Timer = 5000; } else diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp index 683eb97a4f7..4ff0bd1e5cb 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/halls_of_stone.cpp @@ -102,15 +102,12 @@ enum Spells // Kadrak SPELL_GLARE_OF_THE_TRIBUNAL = 50988, - H_SPELL_GLARE_OF_THE_TRIBUNAL = 59868, // Marnak SPELL_DARK_MATTER = 51012, - H_SPELL_DARK_MATTER = 59868, // Abedneum SPELL_SEARING_GAZE = 51136, - H_SPELL_SEARING_GAZE = 59867, SPELL_REWARD_ACHIEVEMENT = 59046, }; @@ -214,7 +211,7 @@ public: if (Creature* pKaddrak = ObjectAccessor::GetCreature(*me, *itr)) { if (pKaddrak->IsAlive()) - pKaddrak->CastSpell(target, DUNGEON_MODE(SPELL_GLARE_OF_THE_TRIBUNAL, H_SPELL_GLARE_OF_THE_TRIBUNAL), true); + pKaddrak->CastSpell(target, SPELL_GLARE_OF_THE_TRIBUNAL, true); } } uiKaddrakEncounterTimer = 1500; @@ -230,7 +227,7 @@ public: { summon->SetDisplayId(11686); summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - summon->CastSpell(target, DUNGEON_MODE(SPELL_DARK_MATTER, H_SPELL_DARK_MATTER), true); + summon->CastSpell(target, SPELL_DARK_MATTER, true); } } uiMarnakEncounterTimer = urand(30000, 31000); @@ -246,7 +243,7 @@ public: { summon->SetDisplayId(11686); summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); - summon->CastSpell(target, DUNGEON_MODE(SPELL_SEARING_GAZE, H_SPELL_SEARING_GAZE), true); + summon->CastSpell(target, SPELL_SEARING_GAZE, true); } } uiAbedneumEncounterTimer = urand(30000, 31000); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp index 9a08f01c279..60698aac95e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_assembly_of_iron.cpp @@ -54,8 +54,7 @@ enum AssemblySpells SPELL_CHAIN_LIGHTNING = 61879, SPELL_OVERLOAD = 61869, SPELL_LIGHTNING_WHIRL = 61915, - SPELL_LIGHTNING_TENDRILS_10M = 61887, - SPELL_LIGHTNING_TENDRILS_25M = 63486, + SPELL_LIGHTNING_TENDRILS = 61887, SPELL_LIGHTNING_TENDRILS_VISUAL = 61883, SPELL_STORMSHIELD = 64187 }; @@ -561,8 +560,8 @@ class boss_stormcaller_brundir : public CreatureScript break; case EVENT_LIGHTNING_TENDRILS: Talk(SAY_BRUNDIR_FLIGHT); - DoCast(RAID_MODE(SPELL_LIGHTNING_TENDRILS_10M, SPELL_LIGHTNING_TENDRILS_25M)); - DoCast(SPELL_LIGHTNING_TENDRILS_VISUAL); + DoCast(me, SPELL_LIGHTNING_TENDRILS); + DoCast(me, SPELL_LIGHTNING_TENDRILS_VISUAL); me->AttackStop(); //me->SetLevitate(true); me->GetMotionMaster()->Initialize(); @@ -592,7 +591,7 @@ class boss_stormcaller_brundir : public CreatureScript break; case EVENT_GROUND: //me->SetLevitate(false); - me->RemoveAurasDueToSpell(RAID_MODE(SPELL_LIGHTNING_TENDRILS_10M, SPELL_LIGHTNING_TENDRILS_25M)); + me->RemoveAurasDueToSpell(sSpellMgr->GetSpellIdForDifficulty(SPELL_LIGHTNING_TENDRILS, me)); me->RemoveAurasDueToSpell(SPELL_LIGHTNING_TENDRILS_VISUAL); DoStartMovement(me->GetVictim()); events.CancelEvent(EVENT_GROUND); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp index 7f4d585b0a4..a3d80beb546 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp @@ -324,6 +324,12 @@ class boss_hodir : public CreatureScript void Reset() override { + gettingColdInHereTimer = 0; + gettingColdInHere = false; + cheeseTheFreeze = false; + iHaveTheCoolestFriends = false; + iCouldSayThatThisCacheWasRare = false; + _Reset(); me->SetReactState(REACT_PASSIVE); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index 69240866742..3a137a8658e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -172,7 +172,7 @@ enum Spells SPELL_MAGNETIC_CORE = 64436, SPELL_MAGNETIC_CORE_VISUAL = 64438, SPELL_HALF_HEAL = 64188, - SPELL_CLEAR_ALL_DEBUFFS = 34098, // TODO: make use of this spell... + SPELL_CLEAR_ALL_DEBUFFS = 34098, /// @todo: make use of this spell... SPELL_FREEZE_ANIM_STUN = 63354, // used to prevent mkii from doing stuff?.. SPELL_FREEZE_ANIM = 16245 // Idle aura. Freezes animation. }; @@ -303,17 +303,21 @@ enum Actions enum Phases { - // Leviathan MK II - PHASE_LEVIATHAN_SOLO = 1, - PHASE_LEVIATHAN_ASSEMBLED, - - // VX-001 - PHASE_VX001_SOLO, - PHASE_VX001_ASSEMBLED, + PHASE_LEVIATHAN_MK_II = 1, + PHASE_VX_001, + PHASE_AERIAL_COMMAND_UNIT, + PHASE_VOL7RON +}; - // Aerial Command Unit - PHASE_AERIAL_SOLO, - PHASE_AERIAL_ASSEMBLED +enum Waypoints +{ + WP_MKII_P1_IDLE = 1, + WP_MKII_P4_POS_1, + WP_MKII_P4_POS_2, + WP_MKII_P4_POS_3, + WP_MKII_P4_POS_4, + WP_MKII_P4_POS_5, + WP_AERIAL_P4_POS }; uint32 const RepairSpells[4] = @@ -324,7 +328,1321 @@ uint32 const RepairSpells[4] = SPELL_SEAT_5 }; -// 63801 Bomb Bot +Position const VehicleRelocation[] = +{ + { 0.0f, 0.0f, 0.0f}, + { 2792.070f, 2596.320f, 364.3136f }, // WP_MKII_P1_IDLE + { 2765.945f, 2571.095f, 364.0636f }, // WP_MKII_P4_POS_1 + { 2768.195f, 2573.095f, 364.0636f }, // WP_MKII_P4_POS_2 + { 2763.820f, 2568.870f, 364.3136f }, // WP_MKII_P4_POS_3 + { 2761.215f, 2568.875f, 364.0636f }, // WP_MKII_P4_POS_4 + { 2744.610f, 2569.380f, 364.3136f }, // WP_MKII_P4_POS_5 + { 2748.513f, 2569.051f, 364.3136f } // WP_AERIAL_P4_POS +}; + +Position const VX001SummonPos = { 2744.431f, 2569.385f, 364.3968f, 3.141593f }; +Position const ACUSummonPos = { 2744.650f, 2569.460f, 380.0000f, 0.0f }; + +static bool IsEncounterFinished(Unit* who) +{ + InstanceScript* instance = who->GetInstanceScript(); + + Creature* mkii = ObjectAccessor::GetCreature(*who, instance->GetData64(DATA_LEVIATHAN_MK_II)); + Creature* vx001 = ObjectAccessor::GetCreature(*who, instance->GetData64(DATA_VX_001)); + Creature* aerial = ObjectAccessor::GetCreature(*who, instance->GetData64(DATA_AERIAL_COMMAND_UNIT)); + if (!mkii || !vx001 || !aerial) + return false; + + if (mkii->getStandState() == UNIT_STAND_STATE_DEAD && + vx001->getStandState() == UNIT_STAND_STATE_DEAD && + aerial->getStandState() == UNIT_STAND_STATE_DEAD) + { + who->Kill(mkii); + who->Kill(vx001); + who->Kill(aerial); + mkii->DespawnOrUnsummon(120000); + vx001->DespawnOrUnsummon(120000); + aerial->DespawnOrUnsummon(120000); + if (Creature* mimiron = ObjectAccessor::GetCreature(*who, instance->GetData64(BOSS_MIMIRON))) + mimiron->AI()->JustDied(who); + return true; + } + return false; +} + +class boss_mimiron : public CreatureScript +{ + public: + boss_mimiron() : CreatureScript("boss_mimiron") { } + + struct boss_mimironAI : public BossAI + { + boss_mimironAI(Creature* creature) : BossAI(creature, BOSS_MIMIRON) + { + me->SetReactState(REACT_PASSIVE); + _fireFighter = false; + } + + void DoAction(int32 action) override + { + switch (action) + { + case DO_ACTIVATE_VX001: + events.ScheduleEvent(EVENT_VX001_ACTIVATION_1, 1000); + break; + case DO_ACTIVATE_AERIAL: + events.ScheduleEvent(EVENT_AERIAL_ACTIVATION_1, 5000); + break; + case DO_ACTIVATE_V0L7R0N_1: + Talk(SAY_AERIAL_DEATH); + if (Creature* mkii = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_LEVIATHAN_MK_II))) + mkii->GetMotionMaster()->MovePoint(WP_MKII_P4_POS_1, VehicleRelocation[WP_MKII_P4_POS_1]); + break; + case DO_ACTIVATE_V0L7R0N_2: + events.ScheduleEvent(EVENT_VOL7RON_ACTIVATION_1, 1000); + break; + case DO_ACTIVATE_HARD_MODE: + _fireFighter = true; + DoZoneInCombat(me); + break; + default: + break; + } + } + + void EnterCombat(Unit* /*who*/) override + { + if (!me->GetVehicleBase()) + return; + + _EnterCombat(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->RemoveAurasDueToSpell(SPELL_WELD); + DoCast(me->GetVehicleBase(), SPELL_SEAT_6); + + if (GameObject* button = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_MIMIRON_BUTTON))) + button->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + + if (_fireFighter) + events.ScheduleEvent(EVENT_SUMMON_FLAMES, 3000); + events.ScheduleEvent(EVENT_INTRO_1, 1500); + } + + void JustDied(Unit* /*who*/) override + { + instance->SetBossState(BOSS_MIMIRON, DONE); + events.Reset(); + me->CombatStop(true); + me->SetDisableGravity(false); + DoCast(me, SPELL_SLEEP_VISUAL_1); + DoCastAOE(SPELL_DESPAWN_ASSAULT_BOTS); + me->ExitVehicle(); + // ExitVehicle() offset position is not implemented, so we make up for that with MoveJump()... + me->GetMotionMaster()->MoveJump(me->GetPositionX() + (10.f * std::cos(me->GetOrientation())), me->GetPositionY() + (10.f * std::sin(me->GetOrientation())), me->GetPositionZ(), 10.f, 5.f); + events.ScheduleEvent(EVENT_OUTTRO_1, 7000); + } + + void Reset() override + { + if (instance->GetBossState(BOSS_MIMIRON) == DONE) // Mimiron will attempt to reset because he is not dead and will be set to friendly before despawning. + return; + + _Reset(); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + if (GameObject* elevator = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_MIMIRON_ELEVATOR))) + elevator->SetGoState(GO_STATE_ACTIVE); + + if (_fireFighter) + if (Creature* computer = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_COMPUTER))) + computer->AI()->DoAction(DO_DEACTIVATE_COMPUTER); + + if (GameObject* button = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_MIMIRON_BUTTON))) + { + button->SetGoState(GO_STATE_READY); + button->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + } + + _fireFighter = false; + DoCast(me, SPELL_WELD); + + if (Unit* mkii = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_LEVIATHAN_MK_II))) + DoCast(mkii, SPELL_SEAT_3); + } + + void UpdateAI(uint32 diff) override + { + if ((!UpdateVictim() || !CheckInRoom()) && instance->GetBossState(BOSS_MIMIRON) != DONE) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SUMMON_FLAMES: + if (Unit* worldtrigger = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_MIMIRON_WORLD_TRIGGER))) + worldtrigger->CastCustomSpell(SPELL_SCRIPT_EFFECT_SUMMON_FLAMES_INITIAL, SPELLVALUE_MAX_TARGETS, 3, NULL, true, NULL, NULL, me->GetGUID()); + events.RescheduleEvent(EVENT_SUMMON_FLAMES, 28000); + break; + case EVENT_INTRO_1: + Talk(_fireFighter ? SAY_HARDMODE_ON : SAY_MKII_ACTIVATE); + events.ScheduleEvent(EVENT_INTRO_2, 5000); + break; + case EVENT_INTRO_2: + if (Unit* mkii = me->GetVehicleBase()) + { + DoCast(mkii, SPELL_SEAT_7); + mkii->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); + mkii->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + } + events.ScheduleEvent(EVENT_INTRO_3, 2000); + break; + case EVENT_INTRO_3: + if (Creature* mkii = me->GetVehicleCreatureBase()) + mkii->AI()->DoAction(_fireFighter ? DO_HARDMODE_MKII : DO_START_MKII); + break; + case EVENT_VX001_ACTIVATION_1: + if (Unit* mkii = me->GetVehicleBase()) + mkii->SetFacingTo(3.686f); // fix magic number + events.ScheduleEvent(EVENT_VX001_ACTIVATION_2, 1000); + break; + case EVENT_VX001_ACTIVATION_2: + if (Unit* mkii = me->GetVehicleBase()) + DoCast(mkii, SPELL_SEAT_6); + events.ScheduleEvent(EVENT_VX001_ACTIVATION_3, 1000); + break; + case EVENT_VX001_ACTIVATION_3: + Talk(SAY_MKII_DEATH); + events.ScheduleEvent(EVENT_VX001_ACTIVATION_4, 5000); + break; + case EVENT_VX001_ACTIVATION_4: + if (GameObject* elevator = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_MIMIRON_ELEVATOR))) + elevator->SetGoState(GO_STATE_READY); + if (Unit* worldtrigger = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_MIMIRON_WORLD_TRIGGER))) + worldtrigger->CastSpell(worldtrigger, SPELL_ELEVATOR_KNOCKBACK); + events.ScheduleEvent(EVENT_VX001_ACTIVATION_5, 6000); + break; + case EVENT_VX001_ACTIVATION_5: + if (GameObject* elevator = ObjectAccessor::GetGameObject(*me, instance->GetData64(DATA_MIMIRON_ELEVATOR))) + elevator->SetGoState(GO_STATE_ACTIVE_ALTERNATIVE); + if (Creature* vx001 = me->SummonCreature(NPC_VX_001, VX001SummonPos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 120000)) + vx001->CastSpell(vx001, SPELL_FREEZE_ANIM); + events.ScheduleEvent(EVENT_VX001_ACTIVATION_6, 19000); + break; + case EVENT_VX001_ACTIVATION_6: + if (Unit* vx001 = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_VX_001))) + DoCast(vx001, SPELL_SEAT_1); + events.ScheduleEvent(EVENT_VX001_ACTIVATION_7, 3500); + break; + case EVENT_VX001_ACTIVATION_7: + Talk(SAY_VX001_ACTIVATE); + events.ScheduleEvent(EVENT_VX001_ACTIVATION_8, 4000); + break; + case EVENT_VX001_ACTIVATION_8: + if (Unit* vx001 = me->GetVehicleBase()) + DoCast(vx001, SPELL_SEAT_2); + events.ScheduleEvent(EVENT_VX001_ACTIVATION_9, 3000); + break; + case EVENT_VX001_ACTIVATION_9: + if (Creature* vx001 = me->GetVehicleCreatureBase()) + vx001->AI()->DoAction(_fireFighter ? DO_HARDMODE_VX001 : DO_START_VX001); + break; + case EVENT_AERIAL_ACTIVATION_1: + if (Unit* mkii = me->GetVehicleBase()) + DoCast(mkii, SPELL_SEAT_5); + events.ScheduleEvent(EVENT_AERIAL_ACTIVATION_2, 2500); + break; + case EVENT_AERIAL_ACTIVATION_2: + Talk(SAY_VX001_DEATH); + events.ScheduleEvent(EVENT_AERIAL_ACTIVATION_3, 5000); + break; + case EVENT_AERIAL_ACTIVATION_3: + me->SummonCreature(NPC_AERIAL_COMMAND_UNIT, ACUSummonPos, TEMPSUMMON_MANUAL_DESPAWN); + events.ScheduleEvent(EVENT_AERIAL_ACTIVATION_4, 5000); + break; + case EVENT_AERIAL_ACTIVATION_4: + if (Unit* aerial = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_AERIAL_COMMAND_UNIT))) + me->CastSpell(aerial, SPELL_SEAT_1); + events.ScheduleEvent(EVENT_AERIAL_ACTIVATION_5, 2000); + break; + case EVENT_AERIAL_ACTIVATION_5: + Talk(SAY_AERIAL_ACTIVATE); + events.ScheduleEvent(EVENT_AERIAL_ACTIVATION_6, 8000); + break; + case EVENT_AERIAL_ACTIVATION_6: + if (Creature* acu = me->GetVehicleCreatureBase()) + acu->AI()->DoAction(_fireFighter? DO_HARDMODE_AERIAL : DO_START_AERIAL); + break; + case EVENT_VOL7RON_ACTIVATION_1: + if (Creature* mkii = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_LEVIATHAN_MK_II))) + mkii->SetFacingTo(float(M_PI)); + events.ScheduleEvent(EVENT_VOL7RON_ACTIVATION_2, 1000); + break; + case EVENT_VOL7RON_ACTIVATION_2: + if (Creature* mkii = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_LEVIATHAN_MK_II))) + { + if (Creature* vx001 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_VX_001))) + { + vx001->RemoveAurasDueToSpell(SPELL_TORSO_DISABLED); + vx001->CastSpell(mkii, SPELL_MOUNT_MKII); + } + } + events.ScheduleEvent(EVENT_VOL7RON_ACTIVATION_3, 4500); + break; + case EVENT_VOL7RON_ACTIVATION_3: + if (Creature* mkii = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_LEVIATHAN_MK_II))) + mkii->GetMotionMaster()->MovePoint(WP_MKII_P4_POS_4, VehicleRelocation[WP_MKII_P4_POS_4]); + events.ScheduleEvent(EVENT_VOL7RON_ACTIVATION_4, 5000); + break; + case EVENT_VOL7RON_ACTIVATION_4: + if (Creature* vx001 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_VX_001))) + { + if (Creature* aerial = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_AERIAL_COMMAND_UNIT))) + { + aerial->GetMotionMaster()->MoveLand(0, (aerial->GetPositionX(), aerial->GetPositionY(), aerial->GetPositionZMinusOffset())); + aerial->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + aerial->CastSpell(vx001, SPELL_MOUNT_VX_001); + aerial->CastSpell(aerial, SPELL_HALF_HEAL); + } + } + events.ScheduleEvent(EVENT_VOL7RON_ACTIVATION_5, 4000); + break; + case EVENT_VOL7RON_ACTIVATION_5: + Talk(SAY_V07TRON_ACTIVATE); + events.ScheduleEvent(EVENT_VOL7RON_ACTIVATION_6, 3000); + break; + case EVENT_VOL7RON_ACTIVATION_6: + if (Creature* vx001 = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_VX_001))) + DoCast(vx001, SPELL_SEAT_2); + events.ScheduleEvent(EVENT_VOL7RON_ACTIVATION_7, 5000); + break; + case EVENT_VOL7RON_ACTIVATION_7: + for (uint8 data = DATA_LEVIATHAN_MK_II; data <= DATA_AERIAL_COMMAND_UNIT; ++data) + if (Creature* mimironVehicle = ObjectAccessor::GetCreature(*me, instance->GetData64(data))) + mimironVehicle->AI()->DoAction(DO_ASSEMBLED_COMBAT); + break; + case EVENT_OUTTRO_1: + me->RemoveAurasDueToSpell(SPELL_SLEEP_VISUAL_1); + DoCast(me, SPELL_SLEEP_VISUAL_2); + me->setFaction(35); + events.ScheduleEvent(EVENT_OUTTRO_2, 3000); + break; + case EVENT_OUTTRO_2: + Talk(SAY_V07TRON_DEATH); + if (_fireFighter) + { + if (Creature* computer = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_COMPUTER))) + computer->AI()->DoAction(DO_DEACTIVATE_COMPUTER); + me->SummonGameObject(RAID_MODE(GO_CACHE_OF_INNOVATION_FIREFIGHTER, GO_CACHE_OF_INNOVATION_FIREFIGHTER_HERO), 2744.040f, 2569.352f, 364.3135f, 3.124123f, 0.f, 0.f, 0.9999619f, 0.008734641f, 604800); + } + else + me->SummonGameObject(RAID_MODE(GO_CACHE_OF_INNOVATION, GO_CACHE_OF_INNOVATION_HERO), 2744.040f, 2569.352f, 364.3135f, 3.124123f, 0.f, 0.f, 0.9999619f, 0.008734641f, 604800); + events.ScheduleEvent(EVENT_OUTTRO_3, 11000); + break; + case EVENT_OUTTRO_3: + DoCast(me, SPELL_TELEPORT_VISUAL); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->DespawnOrUnsummon(1000); // sniffs say 6 sec after, but it doesnt matter. + break; + default: + break; + } + } + } + + private: + bool _fireFighter; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<boss_mimironAI>(creature); + } +}; + +class boss_leviathan_mk_ii : public CreatureScript +{ + public: + boss_leviathan_mk_ii() : CreatureScript("boss_leviathan_mk_ii") { } + + struct boss_leviathan_mk_iiAI : public BossAI + { + boss_leviathan_mk_iiAI(Creature* creature) : BossAI(creature, BOSS_MIMIRON) + { + _fireFighter = false; + _setupMine = true; + _setupBomb = true; + _setupRocket = true; + } + + void DamageTaken(Unit* who, uint32 &damage) override + { + if (damage >= me->GetHealth()) + { + damage = me->GetHealth() - 1; // Let creature fall to 1 hp, but do not let it die or damage itself with SetHealth(). + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + DoCast(me, SPELL_VEHICLE_DAMAGED, true); + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE, SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT); + + if (events.IsInPhase(PHASE_LEVIATHAN_MK_II)) + { + me->CastStop(); + if (Unit* turret = me->GetVehicleKit()->GetPassenger(3)) + turret->Kill(turret); + + me->SetSpeed(MOVE_RUN, 1.5f, true); + me->GetMotionMaster()->MovePoint(WP_MKII_P1_IDLE, VehicleRelocation[WP_MKII_P1_IDLE]); + } + else if (events.IsInPhase(PHASE_VOL7RON)) + { + me->SetStandState(UNIT_STAND_STATE_DEAD); + + if (IsEncounterFinished(who)) + return; + + me->CastStop(); + DoCast(me, SPELL_SELF_REPAIR); + } + events.Reset(); + } + } + + void DoAction(int32 action) override + { + switch (action) + { + case DO_HARDMODE_MKII: + _fireFighter = true; + DoCast(me, SPELL_EMERGENCY_MODE); + DoCastAOE(SPELL_EMERGENCY_MODE_TURRET); + events.ScheduleEvent(EVENT_FLAME_SUPPRESSANT_MK, 60000, 0, PHASE_LEVIATHAN_MK_II); + // Missing break intended. + case DO_START_MKII: + me->SetReactState(REACT_AGGRESSIVE); + events.SetPhase(PHASE_LEVIATHAN_MK_II); + + events.ScheduleEvent(EVENT_NAPALM_SHELL, 3000, 0, PHASE_LEVIATHAN_MK_II); + events.ScheduleEvent(EVENT_PLASMA_BLAST, 15000, 0, PHASE_LEVIATHAN_MK_II); + events.ScheduleEvent(EVENT_PROXIMITY_MINE, 5000); + events.ScheduleEvent(EVENT_SHOCK_BLAST, 18000); + break; + case DO_ASSEMBLED_COMBAT: + me->SetStandState(UNIT_STAND_STATE_STAND); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + + events.SetPhase(PHASE_VOL7RON); + events.ScheduleEvent(EVENT_PROXIMITY_MINE, 15000); + events.ScheduleEvent(EVENT_SHOCK_BLAST, 45000); + break; + default: + break; + } + } + + uint32 GetData(uint32 type) const override + { + switch (type) + { + case DATA_SETUP_MINE: + return _setupMine; + case DATA_SETUP_BOMB: + return _setupBomb; + case DATA_SETUP_ROCKET: + return _setupRocket; + case DATA_FIREFIGHTER: + return _fireFighter; + default: + return 0; + } + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) + mimiron->AI()->Talk(events.IsInPhase(PHASE_LEVIATHAN_MK_II) ? SAY_MKII_SLAY : SAY_V07TRON_SLAY); + } + + void MovementInform(uint32 type, uint32 point) override + { + if (type != POINT_MOTION_TYPE) + return; + + switch (point) + { + case WP_MKII_P1_IDLE: + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_HALF_HEAL); + + if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) + mimiron->AI()->DoAction(DO_ACTIVATE_VX001); + break; + case WP_MKII_P4_POS_1: + events.ScheduleEvent(EVENT_MOVE_POINT_2, 1); + break; + case WP_MKII_P4_POS_2: + events.ScheduleEvent(EVENT_MOVE_POINT_3, 1); + break; + case WP_MKII_P4_POS_3: + if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) + mimiron->AI()->DoAction(DO_ACTIVATE_V0L7R0N_2); + break; + case WP_MKII_P4_POS_4: + events.ScheduleEvent(EVENT_MOVE_POINT_5, 1); + break; + default: + break; + } + } + + void Reset() override + { + _Reset(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_PASSIVE); + _fireFighter = false; + _setupMine = true; + _setupBomb = true; + _setupRocket = true; + DoCast(me, SPELL_FREEZE_ANIM); + } + + void SetData(uint32 id, uint32 data) override + { + switch (id) + { + case DATA_SETUP_MINE: + _setupMine = data != 0; + break; + case DATA_SETUP_BOMB: + _setupBomb = data != 0; + break; + case DATA_SETUP_ROCKET: + _setupRocket = data != 0; + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() || !CheckInRoom()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_PROXIMITY_MINE: + DoCastAOE(SPELL_PROXIMITY_MINES); + events.RescheduleEvent(EVENT_PROXIMITY_MINE, 35000); + break; + case EVENT_PLASMA_BLAST: + DoCastVictim(SPELL_SCRIPT_EFFECT_PLASMA_BLAST); + events.RescheduleEvent(EVENT_PLASMA_BLAST, urand(30000, 45000), 0, PHASE_LEVIATHAN_MK_II); + + if (events.GetTimeUntilEvent(EVENT_NAPALM_SHELL) < 9000) + events.RescheduleEvent(EVENT_NAPALM_SHELL, 9000, 0, PHASE_LEVIATHAN_MK_II); // The actual spell is cast by the turret, we should not let it interrupt itself. + break; + case EVENT_SHOCK_BLAST: + DoCastAOE(SPELL_SHOCK_BLAST); + events.RescheduleEvent(EVENT_SHOCK_BLAST, urand(34000, 36000)); + break; + case EVENT_FLAME_SUPPRESSANT_MK: + DoCastAOE(SPELL_FLAME_SUPPRESSANT_MK); + events.RescheduleEvent(EVENT_FLAME_SUPPRESSANT_MK, 60000, 0, PHASE_LEVIATHAN_MK_II); + break; + case EVENT_NAPALM_SHELL: + DoCastAOE(SPELL_FORCE_CAST_NAPALM_SHELL); + events.RescheduleEvent(EVENT_NAPALM_SHELL, urand(6000, 15000), 0, PHASE_LEVIATHAN_MK_II); + + if (events.GetTimeUntilEvent(EVENT_PLASMA_BLAST) < 2000) + events.RescheduleEvent(EVENT_PLASMA_BLAST, 2000, 0, PHASE_LEVIATHAN_MK_II); // The actual spell is cast by the turret, we should not let it interrupt itself. + break; + case EVENT_MOVE_POINT_2: + me->GetMotionMaster()->MovePoint(WP_MKII_P4_POS_2, VehicleRelocation[WP_MKII_P4_POS_2]); + break; + case EVENT_MOVE_POINT_3: + me->GetMotionMaster()->MovePoint(WP_MKII_P4_POS_3, VehicleRelocation[WP_MKII_P4_POS_3]); + break; + case EVENT_MOVE_POINT_5: + me->GetMotionMaster()->MovePoint(WP_MKII_P4_POS_5, VehicleRelocation[WP_MKII_P4_POS_5]); + break; + default: + break; + } + } + DoMeleeAttackIfReady(); + } + + private: + bool _fireFighter; + bool _setupMine; + bool _setupBomb; + bool _setupRocket; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<boss_leviathan_mk_iiAI>(creature); + } +}; + +class boss_vx_001 : public CreatureScript +{ + public: + boss_vx_001() : CreatureScript("boss_vx_001") { } + + struct boss_vx_001AI : public BossAI + { + boss_vx_001AI(Creature* creature) : BossAI(creature, BOSS_MIMIRON) + { + me->SetDisableGravity(true); // This is the unfold visual state of VX-001, it has to be set on create as it requires an objectupdate if set later. + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_SPECIAL_UNARMED); // This is a hack to force the yet to be unfolded visual state. + me->SetReactState(REACT_PASSIVE); + _fireFighter = false; + } + + void DamageTaken(Unit* who, uint32 &damage) override + { + if (damage >= me->GetHealth()) + { + damage = me->GetHealth() - 1; // Let creature fall to 1 hp, but do not let it die or damage itself with SetHealth(). + me->AttackStop(); + DoCast(me, SPELL_VEHICLE_DAMAGED, true); + me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE, SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT); + + if (events.IsInPhase(PHASE_VX_001)) + { + me->CastStop(); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); // | UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_HALF_HEAL); // has no effect, wat + DoCast(me, SPELL_TORSO_DISABLED); + if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) + mimiron->AI()->DoAction(DO_ACTIVATE_AERIAL); + } + else if (events.IsInPhase(PHASE_VOL7RON)) + { + me->SetStandState(UNIT_STAND_STATE_DEAD); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + + if (IsEncounterFinished(who)) + return; + + me->CastStop(); + DoCast(me, SPELL_SELF_REPAIR); + } + events.Reset(); + } + } + + void DoAction(int32 action) override + { + switch (action) + { + case DO_HARDMODE_VX001: + _fireFighter = true; + DoCast(me, SPELL_EMERGENCY_MODE); + events.ScheduleEvent(EVENT_FROST_BOMB, 1000); + events.ScheduleEvent(EVENT_FLAME_SUPPRESSANT_VX, 6000); + // Missing break intended. + case DO_START_VX001: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->RemoveAurasDueToSpell(SPELL_FREEZE_ANIM); + me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE); // Remove emotestate. + //me->SetUInt32Value(UNIT_FIELD_BYTES_1, 33554432); Blizzard handles hover animation like this it seems. + DoCast(me, SPELL_HEAT_WAVE_AURA); + + events.SetPhase(PHASE_VX_001); + events.ScheduleEvent(EVENT_ROCKET_STRIKE, 20000); + events.ScheduleEvent(EVENT_SPINNING_UP, urand(30000, 35000)); + events.ScheduleEvent(EVENT_RAPID_BURST, 500, 0, PHASE_VX_001); + break; + case DO_ASSEMBLED_COMBAT: + me->SetStandState(UNIT_STAND_STATE_STAND); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + + events.SetPhase(PHASE_VOL7RON); + events.ScheduleEvent(EVENT_ROCKET_STRIKE, 20000); + events.ScheduleEvent(EVENT_SPINNING_UP, urand(30000, 35000)); + events.ScheduleEvent(EVENT_HAND_PULSE, 500, 0, PHASE_VOL7RON); + if (_fireFighter) + events.ScheduleEvent(EVENT_FROST_BOMB, 1000); + break; + default: + break; + } + } + + void EnterEvadeMode() override + { + summons.DespawnAll(); + } + + void JustSummoned(Creature* summon) override + { + summons.Summon(summon); + if (summon->GetEntry() == NPC_BURST_TARGET) + summon->CastSpell(me, SPELL_RAPID_BURST_TARGET_ME); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) + mimiron->AI()->Talk(events.IsInPhase(PHASE_VX_001) ? SAY_VX001_SLAY : SAY_V07TRON_SLAY); + } + + void SpellHit(Unit* caster, SpellInfo const* /*spellProto*/) override + { + if (caster->GetEntry() == NPC_BURST_TARGET && !me->HasUnitState(UNIT_STATE_CASTING)) + DoCast(caster, SPELL_RAPID_BURST); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + // Handle rotation during SPELL_SPINNING_UP, SPELL_P3WX2_LASER_BARRAGE, SPELL_RAPID_BURST, and SPELL_HAND_PULSE_LEFT/RIGHT + if (me->HasUnitState(UNIT_STATE_CASTING)) + { + if (Creature* channelTarget = ObjectAccessor::GetCreature(*me, me->GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT))) + me->SetFacingToObject(channelTarget); + return; + } + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_RAPID_BURST: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 120, true)) + DoCast(target, SPELL_SUMMON_BURST_TARGET); + events.RescheduleEvent(EVENT_RAPID_BURST, 3000, 0, PHASE_VX_001); + break; + case EVENT_ROCKET_STRIKE: + DoCastAOE(events.IsInPhase(PHASE_VX_001) ? SPELL_ROCKET_STRIKE_LEFT : SPELL_ROCKET_STRIKE_BOTH); + events.ScheduleEvent(EVENT_RELOAD, 10000); + events.RescheduleEvent(EVENT_ROCKET_STRIKE, urand(20000, 25000)); + break; + case EVENT_RELOAD: + for (uint8 seat = 6; seat <= 7; seat++) + if (Unit* rocket = me->GetVehicleKit()->GetPassenger(seat)) + rocket->SetDisplayId(rocket->GetNativeDisplayId()); + break; + case EVENT_HAND_PULSE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 120, true)) + DoCast(target, urand(0, 1) == 0 ? SPELL_HAND_PULSE_LEFT : SPELL_HAND_PULSE_RIGHT); + events.RescheduleEvent(EVENT_HAND_PULSE, urand(1500, 3000), 0, PHASE_VOL7RON); + break; + case EVENT_FROST_BOMB: + DoCastAOE(SPELL_SCRIPT_EFFECT_FROST_BOMB); + events.RescheduleEvent(EVENT_FROST_BOMB, 45000); + break; + case EVENT_SPINNING_UP: + DoCastAOE(SPELL_SPINNING_UP); + events.DelayEvents(14000); + events.RescheduleEvent(EVENT_SPINNING_UP, urand(55000, 65000)); + break; + case EVENT_FLAME_SUPPRESSANT_VX: + DoCastAOE(SPELL_FLAME_SUPPRESSANT_VX); + events.RescheduleEvent(EVENT_FLAME_SUPPRESSANT_VX, urand(10000, 12000), 0, PHASE_VX_001); + break; + default: + break; + } + } + } + + private: + bool _fireFighter; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<boss_vx_001AI>(creature); + } +}; + +class boss_aerial_command_unit : public CreatureScript +{ + public: + boss_aerial_command_unit() : CreatureScript("boss_aerial_command_unit") { } + + struct boss_aerial_command_unitAI : public BossAI + { + boss_aerial_command_unitAI(Creature* creature) : BossAI(creature, BOSS_MIMIRON) + { + me->SetReactState(REACT_PASSIVE); + fireFigther = false; + } + + void DamageTaken(Unit* who, uint32 &damage) override + { + if (damage >= me->GetHealth()) + { + damage = me->GetHealth() - 1; // Let creature fall to 1 hp, but do not let it die or damage itself with SetHealth(). + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + DoCast(me, SPELL_VEHICLE_DAMAGED, true); + me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE, SPELL_AURA_MOD_INCREASE_HEALTH_PERCENT); + + if (events.IsInPhase(PHASE_AERIAL_COMMAND_UNIT)) + { + me->GetMotionMaster()->Clear(true); + me->GetMotionMaster()->MovePoint(WP_AERIAL_P4_POS, VehicleRelocation[WP_AERIAL_P4_POS]); + } + else if (events.IsInPhase(PHASE_VOL7RON)) + { + me->SetStandState(UNIT_STAND_STATE_DEAD); + + if (IsEncounterFinished(who)) + return; + + me->CastStop(); + DoCast(me, SPELL_SELF_REPAIR); + } + events.Reset(); + } + } + + void DoAction(int32 action) override + { + switch (action) + { + case DO_HARDMODE_AERIAL: + fireFigther = true; + DoCast(me, SPELL_EMERGENCY_MODE); + events.ScheduleEvent(EVENT_SUMMON_FIRE_BOTS, 1000, 0, PHASE_AERIAL_COMMAND_UNIT); + // Missing break intended. + case DO_START_AERIAL: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + + events.SetPhase(PHASE_AERIAL_COMMAND_UNIT); + events.ScheduleEvent(EVENT_SUMMON_JUNK_BOT, 5000, 0, PHASE_AERIAL_COMMAND_UNIT); + events.ScheduleEvent(EVENT_SUMMON_ASSAULT_BOT, 9000, 0, PHASE_AERIAL_COMMAND_UNIT); + events.ScheduleEvent(EVENT_SUMMON_BOMB_BOT, 9000, 0, PHASE_AERIAL_COMMAND_UNIT); + break; + case DO_DISABLE_AERIAL: + me->CastStop(); + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + me->GetMotionMaster()->MoveFall(); + events.DelayEvents(23000); + break; + case DO_ENABLE_AERIAL: + me->SetReactState(REACT_AGGRESSIVE); + break; + case DO_ASSEMBLED_COMBAT: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + me->SetStandState(UNIT_STAND_STATE_STAND); + events.SetPhase(PHASE_VOL7RON); + break; + default: + break; + } + } + + void EnterEvadeMode() override + { + summons.DespawnAll(); + } + + void JustSummoned(Creature* summon) override + { + if (fireFigther && (summon->GetEntry() == NPC_ASSAULT_BOT || summon->GetEntry() == NPC_JUNK_BOT)) + summon->CastSpell(summon, SPELL_EMERGENCY_MODE); + BossAI::JustSummoned(summon); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetTypeId() == TYPEID_PLAYER) + if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) + mimiron->AI()->Talk(events.IsInPhase(PHASE_AERIAL_COMMAND_UNIT) ? SAY_AERIAL_SLAY : SAY_V07TRON_SLAY); + } + + void MovementInform(uint32 type, uint32 point) override + { + if (type == POINT_MOTION_TYPE && point == WP_AERIAL_P4_POS) + { + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + + if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) + mimiron->AI()->DoAction(DO_ACTIVATE_V0L7R0N_1); + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SUMMON_FIRE_BOTS: + me->CastCustomSpell(SPELL_SUMMON_FIRE_BOT_TRIGGER, SPELLVALUE_MAX_TARGETS, 3, NULL, true); + events.RescheduleEvent(EVENT_SUMMON_FIRE_BOTS, 45000, 0, PHASE_AERIAL_COMMAND_UNIT); + break; + case EVENT_SUMMON_JUNK_BOT: + me->CastCustomSpell(SPELL_SUMMON_JUNK_BOT_TRIGGER, SPELLVALUE_MAX_TARGETS, 1, NULL, true); + events.RescheduleEvent(EVENT_SUMMON_JUNK_BOT, urand(11000, 12000), 0, PHASE_AERIAL_COMMAND_UNIT); + break; + case EVENT_SUMMON_ASSAULT_BOT: + me->CastCustomSpell(SPELL_SUMMON_ASSAULT_BOT_TRIGGER, SPELLVALUE_MAX_TARGETS, 1, NULL, true); + events.RescheduleEvent(EVENT_SUMMON_ASSAULT_BOT, 30000, 0, PHASE_AERIAL_COMMAND_UNIT); + break; + case EVENT_SUMMON_BOMB_BOT: + DoCast(me, SPELL_SUMMON_BOMB_BOT); + events.RescheduleEvent(EVENT_SUMMON_BOMB_BOT, urand(15000, 20000), 0, PHASE_AERIAL_COMMAND_UNIT); + break; + default: + break; + } + } + DoSpellAttackIfReady(events.IsInPhase(PHASE_AERIAL_COMMAND_UNIT) ? SPELL_PLASMA_BALL_P1 : SPELL_PLASMA_BALL_P2); + } + + private: + bool fireFigther; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<boss_aerial_command_unitAI>(creature); + } +}; + +class npc_mimiron_assault_bot : public CreatureScript +{ + public: + npc_mimiron_assault_bot() : CreatureScript("npc_mimiron_assault_bot") { } + + struct npc_mimiron_assault_botAI : public ScriptedAI + { + npc_mimiron_assault_botAI(Creature* creature) : ScriptedAI(creature) + { + } + + void EnterCombat(Unit* /*who*/) override + { + events.ScheduleEvent(EVENT_MAGNETIC_FIELD, 14000); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_ROOT)) + { + if (Unit* newTarget = SelectTarget(SELECT_TARGET_NEAREST, 0, 30.0f, true)) + { + me->DeleteThreatList(); + AttackStart(newTarget); + } + } + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_MAGNETIC_FIELD: + DoCastVictim(SPELL_MAGNETIC_FIELD); + me->ClearUnitState(UNIT_STATE_CASTING); + events.RescheduleEvent(EVENT_MAGNETIC_FIELD, 30000); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_mimiron_assault_botAI>(creature); + } +}; + +class npc_mimiron_emergency_fire_bot : public CreatureScript +{ + public: + npc_mimiron_emergency_fire_bot() : CreatureScript("npc_mimiron_emergency_fire_bot") { } + + struct npc_mimiron_emergency_fire_botAI : public ScriptedAI + { + npc_mimiron_emergency_fire_botAI(Creature* creature) : ScriptedAI(creature) + { + me->SetReactState(REACT_PASSIVE); + isWaterSprayReady = true; + moveNew = true; + } + + uint32 GetData(uint32 id) const override + { + if (id == DATA_WATERSPRAY) + return isWaterSprayReady; + if (id == DATA_MOVE_NEW) + return moveNew; + return 0; + } + + void SetData(uint32 id, uint32 data) override + { + if (id == DATA_WATERSPRAY) + isWaterSprayReady = false; + else if (id == DATA_MOVE_NEW) + moveNew = data ? true : false; + } + + void Reset() override + { + events.ScheduleEvent(EVENT_WATER_SPRAY, 7000); + isWaterSprayReady = true; + moveNew = true; + } + + void UpdateAI(uint32 diff) override + { + if (!isWaterSprayReady) + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_WATER_SPRAY: + isWaterSprayReady = true; + events.RescheduleEvent(EVENT_WATER_SPRAY, urand(7000, 9000)); + break; + default: + break; + } + } + } + + private: + EventMap events; + bool isWaterSprayReady; + bool moveNew; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_mimiron_emergency_fire_botAI>(creature); + } +}; + +class npc_mimiron_computer : public CreatureScript +{ + public: + npc_mimiron_computer() : CreatureScript("npc_mimiron_computer") { } + + struct npc_mimiron_computerAI : public ScriptedAI + { + npc_mimiron_computerAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + } + + void DoAction(int32 action) override + { + switch (action) + { + case DO_ACTIVATE_COMPUTER: + Talk(SAY_SELF_DESTRUCT_INITIATED); + events.ScheduleEvent(EVENT_SELF_DESTRUCT_10, 3000); + break; + case DO_DEACTIVATE_COMPUTER: + Talk(SAY_SELF_DESTRUCT_TERMINATED); + me->RemoveAurasDueToSpell(SPELL_SELF_DESTRUCTION_AURA); + me->RemoveAurasDueToSpell(SPELL_SELF_DESTRUCTION_VISUAL); + events.Reset(); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SELF_DESTRUCT_10: + Talk(SAY_SELF_DESTRUCT_10); + if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) + mimiron->AI()->DoAction(DO_ACTIVATE_HARD_MODE); + events.ScheduleEvent(EVENT_SELF_DESTRUCT_9, 60000); + break; + case EVENT_SELF_DESTRUCT_9: + Talk(SAY_SELF_DESTRUCT_9); + events.ScheduleEvent(EVENT_SELF_DESTRUCT_8, 60000); + break; + case EVENT_SELF_DESTRUCT_8: + Talk(SAY_SELF_DESTRUCT_8); + events.ScheduleEvent(EVENT_SELF_DESTRUCT_7, 60000); + break; + case EVENT_SELF_DESTRUCT_7: + Talk(SAY_SELF_DESTRUCT_7); + events.ScheduleEvent(EVENT_SELF_DESTRUCT_6, 60000); + break; + case EVENT_SELF_DESTRUCT_6: + Talk(SAY_SELF_DESTRUCT_6); + events.ScheduleEvent(EVENT_SELF_DESTRUCT_5, 60000); + break; + case EVENT_SELF_DESTRUCT_5: + Talk(SAY_SELF_DESTRUCT_5); + events.ScheduleEvent(EVENT_SELF_DESTRUCT_4, 60000); + break; + case EVENT_SELF_DESTRUCT_4: + Talk(SAY_SELF_DESTRUCT_4); + events.ScheduleEvent(EVENT_SELF_DESTRUCT_3, 60000); + break; + case EVENT_SELF_DESTRUCT_3: + Talk(SAY_SELF_DESTRUCT_3); + events.ScheduleEvent(EVENT_SELF_DESTRUCT_2, 60000); + break; + case EVENT_SELF_DESTRUCT_2: + Talk(SAY_SELF_DESTRUCT_2); + events.ScheduleEvent(EVENT_SELF_DESTRUCT_1, 60000); + break; + case EVENT_SELF_DESTRUCT_1: + Talk(SAY_SELF_DESTRUCT_1); + events.ScheduleEvent(EVENT_SELF_DESTRUCT_FINALIZED, 60000); + break; + case EVENT_SELF_DESTRUCT_FINALIZED: + Talk(SAY_SELF_DESTRUCT_FINALIZED); + if (Creature* mimiron = ObjectAccessor::GetCreature(*me, instance->GetData64(BOSS_MIMIRON))) + mimiron->AI()->DoAction(DO_ACTIVATE_SELF_DESTRUCT); + DoCast(me, SPELL_SELF_DESTRUCTION_AURA); + DoCast(me, SPELL_SELF_DESTRUCTION_VISUAL); + break; + default: + break; + } + } + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_mimiron_computerAI>(creature); + } +}; + +class npc_mimiron_flames : public CreatureScript +{ + public: + npc_mimiron_flames() : CreatureScript("npc_mimiron_flames") { } + + struct npc_mimiron_flamesAI : public ScriptedAI + { + npc_mimiron_flamesAI(Creature* creature) : ScriptedAI(creature) + { + instance = me->GetInstanceScript(); + } + + void Reset() override // Reset is possibly more suitable for this case. + { + events.ScheduleEvent(EVENT_SPREAD_FLAMES, 4000); + } + + void UpdateAI(uint32 diff) override + { + if (instance->GetBossState(BOSS_MIMIRON) != IN_PROGRESS) + me->DespawnOrUnsummon(); + + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SPREAD_FLAMES: + DoCastAOE(SPELL_SUMMON_FLAMES_SPREAD_TRIGGER); + break; + default: + break; + } + } + } + + private: + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_mimiron_flamesAI>(creature); + } +}; + +class npc_mimiron_frost_bomb : public CreatureScript +{ + public: + npc_mimiron_frost_bomb() : CreatureScript("npc_mimiron_frost_bomb") { } + + struct npc_mimiron_frost_bombAI : public ScriptedAI + { + npc_mimiron_frost_bombAI(Creature* creature) : ScriptedAI(creature) + { + } + + void Reset() override + { + events.ScheduleEvent(EVENT_FROST_BOMB_EXPLOSION, 10000); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FROST_BOMB_EXPLOSION: + DoCastAOE(SPELL_FROST_BOMB_EXPLOSION); + events.ScheduleEvent(EVENT_FROST_BOMB_CLEAR_FIRES, 3000); + break; + case EVENT_FROST_BOMB_CLEAR_FIRES: + DoCastAOE(SPELL_CLEAR_FIRES); + me->DespawnOrUnsummon(3000); + break; + default: + break; + } + } + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_mimiron_frost_bombAI>(creature); + } +}; + +class npc_mimiron_proximity_mine : public CreatureScript +{ + public: + npc_mimiron_proximity_mine() : CreatureScript("npc_mimiron_proximity_mine") { } + + struct npc_mimiron_proximity_mineAI : public ScriptedAI + { + npc_mimiron_proximity_mineAI(Creature* creature) : ScriptedAI(creature) + { + } + + void Reset() override + { + events.ScheduleEvent(EVENT_PROXIMITY_MINE_ARM, 1500); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_PROXIMITY_MINE_ARM: + DoCast(me, SPELL_PROXIMITY_MINE_PERIODIC_TRIGGER); + events.ScheduleEvent(EVENT_PROXIMITY_MINE_DETONATION, 33500); + break; + case EVENT_PROXIMITY_MINE_DETONATION: + if (me->HasAura(SPELL_PROXIMITY_MINE_PERIODIC_TRIGGER)) + DoCastAOE(SPELL_PROXIMITY_MINE_EXPLOSION); + me->DespawnOrUnsummon(1000); + break; + default: + break; + } + } + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetUlduarAI<npc_mimiron_proximity_mineAI>(creature); + } +}; + +class go_mimiron_hardmode_button : public GameObjectScript +{ + public: + go_mimiron_hardmode_button() : GameObjectScript("go_mimiron_hardmode_button") { } + + bool OnGossipHello(Player* /*player*/, GameObject* go) + { + InstanceScript* instance = go->GetInstanceScript(); + if (!instance) + return false; + + if (Creature* computer = ObjectAccessor::GetCreature(*go, instance->GetData64(DATA_COMPUTER))) + computer->AI()->DoAction(DO_ACTIVATE_COMPUTER); + go->SetGoState(GO_STATE_ACTIVE); + go->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE); + return true; + } +}; + +// 63801 - Bomb Bot class spell_mimiron_bomb_bot : public SpellScriptLoader { public: @@ -538,7 +1856,7 @@ class spell_mimiron_magnetic_core : public SpellScriptLoader { if (Creature* target = GetTarget()->ToCreature()) { - target->GetAI()->DoAction(DO_DISABLE_AERIAL); + target->AI()->DoAction(DO_DISABLE_AERIAL); target->CastSpell(target, SPELL_MAGNETIC_CORE_VISUAL, true); } } @@ -547,7 +1865,7 @@ class spell_mimiron_magnetic_core : public SpellScriptLoader { if (Creature* target = GetTarget()->ToCreature()) { - target->GetAI()->DoAction(DO_ENABLE_AERIAL); + target->AI()->DoAction(DO_ENABLE_AERIAL); target->RemoveAurasDueToSpell(SPELL_MAGNETIC_CORE_VISUAL); } } @@ -1426,8 +2744,66 @@ class spell_mimiron_weld : public SpellScriptLoader } }; +class achievement_setup_boom : public AchievementCriteriaScript +{ + public: + achievement_setup_boom() : AchievementCriteriaScript("achievement_setup_boom") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + return target && target->GetAI()->GetData(DATA_SETUP_BOMB); + } +}; + +class achievement_setup_mine : public AchievementCriteriaScript +{ + public: + achievement_setup_mine() : AchievementCriteriaScript("achievement_setup_mine") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + return target && target->GetAI()->GetData(DATA_SETUP_MINE); + } +}; + +class achievement_setup_rocket : public AchievementCriteriaScript +{ + public: + achievement_setup_rocket() : AchievementCriteriaScript("achievement_setup_rocket") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + return target && target->GetAI()->GetData(DATA_SETUP_ROCKET); + } +}; + +class achievement_firefighter : public AchievementCriteriaScript +{ + public: + achievement_firefighter() : AchievementCriteriaScript("achievement_firefighter") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + return target && target->GetAI()->GetData(DATA_FIREFIGHTER); + } +}; + void AddSC_boss_mimiron() { + new boss_aerial_command_unit(); + new boss_leviathan_mk_ii(); + new boss_mimiron(); + new boss_vx_001(); + + new npc_mimiron_assault_bot(); + new npc_mimiron_emergency_fire_bot(); + new npc_mimiron_computer(); + new npc_mimiron_flames(); + new npc_mimiron_frost_bomb(); + new npc_mimiron_proximity_mine(); + + new go_mimiron_hardmode_button(); + new spell_mimiron_bomb_bot(); new spell_mimiron_clear_fires(); new spell_mimiron_despawn_assault_bots(); @@ -1454,4 +2830,9 @@ void AddSC_boss_mimiron() new spell_mimiron_summon_junk_bot(); new spell_mimiron_summon_junk_bot_target(); new spell_mimiron_weld(); + + new achievement_setup_boom(); + new achievement_setup_mine(); + new achievement_setup_rocket(); + new achievement_firefighter(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp index 399113e18c8..f5fe255fdf3 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_razorscale.cpp @@ -242,7 +242,7 @@ class boss_razorscale_controller : public CreatureScript break; case ACTION_PLACE_BROKEN_HARPOON: for (uint8 n = 0; n < RAID_MODE(2, 4); n++) - me->SummonGameObject(GO_RAZOR_BROKEN_HARPOON, PosHarpoon[n].GetPositionX(), PosHarpoon[n].GetPositionY(), PosHarpoon[n].GetPositionZ(), 2.286f, 0, 0, 0, 0, 180000); + me->SummonGameObject(GO_RAZOR_BROKEN_HARPOON, PosHarpoon[n].GetPositionX(), PosHarpoon[n].GetPositionY(), PosHarpoon[n].GetPositionZ(), 2.286f, 0, 0, 0, 0, 180); break; } } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp index 8520e317ba3..1d2b1b24322 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_xt002.cpp @@ -36,17 +36,14 @@ enum Spells { SPELL_TYMPANIC_TANTRUM = 62776, - SPELL_SEARING_LIGHT_10 = 63018, - SPELL_SEARING_LIGHT_25 = 65121, + SPELL_SEARING_LIGHT = 63018, SPELL_SUMMON_LIFE_SPARK = 64210, SPELL_SUMMON_VOID_ZONE = 64203, - SPELL_GRAVITY_BOMB_10 = 63024, - SPELL_GRAVITY_BOMB_25 = 64234, + SPELL_GRAVITY_BOMB = 63024, - SPELL_HEARTBREAK_10 = 65737, - SPELL_HEARTBREAK_25 = 64193, + SPELL_HEARTBREAK = 65737, // Cast by 33337 at Heartbreak: SPELL_RECHARGE_PUMMELER = 62831, // Summons 33344 @@ -66,12 +63,10 @@ enum Spells SPELL_SUBMERGE = 37751, //------------------VOID ZONE-------------------- - SPELL_VOID_ZONE_10 = 64203, - SPELL_VOID_ZONE_25 = 64235, + SPELL_VOID_ZONE = 64203, // Life Spark - SPELL_STATIC_CHARGED_10 = 64227, - SPELL_STATIC_CHARGED_25 = 64236, + SPELL_STATIC_CHARGED = 64227, SPELL_SHOCK = 64230, //----------------XT-002 HEART------------------- @@ -279,13 +274,13 @@ class boss_xt002 : public CreatureScript { case EVENT_SEARING_LIGHT: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, RAID_MODE(SPELL_SEARING_LIGHT_10, SPELL_SEARING_LIGHT_25)); + DoCast(target, SPELL_SEARING_LIGHT); events.ScheduleEvent(EVENT_SEARING_LIGHT, TIMER_SEARING_LIGHT); break; case EVENT_GRAVITY_BOMB: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, RAID_MODE(SPELL_GRAVITY_BOMB_10, SPELL_GRAVITY_BOMB_25)); + DoCast(target, SPELL_GRAVITY_BOMB); events.ScheduleEvent(EVENT_GRAVITY_BOMB, TIMER_GRAVITY_BOMB); break; @@ -304,7 +299,7 @@ class boss_xt002 : public CreatureScript break; case EVENT_ENTER_HARD_MODE: me->SetFullHealth(); - DoCast(me, RAID_MODE(SPELL_HEARTBREAK_10, SPELL_HEARTBREAK_25), true); + DoCast(me, SPELL_HEARTBREAK, true); me->AddLootMode(LOOT_MODE_HARD_MODE_1); _hardMode = true; SetPhaseOne(); @@ -735,7 +730,7 @@ class npc_life_spark : public CreatureScript void Reset() override { - DoCast(me, RAID_MODE(SPELL_STATIC_CHARGED_10, SPELL_STATIC_CHARGED_25)); + DoCast(me, SPELL_STATIC_CHARGED); _shockTimer = 0; // first one is immediate. } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 1f9bfe4c3f3..a074ce28181 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -15,12 +15,13 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "ulduar.h" +#include "InstanceScript.h" #include "Player.h" #include "ScriptedCreature.h" #include "ScriptMgr.h" #include "SpellScript.h" #include "WorldPacket.h" +#include "ulduar.h" static DoorData const doorData[] = { @@ -821,10 +822,6 @@ class instance_ulduar : public InstanceMapScript case DATA_UNBROKEN: Unbroken = data != 0; break; - case DATA_MIMIRON_ELEVATOR: - if (GameObject* gameObject = instance->GetGameObject(MimironElevatorGUID)) - gameObject->SetGoState((GOState)data); - break; case DATA_ILLUSION: illusion = data; break; @@ -924,6 +921,8 @@ class instance_ulduar : public InstanceMapScript return MimironComputerGUID; case DATA_MIMIRON_WORLD_TRIGGER: return MimironWorldTriggerGUID; + case DATA_MIMIRON_ELEVATOR: + return MimironElevatorGUID; case DATA_MIMIRON_BUTTON: return MimironButtonGUID; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 81cb469318f..5dfc2b54f6e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -18,8 +18,6 @@ #ifndef DEF_ULDUAR_H #define DEF_ULDUAR_H -#include "InstanceScript.h" -#include "ObjectMgr.h" #define UlduarScriptName "instance_ulduar" extern Position const ObservationRingKeepersPos[4]; diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_ymiron.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_ymiron.cpp index dfef80133c4..01e09ca2f9a 100644 --- a/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_ymiron.cpp +++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardePinnacle/boss_ymiron.cpp @@ -31,15 +31,11 @@ Script Data End */ enum Spells { SPELL_BANE = 48294, - H_SPELL_BANE = 59301, SPELL_DARK_SLASH = 48292, SPELL_FETID_ROT = 48291, - H_SPELL_FETID_ROT = 59300, SPELL_SCREAMS_OF_THE_DEAD = 51750, SPELL_SPIRIT_BURST = 48529, - H_SPELL_SPIRIT_BURST = 59305, SPELL_SPIRIT_STRIKE = 48423, - H_SPELL_SPIRIT_STRIKE = 59304, SPELL_ANCESTORS_VENGEANCE = 16939, SPELL_SUMMON_AVENGING_SPIRIT = 48592, @@ -48,8 +44,7 @@ enum Spells SPELL_CHANNEL_SPIRIT_TO_YMIRON = 48316, SPELL_CHANNEL_YMIRON_TO_SPIRIT = 48307, - SPELL_SPIRIT_FOUNT = 48380, - H_SPELL_SPIRIT_FOUNT = 59320 + SPELL_SPIRIT_FOUNT = 48380 }; //not in db @@ -278,7 +273,7 @@ public: if (Creature* temp = me->SummonCreature(NPC_SPIRIT_FOUNT, 385.0f + rand32() % 10, -330.0f + rand32() % 10, 104.756f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 180000)) { temp->SetSpeed(MOVE_RUN, 0.4f); - temp->CastSpell(temp, DUNGEON_MODE(SPELL_SPIRIT_FOUNT, H_SPELL_SPIRIT_FOUNT), true); + temp->CastSpell(temp, SPELL_SPIRIT_FOUNT, true); temp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE); temp->SetDisplayId(11686); m_uiOrbGUID = temp->GetGUID(); diff --git a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp index 9e2bb85e27a..1c106f399de 100644 --- a/src/server/scripts/Northrend/VioletHold/violet_hold.cpp +++ b/src/server/scripts/Northrend/VioletHold/violet_hold.cpp @@ -50,7 +50,6 @@ enum AzureInvaderSpells { SPELL_CLEAVE = 15496, SPELL_IMPALE = 58459, - H_SPELL_IMPALE = 59256, SPELL_BRUTAL_STRIKE = 58460, SPELL_SUNDER_ARMOR = 58461 }; @@ -58,23 +57,17 @@ enum AzureInvaderSpells enum AzureSellbreakerSpells { SPELL_ARCANE_BLAST = 58462, - H_SPELL_ARCANE_BLAST = 59257, SPELL_SLOW = 25603, SPELL_CHAINS_OF_ICE = 58464, - SPELL_CONE_OF_COLD = 58463, - H_SPELL_CONE_OF_COLD = 59258 + SPELL_CONE_OF_COLD = 58463 }; enum AzureBinderSpells { SPELL_ARCANE_BARRAGE = 58456, - H_SPELL_ARCANE_BARRAGE = 59248, SPELL_ARCANE_EXPLOSION = 58455, - H_SPELL_ARCANE_EXPLOSION = 59245, SPELL_FROST_NOVA = 58458, - H_SPELL_FROST_NOVA = 59253, - SPELL_FROSTBOLT = 58457, - H_SPELL_FROSTBOLT = 59251, + SPELL_FROSTBOLT = 58457 }; enum AzureMageSlayerSpells @@ -92,9 +85,7 @@ enum AzureCaptainSpells enum AzureSorcerorSpells { SPELL_ARCANE_STREAM = 60181, - H_SPELL_ARCANE_STREAM = 60204, - SPELL_MANA_DETONATION = 60182, - H_SPELL_MANA_DETONATION = 60205 + SPELL_MANA_DETONATION = 60182 }; enum AzureRaiderSpells @@ -912,7 +903,7 @@ public: { if (uiArcaneExplosionTimer <= diff) { - DoCast(DUNGEON_MODE(SPELL_ARCANE_EXPLOSION, H_SPELL_ARCANE_EXPLOSION)); + DoCast(SPELL_ARCANE_EXPLOSION); uiArcaneExplosionTimer = 5000; } else uiArcaneExplosionTimer -= diff; @@ -920,7 +911,7 @@ public: { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (target) - DoCast(target, DUNGEON_MODE(SPELL_ARCANE_BARRAGE, H_SPELL_ARCANE_BARRAGE)); + DoCast(target, SPELL_ARCANE_BARRAGE); uiArcainBarrageTimer = 6000; } else uiArcainBarrageTimer -= diff; } @@ -929,7 +920,7 @@ public: { if (uiFrostNovaTimer <= diff) { - DoCast(DUNGEON_MODE(SPELL_FROST_NOVA, H_SPELL_FROST_NOVA)); + DoCast(SPELL_FROST_NOVA); uiFrostNovaTimer = 5000; } else uiFrostNovaTimer -= diff; @@ -937,7 +928,7 @@ public: { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (target) - DoCast(target, DUNGEON_MODE(SPELL_FROSTBOLT, H_SPELL_FROSTBOLT)); + DoCast(target, SPELL_FROSTBOLT); uiFrostboltTimer = 6000; } else uiFrostboltTimer -= diff; } @@ -1164,7 +1155,7 @@ public: { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (target) - DoCast(target, DUNGEON_MODE(SPELL_ARCANE_BLAST, H_SPELL_ARCANE_BLAST)); + DoCast(target, SPELL_ARCANE_BLAST); uiArcaneBlastTimer = 6000; } else uiArcaneBlastTimer -= diff; @@ -1189,7 +1180,7 @@ public: if (uiConeOfColdTimer <= diff) { - DoCast(DUNGEON_MODE(SPELL_CONE_OF_COLD, H_SPELL_CONE_OF_COLD)); + DoCast(SPELL_CONE_OF_COLD); uiConeOfColdTimer = 5000; } else uiConeOfColdTimer -= diff; } @@ -1296,14 +1287,14 @@ public: { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (target) - DoCast(target, DUNGEON_MODE(SPELL_ARCANE_STREAM, H_SPELL_ARCANE_STREAM)); + DoCast(target, SPELL_ARCANE_STREAM); uiArcaneStreamTimer = urand(0, 5000)+5000; uiArcaneStreamTimerStartingValueHolder = uiArcaneStreamTimer; } else uiArcaneStreamTimer -= diff; if (uiManaDetonationTimer <= diff && uiArcaneStreamTimer >=1500 && uiArcaneStreamTimer <= uiArcaneStreamTimerStartingValueHolder/2) { - DoCast(DUNGEON_MODE(SPELL_MANA_DETONATION, H_SPELL_MANA_DETONATION)); + DoCast(SPELL_MANA_DETONATION); uiManaDetonationTimer = urand(2000, 6000); } else uiManaDetonationTimer -= diff; diff --git a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp index d454b646647..905fe67af97 100644 --- a/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp +++ b/src/server/scripts/Outland/Auchindoun/ShadowLabyrinth/boss_grandmaster_vorpil.cpp @@ -52,7 +52,6 @@ enum GrandmasterVorpil SPELL_SACRIFICE = 33587, SPELL_SHADOW_NOVA = 33846, SPELL_EMPOWERING_SHADOWS = 33783, - H_SPELL_EMPOWERING_SHADOWS = 39364, NPC_VOID_PORTAL = 19224, SPELL_SUMMON_PORTAL = 33566, @@ -245,7 +244,7 @@ class npc_voidtraveler : public CreatureScript if (_sacrificed) { - DoCastAOE(DUNGEON_MODE(SPELL_EMPOWERING_SHADOWS, H_SPELL_EMPOWERING_SHADOWS), true); + DoCastAOE(SPELL_EMPOWERING_SHADOWS, true); DoCast(me, SPELL_SHADOW_NOVA, true); me->Kill(me); return; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp index d4fdb262c8e..dfbc49e1e34 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp @@ -110,11 +110,6 @@ class boss_hydromancer_thespia : public CreatureScript break; } } - - void UpdateAI(uint32 diff) override - { - BossAI::UpdateAI(diff); - } }; CreatureAI* GetAI(Creature* creature) const override diff --git a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp index 839dd800721..d2a93caf7a3 100644 --- a/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp +++ b/src/server/scripts/Outland/HellfireCitadel/HellfireRamparts/boss_vazruden_the_herald.cpp @@ -43,9 +43,7 @@ enum Says enum Spells { SPELL_FIREBALL = 34653, - SPELL_FIREBALL_H = 36920, SPELL_CONE_OF_FIRE = 30926, - SPELL_CONE_OF_FIRE_H = 36921, SPELL_SUMMON_LIQUID_FIRE = 23971, SPELL_SUMMON_LIQUID_FIRE_H = 30928, SPELL_BELLOWING_ROAR = 39427, @@ -116,7 +114,7 @@ class boss_nazan : public CreatureScript if (Fireball_Timer <= diff) { if (Unit* victim = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(victim, DUNGEON_MODE(SPELL_FIREBALL, SPELL_FIREBALL_H), true); + DoCast(victim, SPELL_FIREBALL, true); Fireball_Timer = urand(4000, 7000); } else @@ -156,7 +154,7 @@ class boss_nazan : public CreatureScript { if (ConeOfFire_Timer <= diff) { - DoCast(me, DUNGEON_MODE(SPELL_CONE_OF_FIRE, SPELL_CONE_OF_FIRE_H)); + DoCast(me, SPELL_CONE_OF_FIRE); ConeOfFire_Timer = 12000; Fireball_Timer = 4000; } diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_thorngrin_the_tender.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_thorngrin_the_tender.cpp index d2a1d101ae4..9114027b9fb 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_thorngrin_the_tender.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_thorngrin_the_tender.cpp @@ -34,8 +34,7 @@ enum Says enum Spells { SPELL_SACRIFICE = 34661, - SPELL_HELLFIRE_NORMAL = 34659, - SPELL_HELLFIRE_HEROIC = 39131, + SPELL_HELLFIRE = 34659, SPELL_ENRAGE = 34670 }; @@ -119,7 +118,7 @@ class boss_thorngrin_the_tender : public CreatureScript break; case EVENT_HELLFIRE: Talk(SAY_CAST_HELLFIRE); - DoCastVictim(DUNGEON_MODE(SPELL_HELLFIRE_NORMAL, SPELL_HELLFIRE_HEROIC), true); + DoCastVictim(SPELL_HELLFIRE, true); events.ScheduleEvent(EVENT_HELLFIRE, IsHeroic() ? urand(17400, 19300) : 18000); break; case EVENT_ENRAGE: diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp index bbb384ed0f8..8bc9d0982e3 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp @@ -40,7 +40,6 @@ enum Spells WAR_STOMP = 34716, SUMMON_TREANTS = 34727, // DBC: 34727, 34731, 34733, 34734, 34736, 34739, 34741 (with Ancestral Life spell 34742) // won't work (guardian summon) ARCANE_VOLLEY = 36705, - ARCANE_VOLLEY_H = 39133, SPELL_HEAL_FATHER = 6262 }; @@ -208,7 +207,7 @@ class boss_warp_splinter : public CreatureScript //Check for Arcane Volley if (Arcane_Volley_Timer <= diff) { - DoCastVictim(DUNGEON_MODE(ARCANE_VOLLEY, ARCANE_VOLLEY_H)); + DoCastVictim(ARCANE_VOLLEY); Arcane_Volley_Timer = urand(20000, 35000); } else diff --git a/src/server/scripts/Outland/zone_blades_edge_mountains.cpp b/src/server/scripts/Outland/zone_blades_edge_mountains.cpp index d54eb6fff8c..03b8e7e69c8 100644 --- a/src/server/scripts/Outland/zone_blades_edge_mountains.cpp +++ b/src/server/scripts/Outland/zone_blades_edge_mountains.cpp @@ -1143,7 +1143,7 @@ public: { // Spell 37392 does not exist in dbc, manually spawning me->SummonCreature(NPC_OSCILLATING_FREQUENCY_SCANNER_TOP_BUNNY, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 0.5f, me->GetOrientation(), TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 50000); - me->SummonGameObject(GO_OSCILLATING_FREQUENCY_SCANNER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), 0, 0, 0, 0, 50000); + me->SummonGameObject(GO_OSCILLATING_FREQUENCY_SCANNER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation(), 0, 0, 0, 0, 50); me->DespawnOrUnsummon(50000); } diff --git a/src/server/scripts/Spells/spell_quest.cpp b/src/server/scripts/Spells/spell_quest.cpp index 173e03fef7c..f17aac51519 100644 --- a/src/server/scripts/Spells/spell_quest.cpp +++ b/src/server/scripts/Spells/spell_quest.cpp @@ -2026,7 +2026,6 @@ class spell_q12308_escape_from_silverbrook_summon_worgen : public SpellScriptLoa } }; - enum DeathComesFromOnHigh { SPELL_FORGE_CREDIT = 51974, @@ -2097,6 +2096,37 @@ class spell_q12641_death_comes_from_on_high : public SpellScriptLoader } }; +// 52694 - Recall Eye of Acherus +class spell_q12641_recall_eye_of_acherus : public SpellScriptLoader +{ + public: + spell_q12641_recall_eye_of_acherus() : SpellScriptLoader("spell_q12641_recall_eye_of_acherus") { } + + class spell_q12641_recall_eye_of_acherus_SpellScript : public SpellScript + { + PrepareSpellScript(spell_q12641_recall_eye_of_acherus_SpellScript); + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (Player* player = GetCaster()->GetCharmerOrOwner()->ToPlayer()) + { + player->StopCastingCharm(); + player->StopCastingBindSight(); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_q12641_recall_eye_of_acherus_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_q12641_recall_eye_of_acherus_SpellScript(); + } +}; + // 51769 - Emblazon Runeblade class spell_q12619_emblazon_runeblade : public SpellScriptLoader { @@ -2364,6 +2394,7 @@ void AddSC_quest_spell_scripts() new spell_q12308_escape_from_silverbrook_summon_worgen(); new spell_q12308_escape_from_silverbrook(); new spell_q12641_death_comes_from_on_high(); + new spell_q12641_recall_eye_of_acherus(); new spell_q12619_emblazon_runeblade(); new spell_q12619_emblazon_runeblade_effect(); new spell_q12919_gymers_grab(); diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 593ce9a54de..bba1f4e298b 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -312,7 +312,7 @@ class spell_sha_earth_shield : public SpellScriptLoader amount = GetUnitOwner()->SpellHealingBonusTaken(caster, GetSpellInfo(), amount, HEAL); //! WORKAROUND - // If target is affected by healing reduction, modifier is guaranteed to be negative + // If target is affected by healing reduction, modifier is guaranteed to be negative // value (e.g. -50). To revert the effect, multiply amount with reciprocal of relative value: // (100 / ((-1) * modifier)) * 100 = (-1) * 100 * 100 / modifier = -10000 / modifier if (int32 modifier = GetUnitOwner()->GetMaxNegativeAuraModifier(SPELL_AURA_MOD_HEALING_PCT)) diff --git a/src/server/scripts/World/item_scripts.cpp b/src/server/scripts/World/item_scripts.cpp index 4cf2ef971eb..a191f37c76c 100644 --- a/src/server/scripts/World/item_scripts.cpp +++ b/src/server/scripts/World/item_scripts.cpp @@ -241,7 +241,7 @@ public: float x, y, z; go->GetClosePoint(x, y, z, go->GetObjectSize() / 3, 7.0f); - go->SummonGameObject(GO_HIGH_QUALITY_FUR, go->GetPositionX(), go->GetPositionY(), go->GetPositionZ(), 0, 0, 0, 0, 0, 1000); + go->SummonGameObject(GO_HIGH_QUALITY_FUR, go->GetPositionX(), go->GetPositionY(), go->GetPositionZ(), 0, 0, 0, 0, 0, 1); if (TempSummon* summon = player->SummonCreature(NPC_NESINGWARY_TRAPPER, x, y, z, go->GetOrientation(), TEMPSUMMON_DEAD_DESPAWN, 1000)) { summon->SetVisible(false); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 24e61e7399a..0669d0b84f9 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -600,4 +600,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID, "UPDATE character_pet SET slot = ? WHERE owner = ? AND id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_BY_ID, "DELETE FROM character_pet WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_PET_BY_SLOT, "DELETE FROM character_pet WHERE owner = ? AND (slot = ? OR slot > ?)", CONNECTION_ASYNC); + + // PvPstats + PrepareStatement(CHAR_SEL_PVPSTATS_MAXID, "SELECT MAX(id) FROM pvpstats_battlegrounds", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_PVPSTATS_BATTLEGROUND, "INSERT INTO pvpstats_battlegrounds (id, winner_faction, bracket_id, type, date) VALUES (?, ?, ?, ?, NOW())", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_PVPSTATS_PLAYER, "INSERT INTO pvpstats_players (battleground_id, character_guid, score_killing_blows, score_deaths, score_honorable_kills, score_bonus_honor, score_damage_done, score_healing_done, attr_1, attr_2, attr_3, attr_4, attr_5) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index c73f0df8d00..19b5fef82eb 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -534,6 +534,10 @@ enum CharacterDatabaseStatements CHAR_DEL_ITEMCONTAINER_MONEY, CHAR_INS_ITEMCONTAINER_MONEY, + CHAR_SEL_PVPSTATS_MAXID, + CHAR_INS_PVPSTATS_BATTLEGROUND, + CHAR_INS_PVPSTATS_PLAYER, + MAX_CHARACTERDATABASE_STATEMENTS }; diff --git a/src/server/worldserver/RemoteAccess/RASession.cpp b/src/server/worldserver/RemoteAccess/RASession.cpp index 846a4eb39e3..9892019ae5a 100644 --- a/src/server/worldserver/RemoteAccess/RASession.cpp +++ b/src/server/worldserver/RemoteAccess/RASession.cpp @@ -31,12 +31,12 @@ using boost::asio::ip::tcp; void RASession::Start() { - boost::asio::socket_base::bytes_readable command(true); - _socket.io_control(command); - std::size_t bytes_readable = command.get(); + // wait 1 second for active connections to send negotiation request + for (int counter = 0; counter < 10 && _socket.available() == 0; counter++) + std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Check if there are bytes available, if they are, then the client is requesting the negotiation - if (bytes_readable > 0) + if (_socket.available() > 0) { // Handle subnegotiation boost::array<char, 1024> buf; diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index d98a061b9f3..9a78d74bb45 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -2060,6 +2060,14 @@ Battleground.QueueAnnouncer.Enable = 0 Battleground.QueueAnnouncer.PlayerOnly = 0 # +# Battleground.StoreStatistics.Enable +# Description: Store Battleground scores in the database. +# Default: 0 - (Disabled) +# 1 - (Enabled) + +Battleground.StoreStatistics.Enable = 0 + +# # Battleground.InvitationType # Description: Set Battleground invitation type. # Default: 0 - (Normal, Invite as much players to battlegrounds as queued, @@ -2622,6 +2630,357 @@ UI.ShowQuestLevelsInDialogs = 0 # ################################################################################################### +################################### +# Auction House Bot Configuration # +################################### + +################################################################################################################### +# AUCTION HOUSE BOT SETTINGS +# +# AuctionHouseBot.Update.Interval +# Description: Interval in seconds for AHBot to get updated +# Default: 20 +# + +AuctionHouseBot.Update.Interval = 20 + +# +# AuctionHouseBot.Seller.Enabled +# Description: General enable or disable AuctionHouseBot Seller functionality +# Default: 0 - (Disabled) +# 1 - (Enabled) + +AuctionHouseBot.Seller.Enabled = 0 + +# +# AuctionHouseBot.Alliance.Items.Amount.Ratio +# Description: Enable/Disable (disabled if 0) the part of AHBot that puts items up for auction on Alliance AH +# Default: 100 - (Enabled with 100% of items specified in AuctionHouse.Items.Amount.color section) + +AuctionHouseBot.Alliance.Items.Amount.Ratio = 100 + +# +# AuctionHouseBot.Horde.Items.Amount.Ratio +# Enable/Disable (disabled if 0) the part of AHBot that puts items up for auction on Horde AH +# Default: 100 (Enabled with 100% of items specified in AuctionHouse.Items.Amount.color section) + +AuctionHouseBot.Horde.Items.Amount.Ratio = 100 + +# +# AuctionHouseBot.Neutral.Items.Amount.Ratio +# Description: Enable/Disable (disabled if 0) the part of AHBot that puts items up for auction on Neutral AH +# Default: 100 - (Enabled with 100% of items specified in AuctionHouse.Items.Amount.color section) + +AuctionHouseBot.Neutral.Items.Amount.Ratio = 100 + +# +# AuctionHouseBot.MinTime +# Description: Minimum time for the new auction in hours +# Default: 1 - (Hour) + +AuctionHouseBot.MinTime = 1 + +# +# AuctionHouseBot.MaxTime +# Description: Maximum time for the new auction in hours +# Default: 72 - (Hours) + +AuctionHouseBot.MaxTime = 72 + +# +# AuctionHouseBot.Items.Vendor +# Description: Include items that can be bought from vendors. +# Default: 0 - (Disabled) +# 1 - (Enabled) + +AuctionHouseBot.Items.Vendor = 0 + +# +# AuctionHouseBot.Items.Loot +# Description: Include items that can be looted or fished for. +# Default: 1 - (Enabled) +# 0 - (Disabled) + +AuctionHouseBot.Items.Loot = 1 + +# +# AuctionHouseBot.Items.Misc +# Description: Include misc. items. +# Default: 0 - (Disabled) +# 1 - (Enabled) + +AuctionHouseBot.Items.Misc = 0 + +# +# AuctionHouseBot.Bind.* +# Description: Indicates which bonding types to allow the bot to put up for auction +# No - Items that don't bind Default 1 (Allowed) +# Pickup - Items that bind on pickup Default 0 (Not Allowed) +# Equip - Items that bind on equip Default 1 (Allowed) +# Use - Items that bind on use Default 1 (Allowed) +# Quest - Quest Items Default 0 (Not Allowed) +# Values: 0 - (Disabled) +# 1 - (Enabled) + +AuctionHouseBot.Bind.No = 1 +AuctionHouseBot.Bind.Pickup = 0 +AuctionHouseBot.Bind.Equip = 1 +AuctionHouseBot.Bind.Use = 1 +AuctionHouseBot.Bind.Quest = 0 + +# +# AuctionHouseBot.LockBox.Enabled +# Description: Enable or not lockbox in auctionhouse +# Default 0 - (Disabled) +# 1 - (Enabled) + +AuctionHouseBot.LockBox.Enabled = 0 + +# +# AuctionHouseBot.ItemsPerCycle.Boost +# Description: This value is used to fill AH faster than normal when there is more than this value on missed items (not auctioned items). +# Usually this value is only used once on server start with empty auction table. +# Default: 1000 + +AuctionHouseBot.ItemsPerCycle.Boost = 1000 + +# +# AuctionHouseBot.ItemsPerCycle.Normal +# Description: This value is used to fill AH for sold and expired items. A high value will be more resource intensive +# Usually this value is used always when auction table is already initialised. +# Default: 20 + +AuctionHouseBot.ItemsPerCycle.Normal = 20 + +# +# AuctionHouseBot.BuyPrice.Seller +# Description: Should the Seller use BuyPrice or SellPrice to determine Bid Prices +# Default: 1 - (use SellPrice) +# 0 - (use BuyPrice) + +AuctionHouseBot.BuyPrice.Seller = 1 + +# +# AuctionHouseBot.Alliance.Price.Ratio +# Description: Percentage by which the price of items selled on Alliance Auction House is incremented / decreased +# Default: 100 - (Not modify) + +AuctionHouseBot.Alliance.Price.Ratio = 100 + +# +# AuctionHouseBot.Horde.Price.Ratio +# Description: Percentage by which the price of items selled on Horde Auction House is incremented / decreased +# Default: 100 - (Not modify) + +AuctionHouseBot.Horde.Price.Ratio = 100 + +# +# AuctionHouseBot.Neutral.Price.Ratio +# Description: Percentage by which the price of items selled on Neutral Auction House is incremented / decreased +# Default: 100 - (Not modify) + +AuctionHouseBot.Neutral.Price.Ratio = 100 + +# +# AuctionHouseBot.Items.ItemLevel.* +# Description: Prevent seller from listing items below/above this item level +# Default: 0 - (Disabled) + +AuctionHouseBot.Items.ItemLevel.Min = 0 +AuctionHouseBot.Items.ItemLevel.Max = 0 + +# +# AuctionHouseBot.Items.ReqLevel.* +# Prevent seller from listing items below/above this required level +# Default: - 0 (Disabled) + +AuctionHouseBot.Items.ReqLevel.Min = 0 +AuctionHouseBot.Items.ReqLevel.Max = 0 + +# +# AuctionHouseBot.Items.ReqSkill.* +# Description: Prevent seller from listing items below/above this skill level +# Default: 0 - (Disabled) +# 1 - (Enabled) + +AuctionHouseBot.Items.ReqSkill.Min = 0 +AuctionHouseBot.Items.ReqSkill.Max = 0 + +# +# AuctionHouseBot.Items.Amount.* +# Description: Define here for every item qualities how many items you want to be shown in Auction House +# This value will be adjusted by AuctionHouseBot.FACTION.Items.Amount.Ratio to define the exact amount of +# items that will finally be shown on Auction House +# Default: 0, 2000, 2500, 1500, 1000, 0, 0 (Gray, white, green, blue, purple, orange, yellow) + +AuctionHouseBot.Items.Amount.Gray = 0 +AuctionHouseBot.Items.Amount.White = 2000 +AuctionHouseBot.Items.Amount.Green = 2500 +AuctionHouseBot.Items.Amount.Blue = 1500 +AuctionHouseBot.Items.Amount.Purple = 1000 +AuctionHouseBot.Items.Amount.Orange = 0 +AuctionHouseBot.Items.Amount.Yellow = 0 + +# +# AustionHouseBot.Class.* +# Description: Here you can set the class of items you prefer to be show on AH +# These value are sorted by preference, from 0 (disabled) to 10 (max. preference) +# Default: Consumable: 6 +# Container: 4 +# Weapon: 8 +# Gem: 3 +# Armor: 8 +# Reagent: 1 +# Projectile: 2 +# TradeGod: 10 +# Generic: 1 +# Recipe: 6 +# Quiver: 1 +# Quest: 1 +# Key: 1 +# Misc: 5 +# Glyph: 3 + +AuctionHouseBot.Class.Consumable = 6 +AuctionHouseBot.Class.Container = 4 +AuctionHouseBot.Class.Weapon = 8 +AuctionHouseBot.Class.Gem = 3 +AuctionHouseBot.Class.Armor = 8 +AuctionHouseBot.Class.Reagent = 1 +AuctionHouseBot.Class.Projectile = 2 +AuctionHouseBot.Class.TradeGood = 10 +AuctionHouseBot.Class.Generic = 1 +AuctionHouseBot.Class.Recipe = 6 +AuctionHouseBot.Class.Quiver = 1 +AuctionHouseBot.Class.Quest = 1 +AuctionHouseBot.Class.Key = 1 +AuctionHouseBot.Class.Misc = 5 +AuctionHouseBot.Class.Glyph = 3 + +################################################################################################################### +# +# AHBot ITEM FINE TUNING +# The following are usefull for limiting what character levels can +# benefit from the auction house +# +# AuctionHouseBot.Class.Misc.Mount.ReqLevel.* +# Description: Prevent seller from listing mounts below/above this required level +# Default: 0 + +AuctionHouseBot.Class.Misc.Mount.ReqLevel.Min = 0 +AuctionHouseBot.Class.Misc.Mount.ReqLevel.Max = 0 + +# +# AuctionHouseBot.Class.Misc.Mount.ReqSkill.* +# Description: Prevent seller from listing mounts below/above this skill level +# Default: 0 + +AuctionHouseBot.Class.Misc.Mount.ReqSkill.Min = 0 +AuctionHouseBot.Class.Misc.Mount.ReqSkill.Max = 0 + +# +# AuctionHouseBot.Class.Glyph.ReqLevel.* +# Description: Prevent seller from listing glyphs below/above this required level +# Default: 0 + +AuctionHouseBot.Class.Glyph.ReqLevel.Min = 0 +AuctionHouseBot.Class.Glyph.ReqLevel.Max = 0 + +# +# AuctionHouseBot.Class.Glyph.ItemLevel.* +# Description: Prevent seller from listing glyphs below/above this item level +# Default: 0 + +AuctionHouseBot.Class.Glyph.ItemLevel.Min = 0 +AuctionHouseBot.Class.Glyph.ItemLevel.Max = 0 + +# +# AuctionHouseBot.Class.TradeGood.ItemLevel.* +# Description: Prevent seller from listing trade good items below/above this item level +# Default: 0 + +AuctionHouseBot.Class.TradeGood.ItemLevel.Min = 0 +AuctionHouseBot.Class.TradeGood.ItemLevel.Max = 0 + +# +# AuctionHouseBot.Class.Container.ItemLevel.* +# Description: Prevent seller from listing contianers below/above this item level +# Default: 0 + +AuctionHouseBot.Class.Container.ItemLevel.Min = 0 +AuctionHouseBot.Class.Container.ItemLevel.Max = 0 + +# +# AuctionHouseBot.forceIncludeItems +# Description: Include these items and ignore ALL filters +# List of ids with delimiter ',' +# Default: "" + +AuctionHouseBot.forceIncludeItems = "" + +# +# AuctionHouseBot.forceExcludeItems +# Description: Exclude these items even if they would pass the filters +# List of ids with delimiter ',' +# Example: "21878,27774,27811,28117,28122,43949" (this removes old items) +# Default: "" +# + +AuctionHouseBot.forceExcludeItems = "" + +# +################################################################################################################### + +################################################################################################################### +# AHBot Buyer config +# +# AuctionHouseBot.Buyer.Enabled +# Description: General enable or disable AuctionHouseBot Buyer functionality +# Default: 0 - (Disabled) +# 1 - (Enabled) + +AuctionHouseBot.Buyer.Enabled = 0 + +# +# AuctionHouseBot.Buyer.FACTION.Enabled +# Description: Enable or disable buyer independently by faction +# Default: 0 - (Disabled) +# 1 - (Enabled) + +AuctionHouseBot.Buyer.Alliance.Enabled = 0 +AuctionHouseBot.Buyer.Horde.Enabled = 0 +AuctionHouseBot.Buyer.Neutral.Enabled = 0 + +# +# AuctionHouseBot.BuyPrice.Buyer +# Description: Should the Buyer use BuyPrice or SellPrice to determine Bid Prices +# Default: 1 - (use BuyPrice) +# 0 - (use SellPrice) + +AuctionHouseBot.Buyer.Buyprice = 1 + +# +# AuctionHouseBot.Buyer.Recheck.Interval +# Description: This specifies the time interval (in minutes) between two evaluations of the same selled item. +# The lesser this value is, the more chances you give for item to be bought by ahbot. +# Default: 20 (20min.) + +AuctionHouseBot.Buyer.Recheck.Interval = 20 + +# +# AuctionHouseBot.Buyer.Alliance.Chance.Ratio +# Description: Chance ratio for the buyer to buy an item. Higher the value, lesser the probability +# Example: 3 (1 out of 3 change, that is, 33%). +# Default: 3 +# + +AuctionHouseBot.Buyer.Alliance.Chance.Ratio = 3 +AuctionHouseBot.Buyer.Horde.Chance.Ratio = 3 +AuctionHouseBot.Buyer.Neutral.Chance.Ratio = 3 + +# +################################################################################################################### + ################################################################################################### # LOGGING SYSTEM SETTINGS # @@ -2718,6 +3077,7 @@ Logger.commands.gm=3,Console GM Logger.sql.sql=5,Console DBErrors #Logger.achievement=3,Console Server +#Logger.ahbot=3,Console Server #Logger.auctionHouse=3,Console Server #Logger.bg.arena=3,Console Server #Logger.bg.battlefield=3,Console Server |