diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Accounts/RBAC.h | 1 | ||||
-rw-r--r-- | src/server/game/AuctionHouseBot/AuctionHouseBot.cpp | 6 | ||||
-rw-r--r-- | src/server/game/AuctionHouseBot/AuctionHouseBot.h | 2 | ||||
-rw-r--r-- | src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp | 42 | ||||
-rw-r--r-- | src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h | 2 | ||||
-rw-r--r-- | src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp | 64 | ||||
-rw-r--r-- | src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 15 | ||||
-rw-r--r-- | src/server/game/Guilds/Guild.h | 3 | ||||
-rw-r--r-- | src/server/game/Miscellaneous/Language.h | 9 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 10 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_guild.cpp | 58 | ||||
-rw-r--r-- | src/server/scripts/Northrend/Ulduar/Ulduar/boss_hodir.cpp | 6 | ||||
-rw-r--r-- | src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp | 1385 | ||||
-rw-r--r-- | src/server/worldserver/worldserver.conf.dist | 9 |
15 files changed, 1547 insertions, 67 deletions
diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index 7aeceff87ae..fc22f76e949 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -697,6 +697,7 @@ enum RBACPermissions 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 index 707e143ac39..6bf5fa0aaa5 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.cpp @@ -294,8 +294,7 @@ void AuctionHouseBot::InitializeAgents() { if (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_SELLER_ENABLED)) { - if (_seller) - delete _seller; + delete _seller; _seller = new AuctionBotSeller(); if (!_seller->Initialize()) @@ -307,8 +306,7 @@ void AuctionHouseBot::InitializeAgents() if (sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_ENABLED)) { - if (_buyer) - delete _buyer; + delete _buyer; _buyer = new AuctionBotBuyer(); if (!_buyer->Initialize()) diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBot.h b/src/server/game/AuctionHouseBot/AuctionHouseBot.h index 8c1a2425f7c..04ca96dfdd9 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBot.h +++ b/src/server/game/AuctionHouseBot/AuctionHouseBot.h @@ -168,7 +168,7 @@ enum AuctionBotConfigBoolValues class AuctionBotConfig { private: - AuctionBotConfig() {} + AuctionBotConfig(): _itemsPerCycleBoost(1000), _itemsPerCycleNormal(20) {} ~AuctionBotConfig() {} AuctionBotConfig(const AuctionBotConfig&); AuctionBotConfig& operator=(const AuctionBotConfig&); diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp index f7c8003fc76..0043482c77f 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.cpp @@ -20,7 +20,7 @@ #include "ItemPrototype.h" #include "AuctionHouseBotBuyer.h" -AuctionBotBuyer::AuctionBotBuyer() +AuctionBotBuyer::AuctionBotBuyer(): _checkInterval(20) { // Define faction for our main data class. for (int i = 0; i < MAX_AUCTION_HOUSE_TYPE; ++i) @@ -50,7 +50,7 @@ bool AuctionBotBuyer::Initialize() //load Check interval _checkInterval = sAuctionBotConfig->GetConfig(CONFIG_AHBOT_BUYER_RECHECK_INTERVAL) * MINUTE; - TC_LOG_INFO("ahbot", "AHBot buyer interval between 2 check = %u", _checkInterval); + TC_LOG_DEBUG("ahbot", "AHBot buyer interval between 2 check = %u", _checkInterval); return true; } @@ -150,8 +150,8 @@ uint32 AuctionBotBuyer::GetBuyableEntry(BuyerConfiguration& config) } } - TC_LOG_INFO("ahbot", "AHBot: %u items added to buyable vector for ah type: %u", count, config.GetHouseType()); - TC_LOG_INFO("ahbot", "AHBot: SameItemInfo size = %u", (uint32)config.SameItemInfo.size()); + 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; } @@ -167,7 +167,7 @@ void AuctionBotBuyer::PrepareListOfEntry(BuyerConfiguration& config) ++itr; } - TC_LOG_INFO("ahbot", "AHBot: CheckedEntry size = %u", (uint32)config.CheckedEntry.size()); + 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) @@ -227,12 +227,12 @@ bool AuctionBotBuyer::IsBuyableEntry(uint32 buyoutPrice, double inGameBuyPrice, if (urand(1, chanceRatio) <= chance) { - TC_LOG_INFO("ahbot", "AHBot: WIN BUY! Chance = %u, num = %u.", chance, chanceRatio); + TC_LOG_DEBUG("ahbot", "AHBot: WIN BUY! Chance = %u, num = %u.", chance, chanceRatio); return true; } else { - TC_LOG_INFO("ahbot", "AHBot: LOOSE BUY! Chance = %u, num = %u.", chance, chanceRatio); + TC_LOG_DEBUG("ahbot", "AHBot: LOOSE BUY! Chance = %u, num = %u.", chance, chanceRatio); return false; } } @@ -274,25 +274,25 @@ bool AuctionBotBuyer::IsBidableEntry(uint32 bidPrice, double inGameBuyPrice, dou if (urand(1, chanceRatio) <= chance) { - TC_LOG_INFO("ahbot", "AHBot: WIN BID! Chance = %u, num = %u.", chance, chanceRatio); + TC_LOG_DEBUG("ahbot", "AHBot: WIN BID! Chance = %u, num = %u.", chance, chanceRatio); return true; } else { - TC_LOG_INFO("ahbot", "AHBot: LOOSE BID! Chance = %u, num = %u.", chance, chanceRatio); + TC_LOG_DEBUG("ahbot", "AHBot: LOOSE BID! Chance = %u, num = %u.", chance, chanceRatio); return false; } } void AuctionBotBuyer::PlaceBidToEntry(AuctionEntry* auction, uint32 bidPrice) { - TC_LOG_INFO("ahbot", "AHBot: Bid placed to entry %u, %.2fg", auction->Id, float(bidPrice) / 10000.0f); + 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_INFO("ahbot", "AHBot: Entry %u bought at %.2fg", auction->Id, float(auction->buyout) / 10000.0f); + TC_LOG_DEBUG("ahbot", "AHBot: Entry %u bought at %.2fg", auction->Id, float(auction->buyout) / 10000.0f); auction->bid = auction->buyout; } @@ -307,7 +307,7 @@ void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config) if (config.CheckedEntry.size() > sAuctionBotConfig->GetItemPerCycleBoost()) { buyCycles = sAuctionBotConfig->GetItemPerCycleBoost(); - TC_LOG_INFO("ahbot", "AHBot: Boost value used for Buyer! (if this happens often adjust both ItemsPerCycle in worldserver.conf)"); + TC_LOG_DEBUG("ahbot", "AHBot: Boost value used for Buyer! (if this happens often adjust both ItemsPerCycle in worldserver.conf)"); } else buyCycles = sAuctionBotConfig->GetItemPerCycleNormal(); @@ -317,8 +317,8 @@ void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config) AuctionEntry* auction = auctionHouse->GetAuction(itr->second.AuctionId); if (!auction) // is auction not active now { - TC_LOG_INFO("ahbot", "AHBot: Entry %u on ah %u doesn't exists, perhaps bought already?", - itr->second.AuctionId, auction->GetHouseId()); + TC_LOG_DEBUG("ahbot", "AHBot: Entry %u doesn't exists, perhaps bought already?", + itr->second.AuctionId); config.CheckedEntry.erase(itr++); continue; @@ -326,7 +326,7 @@ void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config) if (itr->second.LastChecked != 0 && (now - itr->second.LastChecked) <= _checkInterval) { - TC_LOG_INFO("ahbot", "AHBot: In time interval wait for entry %u!", auction->Id); + TC_LOG_DEBUG("ahbot", "AHBot: In time interval wait for entry %u!", auction->Id); ++itr; continue; } @@ -382,12 +382,12 @@ void AuctionBotBuyer::AddNewAuctionBuyerBotBid(BuyerConfiguration& config) double maxBidablePrice = maxBuyablePrice - (maxBuyablePrice / 30); // Max Bidable price defined to 70% of max buyable price - TC_LOG_INFO("ahbot", "AHBot: Auction added with data:"); - TC_LOG_INFO("ahbot", "AHBot: MaxPrice of Entry %u is %.1fg.", itr->second.AuctionId, maxBuyablePrice / 10000); - TC_LOG_INFO("ahbot", "AHBot: GamePrice buy=%.1fg, bid=%.1fg.", inGameBuyPrice / 10000, inGameBidPrice / 10000); - TC_LOG_INFO("ahbot", "AHBot: Minimal price see in AH Buy=%ug, Bid=%ug.", + 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_INFO("ahbot", "AHBot: Actual Entry price, Buy=%ug, Bid=%ug.", buyoutPrice / 10000, bidPrice / 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) @@ -422,7 +422,7 @@ bool AuctionBotBuyer::Update(AuctionHouseType houseType) { if (sAuctionBotConfig->GetConfigBuyerEnabled(houseType)) { - TC_LOG_INFO("ahbot", "AHBot: %s buying ...", AuctionBotConfig::GetHouseTypeName(houseType)); + TC_LOG_DEBUG("ahbot", "AHBot: %s buying ...", AuctionBotConfig::GetHouseTypeName(houseType)); if (GetBuyableEntry(_houseConfig[houseType]) > 0) AddNewAuctionBuyerBotBid(_houseConfig[houseType]); return true; diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h index 89be1b8b052..1148435f1c1 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotBuyer.h @@ -47,7 +47,7 @@ typedef std::map<uint32, BuyerAuctionEval> CheckEntryMap; struct BuyerConfiguration { - BuyerConfiguration(): _houseType(AUCTION_HOUSE_NEUTRAL) {} + BuyerConfiguration(): FactionChance(3), BuyerEnabled(false), BuyerPriceRatio(100), _houseType(AUCTION_HOUSE_NEUTRAL) {} void Initialize(AuctionHouseType houseType) { diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp index 0e6cfcaf22e..5d8da598299 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.cpp @@ -39,7 +39,7 @@ bool AuctionBotSeller::Initialize() std::vector<uint32> includeItems; std::vector<uint32> excludeItems; - TC_LOG_INFO("ahbot", "AHBot seller filters:"); + TC_LOG_DEBUG("ahbot", "AHBot seller filters:"); { std::stringstream includeStream(sAuctionBotConfig->GetAHBotIncludes()); @@ -55,10 +55,10 @@ bool AuctionBotSeller::Initialize() excludeItems.push_back(atoi(temp.c_str())); } - TC_LOG_INFO("ahbot", "Forced Inclusion %u items", (uint32)includeItems.size()); - TC_LOG_INFO("ahbot", "Forced Exclusion %u items", (uint32)excludeItems.size()); + TC_LOG_DEBUG("ahbot", "Forced Inclusion %u items", (uint32)includeItems.size()); + TC_LOG_DEBUG("ahbot", "Forced Exclusion %u items", (uint32)excludeItems.size()); - TC_LOG_INFO("ahbot", "Loading npc vendor items for filter.."); + 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) @@ -72,9 +72,9 @@ bool AuctionBotSeller::Initialize() for (std::set<uint32>::const_iterator it = tempItems.begin(); it != tempItems.end(); ++it) npcItems.push_back(*it); - TC_LOG_INFO("ahbot", "Npc vendor filter has %u items", (uint32)npcItems.size()); + TC_LOG_DEBUG("ahbot", "Npc vendor filter has %u items", (uint32)npcItems.size()); - TC_LOG_INFO("ahbot", "Loading loot items for filter.."); + 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 " @@ -101,8 +101,8 @@ bool AuctionBotSeller::Initialize() } while (result->NextRow()); } - TC_LOG_INFO("ahbot", "Loot filter has %u items", (uint32)lootItems.size()); - TC_LOG_INFO("ahbot", "Sorting and cleaning items for AHBot seller..."); + 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; @@ -382,18 +382,18 @@ bool AuctionBotSeller::Initialize() return false; } - TC_LOG_INFO("ahbot", "AuctionHouseBot seller will use %u items to fill auction house (according your config choices)", itemsAdded); + TC_LOG_DEBUG("ahbot", "AuctionHouseBot seller will use %u items to fill auction house (according your config choices)", itemsAdded); LoadConfig(); - TC_LOG_INFO("ahbot", "Items loaded \tGray\tWhite\tGreen\tBlue\tPurple\tOrange\tYellow"); + TC_LOG_DEBUG("ahbot", "Items loaded \tGray\tWhite\tGreen\tBlue\tPurple\tOrange\tYellow"); for (uint32 i = 0; i < MAX_ITEM_CLASS; ++i) - TC_LOG_INFO("ahbot", "\t\t%u\t%u\t%u\t%u\t%u\t%u\t%u", + 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_INFO("ahbot", "AHBot seller configuration data loaded and initialized"); + TC_LOG_DEBUG("ahbot", "AHBot seller configuration data loaded and initialized"); return true; } @@ -594,17 +594,17 @@ void AuctionBotSeller::LoadSellerValues(SellerConfiguration& config) config.SetMinTime(sAuctionBotConfig->GetConfig(CONFIG_AHBOT_MINTIME)); config.SetMaxTime(sAuctionBotConfig->GetConfig(CONFIG_AHBOT_MAXTIME)); - TC_LOG_INFO("ahbot", "AHBot: minTime = %u", config.GetMinTime()); - TC_LOG_INFO("ahbot", "AHBot: maxTime = %u", config.GetMaxTime()); - - TC_LOG_INFO("ahbot", "AHBot: For AH type %u", config.GetHouseType()); - TC_LOG_INFO("ahbot", "AHBot: GrayItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_GRAY)); - TC_LOG_INFO("ahbot", "AHBot: WhiteItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_WHITE)); - TC_LOG_INFO("ahbot", "AHBot: GreenItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_GREEN)); - TC_LOG_INFO("ahbot", "AHBot: BlueItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_BLUE)); - TC_LOG_INFO("ahbot", "AHBot: PurpleItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_PURPLE)); - TC_LOG_INFO("ahbot", "AHBot: OrangeItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_ORANGE)); - TC_LOG_INFO("ahbot", "AHBot: YellowItems = %u", config.GetItemsAmountPerQuality(AUCTION_QUALITY_YELLOW)); + 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. @@ -637,10 +637,10 @@ uint32 AuctionBotSeller::SetStat(SellerConfiguration& config) } } - TC_LOG_INFO("ahbot", "AHBot: Missed Item \tGray\tWhite\tGreen\tBlue\tPurple\tOrange\tYellow"); + 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_INFO("ahbot", "AHBot: \t\t%u\t%u\t%u\t%u\t%u\t%u\t%u", + 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), @@ -899,13 +899,13 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config) if (config.LastMissedItem > sAuctionBotConfig->GetItemPerCycleBoost()) { items = sAuctionBotConfig->GetItemPerCycleBoost(); - TC_LOG_INFO("ahbot", "AHBot: Boost value used to fill AH! (if this happens often adjust both ItemsPerCycle in worldserver.conf)"); + 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; - uint32 auctioneer; + uint32 houseid = 0; + uint32 auctioneer = 0; switch (config.GetHouseType()) { case AUCTION_HOUSE_ALLIANCE: @@ -938,14 +938,14 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config) if (!itemId) { - TC_LOG_INFO("ahbot", "AHBot: Item entry 0 auction creating attempt."); + TC_LOG_DEBUG("ahbot", "AHBot: Item entry 0 auction creating attempt."); continue; } ItemTemplate const* prototype = sObjectMgr->GetItemTemplate(itemId); if (!prototype) { - TC_LOG_INFO("ahbot", "AHBot: Unknown item %u auction creating attempt.", itemId); + TC_LOG_DEBUG("ahbot", "AHBot: Unknown item %u auction creating attempt.", itemId); continue; } @@ -1012,14 +1012,14 @@ void AuctionBotSeller::AddNewAuctions(SellerConfiguration& config) } CharacterDatabase.CommitTransaction(trans); - TC_LOG_INFO("ahbot", "AHBot: Added %u items to auction", count); + TC_LOG_DEBUG("ahbot", "AHBot: Added %u items to auction", count); } bool AuctionBotSeller::Update(AuctionHouseType houseType) { if (sAuctionBotConfig->GetConfigItemAmountRatio(houseType) > 0) { - TC_LOG_INFO("ahbot", "AHBot: %s selling ...", AuctionBotConfig::GetHouseTypeName(houseType)); + TC_LOG_DEBUG("ahbot", "AHBot: %s selling ...", AuctionBotConfig::GetHouseTypeName(houseType)); if (SetStat(_houseConfig[houseType])) AddNewAuctions(_houseConfig[houseType]); return true; diff --git a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h index a1820196dc8..014fe23f71a 100644 --- a/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h +++ b/src/server/game/AuctionHouseBot/AuctionHouseBotSeller.h @@ -55,7 +55,7 @@ struct SellerItemInfo class SellerConfiguration { public: - SellerConfiguration(): _houseType(AUCTION_HOUSE_NEUTRAL) + SellerConfiguration(): LastMissedItem(0), _houseType(AUCTION_HOUSE_NEUTRAL), _minTime(1), _maxTime(72) { } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d9c92d00a18..3cfe73e4d8c 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -15321,6 +15321,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); + } } } } @@ -15341,7 +15354,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); diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index da5f16d38c5..c8ee4d7b0a8 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -767,6 +767,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/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index d2d314fde31..9e4bd55671a 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -970,7 +970,14 @@ enum TrinityStrings LANG_AHBOT_QUALITY_YELLOW = 1174, LANG_AHBOT_ITEMS_AMOUNT = 1175, LANG_AHBOT_ITEMS_RATIO = 1176, - // Room for more level 3 1177-1199 not used + 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/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 0e5264bf56a..18c529d0515 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3360,6 +3360,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/scripts/Commands/cs_guild.cpp b/src/server/scripts/Commands/cs_guild.cpp index dfc681a1d87..99d9e0a2a8a 100644 --- a/src/server/scripts/Commands/cs_guild.cpp +++ b/src/server/scripts/Commands/cs_guild.cpp @@ -45,6 +45,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[] = @@ -244,6 +245,63 @@ public: handler->PSendSysMessage(LANG_GUILD_RENAME_DONE, oldGuildStr, newGuildStr); return true; } + + static bool HandleGuildInfoCommand(ChatHandler* handler, char const* args) + { + Player* target; + uint32 guildId; + std::string guildName; + std::string guildMasterName; + Guild* guild; + + if (!*args) + { + // Look for the guild of the selected player or ourselves + if (target = handler->getSelectedPlayerOrSelf()) + guild = target->GetGuild(); + else + // getSelectedPlayerOrSelf will return null if there is no session + // so target becomes nullptr if the command is ran through console + // without specifying args. + return false; + } + else if (guildId = atoi(args)) // Try searching by Id + guild = sGuildMgr->GetGuildById(guildId); + else + { + // Try to extract a guild name + char* tailStr = *args != '"' ? strtok(NULL, "") : (char*)args; + if (!tailStr) + return false; + + char* guildStr = handler->extractQuotedArg((char*)args); + if (!guildStr) + return false; + + guildName = guildStr; + guild = sGuildMgr->GetGuildByName(guildName); + } + + if (!guild) + return false; + + // Display Guild Information + handler->PSendSysMessage(LANG_GUILD_INFO_NAME, guild->GetName().c_str(), guild->GetId()); // Guild Id + Name + 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/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..f1d44e72684 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -316,6 +316,17 @@ enum Phases 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] = { SPELL_SEAT_1, @@ -324,6 +335,1317 @@ uint32 const RepairSpells[4] = SPELL_SEAT_5 }; +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); + instance->SetData(DATA_MIMIRON_ELEVATOR, 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: + instance->SetData(DATA_MIMIRON_ELEVATOR, 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 (Creature* vx001 = me->SummonCreature(NPC_VX_001, VX001SummonPos, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 120000)) + vx001->CastSpell(vx001, SPELL_FREEZE_ANIM); + instance->SetData(DATA_MIMIRON_ELEVATOR, GO_STATE_ACTIVE_ALTERNATIVE); + 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->GetAI()->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_SOLO)) + { + 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_LEVIATHAN_ASSEMBLED)) + { + 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_SOLO); + // Missing break intended. + case DO_START_MKII: + me->SetReactState(REACT_AGGRESSIVE); + events.SetPhase(PHASE_LEVIATHAN_SOLO); + + events.ScheduleEvent(EVENT_NAPALM_SHELL, 3000, 0, PHASE_LEVIATHAN_SOLO); + events.ScheduleEvent(EVENT_PLASMA_BLAST, 15000, 0, PHASE_LEVIATHAN_SOLO); + 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_LEVIATHAN_ASSEMBLED); + 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_SOLO) ? 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_SOLO); + + if (events.GetTimeUntilEvent(EVENT_NAPALM_SHELL) < 9000) + events.RescheduleEvent(EVENT_NAPALM_SHELL, 9000, 0, PHASE_LEVIATHAN_SOLO); // 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_SOLO); + break; + case EVENT_NAPALM_SHELL: + DoCastAOE(SPELL_FORCE_CAST_NAPALM_SHELL); + events.RescheduleEvent(EVENT_NAPALM_SHELL, urand(6000, 15000), 0, PHASE_LEVIATHAN_SOLO); + + if (events.GetTimeUntilEvent(EVENT_PLASMA_BLAST) < 2000) + events.RescheduleEvent(EVENT_PLASMA_BLAST, 2000, 0, PHASE_LEVIATHAN_SOLO); // 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_VX001_SOLO)) + { + 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_VX001_ASSEMBLED)) + { + 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_VX001_SOLO); + events.ScheduleEvent(EVENT_ROCKET_STRIKE, 20000); + events.ScheduleEvent(EVENT_SPINNING_UP, urand(30000, 35000)); + events.ScheduleEvent(EVENT_RAPID_BURST, 500, 0, PHASE_VX001_SOLO); + 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_VX001_ASSEMBLED); + events.ScheduleEvent(EVENT_ROCKET_STRIKE, 20000); + events.ScheduleEvent(EVENT_SPINNING_UP, urand(30000, 35000)); + events.ScheduleEvent(EVENT_HAND_PULSE, 500, 0, PHASE_VX001_ASSEMBLED); + 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_VX001_SOLO) ? 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_VX001_SOLO); + break; + case EVENT_ROCKET_STRIKE: + DoCastAOE(events.IsInPhase(PHASE_VX001_SOLO) ? 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_VX001_ASSEMBLED); + 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_VX001_SOLO); + 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_SOLO)) + { + me->GetMotionMaster()->Clear(true); + me->GetMotionMaster()->MovePoint(WP_AERIAL_P4_POS, VehicleRelocation[WP_AERIAL_P4_POS]); + } + else if (events.IsInPhase(PHASE_AERIAL_ASSEMBLED)) + { + 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_SOLO); + // 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_SOLO); + events.ScheduleEvent(EVENT_SUMMON_JUNK_BOT, 5000, 0, PHASE_AERIAL_SOLO); + events.ScheduleEvent(EVENT_SUMMON_ASSAULT_BOT, 9000, 0, PHASE_AERIAL_SOLO); + events.ScheduleEvent(EVENT_SUMMON_BOMB_BOT, 9000, 0, PHASE_AERIAL_SOLO); + 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_AERIAL_ASSEMBLED); + 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_SOLO) ? 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_SOLO); + 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_SOLO); + 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_SOLO); + break; + case EVENT_SUMMON_BOMB_BOT: + DoCast(me, SPELL_SUMMON_BOMB_BOT); + events.RescheduleEvent(EVENT_SUMMON_BOMB_BOT, urand(15000, 20000), 0, PHASE_AERIAL_SOLO); + break; + default: + break; + } + } + DoSpellAttackIfReady(events.IsInPhase(PHASE_AERIAL_SOLO) ? 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 { @@ -1426,8 +2748,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 +2834,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/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index e93e3670864..14ac9a34cf5 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -2706,16 +2706,16 @@ AuctionHouseBot.LockBox.Enabled = 0 # # AuctionHouseBot.ItemsPerCycle.Boost -# Description: This value is used to fill DB faster than normal when there is more than this value on missed items (not auctioned items). -# Normaly this value is only used once on server start with empty auction table. +# 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 DB with way with less cpu/db using. -# Normaly this value is used always when auction table is already initialised. +# 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 @@ -2753,7 +2753,6 @@ AuctionHouseBot.Neutral.Price.Ratio = 100 # AuctionHouseBot.Items.ItemLevel.* # Description: Prevent seller from listing items below/above this item level # Default: 0 - (Disabled) -# 1-80 (Levels) AuctionHouseBot.Items.ItemLevel.Min = 0 AuctionHouseBot.Items.ItemLevel.Max = 0 |