diff --git a/src/strategy/actions/BossAuraActions.cpp b/src/strategy/actions/BossAuraActions.cpp new file mode 100644 index 00000000..ca77d634 --- /dev/null +++ b/src/strategy/actions/BossAuraActions.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it + * and/or modify it under version 2 of the License, or (at your option), any later version. + */ + +#include +#include +#include + +#include "BossAuraActions.h" +#include "BossAuraTriggers.h" + +const std::string ADD_STRATEGY_CHAR = "+"; + +bool BossFireResistanceAction::isUseful() +{ + BossFireResistanceTrigger bossFireResistanceTrigger(botAI, bossName); + return bossFireResistanceTrigger.IsActive(); +} + +bool BossFireResistanceAction::Execute(Event event) +{ + PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI); + botAI->ChangeStrategy(ADD_STRATEGY_CHAR + paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT); + return true; +} + +bool BossFrostResistanceAction::isUseful() +{ + BossFrostResistanceTrigger bossFrostResistanceTrigger(botAI, bossName); + return bossFrostResistanceTrigger.IsActive(); +} + +bool BossFrostResistanceAction::Execute(Event event) +{ + PaladinFrostResistanceStrategy paladinFrostResistanceStrategy(botAI); + botAI->ChangeStrategy(ADD_STRATEGY_CHAR + paladinFrostResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT); + return true; +} + +bool BossNatureResistanceAction::isUseful() +{ + BossNatureResistanceTrigger bossNatureResistanceTrigger(botAI, bossName); + return bossNatureResistanceTrigger.IsActive(); +} + +bool BossNatureResistanceAction::Execute(Event event) +{ + HunterNatureResistanceStrategy hunterNatureResistanceStrategy(botAI); + botAI->ChangeStrategy(ADD_STRATEGY_CHAR + hunterNatureResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT); + return true; +} diff --git a/src/strategy/actions/BossAuraActions.h b/src/strategy/actions/BossAuraActions.h new file mode 100644 index 00000000..b1bc0dd9 --- /dev/null +++ b/src/strategy/actions/BossAuraActions.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it + * and/or modify it under version 2 of the License, or (at your option), any later version. + */ + +#ifndef _PLAYERBOT_BOSSAURAACTION_H +#define _PLAYERBOT_BOSSAURAACTION_H + +#include + +#include "Action.h" + +class PlayerbotAI; + +class BossFireResistanceAction : public Action +{ +public: + BossFireResistanceAction(PlayerbotAI* botAI, std::string const bossName) + : Action(botAI, bossName + " fire resistance action"), bossName(bossName) + { + } + bool Execute(Event event) override; + bool isUseful() override; + +private: + std::string bossName; +}; + +class BossFrostResistanceAction : public Action +{ +public: + BossFrostResistanceAction(PlayerbotAI* botAI, std::string const bossName) + : Action(botAI, bossName + " frost resistance action"), bossName(bossName) + { + } + bool Execute(Event event) override; + bool isUseful() override; + +private: + std::string bossName; +}; + +class BossNatureResistanceAction : public Action +{ +public: + BossNatureResistanceAction(PlayerbotAI* botAI, std::string const bossName) + : Action(botAI, bossName + " nature resistance action"), bossName(bossName) + { + } + bool Execute(Event event) override; + bool isUseful() override; + +private: + std::string bossName; +}; + +#endif diff --git a/src/strategy/raids/ulduar/RaidUlduarActionContext.h b/src/strategy/raids/ulduar/RaidUlduarActionContext.h index f52711ba..11a6f0c1 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActionContext.h +++ b/src/strategy/raids/ulduar/RaidUlduarActionContext.h @@ -9,6 +9,7 @@ #include "Action.h" #include "NamedObjectContext.h" #include "RaidUlduarActions.h" +#include "BossAuraActions.h" class RaidUlduarActionContext : public NamedObjectContext { @@ -36,7 +37,12 @@ public: creators["hodir biting cold jump"] = &RaidUlduarActionContext::hodir_biting_cold_jump; creators["hodir frost resistance action"] = &RaidUlduarActionContext::hodir_frost_resistance_action; creators["freya move away nature bomb"] = &RaidUlduarActionContext::freya_move_away_nature_bomb; - creators["freya mark eonars gift"] = &RaidUlduarActionContext::freya_mark_eonars_gift; + creators["freya fire resistance action"] = &RaidUlduarActionContext::freya_fire_resistance_action; + creators["freya nature resistance action"] = &RaidUlduarActionContext::freya_nature_resistance_action; + creators["freya mark dps target action"] = &RaidUlduarActionContext::freya_mark_dps_target_action; + creators["freya move to healing spore action"] = &RaidUlduarActionContext::freya_move_to_healing_spore_action; + creators["thorim nature resistance action"] = &RaidUlduarActionContext::thorim_nature_resistance_action; + creators["mimiron fire resistance action"] = &RaidUlduarActionContext::mimiron_fire_resistance_action; } private: @@ -49,19 +55,24 @@ private: static Action* razorscale_grounded(PlayerbotAI* ai) { return new RazorscaleGroundedAction(ai); } static Action* razorscale_harpoon_action(PlayerbotAI* ai) { return new RazorscaleHarpoonAction(ai); } static Action* razorscale_fuse_armor_action(PlayerbotAI* ai) { return new RazorscaleFuseArmorAction(ai); } - static Action* razorscale_fire_resistance_action(PlayerbotAI* ai) { return new RazorscaleFireResistanceAction(ai); } - static Action* ignis_fire_resistance_action(PlayerbotAI* ai) { return new IgnisFireResistanceAction(ai); } + static Action* razorscale_fire_resistance_action(PlayerbotAI* ai) { return new BossFireResistanceAction(ai, "razorscale"); } + static Action* ignis_fire_resistance_action(PlayerbotAI* ai) { return new BossFireResistanceAction(ai, "ignis the furnace master"); } static Action* iron_assembly_lightning_tendrils_action(PlayerbotAI* ai) { return new IronAssemblyLightningTendrilsAction(ai); } static Action* iron_assembly_overload_action(PlayerbotAI* ai) { return new IronAssemblyOverloadAction(ai); } static Action* kologarn_mark_dps_target_action(PlayerbotAI* ai) { return new KologarnMarkDpsTargetAction(ai); } static Action* kologarn_fall_from_floor_action(PlayerbotAI* ai) { return new KologarnFallFromFloorAction(ai); } - static Action* kologarn_nature_resistance_action(PlayerbotAI* ai) { return new KologarnNatureResistanceAction(ai); } + static Action* kologarn_nature_resistance_action(PlayerbotAI* ai) { return new BossNatureResistanceAction(ai, "kologarn"); } static Action* kologarn_rubble_slowdown_action(PlayerbotAI* ai) { return new KologarnRubbleSlowdownAction(ai); } static Action* hodir_move_snowpacked_icicle(PlayerbotAI* ai) { return new HodirMoveSnowpackedIcicleAction(ai); } static Action* hodir_biting_cold_jump(PlayerbotAI* ai) { return new HodirBitingColdJumpAction(ai); } - static Action* hodir_frost_resistance_action(PlayerbotAI* ai) { return new HodirFrostResistanceAction(ai); } + static Action* hodir_frost_resistance_action(PlayerbotAI* ai) { return new BossFrostResistanceAction(ai, "hodir"); } static Action* freya_move_away_nature_bomb(PlayerbotAI* ai) { return new FreyaMoveAwayNatureBombAction(ai); } - static Action* freya_mark_eonars_gift(PlayerbotAI* ai) { return new FreyaMarkEonarsGiftAction(ai); } + static Action* freya_fire_resistance_action(PlayerbotAI* ai) { return new BossFireResistanceAction(ai, "freya"); } + static Action* freya_nature_resistance_action(PlayerbotAI* ai) { return new BossNatureResistanceAction(ai, "freya"); } + static Action* freya_mark_dps_target_action(PlayerbotAI* ai) { return new FreyaMarkDpsTargetAction(ai); } + static Action* freya_move_to_healing_spore_action(PlayerbotAI* ai) { return new FreyaMoveToHealingSporeAction(ai); } + static Action* thorim_nature_resistance_action(PlayerbotAI* ai) { return new BossNatureResistanceAction(ai, "thorim"); } + static Action* mimiron_fire_resistance_action(PlayerbotAI* ai) { return new BossFireResistanceAction(ai, "mimiron"); } }; #endif diff --git a/src/strategy/raids/ulduar/RaidUlduarActions.cpp b/src/strategy/raids/ulduar/RaidUlduarActions.cpp index cdd7dd4f..4221238e 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActions.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarActions.cpp @@ -24,8 +24,6 @@ #include "SharedDefines.h" #include "Unit.h" #include "Vehicle.h" -#include -#include const std::vector availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER, NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE, @@ -1168,32 +1166,6 @@ bool RazorscaleFuseArmorAction::Execute(Event event) return true; } -bool RazorscaleFireResistanceAction::isUseful() -{ - RazorscaleFireResistanceTrigger razorscaleFireResistanceTrigger(botAI); - return razorscaleFireResistanceTrigger.IsActive(); -} - -bool RazorscaleFireResistanceAction::Execute(Event event) -{ - PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI); - botAI->ChangeStrategy(std::string("+") + paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT); - return true; -} - -bool IgnisFireResistanceAction::isUseful() -{ - IgnisFireResistanceTrigger ignisFireResistanceTrigger(botAI); - return ignisFireResistanceTrigger.IsActive(); -} - -bool IgnisFireResistanceAction::Execute(Event event) -{ - PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI); - botAI->ChangeStrategy(std::string("+") + paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT); - return true; -} - bool IronAssemblyLightningTendrilsAction::isUseful() { IronAssemblyLightningTendrilsTrigger ironAssemblyLightningTendrilsTrigger(botAI); @@ -1377,19 +1349,6 @@ bool KologarnFallFromFloorAction::isUseful() return kologarnFallFromFloorTrigger.IsActive(); } -bool KologarnNatureResistanceAction::Execute(Event event) -{ - HunterNatureResistanceStrategy hunterNatureResistanceStrategy(botAI); - botAI->ChangeStrategy(std::string("+") + hunterNatureResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT); - return true; -} - -bool KologarnNatureResistanceAction::isUseful() -{ - KologarnNatureResistanceTrigger kologarnNatureResistanceTrigger(botAI); - return kologarnNatureResistanceTrigger.IsActive(); -} - bool KologarnRubbleSlowdownAction::Execute(Event event) { Group* group = bot->GetGroup(); @@ -1478,19 +1437,6 @@ bool HodirBitingColdJumpAction::Execute(Event event) // return true; } -bool HodirFrostResistanceAction::isUseful() -{ - HodirFrostResistanceTrigger hodirFrostResistanceTrigger(botAI); - return hodirFrostResistanceTrigger.IsActive(); -} - -bool HodirFrostResistanceAction::Execute(Event event) -{ - PaladinFrostResistanceStrategy paladinFrostResistanceStrategy(botAI); - botAI->ChangeStrategy(std::string("+") + paladinFrostResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT); - return true; -} - bool FreyaMoveAwayNatureBombAction::isUseful() { // Check boss and it is alive @@ -1517,79 +1463,118 @@ bool FreyaMoveAwayNatureBombAction::Execute(Event event) return FleePosition(target->GetPosition(), 13.0f); } -bool FreyaMarkEonarsGiftAction::isUseful() +bool FreyaMarkDpsTargetAction::isUseful() { - // Only tank bot can mark target - if (!botAI->IsTank(bot)) - { + FreyaMarkDpsTargetTrigger freyaMarkDpsTargetTrigger(botAI); + return freyaMarkDpsTargetTrigger.IsActive(); +} + +bool FreyaMarkDpsTargetAction::Execute(Event event) +{ + Unit* boss = AI_VALUE2(Unit*, "find target", "freya"); + if (!boss || !boss->IsAlive()) return false; - } - // Check Eonar's gift and it is alive + Unit* targetToMark = nullptr; + + // Check which adds is up + Unit* eonarsGift = nullptr; + Unit* ancientConservator = nullptr; + Unit* snaplasher = nullptr; + Unit* ancientWaterSpirit = nullptr; + Unit* stormLasher = nullptr; + Unit* firstDetonatingLasher = nullptr; - // Target is not findable from threat table using AI_VALUE2(), - // therefore need to search manually for the unit id GuidVector targets = AI_VALUE(GuidVector, "possible targets"); Unit* target = nullptr; for (auto i = targets.begin(); i != targets.end(); ++i) { target = botAI->GetUnit(*i); - if (!target) - { + if (!target || !target->IsAlive()) continue; - } - uint32 creatureId = target->GetEntry(); - if (creatureId == NPC_EONARS_GIFT && target->IsAlive()) + if (target->GetEntry() == NPC_EONARS_GIFT) { - break; + eonarsGift = target; + } + else if (target->GetEntry() == NPC_ANCIENT_CONSERVATOR) + { + ancientConservator = target; + } + else if (target->GetEntry() == NPC_SNAPLASHER) + { + snaplasher = target; + } + else if (target->GetEntry() == NPC_ANCIENT_WATER_SPIRIT) + { + ancientWaterSpirit = target; + } + else if (target->GetEntry() == NPC_STORM_LASHER) + { + stormLasher = target; + } + else if (target->GetEntry() == NPC_DETONATING_LASHER && !firstDetonatingLasher) + { + firstDetonatingLasher = target; } } - // Check if Eonar's Gift is already set as the skull marker - Group* group = bot->GetGroup(); - if (!group) + // Check that eonars gift is need to be mark + if (eonarsGift) { - return false; + targetToMark = eonarsGift; } - int8 skullIndex = 7; - ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex); - if (!target || currentSkullTarget == target->GetGUID()) + // Check that ancient conservator is need to be mark + if (ancientConservator && !targetToMark) { - return false; // Skull marker is already correctly set or no Eonar's Gift found + targetToMark = ancientConservator; } - return true; -} + // Check that trio of adds is need to be mark + if ((snaplasher || ancientWaterSpirit || stormLasher) && !targetToMark) + { + Unit* highestHealthUnit = nullptr; + uint32 highestHealth = 0; + + if (snaplasher && snaplasher->GetHealth() > highestHealth) + { + highestHealth = snaplasher->GetHealth(); + highestHealthUnit = snaplasher; + } + if (ancientWaterSpirit && ancientWaterSpirit->GetHealth() > highestHealth) + { + highestHealth = ancientWaterSpirit->GetHealth(); + highestHealthUnit = ancientWaterSpirit; + } + if (stormLasher && stormLasher->GetHealth() > highestHealth) + { + highestHealthUnit = stormLasher; + } + + // If the highest health unit is not already marked, mark it + if (highestHealthUnit) + { + targetToMark = highestHealthUnit; + } + } + + // Check that detonating lasher is need to be mark + if (firstDetonatingLasher && !targetToMark) + { + targetToMark = firstDetonatingLasher; + } + + if (!targetToMark) + { + return false; // No target to mark + } -bool FreyaMarkEonarsGiftAction::Execute(Event event) -{ bool isMainTank = botAI->IsMainTank(bot); Unit* mainTankUnit = AI_VALUE(Unit*, "main tank"); Player* mainTank = mainTankUnit ? mainTankUnit->ToPlayer() : nullptr; - - GuidVector targets = AI_VALUE(GuidVector, "possible targets"); - Unit* target = nullptr; - for (auto i = targets.begin(); i != targets.end(); ++i) - { - Unit* unit = botAI->GetUnit(*i); - if (!unit) - { - continue; - } - - uint32 creatureId = unit->GetEntry(); - if (creatureId == NPC_EONARS_GIFT && unit->IsAlive()) - { - target = unit; - } - } - - if (!target) - { - return false; - } + int8 squareIndex = 5; // Square + int8 skullIndex = 7; // Skull if (mainTank && !GET_PLAYERBOT_AI(mainTank)) // Main tank is a real player { @@ -1599,19 +1584,18 @@ bool FreyaMarkEonarsGiftAction::Execute(Event event) if (botAI->IsAssistTankOfIndex(bot, i) && GET_PLAYERBOT_AI(bot)) // Bot is a valid tank { Group* group = bot->GetGroup(); - if (group && target) + if (group) { - int8 skullIndex = 7; // Skull ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex); - - // If there's no skull set yet, or the skull is on a different target, set the Eonar's Gift - if (!currentSkullTarget || (target->GetGUID() != currentSkullTarget)) + + if (!currentSkullTarget || (targetToMark->GetGUID() != currentSkullTarget)) { - group->SetTargetIcon(skullIndex, bot->GetGUID(), target->GetGUID()); + group->SetTargetIcon(skullIndex, bot->GetGUID(), targetToMark->GetGUID()); + group->SetTargetIcon(squareIndex, bot->GetGUID(), boss->GetGUID()); return true; } } - break; // Stop after finding the first valid bot tank + break; } } } @@ -1620,13 +1604,13 @@ bool FreyaMarkEonarsGiftAction::Execute(Event event) Group* group = bot->GetGroup(); if (group) { - int8 skullIndex = 7; // Skull ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex); - - // If there's no skull set yet, or the skull is on a different target, set the Eonar's Gift - if (!currentSkullTarget || (target->GetGUID() != currentSkullTarget)) + + if (!currentSkullTarget || (targetToMark->GetGUID() != currentSkullTarget)) { - group->SetTargetIcon(skullIndex, bot->GetGUID(), target->GetGUID()); + group->SetTargetIcon(skullIndex, bot->GetGUID(), targetToMark->GetGUID()); + group->SetTargetIcon(squareIndex, bot->GetGUID(), boss->GetGUID()); + botAI->GetAiObjectContext()->GetValue("rti")->Set("square"); return true; } } @@ -1634,3 +1618,40 @@ bool FreyaMarkEonarsGiftAction::Execute(Event event) return false; } + +bool FreyaMoveToHealingSporeAction::isUseful() +{ + FreyaMoveToHealingSporeTrigger freyaMoveToHealingSporeTrigger(botAI); + return freyaMoveToHealingSporeTrigger.IsActive(); +} + +bool FreyaMoveToHealingSporeAction::Execute(Event event) +{ + GuidVector targets = AI_VALUE(GuidVector, "nearest npcs"); + Creature* nearestSpore = nullptr; + float nearestDistance = std::numeric_limits::max(); + + for (auto guid : targets) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit) + continue; + + // Check if this unit is a healthy spore and alive + if (unit->GetEntry() != NPC_HEALTHY_SPORE || !unit->IsAlive()) + continue; + + float distance = bot->GetDistance2d(unit); + if (distance < nearestDistance) + { + nearestDistance = distance; + nearestSpore = static_cast(unit); + } + } + + if (!nearestSpore) + return false; + + return MoveTo(nearestSpore->GetMapId(), nearestSpore->GetPositionX(), nearestSpore->GetPositionY(), + nearestSpore->GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT); +} diff --git a/src/strategy/raids/ulduar/RaidUlduarActions.h b/src/strategy/raids/ulduar/RaidUlduarActions.h index f7da8435..5889b07f 100644 --- a/src/strategy/raids/ulduar/RaidUlduarActions.h +++ b/src/strategy/raids/ulduar/RaidUlduarActions.h @@ -106,25 +106,6 @@ public: bool isUseful() override; }; -class RazorscaleFireResistanceAction : public Action -{ -public: - RazorscaleFireResistanceAction(PlayerbotAI* botAI) : Action(botAI, "razorscale fire resistance action") {} - bool Execute(Event event) override; - bool isUseful() override; -}; - -// -// Ignis -// -class IgnisFireResistanceAction : public Action -{ -public: - IgnisFireResistanceAction(PlayerbotAI* botAI) : Action(botAI, "ignis fire resistance action") {} - bool Execute(Event event) override; - bool isUseful() override; -}; - class HodirMoveSnowpackedIcicleAction : public MovementAction { public: @@ -133,14 +114,6 @@ public: bool isUseful() override; }; -class HodirFrostResistanceAction : public Action -{ -public: - HodirFrostResistanceAction(PlayerbotAI* botAI) : Action(botAI, "hodir frost resistance action") {} - bool Execute(Event event) override; - bool isUseful() override; -}; - class IronAssemblyLightningTendrilsAction : public MovementAction { public: @@ -173,14 +146,6 @@ public: bool isUseful() override; }; -class KologarnNatureResistanceAction : public Action -{ -public: - KologarnNatureResistanceAction(PlayerbotAI* botAI) : Action(botAI, "kologarn nature resistance action") {} - bool Execute(Event event) override; - bool isUseful() override; -}; - class KologarnRubbleSlowdownAction : public Action { public: @@ -203,10 +168,19 @@ public: bool isUseful() override; }; -class FreyaMarkEonarsGiftAction : public MovementAction +class FreyaMarkDpsTargetAction : public MovementAction { public: - FreyaMarkEonarsGiftAction(PlayerbotAI* botAI) : MovementAction(botAI, "freya mark eonars gift") {} + FreyaMarkDpsTargetAction(PlayerbotAI* botAI) : MovementAction(botAI, "freya mark dps target action") {} + bool Execute(Event event) override; + bool isUseful() override; +}; + +class FreyaMoveToHealingSporeAction : public MovementAction +{ +public: + FreyaMoveToHealingSporeAction(PlayerbotAI* ai) : MovementAction(ai, "freya move to healing spore action") {} + bool Execute(Event event) override; bool isUseful() override; }; diff --git a/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp b/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp index c0ff5616..4701b49f 100644 --- a/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarStrategy.cpp @@ -105,13 +105,39 @@ void RaidUlduarStrategy::InitTriggers(std::vector& triggers) // // Freya // - triggers.push_back(new TriggerNode( - "freya tank near eonars gift", - NextAction::array(0, new NextAction("freya mark eonars gift", ACTION_RAID + 1), nullptr))); - triggers.push_back(new TriggerNode( "freya near nature bomb", NextAction::array(0, new NextAction("freya move away nature bomb", ACTION_RAID), nullptr))); + + triggers.push_back(new TriggerNode( + "freya nature resistance trigger", + NextAction::array(0, new NextAction("freya nature resistance action", ACTION_RAID), nullptr))); + + triggers.push_back(new TriggerNode( + "freya fire resistance trigger", + NextAction::array(0, new NextAction("freya fire resistance action", ACTION_RAID), nullptr))); + + triggers.push_back(new TriggerNode( + "freya mark dps target trigger", + NextAction::array(0, new NextAction("freya mark dps target action", ACTION_RAID), nullptr))); + + triggers.push_back(new TriggerNode( + "freya move to healing spore trigger", + NextAction::array(0, new NextAction("freya move to healing spore action", ACTION_RAID), nullptr))); + + // + // Thorim + // + triggers.push_back(new TriggerNode( + "thorim nature resistance trigger", + NextAction::array(0, new NextAction("thorim nature resistance action", ACTION_RAID), nullptr))); + + // + // Mimiron + // + triggers.push_back(new TriggerNode( + "mimiron fire resistance trigger", + NextAction::array(0, new NextAction("mimiron fire resistance action", ACTION_RAID), nullptr))); } void RaidUlduarStrategy::InitMultipliers(std::vector& multipliers) diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h b/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h index f6160a87..8889b09d 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h +++ b/src/strategy/raids/ulduar/RaidUlduarTriggerContext.h @@ -9,6 +9,7 @@ #include "AiObjectContext.h" #include "NamedObjectContext.h" #include "RaidUlduarTriggers.h" +#include "BossAuraTriggers.h" class RaidUlduarTriggerContext : public NamedObjectContext { @@ -36,7 +37,12 @@ public: creators["hodir near snowpacked icicle"] = &RaidUlduarTriggerContext::hodir_near_snowpacked_icicle; creators["hodir frost resistance trigger"] = &RaidUlduarTriggerContext::hodir_frost_resistance_trigger; creators["freya near nature bomb"] = &RaidUlduarTriggerContext::freya_near_nature_bomb; - creators["freya tank near eonars gift"] = &RaidUlduarTriggerContext::freya_tank_near_eonars_gift; + creators["freya fire resistance trigger"] = &RaidUlduarTriggerContext::freya_fire_resistance_trigger; + creators["freya nature resistance trigger"] = &RaidUlduarTriggerContext::freya_nature_resistance_trigger; + creators["freya mark dps target trigger"] = &RaidUlduarTriggerContext::freya_mark_dps_target_trigger; + creators["freya move to healing spore trigger"] = &RaidUlduarTriggerContext::freya_move_to_healing_spore_trigger; + creators["thorim nature resistance trigger"] = &RaidUlduarTriggerContext::thorim_nature_resistance_trigger; + creators["mimiron fire resistance trigger"] = &RaidUlduarTriggerContext::mimiron_fire_resistance_trigger; } private: @@ -49,19 +55,24 @@ private: static Trigger* razorscale_grounded(PlayerbotAI* ai) { return new RazorscaleGroundedTrigger(ai); } static Trigger* razorscale_harpoon_trigger(PlayerbotAI* ai) { return new RazorscaleHarpoonAvailableTrigger(ai); } static Trigger* razorscale_fuse_armor_trigger(PlayerbotAI* ai) { return new RazorscaleFuseArmorTrigger(ai); } - static Trigger* razorscale_fire_resistance_trigger(PlayerbotAI* ai) { return new RazorscaleFireResistanceTrigger(ai); } - static Trigger* ignis_fire_resistance_trigger(PlayerbotAI* ai) { return new IgnisFireResistanceTrigger(ai); } + static Trigger* razorscale_fire_resistance_trigger(PlayerbotAI* ai) { return new BossFireResistanceTrigger(ai, "razorscale"); } + static Trigger* ignis_fire_resistance_trigger(PlayerbotAI* ai) { return new BossFireResistanceTrigger(ai, "ignis the furnace master"); } static Trigger* iron_assembly_lightning_tendrils_trigger(PlayerbotAI* ai) { return new IronAssemblyLightningTendrilsTrigger(ai); } static Trigger* iron_assembly_overload_trigger(PlayerbotAI* ai) { return new IronAssemblyOverloadTrigger(ai); } static Trigger* kologarn_mark_dps_target_trigger(PlayerbotAI* ai) { return new KologarnMarkDpsTargetTrigger(ai); } static Trigger* kologarn_fall_from_floor_trigger(PlayerbotAI* ai) { return new KologarnFallFromFloorTrigger(ai); } - static Trigger* kologarn_nature_resistance_trigger(PlayerbotAI* ai) { return new KologarnNatureResistanceTrigger(ai); } + static Trigger* kologarn_nature_resistance_trigger(PlayerbotAI* ai) { return new BossNatureResistanceTrigger(ai, "kologarn"); } static Trigger* kologarn_rubble_slowdown_trigger(PlayerbotAI* ai) { return new KologarnRubbleSlowdownTrigger(ai); } static Trigger* hodir_biting_cold(PlayerbotAI* ai) { return new HodirBitingColdTrigger(ai); } static Trigger* hodir_near_snowpacked_icicle(PlayerbotAI* ai) { return new HodirNearSnowpackedIcicleTrigger(ai); } - static Trigger* hodir_frost_resistance_trigger(PlayerbotAI* ai) { return new HodirFrostResistanceTrigger(ai); } + static Trigger* hodir_frost_resistance_trigger(PlayerbotAI* ai) { return new BossFrostResistanceTrigger(ai, "hodir"); } static Trigger* freya_near_nature_bomb(PlayerbotAI* ai) { return new FreyaNearNatureBombTrigger(ai); } - static Trigger* freya_tank_near_eonars_gift(PlayerbotAI* ai) { return new FreyaTankNearEonarsGiftTrigger(ai); } + static Trigger* freya_fire_resistance_trigger(PlayerbotAI* ai) { return new BossFireResistanceTrigger(ai, "freya"); } + static Trigger* freya_nature_resistance_trigger(PlayerbotAI* ai) { return new BossNatureResistanceTrigger(ai, "freya"); } + static Trigger* freya_mark_dps_target_trigger(PlayerbotAI* ai) { return new FreyaMarkDpsTargetTrigger(ai); } + static Trigger* freya_move_to_healing_spore_trigger(PlayerbotAI* ai) { return new FreyaMoveToHealingSporeTrigger(ai); } + static Trigger* thorim_nature_resistance_trigger(PlayerbotAI* ai) { return new BossNatureResistanceTrigger(ai, "thorim"); } + static Trigger* mimiron_fire_resistance_trigger(PlayerbotAI* ai) { return new BossFireResistanceTrigger(ai, "mimiron"); } }; #endif diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp b/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp index afe65640..97d2fb06 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp +++ b/src/strategy/raids/ulduar/RaidUlduarTriggers.cpp @@ -11,8 +11,6 @@ #include "SharedDefines.h" #include "Trigger.h" #include "Vehicle.h" -#include -#include const std::vector availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER, NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE, @@ -244,100 +242,6 @@ bool RazorscaleFuseArmorTrigger::IsActive() return false; } -bool RazorscaleFireResistanceTrigger::IsActive() -{ - // Check boss and it is alive - Unit* boss = AI_VALUE2(Unit*, "find target", "razorscale"); - if (!boss || !boss->IsAlive()) - return false; - - // Check if bot is paladin - if (bot->getClass() != CLASS_PALADIN) - return false; - - // Check if bot have fire resistance aura - if (bot->HasAura(SPELL_FIRE_RESISTANCE_AURA)) - return false; - - // Check if bot dont have already have fire resistance strategy - PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI); - if (botAI->HasStrategy(paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT)) - return false; - - // Check that the bot actually knows the spell - if (!bot->HasActiveSpell(SPELL_FIRE_RESISTANCE_AURA)) - return false; - - // Get the group and ensure it's a raid group - Group* group = bot->GetGroup(); - if (!group || !group->isRaidGroup()) - return false; - - // Iterate through group members to find the first alive paladin - for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) - { - Player* member = gref->GetSource(); - if (!member || !member->IsAlive()) - continue; - - // Check if the member is a hunter - if (member->getClass() == CLASS_PALADIN) - { - // Return true only if the current bot is the first alive paladin - return member == bot; - } - } - - return false; -} - -bool IgnisFireResistanceTrigger::IsActive() -{ - // Check boss and it is alive - Unit* boss = AI_VALUE2(Unit*, "find target", "ignis the furnace master"); - if (!boss || !boss->IsAlive()) - return false; - - // Check if bot is paladin - if (bot->getClass() != CLASS_PALADIN) - return false; - - // Check if bot have fire resistance aura - if (bot->HasAura(SPELL_FIRE_RESISTANCE_AURA)) - return false; - - // Check if bot dont have already have fire resistance strategy - PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI); - if (botAI->HasStrategy(paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT)) - return false; - - // Check that the bot actually knows the spell - if (!bot->HasActiveSpell(SPELL_FIRE_RESISTANCE_AURA)) - return false; - - // Get the group and ensure it's a raid group - Group* group = bot->GetGroup(); - if (!group || !group->isRaidGroup()) - return false; - - // Iterate through group members to find the first alive paladin - for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) - { - Player* member = gref->GetSource(); - if (!member || !member->IsAlive()) - continue; - - // Check if the member is a hunter - if (member->getClass() == CLASS_PALADIN) - { - // Return true only if the current bot is the first alive paladin - return member == bot; - } - } - - return false; -} - bool IronAssemblyLightningTendrilsTrigger::IsActive() { // Check boss and it is alive @@ -451,57 +355,6 @@ bool KologarnFallFromFloorTrigger::IsActive() return bot->GetPositionZ() < ULDUAR_KOLOGARN_AXIS_Z_PATHING_ISSUE_DETECT; } -bool KologarnNatureResistanceTrigger::IsActive() -{ - // Check boss and it is alive - Unit* boss = AI_VALUE2(Unit*, "find target", "kologarn"); - if (!boss || !boss->IsAlive()) - return false; - - // Check if bot is alive - if (!bot->IsAlive()) - return false; - - // Check if bot is hunter - if (bot->getClass() != CLASS_HUNTER) - return false; - - // Check if bot have nature resistance aura - if (bot->HasAura(SPELL_ASPECT_OF_THE_WILD)) - return false; - - // Check if bot dont have already setted nature resistance aura - HunterNatureResistanceStrategy hunterNatureResistanceStrategy(botAI); - if (botAI->HasStrategy(hunterNatureResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT)) - return false; - - // Check that the bot actually knows Aspect of the Wild - if (!bot->HasActiveSpell(SPELL_ASPECT_OF_THE_WILD)) - return false; - - // Get the group and ensure it's a raid group - Group* group = bot->GetGroup(); - if (!group || !group->isRaidGroup()) - return false; - - // Iterate through group members to find the first alive hunter - for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) - { - Player* member = gref->GetSource(); - if (!member || !member->IsAlive()) - continue; - - // Check if the member is a hunter - if (member->getClass() == CLASS_HUNTER) - { - // Return true only if the current bot is the first alive hunter - return member == bot; - } - } - - return false; -} - bool KologarnRubbleSlowdownTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "kologarn"); @@ -579,53 +432,6 @@ bool HodirNearSnowpackedIcicleTrigger::IsActive() return true; } -bool HodirFrostResistanceTrigger::IsActive() -{ - // Check boss and it is alive - Unit* boss = AI_VALUE2(Unit*, "find target", "hodir"); - if (!boss || !boss->IsAlive()) - return false; - - // Check if bot is paladin - if (bot->getClass() != CLASS_PALADIN) - return false; - - // Check if bot have frost resistance aura - if (bot->HasAura(SPELL_FROST_RESISTANCE_AURA)) - return false; - - // Check if bot dont have already have frost resistance strategy - PaladinFrostResistanceStrategy paladinFrostResistanceStrategy(botAI); - if (botAI->HasStrategy(paladinFrostResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT)) - return false; - - // Check that the bot actually knows the spell - if (!bot->HasActiveSpell(SPELL_FROST_RESISTANCE_AURA)) - return false; - - // Get the group and ensure it's a raid group - Group* group = bot->GetGroup(); - if (!group || !group->isRaidGroup()) - return false; - - // Iterate through group members to find the first alive paladin - for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) - { - Player* member = gref->GetSource(); - if (!member || !member->IsAlive()) - continue; - - // Check if the member is a hunter - if (member->getClass() == CLASS_PALADIN) - { - // Return true only if the current bot is the first alive paladin - return member == bot; - } - } - - return false; -} - bool FreyaNearNatureBombTrigger::IsActive() { // Check boss and it is alive @@ -640,34 +446,185 @@ bool FreyaNearNatureBombTrigger::IsActive() return target != nullptr; } -bool FreyaTankNearEonarsGiftTrigger::IsActive() +bool FreyaMarkDpsTargetTrigger::IsActive() { + // Check boss and it is alive + Unit* boss = AI_VALUE2(Unit*, "find target", "freya"); + if (!boss || !boss->IsAlive()) + return false; + // Only tank bot can mark target if (!botAI->IsTank(bot)) - { return false; + + // Get current raid dps target + Group* group = bot->GetGroup(); + if (!group) + return false; + + int8 skullIndex = 7; + ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex); + Unit* currentSkullUnit = botAI->GetUnit(currentSkullTarget); + + if (currentSkullUnit && !currentSkullUnit->IsAlive()) + { + currentSkullUnit = nullptr; } - // Check Eonar's gift and it is alive + // Check which adds is up + Unit* eonarsGift = nullptr; + Unit* ancientConservator = nullptr; + Unit* snaplasher = nullptr; + Unit* ancientWaterSpirit = nullptr; + Unit* stormLasher = nullptr; + Unit* firstDetonatingLasher = nullptr; - // Target is not findable from threat table using AI_VALUE2(), - // therefore need to search manually for the unit id GuidVector targets = AI_VALUE(GuidVector, "possible targets"); - + Unit* target = nullptr; for (auto i = targets.begin(); i != targets.end(); ++i) { - Unit* unit = botAI->GetUnit(*i); - if (!unit) - { + target = botAI->GetUnit(*i); + if (!target || !target->IsAlive()) continue; + + if (target->GetEntry() == NPC_EONARS_GIFT) + { + eonarsGift = target; + } + else if (target->GetEntry() == NPC_ANCIENT_CONSERVATOR) + { + ancientConservator = target; + } + else if (target->GetEntry() == NPC_SNAPLASHER) + { + snaplasher = target; + } + else if (target->GetEntry() == NPC_ANCIENT_WATER_SPIRIT) + { + ancientWaterSpirit = target; + } + else if (target->GetEntry() == NPC_STORM_LASHER) + { + stormLasher = target; + } + else if (target->GetEntry() == NPC_DETONATING_LASHER && !firstDetonatingLasher) + { + firstDetonatingLasher = target; + } + } + + // Check that eonars gift is need to be mark + if (eonarsGift && + (!currentSkullUnit || currentSkullUnit->GetEntry() != eonarsGift->GetEntry())) + { + return true; + } + + // Check that ancient conservator is need to be mark + if (ancientConservator && + (!currentSkullUnit || currentSkullUnit->GetEntry() != ancientConservator->GetEntry())) + { + return true; + } + + // Check that trio of adds is need to be mark + if (snaplasher || ancientWaterSpirit || stormLasher) + { + Unit* highestHealthUnit = nullptr; + uint32 highestHealth = 0; + + if (snaplasher && snaplasher->GetHealth() > highestHealth) + { + highestHealth = snaplasher->GetHealth(); + highestHealthUnit = snaplasher; + } + if (ancientWaterSpirit && ancientWaterSpirit->GetHealth() > highestHealth) + { + highestHealth = ancientWaterSpirit->GetHealth(); + highestHealthUnit = ancientWaterSpirit; + } + if (stormLasher && stormLasher->GetHealth() > highestHealth) + { + highestHealthUnit = stormLasher; } - uint32 creatureId = unit->GetEntry(); - if (creatureId == NPC_EONARS_GIFT && unit->IsAlive()) + // If the highest health unit is not already marked, mark it + if (highestHealthUnit && + (!currentSkullUnit || currentSkullUnit->GetEntry() != highestHealthUnit->GetEntry())) { return true; } } + // Check that detonating lasher is need to be mark + if (firstDetonatingLasher && + (!currentSkullUnit || currentSkullUnit->GetEntry() != firstDetonatingLasher->GetEntry())) + { + Map* map = bot->GetMap(); + if (!map || !map->IsRaid()) + return false; + + uint32 healthThreshold = map->Is25ManRaid() ? 7200 : 4900; // Detonate maximum damage + + // Check that detonate lasher dont kill raid members + for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* member = gref->GetSource(); + if (!member || !member->IsAlive()) + continue; + + if (member->GetHealth() < healthThreshold) + return false; + } + + return true; + } + return false; } + +bool FreyaMoveToHealingSporeTrigger::IsActive() +{ + // Check for the Freya boss + Unit* boss = AI_VALUE2(Unit*, "find target", "freya"); + if (!boss || !boss->IsAlive()) + return false; + + if (!botAI->IsRanged(bot)) + return false; + + Unit* conservatory = AI_VALUE2(Unit*, "find target", "ancient conservator"); + if (!conservatory || !conservatory->IsAlive()) + return false; + + + GuidVector targets = AI_VALUE(GuidVector, "nearest npcs"); + float nearestDistance = std::numeric_limits::max(); + bool foundSpore = false; + + // Iterate through all targets to find healthy spores + for (const ObjectGuid& guid : targets) + { + Unit* unit = botAI->GetUnit(guid); + if (!unit || !unit->IsAlive()) + continue; + + // Check if the unit is a healthy spore + if (unit->GetEntry() == NPC_HEALTHY_SPORE) + { + foundSpore = true; + float distance = bot->GetDistance(unit); + if (distance < nearestDistance) + { + nearestDistance = distance; + } + } + } + + // If no healthy spores are found, return false + if (!foundSpore) + return false; + + // If the nearest spore is farther than 6 yards, a move is required + return nearestDistance > 6.0f; +} diff --git a/src/strategy/raids/ulduar/RaidUlduarTriggers.h b/src/strategy/raids/ulduar/RaidUlduarTriggers.h index 807946f7..edb41145 100644 --- a/src/strategy/raids/ulduar/RaidUlduarTriggers.h +++ b/src/strategy/raids/ulduar/RaidUlduarTriggers.h @@ -34,14 +34,17 @@ enum UlduarIDs SPELL_BITING_COLD_PLAYER_AURA = 62039, // Freya + NPC_SNAPLASHER = 32916, + NPC_STORM_LASHER = 32919, + NPC_DETONATING_LASHER = 32918, + NPC_ANCIENT_WATER_SPIRIT = 33202, + NPC_ANCIENT_CONSERVATOR = 33203, + NPC_HEALTHY_SPORE = 33215, NPC_EONARS_GIFT = 33228, GOBJECT_NATURE_BOMB = 194902, // Buffs - SPELL_FROST_TRAP = 13809, - SPELL_FROST_RESISTANCE_AURA = 48945, - SPELL_FIRE_RESISTANCE_AURA = 48947, - SPELL_ASPECT_OF_THE_WILD = 49071, + SPELL_FROST_TRAP = 13809 }; const float ULDUAR_KOLOGARN_AXIS_Z_PATHING_ISSUE_DETECT = 420.0f; @@ -115,23 +118,6 @@ public: bool IsActive() override; }; -class RazorscaleFireResistanceTrigger : public Trigger -{ -public: - RazorscaleFireResistanceTrigger(PlayerbotAI* ai) : Trigger(ai, "razorscale fire resistance trigger") {} - bool IsActive() override; -}; - -// -// Ignis -// -class IgnisFireResistanceTrigger : public Trigger -{ -public: - IgnisFireResistanceTrigger(PlayerbotAI* ai) : Trigger(ai, "ignis fire resistance trigger") {} - bool IsActive() override; -}; - // // Iron Assembly // @@ -166,13 +152,6 @@ public: bool IsActive() override; }; -class KologarnNatureResistanceTrigger : public Trigger -{ -public: - KologarnNatureResistanceTrigger(PlayerbotAI* ai) : Trigger(ai, "kologarn nature resistance trigger") {} - bool IsActive() override; -}; - class KologarnRubbleSlowdownTrigger : public Trigger { public: @@ -197,13 +176,6 @@ public: bool IsActive() override; }; -class HodirFrostResistanceTrigger : public Trigger -{ -public: - HodirFrostResistanceTrigger(PlayerbotAI* ai) : Trigger(ai, "hodir frost resistance trigger") {} - bool IsActive() override; -}; - // // Freya // @@ -214,10 +186,17 @@ public: bool IsActive() override; }; -class FreyaTankNearEonarsGiftTrigger : public Trigger +class FreyaMarkDpsTargetTrigger : public Trigger { public: - FreyaTankNearEonarsGiftTrigger(PlayerbotAI* ai) : Trigger(ai, "freya tank near eonars gift") {} + FreyaMarkDpsTargetTrigger(PlayerbotAI* ai) : Trigger(ai, "freya mark dps target trigger") {} + bool IsActive() override; +}; + +class FreyaMoveToHealingSporeTrigger : public Trigger +{ +public: + FreyaMoveToHealingSporeTrigger(PlayerbotAI* ai) : Trigger(ai, "freya move to healing spore trigger") {} bool IsActive() override; }; diff --git a/src/strategy/triggers/BossAuraTriggers.cpp b/src/strategy/triggers/BossAuraTriggers.cpp new file mode 100644 index 00000000..f9e705f8 --- /dev/null +++ b/src/strategy/triggers/BossAuraTriggers.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it + * and/or modify it under version 2 of the License, or (at your option), any later version. + */ + +#include "BossAuraTriggers.h" + +#include +#include +#include + +#include "Playerbots.h" + +bool BossFireResistanceTrigger::IsActive() +{ + // Check boss and it is alive + Unit* boss = AI_VALUE2(Unit*, "find target", bossName); + if (!boss || !boss->IsAlive()) + return false; + + // Check if bot is paladin + if (bot->getClass() != CLASS_PALADIN) + return false; + + // Check if bot have fire resistance aura + if (bot->HasAura(SPELL_FIRE_RESISTANCE_AURA)) + return false; + + // Check if bot dont have already have fire resistance strategy + PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI); + if (botAI->HasStrategy(paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT)) + return false; + + // Check that the bot actually knows the spell + if (!bot->HasActiveSpell(SPELL_FIRE_RESISTANCE_AURA)) + return false; + + // Get the group and ensure it's a raid group + Group* group = bot->GetGroup(); + if (!group || !group->isRaidGroup()) + return false; + + // Iterate through group members to find the first alive paladin + for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* member = gref->GetSource(); + if (!member || !member->IsAlive()) + continue; + + // Check if the member is a hunter + if (member->getClass() == CLASS_PALADIN) + { + // Return true only if the current bot is the first alive paladin + return member == bot; + } + } + + return false; +} + +bool BossFrostResistanceTrigger::IsActive() +{ + // Check boss and it is alive + Unit* boss = AI_VALUE2(Unit*, "find target", bossName); + if (!boss || !boss->IsAlive()) + return false; + + // Check if bot is paladin + if (bot->getClass() != CLASS_PALADIN) + return false; + + // Check if bot have frost resistance aura + if (bot->HasAura(SPELL_FROST_RESISTANCE_AURA)) + return false; + + // Check if bot dont have already have frost resistance strategy + PaladinFrostResistanceStrategy paladinFrostResistanceStrategy(botAI); + if (botAI->HasStrategy(paladinFrostResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT)) + return false; + + // Check that the bot actually knows the spell + if (!bot->HasActiveSpell(SPELL_FROST_RESISTANCE_AURA)) + return false; + + // Get the group and ensure it's a raid group + Group* group = bot->GetGroup(); + if (!group || !group->isRaidGroup()) + return false; + + // Iterate through group members to find the first alive paladin + for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* member = gref->GetSource(); + if (!member || !member->IsAlive()) + continue; + + // Check if the member is a hunter + if (member->getClass() == CLASS_PALADIN) + { + // Return true only if the current bot is the first alive paladin + return member == bot; + } + } + + return false; +} + +bool BossNatureResistanceTrigger::IsActive() +{ + // Check boss and it is alive + Unit* boss = AI_VALUE2(Unit*, "find target", bossName); + if (!boss || !boss->IsAlive()) + return false; + + // Check if bot is alive + if (!bot->IsAlive()) + return false; + + // Check if bot is hunter + if (bot->getClass() != CLASS_HUNTER) + return false; + + // Check if bot have nature resistance aura + if (bot->HasAura(SPELL_ASPECT_OF_THE_WILD)) + return false; + + // Check if bot dont have already setted nature resistance aura + HunterNatureResistanceStrategy hunterNatureResistanceStrategy(botAI); + if (botAI->HasStrategy(hunterNatureResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT)) + return false; + + // Check that the bot actually knows Aspect of the Wild + if (!bot->HasActiveSpell(SPELL_ASPECT_OF_THE_WILD)) + return false; + + // Get the group and ensure it's a raid group + Group* group = bot->GetGroup(); + if (!group || !group->isRaidGroup()) + return false; + + // Iterate through group members to find the first alive hunter + for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next()) + { + Player* member = gref->GetSource(); + if (!member || !member->IsAlive()) + continue; + + // Check if the member is a hunter + if (member->getClass() == CLASS_HUNTER) + { + // Return true only if the current bot is the first alive hunter + return member == bot; + } + } + + return false; +} diff --git a/src/strategy/triggers/BossAuraTriggers.h b/src/strategy/triggers/BossAuraTriggers.h new file mode 100644 index 00000000..e88b37a5 --- /dev/null +++ b/src/strategy/triggers/BossAuraTriggers.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it + * and/or modify it under version 2 of the License, or (at your option), any later version. + */ + +#ifndef _PLAYERBOT_BOSSAURATRIGGERS_H +#define _PLAYERBOT_BOSSAURATRIGGERS_H + +#include "GenericTriggers.h" + +class PlayerbotAI; + +enum BossAuraIDs +{ + SPELL_FROST_RESISTANCE_AURA = 48945, + SPELL_FIRE_RESISTANCE_AURA = 48947, + SPELL_ASPECT_OF_THE_WILD = 49071, +}; + +class BossFireResistanceTrigger : public Trigger +{ +public: + BossFireResistanceTrigger(PlayerbotAI* ai, std::string const bossName) + : Trigger(ai, bossName + " fire resistance trigger"), bossName(bossName) + { + } + bool IsActive() override; + +private: + std::string bossName; +}; + +class BossFrostResistanceTrigger : public Trigger +{ +public: + BossFrostResistanceTrigger(PlayerbotAI* ai, std::string const bossName) + : Trigger(ai, bossName + " frost resistance trigger"), bossName(bossName) + { + } + bool IsActive() override; + +private: + std::string bossName; +}; + +class BossNatureResistanceTrigger : public Trigger +{ +public: + BossNatureResistanceTrigger(PlayerbotAI* ai, std::string const bossName) + : Trigger(ai, "kologarn nature resistance trigger"), bossName(bossName) + { + } + bool IsActive() override; + +private: + std::string bossName; +}; + +#endif