diff --git a/src/Ai/Raid/Gruul/GruulActionContext.h b/src/Ai/Raid/Gruul/GruulActionContext.h index 1e88b8f79..b64eaf948 100644 --- a/src/Ai/Raid/Gruul/GruulActionContext.h +++ b/src/Ai/Raid/Gruul/GruulActionContext.h @@ -1,5 +1,5 @@ -#ifndef PLAYERBOTS_RAIDGRUULSLAIRACTIONCONTEXT_H -#define PLAYERBOTS_RAIDGRUULSLAIRACTIONCONTEXT_H +#ifndef PLAYERBOTS_GRUULACTIONCONTEXT_H +#define PLAYERBOTS_GRUULACTIONCONTEXT_H #include "GruulActions.h" #include "NamedObjectContext.h" @@ -10,40 +10,101 @@ public: RaidGruulsLairActionContext() { // High King Maulgar - creators["high king maulgar main tank attack maulgar"] = &RaidGruulsLairActionContext::high_king_maulgar_main_tank_attack_maulgar; - creators["high king maulgar first assist tank attack olm"] = &RaidGruulsLairActionContext::high_king_maulgar_first_assist_tank_attack_olm; - creators["high king maulgar second assist tank attack blindeye"] = &RaidGruulsLairActionContext::high_king_maulgar_second_assist_tank_attack_blindeye; - creators["high king maulgar mage tank attack krosh"] = &RaidGruulsLairActionContext::high_king_maulgar_mage_tank_attack_krosh; - creators["high king maulgar moonkin tank attack kiggler"] = &RaidGruulsLairActionContext::high_king_maulgar_moonkin_tank_attack_kiggler; - creators["high king maulgar assign dps priority"] = &RaidGruulsLairActionContext::high_king_maulgar_assign_dps_priority; - creators["high king maulgar healer find safe position"] = &RaidGruulsLairActionContext::high_king_maulgar_healer_find_safe_position; - creators["high king maulgar run away from whirlwind"] = &RaidGruulsLairActionContext::high_king_maulgar_run_away_from_whirlwind; - creators["high king maulgar banish felstalker"] = &RaidGruulsLairActionContext::high_king_maulgar_banish_felstalker; - creators["high king maulgar misdirect olm and blindeye"] = &RaidGruulsLairActionContext::high_king_maulgar_misdirect_olm_and_blindeye; + creators["high king maulgar main tank attack maulgar"] = + &RaidGruulsLairActionContext::high_king_maulgar_main_tank_attack_maulgar; + + creators["high king maulgar first assist tank attack olm"] = + &RaidGruulsLairActionContext::high_king_maulgar_first_assist_tank_attack_olm; + + creators["high king maulgar second assist tank attack blindeye"] = + &RaidGruulsLairActionContext::high_king_maulgar_second_assist_tank_attack_blindeye; + + creators["high king maulgar mage tank attack krosh"] = + &RaidGruulsLairActionContext::high_king_maulgar_mage_tank_attack_krosh; + + creators["high king maulgar moonkin tank attack kiggler"] = + &RaidGruulsLairActionContext::high_king_maulgar_moonkin_tank_attack_kiggler; + + creators["high king maulgar assign dps priority"] = + &RaidGruulsLairActionContext::high_king_maulgar_assign_dps_priority; + + creators["high king maulgar run away from whirlwind"] = + &RaidGruulsLairActionContext::high_king_maulgar_run_away_from_whirlwind; + + creators["high king maulgar move away from blast nova danger"] = + &RaidGruulsLairActionContext::high_king_maulgar_move_away_from_blast_nova_danger; + + creators["high king maulgar banish fel stalker"] = + &RaidGruulsLairActionContext::high_king_maulgar_banish_fel_stalker; + + creators["high king maulgar misdirect ogres to tanks"] = + &RaidGruulsLairActionContext::high_king_maulgar_misdirect_ogres_to_tanks; // Gruul the Dragonkiller - creators["gruul the dragonkiller tanks position boss"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_tanks_position_boss; - creators["gruul the dragonkiller spread ranged"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_spread_ranged; - creators["gruul the dragonkiller shatter spread"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_shatter_spread; + creators["gruul the dragonkiller tanks position boss"] = + &RaidGruulsLairActionContext::gruul_the_dragonkiller_tanks_position_boss; + + creators["gruul the dragonkiller spread ranged"] = + &RaidGruulsLairActionContext::gruul_the_dragonkiller_spread_ranged; + + creators["gruul the dragonkiller shatter spread"] = + &RaidGruulsLairActionContext::gruul_the_dragonkiller_shatter_spread; } private: // High King Maulgar - static Action* high_king_maulgar_main_tank_attack_maulgar(PlayerbotAI* botAI) { return new HighKingMaulgarMainTankAttackMaulgarAction(botAI); } - static Action* high_king_maulgar_first_assist_tank_attack_olm(PlayerbotAI* botAI) { return new HighKingMaulgarFirstAssistTankAttackOlmAction(botAI); } - static Action* high_king_maulgar_second_assist_tank_attack_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarSecondAssistTankAttackBlindeyeAction(botAI); } - static Action* high_king_maulgar_mage_tank_attack_krosh(PlayerbotAI* botAI) { return new HighKingMaulgarMageTankAttackKroshAction(botAI); } - static Action* high_king_maulgar_moonkin_tank_attack_kiggler(PlayerbotAI* botAI) { return new HighKingMaulgarMoonkinTankAttackKigglerAction(botAI); } - static Action* high_king_maulgar_assign_dps_priority(PlayerbotAI* botAI) { return new HighKingMaulgarAssignDPSPriorityAction(botAI); } - static Action* high_king_maulgar_healer_find_safe_position(PlayerbotAI* botAI) { return new HighKingMaulgarHealerFindSafePositionAction(botAI); } - static Action* high_king_maulgar_run_away_from_whirlwind(PlayerbotAI* botAI) { return new HighKingMaulgarRunAwayFromWhirlwindAction(botAI); } - static Action* high_king_maulgar_banish_felstalker(PlayerbotAI* botAI) { return new HighKingMaulgarBanishFelstalkerAction(botAI); } - static Action* high_king_maulgar_misdirect_olm_and_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarMisdirectOlmAndBlindeyeAction(botAI); } + static Action* high_king_maulgar_main_tank_attack_maulgar(PlayerbotAI* botAI) { + return new HighKingMaulgarMainTankAttackMaulgarAction(botAI); + } + + static Action* high_king_maulgar_first_assist_tank_attack_olm(PlayerbotAI* botAI) { + return new HighKingMaulgarFirstAssistTankAttackOlmAction(botAI); + } + + static Action* high_king_maulgar_second_assist_tank_attack_blindeye(PlayerbotAI* botAI) { + return new HighKingMaulgarSecondAssistTankAttackBlindeyeAction(botAI); + } + + static Action* high_king_maulgar_mage_tank_attack_krosh(PlayerbotAI* botAI) { + return new HighKingMaulgarMageTankAttackKroshAction(botAI); + } + + static Action* high_king_maulgar_moonkin_tank_attack_kiggler(PlayerbotAI* botAI) { + return new HighKingMaulgarMoonkinTankAttackKigglerAction(botAI); + } + + static Action* high_king_maulgar_assign_dps_priority(PlayerbotAI* botAI) { + return new HighKingMaulgarAssignDPSPriorityAction(botAI); + } + + static Action* high_king_maulgar_run_away_from_whirlwind(PlayerbotAI* botAI) { + return new HighKingMaulgarRunAwayFromWhirlwindAction(botAI); + } + + static Action* high_king_maulgar_move_away_from_blast_nova_danger(PlayerbotAI* botAI) { + return new HighKingMaulgarMoveAwayFromBlastNovaDangerAction(botAI); + } + + static Action* high_king_maulgar_banish_fel_stalker(PlayerbotAI* botAI) { + return new HighKingMaulgarBanishFelStalkerAction(botAI); + } + + static Action* high_king_maulgar_misdirect_ogres_to_tanks(PlayerbotAI* botAI) { + return new HighKingMaulgarMisdirectOgresToTanksAction(botAI); + } // Gruul the Dragonkiller - static Action* gruul_the_dragonkiller_tanks_position_boss(PlayerbotAI* botAI) { return new GruulTheDragonkillerTanksPositionBossAction(botAI); } - static Action* gruul_the_dragonkiller_spread_ranged(PlayerbotAI* botAI) { return new GruulTheDragonkillerSpreadRangedAction(botAI); } - static Action* gruul_the_dragonkiller_shatter_spread(PlayerbotAI* botAI) { return new GruulTheDragonkillerShatterSpreadAction(botAI); } + static Action* gruul_the_dragonkiller_tanks_position_boss(PlayerbotAI* botAI) { + return new GruulTheDragonkillerTanksPositionBossAction(botAI); + } + + static Action* gruul_the_dragonkiller_spread_ranged(PlayerbotAI* botAI) { + return new GruulTheDragonkillerSpreadRangedAction(botAI); + } + + static Action* gruul_the_dragonkiller_shatter_spread(PlayerbotAI* botAI) { + return new GruulTheDragonkillerShatterSpreadAction(botAI); + } }; #endif diff --git a/src/Ai/Raid/Gruul/GruulActions.cpp b/src/Ai/Raid/Gruul/GruulActions.cpp index f4b8b5d30..539a4e32a 100644 --- a/src/Ai/Raid/Gruul/GruulActions.cpp +++ b/src/Ai/Raid/Gruul/GruulActions.cpp @@ -25,18 +25,19 @@ bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event /*event*/) if (maulgar->GetVictim() == bot) { const Position& position = MAULGAR_TANK_POSITION; - const float maxDistance = 3.0f; + const float distToPosition = + bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - - if (distanceToPosition > maxDistance) + if (distToPosition > 3.0f) { - float dX = position.GetPositionX() - bot->GetPositionX(); - float dY = position.GetPositionY() - bot->GetPositionY(); - float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance; - float moveY = bot->GetPositionY() + (dY / distanceToPosition) * maxDistance; - return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false, - MovementPriority::MOVEMENT_COMBAT, true, true); + const float dX = position.GetPositionX() - bot->GetPositionX(); + const float dY = position.GetPositionY() - bot->GetPositionY(); + const float moveDist = std::min(5.0f, distToPosition); + const float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist; + const float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist; + + return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, + false, false, MovementPriority::MOVEMENT_COMBAT, true, true); } } @@ -59,19 +60,19 @@ bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event /*event*/) if (olm->GetVictim() == bot) { const Position& position = OLM_TANK_POSITION; - const float maxDistance = 3.0f; - const float olmTankLeeway = 30.0f; + const float distToPosition = + bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - float distanceOlmToPosition = olm->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - - if (distanceOlmToPosition > olmTankLeeway) + if (distToPosition > 3.0f) { - float dX = position.GetPositionX() - bot->GetPositionX(); - float dY = position.GetPositionY() - bot->GetPositionY(); - float moveX = bot->GetPositionX() + (dX / distanceOlmToPosition) * maxDistance; - float moveY = bot->GetPositionY() + (dY / distanceOlmToPosition) * maxDistance; - return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false, - MovementPriority::MOVEMENT_COMBAT, true, false); + const float dX = position.GetPositionX() - bot->GetPositionX(); + const float dY = position.GetPositionY() - bot->GetPositionY(); + const float moveDist = std::min(5.0f, distToPosition); + const float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist; + const float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist; + + return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, + false, false, MovementPriority::MOVEMENT_COMBAT, true, true); } } @@ -94,18 +95,19 @@ bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event /*event* if (blindeye->GetVictim() == bot) { const Position& position = BLINDEYE_TANK_POSITION; - const float maxDistance = 3.0f; + const float distToPosition = + bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - - if (distanceToPosition > maxDistance) + if (distToPosition > 3.0f) { - float dX = position.GetPositionX() - bot->GetPositionX(); - float dY = position.GetPositionY() - bot->GetPositionY(); - float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance; - float moveY = bot->GetPositionY() + (dY / distanceToPosition) * maxDistance; - return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false, - MovementPriority::MOVEMENT_COMBAT, true, false); + const float dX = position.GetPositionX() - bot->GetPositionX(); + const float dY = position.GetPositionY() - bot->GetPositionY(); + const float moveDist = std::min(5.0f, distToPosition); + const float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist; + const float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist; + + return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, + false, false, MovementPriority::MOVEMENT_COMBAT, true, true); } } @@ -122,11 +124,17 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event /*event*/) MarkTargetWithTriangle(bot, krosh); SetRtiTarget(botAI, "triangle", krosh); - if (krosh->HasAura(SPELL_SPELL_SHIELD) && botAI->CanCastSpell("spellsteal", krosh)) + if (krosh->HasAura(static_cast(GruulsLairSpells::SPELL_SPELL_SHIELD)) && + botAI->CanCastSpell("spellsteal", krosh)) + { return botAI->CastSpell("spellsteal", krosh); + } - if (!bot->HasAura(SPELL_SPELL_SHIELD) && botAI->CanCastSpell("fire ward", bot)) + if (!bot->HasAura(static_cast(GruulsLairSpells::SPELL_SPELL_SHIELD)) && + botAI->CanCastSpell("fire ward", bot)) + { return botAI->CastSpell("fire ward", bot); + } if (AI_VALUE(Unit*, "current target") != krosh) return Attack(krosh); @@ -134,30 +142,27 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event /*event*/) if (krosh->GetVictim() == bot) { const Position& position = KROSH_TANK_POSITION; - float distanceToKrosh = krosh->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - const float minDistance = 16.0f; - const float maxDistance = 29.0f; - const float tankPositionLeeway = 1.0f; + const float distanceKroshToPosition = + krosh->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); + constexpr float minDistance = 17.0f; + constexpr float maxDistance = 30.0f; - if (distanceToKrosh > minDistance && distanceToKrosh < maxDistance) + if (distanceKroshToPosition > minDistance && distanceKroshToPosition < maxDistance && + bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()) > 1.0f) { - if (!bot->IsWithinDist2d(position.GetPositionX(), position.GetPositionY(), tankPositionLeeway)) - { - return MoveTo(GRUULS_LAIR_MAP_ID, position.GetPositionX(), position.GetPositionY(), position.GetPositionZ(), - false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); - } - - float orientation = atan2(krosh->GetPositionY() - bot->GetPositionY(), - krosh->GetPositionX() - bot->GetPositionX()); - bot->SetFacingTo(orientation); + return MoveTo(GRUULS_LAIR_MAP_ID, position.GetPositionX(), position.GetPositionY(), + position.GetPositionZ(), false, false, false, false, + MovementPriority::MOVEMENT_COMBAT, true, false); } else { - Position safePos; - if (TryGetNewSafePosition(botAI, bot, safePos)) + constexpr float safeDistance = 15.0f; + const float currentDistance = bot->GetDistance2d(krosh); + + if (currentDistance < safeDistance) { - return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), - false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); + botAI->InterruptSpell(); + return MoveAway(krosh, safeDistance - currentDistance); } } } @@ -178,11 +183,16 @@ bool HighKingMaulgarMoonkinTankAttackKigglerAction::Execute(Event /*event*/) if (AI_VALUE(Unit*, "current target") != kiggler) return Attack(kiggler); - Position safePos; - if (TryGetNewSafePosition(botAI, bot, safePos)) + if (kiggler->GetVictim() == bot) { - return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), - false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); + constexpr float safeDistance = 28.5f; + const float currentDistance = bot->GetDistance2d(kiggler); + + if (currentDistance < safeDistance) + { + botAI->InterruptSpell(); + return MoveAway(kiggler, safeDistance - currentDistance); + } } return false; @@ -194,15 +204,7 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/) Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer"); if (blindeye) { - Position safePos; - if (TryGetNewSafePosition(botAI, bot, safePos)) - { - bot->AttackStop(); - bot->InterruptNonMeleeSpells(false); - return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), - false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); - } - + MarkTargetWithStar(bot, blindeye); SetRtiTarget(botAI, "star", blindeye); if (AI_VALUE(Unit*, "current target") != blindeye) @@ -215,15 +217,7 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/) Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner"); if (olm) { - Position safePos; - if (TryGetNewSafePosition(botAI, bot, safePos)) - { - bot->AttackStop(); - bot->InterruptNonMeleeSpells(false); - return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), - false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); - } - + MarkTargetWithCircle(bot, olm); SetRtiTarget(botAI, "circle", olm); if (AI_VALUE(Unit*, "current target") != olm) @@ -236,15 +230,7 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/) Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); if (krosh && botAI->IsRanged(bot)) { - Position safePos; - if (TryGetNewSafePosition(botAI, bot, safePos)) - { - bot->AttackStop(); - bot->InterruptNonMeleeSpells(false); - return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), - false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); - } - + MarkTargetWithTriangle(bot, krosh); SetRtiTarget(botAI, "triangle", krosh); if (AI_VALUE(Unit*, "current target") != krosh) @@ -257,15 +243,7 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/) Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed"); if (kiggler) { - Position safePos; - if (TryGetNewSafePosition(botAI, bot, safePos)) - { - bot->AttackStop(); - bot->InterruptNonMeleeSpells(false); - return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), - false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); - } - + MarkTargetWithDiamond(bot, kiggler); SetRtiTarget(botAI, "diamond", kiggler); if (AI_VALUE(Unit*, "current target") != kiggler) @@ -278,15 +256,7 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/) Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar"); if (maulgar) { - Position safePos; - if (TryGetNewSafePosition(botAI, bot, safePos)) - { - bot->AttackStop(); - bot->InterruptNonMeleeSpells(false); - return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), - false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); - } - + MarkTargetWithSquare(bot, maulgar); SetRtiTarget(botAI, "square", maulgar); if (AI_VALUE(Unit*, "current target") != maulgar) @@ -296,97 +266,70 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/) return false; } -// Avoid Whirlwind and Blast Wave and generally try to stay near the center of the room -bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event /*event*/) -{ - const Position& center = MAULGAR_ROOM_CENTER; - const float maxDistanceFromCenter = 50.0f; - float distToCenter = bot->GetExactDist2d(center.GetPositionX(), center.GetPositionY()); - - if (distToCenter > maxDistanceFromCenter) - { - float angle = atan2(bot->GetPositionY() - center.GetPositionY(), bot->GetPositionX() - center.GetPositionX()); - float destX = center.GetPositionX() + 40.0f * cos(angle); - float destY = center.GetPositionY() + 40.0f * sin(angle); - float destZ = center.GetPositionZ(); - - if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), - bot->GetPositionZ(), destX, destY, destZ)) - return false; - - return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false, - MovementPriority::MOVEMENT_COMBAT, true, false); - } - - Position safePos; - if (TryGetNewSafePosition(botAI, bot, safePos)) - { - bot->AttackStop(); - bot->InterruptNonMeleeSpells(false); - return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), - false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); - } - - return false; -} - -// Run away from Maulgar during Whirlwind (logic for after all other ogres are dead) bool HighKingMaulgarRunAwayFromWhirlwindAction::Execute(Event /*event*/) { Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar"); if (!maulgar) return false; - const float safeDistance = 10.0f; - float distance = bot->GetExactDist2d(maulgar); + constexpr float safeDistance = 8.0f; + const float currentDistance = bot->GetDistance2d(maulgar); - if (distance < safeDistance) + if (currentDistance < safeDistance) { - float angle = atan2(bot->GetPositionY() - maulgar->GetPositionY(), - bot->GetPositionX() - maulgar->GetPositionX()); - float destX = maulgar->GetPositionX() + safeDistance * cos(angle); - float destY = maulgar->GetPositionY() + safeDistance * sin(angle); - float destZ = bot->GetPositionZ(); - - if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), - bot->GetPositionZ(), destX, destY, destZ)) - return false; - - float destDist = maulgar->GetExactDist2d(destX, destY); - - if (destDist >= safeDistance - 0.1f) - { - bot->AttackStop(); - bot->InterruptNonMeleeSpells(true); - return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false, - MovementPriority::MOVEMENT_COMBAT, true, false); - } + botAI->InterruptSpell(); + return MoveAway(maulgar, safeDistance - currentDistance); } return false; } -bool HighKingMaulgarBanishFelstalkerAction::Execute(Event /*event*/) +bool HighKingMaulgarMoveAwayFromBlastNovaDangerAction::Execute(Event /*event*/) +{ + Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); + if (!krosh) + return false; + + constexpr float safeDistance = 20.0f; + constexpr uint32 minInterval = 1000; + const float currentDistance = bot->GetDistance2d(krosh); + + if (currentDistance < safeDistance) + { + botAI->InterruptSpell(); + return FleePosition(krosh->GetPosition(), safeDistance, minInterval); + } + + return false; +} + +bool HighKingMaulgarBanishFelStalkerAction::Execute(Event /*event*/) { Group* group = bot->GetGroup(); if (!group) return false; - const GuidVector& npcs = AI_VALUE(GuidVector, "nearest hostile npcs"); std::vector felStalkers; - for (auto const& npc : npcs) + std::list creatureList; + constexpr float searchRadius = 50.0f; + bot->GetCreatureListWithEntryInGrid( + creatureList, static_cast(GruulsLairNpcs::NPC_WILD_FEL_STALKER), searchRadius); + + for (Creature* creature : creatureList) { - Unit* unit = botAI->GetUnit(npc); - if (unit && unit->GetEntry() == NPC_WILD_FEL_STALKER && unit->IsAlive()) - felStalkers.push_back(unit); + if (creature && creature->IsAlive()) + felStalkers.push_back(creature); } std::vector warlocks; for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { Player* member = ref->GetSource(); - if (member && member->IsAlive() && member->getClass() == CLASS_WARLOCK && GET_PLAYERBOT_AI(member)) + if (member && member->IsAlive() && member->getClass() == CLASS_WARLOCK && + GET_PLAYERBOT_AI(member)) + { warlocks.push_back(member); + } } int warlockIndex = -1; @@ -399,21 +342,26 @@ bool HighKingMaulgarBanishFelstalkerAction::Execute(Event /*event*/) } } - const int64_t felStalkersSize = felStalkers.size(); + const uint8 felStalkersSize = felStalkers.size(); if (warlockIndex >= 0 && warlockIndex < felStalkersSize) { Unit* assignedFelStalker = felStalkers[warlockIndex]; - if (!botAI->HasAura("banish", assignedFelStalker) && botAI->CanCastSpell("banish", assignedFelStalker)) + if (!botAI->HasAura("banish", assignedFelStalker) && + botAI->CanCastSpell("banish", assignedFelStalker)) + { return botAI->CastSpell("banish", assignedFelStalker); + } } return false; } -// Hunter 1: Misdirect Olm to first offtank and have pet attack Blindeye -// Hunter 2: Misdirect Blindeye to second offtank -bool HighKingMaulgarMisdirectOlmAndBlindeyeAction::Execute(Event /*event*/) +// Hunter 1: Misdirect Blindeye to second offtank +// Hunter 2: Misdirect Olm to first offtank +// Hunter 3: Misdirect Kiggler to Moonkin tank +// Hunter 4: Misdirect Krosh to Mage tank +bool HighKingMaulgarMisdirectOgresToTanksAction::Execute(Event /*event*/) { Group* group = bot->GetGroup(); if (!group) @@ -423,68 +371,82 @@ bool HighKingMaulgarMisdirectOlmAndBlindeyeAction::Execute(Event /*event*/) for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { Player* member = ref->GetSource(); - if (member && member->IsAlive() && member->getClass() == CLASS_HUNTER && GET_PLAYERBOT_AI(member)) + if (member && member->IsAlive() && member->getClass() == CLASS_HUNTER && + GET_PLAYERBOT_AI(member)) + { hunters.push_back(member); + } + + if (hunters.size() >= 4) + break; } - int hunterIndex = -1; + int8 hunterIndex = -1; for (size_t i = 0; i < hunters.size(); ++i) { if (hunters[i] == bot) { - hunterIndex = static_cast(i); + hunterIndex = static_cast(i); break; } } + if (hunterIndex == -1) + return false; - Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner"); - Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer"); - Player* olmTank = nullptr; - Player* blindeyeTank = nullptr; - - for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + Unit* ogreTarget = nullptr; + Player* tankTarget = nullptr; + if (hunterIndex == 0) { - Player* member = ref->GetSource(); - if (!member || !member->IsAlive()) - continue; - else if (botAI->IsAssistTankOfIndex(member, 0)) olmTank = member; - else if (botAI->IsAssistTankOfIndex(member, 1)) blindeyeTank = member; + ogreTarget = AI_VALUE2(Unit*, "find target", "blindeye the seer"); + tankTarget = GetGroupAssistTank(botAI, bot, 1); + } + else if (hunterIndex == 1) + { + ogreTarget = AI_VALUE2(Unit*, "find target", "olm the summoner"); + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + if (Player* member = GetGroupAssistTank(botAI, bot, 0)) + { + tankTarget = member; + break; + } + } + } + else if (hunterIndex == 2) + { + ogreTarget = AI_VALUE2(Unit*, "find target", "kiggler the crazed"); + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + if (Player* member = GetKigglerMoonkinTank(bot)) + { + tankTarget = member; + break; + } + } + } + else if (hunterIndex == 3) + { + ogreTarget = AI_VALUE2(Unit*, "find target", "krosh firehand"); + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + if (Player* member = GetKroshMageTank(bot)) + { + tankTarget = member; + break; + } + } } - switch (hunterIndex) + if (!ogreTarget || !tankTarget || !tankTarget->IsAlive()) + return false; + + if (botAI->CanCastSpell("misdirection", tankTarget)) + return botAI->CastSpell("misdirection", tankTarget); + + if (bot->HasAura(static_cast(GruulsLairSpells::SPELL_MISDIRECTION)) && + botAI->CanCastSpell("steady shot", ogreTarget)) { - case 0: - botAI->CastSpell("misdirection", olmTank); - if (bot->HasAura(SPELL_MISDIRECTION)) - { - Pet* pet = bot->GetPet(); - if (pet && pet->IsAlive() && pet->GetVictim() != blindeye) - { - pet->ClearUnitState(UNIT_STATE_FOLLOW); - pet->AttackStop(); - pet->SetTarget(blindeye->GetGUID()); - if (pet->GetCharmInfo()) - { - pet->GetCharmInfo()->SetIsCommandAttack(true); - pet->GetCharmInfo()->SetIsAtStay(false); - pet->GetCharmInfo()->SetIsFollowing(false); - pet->GetCharmInfo()->SetIsCommandFollow(false); - pet->GetCharmInfo()->SetIsReturning(false); - } - pet->ToCreature()->AI()->AttackStart(blindeye); - } - return botAI->CastSpell("steady shot", olm); - } - break; - - case 1: - botAI->CastSpell("misdirection", blindeyeTank); - if (bot->HasAura(SPELL_MISDIRECTION)) - return botAI->CastSpell("steady shot", blindeye); - break; - - default: - break; + return botAI->CastSpell("steady shot", ogreTarget); } return false; @@ -505,19 +467,19 @@ bool GruulTheDragonkillerTanksPositionBossAction::Execute(Event /*event*/) if (gruul->GetVictim() == bot) { const Position& position = GRUUL_TANK_POSITION; - const float maxDistance = 5.0f; + const float distToPosition = + bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - float dX = position.GetPositionX() - bot->GetPositionX(); - float dY = position.GetPositionY() - bot->GetPositionY(); - float distanceToTankPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - - if (distanceToTankPosition > maxDistance) + if (distToPosition > 3.0f) { - float moveX = bot->GetPositionX() + (dX / distanceToTankPosition) * maxDistance; - float moveY = bot->GetPositionY() + (dY / distanceToTankPosition) * maxDistance; - const float moveZ = position.GetPositionZ(); - return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, moveZ, false, false, false, false, - MovementPriority::MOVEMENT_COMBAT, true, false); + const float dX = position.GetPositionX() - bot->GetPositionX(); + const float dY = position.GetPositionY() - bot->GetPositionY(); + const float moveDist = std::min(5.0f, distToPosition); + const float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist; + const float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist; + + return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, + false, false, MovementPriority::MOVEMENT_COMBAT, true, true); } } @@ -528,27 +490,17 @@ bool GruulTheDragonkillerTanksPositionBossAction::Execute(Event /*event*/) // Ranged should spread out 10 yards from each other bool GruulTheDragonkillerSpreadRangedAction::Execute(Event /*event*/) { + Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); + if (!gruul) + return false; + + if (gruul->GetHealth() == gruul->GetMaxHealth()) + _hasReachedInitialPosition = false; + Group* group = bot->GetGroup(); if (!group) return false; - static std::unordered_map initialPositions; - static std::unordered_map hasReachedInitialPosition; - - Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); - if (gruul && gruul->GetHealth() == gruul->GetMaxHealth()) - { - initialPositions.erase(bot->GetGUID()); - hasReachedInitialPosition.erase(bot->GetGUID()); - } - - const Position& position = GRUUL_TANK_POSITION; - const float centerX = position.GetPositionX(); - const float centerY = position.GetPositionY(); - const float centerZ = position.GetPositionZ(); - const float minRadius = 25.0f; - const float maxRadius = 40.0f; - std::vector members; Player* closestMember = nullptr; float closestDist = std::numeric_limits::max(); @@ -559,6 +511,7 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event /*event*/) continue; members.push_back(member); + if (member != bot) { float dist = bot->GetExactDist2d(member); @@ -570,49 +523,53 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event /*event*/) } } - if (!initialPositions.count(bot->GetGUID())) + const Position& position = GRUUL_TANK_POSITION; + + if (_initialPosition.GetPositionX() == 0.0f && _initialPosition.GetPositionY() == 0.0f) { auto it = std::find(members.begin(), members.end(), bot); uint8 botIndex = (it != members.end()) ? std::distance(members.begin(), it) : 0; uint8 count = members.size(); + constexpr float minRadius = 25.0f; + constexpr float maxRadius = 40.0f; float angle = 2 * M_PI * botIndex / count; float radius = minRadius + static_cast(rand()) / static_cast(RAND_MAX) * (maxRadius - minRadius); - float targetX = centerX + radius * cos(angle); - float targetY = centerY + radius * sin(angle); + float targetX = position.GetPositionX() + radius * cos(angle); + float targetY = position.GetPositionY() + radius * sin(angle); - initialPositions[bot->GetGUID()] = Position(targetX, targetY, centerZ); - hasReachedInitialPosition[bot->GetGUID()] = false; + _initialPosition = Position(targetX, targetY, position.GetPositionZ()); } - Position targetPosition = initialPositions[bot->GetGUID()]; - if (!hasReachedInitialPosition[bot->GetGUID()]) + if (!_hasReachedInitialPosition) { - if (!bot->IsWithinDist2d(targetPosition.GetPositionX(), targetPosition.GetPositionY(), 2.0f)) + const float distanceToTarget = + bot->GetExactDist2d(_initialPosition.GetPositionX(), _initialPosition.GetPositionY()); + if (distanceToTarget > 2.0f) { - float destX = targetPosition.GetPositionX(); - float destY = targetPosition.GetPositionY(); - float destZ = targetPosition.GetPositionZ(); + float destX = _initialPosition.GetPositionX(); + float destY = _initialPosition.GetPositionY(); + float destZ = _initialPosition.GetPositionZ(); if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ(), destX, destY, destZ)) + { return false; + } - return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false, - MovementPriority::MOVEMENT_COMBAT, true, false); + return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, + false, MovementPriority::MOVEMENT_COMBAT, true, false); } - hasReachedInitialPosition[bot->GetGUID()] = true; + _hasReachedInitialPosition = true; } - - const float minSpreadDistance = 10.0f; - const float movementThreshold = 2.0f; - - if (closestMember && closestDist < minSpreadDistance - movementThreshold) + else { - return FleePosition(Position(closestMember->GetPositionX(), closestMember->GetPositionY(), - closestMember->GetPositionZ()), minSpreadDistance, 0); + constexpr float minSpreadDistance = 10.0f; + constexpr uint32 minInterval = 1000; + if (closestMember && closestDist < minSpreadDistance) + return FleePosition(closestMember->GetPosition(), minSpreadDistance, minInterval); } return false; @@ -621,33 +578,10 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event /*event*/) // Try to get away from other group members when Ground Slam is cast bool GruulTheDragonkillerShatterSpreadAction::Execute(Event /*event*/) { - Group* group = bot->GetGroup(); - if (!group) - return false; - - GuidVector members = AI_VALUE(GuidVector, "group members"); - Unit* closestMember = nullptr; - float closestDist = std::numeric_limits::max(); - - for (auto& member : members) - { - Unit* unit = botAI->GetUnit(member); - if (!unit || bot->GetGUID() == member) - continue; - - const float dist = bot->GetExactDist2d(unit); - if (dist < closestDist) - { - closestDist = dist; - closestMember = unit; - } - } - - if (closestMember) - { - return FleePosition(Position(closestMember->GetPositionX(), closestMember->GetPositionY(), - closestMember->GetPositionZ()), 6.0f, 0); - } + constexpr float safeDistance = 10.0f; + constexpr uint32 minInterval = 0; + if (Unit* nearestPlayer = GetNearestPlayerInRadius(bot, safeDistance)) + return FleePosition(nearestPlayer->GetPosition(), safeDistance, minInterval); return false; } diff --git a/src/Ai/Raid/Gruul/GruulActions.h b/src/Ai/Raid/Gruul/GruulActions.h index 1ac4e4d1d..4cf858f8c 100644 --- a/src/Ai/Raid/Gruul/GruulActions.h +++ b/src/Ai/Raid/Gruul/GruulActions.h @@ -1,5 +1,5 @@ -#ifndef PLAYERBOTS_RAIDGRUULSLAIRACTIONS_H -#define PLAYERBOTS_RAIDGRUULSLAIRACTIONS_H +#ifndef PLAYERBOTS_GRUULACTIONS_H +#define PLAYERBOTS_GRUULACTIONS_H #include "Action.h" #include "AttackAction.h" @@ -8,104 +8,108 @@ class HighKingMaulgarMainTankAttackMaulgarAction : public AttackAction { public: - HighKingMaulgarMainTankAttackMaulgarAction(PlayerbotAI* botAI, std::string const name = "high king maulgar main tank attack maulgar") : AttackAction(botAI, name) {}; - + HighKingMaulgarMainTankAttackMaulgarAction( + PlayerbotAI* botAI, std::string const name = "high king maulgar main tank attack maulgar") : AttackAction(botAI, name) {}; bool Execute(Event event) override; }; class HighKingMaulgarFirstAssistTankAttackOlmAction : public AttackAction { public: - HighKingMaulgarFirstAssistTankAttackOlmAction(PlayerbotAI* botAI, std::string const name = "high king maulgar first assist tank attack olm") : AttackAction(botAI, name) {}; - + HighKingMaulgarFirstAssistTankAttackOlmAction( + PlayerbotAI* botAI, std::string const name = "high king maulgar first assist tank attack olm") : AttackAction(botAI, name) {}; bool Execute(Event event) override; }; class HighKingMaulgarSecondAssistTankAttackBlindeyeAction : public AttackAction { public: - HighKingMaulgarSecondAssistTankAttackBlindeyeAction(PlayerbotAI* botAI, std::string const name = "high king maulgar second assist tank attack blindeye") : AttackAction(botAI, name) {}; - + HighKingMaulgarSecondAssistTankAttackBlindeyeAction( + PlayerbotAI* botAI, std::string const name = "high king maulgar second assist tank attack blindeye") : AttackAction(botAI, name) {}; bool Execute(Event event) override; }; class HighKingMaulgarMageTankAttackKroshAction : public AttackAction { public: - HighKingMaulgarMageTankAttackKroshAction(PlayerbotAI* botAI, std::string const name = "high king maulgar mage tank attack krosh") : AttackAction(botAI, name) {}; - + HighKingMaulgarMageTankAttackKroshAction( + PlayerbotAI* botAI, std::string const name = "high king maulgar mage tank attack krosh") : AttackAction(botAI, name) {}; bool Execute(Event event) override; }; class HighKingMaulgarMoonkinTankAttackKigglerAction : public AttackAction { public: - HighKingMaulgarMoonkinTankAttackKigglerAction(PlayerbotAI* botAI, std::string const name = "high king maulgar moonkin tank attack kiggler") : AttackAction(botAI, name) {}; - + HighKingMaulgarMoonkinTankAttackKigglerAction( + PlayerbotAI* botAI, std::string const name = "high king maulgar moonkin tank attack kiggler") : AttackAction(botAI, name) {}; bool Execute(Event event) override; }; class HighKingMaulgarAssignDPSPriorityAction : public AttackAction { public: - HighKingMaulgarAssignDPSPriorityAction(PlayerbotAI* botAI, std::string const name = "high king maulgar assign dps priority") : AttackAction(botAI, name) {}; - - bool Execute(Event event) override; -}; - -class HighKingMaulgarHealerFindSafePositionAction : public MovementAction -{ -public: - HighKingMaulgarHealerFindSafePositionAction(PlayerbotAI* botAI, std::string const name = "high king maulgar healer find safe position") : MovementAction(botAI, name) {}; - + HighKingMaulgarAssignDPSPriorityAction( + PlayerbotAI* botAI, std::string const name = "high king maulgar assign dps priority") : AttackAction(botAI, name) {}; bool Execute(Event event) override; }; class HighKingMaulgarRunAwayFromWhirlwindAction : public MovementAction { public: - HighKingMaulgarRunAwayFromWhirlwindAction(PlayerbotAI* botAI, std::string const name = "high king maulgar run away from whirlwind") : MovementAction(botAI, name) {}; - + HighKingMaulgarRunAwayFromWhirlwindAction( + PlayerbotAI* botAI, std::string const name = "high king maulgar run away from whirlwind") : MovementAction(botAI, name) {}; bool Execute(Event event) override; }; -class HighKingMaulgarBanishFelstalkerAction : public AttackAction +class HighKingMaulgarMoveAwayFromBlastNovaDangerAction : public MovementAction { public: - HighKingMaulgarBanishFelstalkerAction(PlayerbotAI* botAI, std::string const name = "high king maulgar banish felstalker") : AttackAction(botAI, name) {}; - + HighKingMaulgarMoveAwayFromBlastNovaDangerAction( + PlayerbotAI* botAI, std::string const name = "high king maulgar move away from blast nova danger") : MovementAction(botAI, name) {}; bool Execute(Event event) override; }; -class HighKingMaulgarMisdirectOlmAndBlindeyeAction : public AttackAction +class HighKingMaulgarBanishFelStalkerAction : public AttackAction { public: - HighKingMaulgarMisdirectOlmAndBlindeyeAction(PlayerbotAI* botAI, std::string const name = "high king maulgar misdirect olm and blindeye") : AttackAction(botAI, name) {}; + HighKingMaulgarBanishFelStalkerAction( + PlayerbotAI* botAI, std::string const name = "high king maulgar banish fel stalker") : AttackAction(botAI, name) {}; + bool Execute(Event event) override; +}; +class HighKingMaulgarMisdirectOgresToTanksAction : public AttackAction +{ +public: + HighKingMaulgarMisdirectOgresToTanksAction( + PlayerbotAI* botAI, std::string const name = "high king maulgar misdirect ogres to tanks") : AttackAction(botAI, name) {}; bool Execute(Event event) override; }; class GruulTheDragonkillerTanksPositionBossAction : public AttackAction { public: - GruulTheDragonkillerTanksPositionBossAction(PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller tanks position boss") : AttackAction(botAI, name) {}; - + GruulTheDragonkillerTanksPositionBossAction( + PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller tanks position boss") : AttackAction(botAI, name) {}; bool Execute(Event event) override; }; class GruulTheDragonkillerSpreadRangedAction : public MovementAction { public: - GruulTheDragonkillerSpreadRangedAction(PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller spread ranged") : MovementAction(botAI, name) {}; - + GruulTheDragonkillerSpreadRangedAction( + PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller spread ranged") : MovementAction(botAI, name) {}; bool Execute(Event event) override; + +private: + Position _initialPosition; + bool _hasReachedInitialPosition = false; }; class GruulTheDragonkillerShatterSpreadAction : public MovementAction { public: - GruulTheDragonkillerShatterSpreadAction(PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller shatter spread") : MovementAction(botAI, name) {}; - + GruulTheDragonkillerShatterSpreadAction( + PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller shatter spread") : MovementAction(botAI, name) {}; bool Execute(Event event) override; }; diff --git a/src/Ai/Raid/Gruul/GruulHelpers.cpp b/src/Ai/Raid/Gruul/GruulHelpers.cpp index 4c90f6e41..50bcb3f2a 100644 --- a/src/Ai/Raid/Gruul/GruulHelpers.cpp +++ b/src/Ai/Raid/Gruul/GruulHelpers.cpp @@ -6,199 +6,96 @@ namespace GruulsLairHelpers { - // Olm does not chase properly due to the Core's caster movement issues - // Thus, the below "OlmTankPosition" is beyond the actual desired tanking location - // It is the spot to which the OlmTank runs to to pull Olm to a decent tanking location - // "MaulgarRoomCenter" is to keep healers in a centralized location - const Position MAULGAR_TANK_POSITION = { 90.686f, 167.047f, -13.234f }; - const Position OLM_TANK_POSITION = { 87.485f, 234.942f, -3.635f }; - const Position BLINDEYE_TANK_POSITION = { 99.681f, 213.989f, -10.345f }; - const Position KROSH_TANK_POSITION = { 116.880f, 166.208f, -14.231f }; - const Position MAULGAR_ROOM_CENTER = { 88.754f, 150.759f, -11.569f }; - const Position GRUUL_TANK_POSITION = { 241.238f, 365.025f, -4.220f }; - bool IsAnyOgreBossAlive(PlayerbotAI* botAI) +const Position MAULGAR_TANK_POSITION = { 90.686f, 167.047f, -13.234f }; +const Position OLM_TANK_POSITION = { 101.050f, 219.359f, -9.503f }; +const Position BLINDEYE_TANK_POSITION = { 99.681f, 213.989f, -10.345f }; +const Position KROSH_TANK_POSITION = { 116.880f, 166.208f, -14.231f }; +const Position MAULGAR_ROOM_CENTER = { 88.754f, 150.759f, -11.569f }; +const Position GRUUL_TANK_POSITION = { 241.238f, 365.025f, -4.220f }; + +Player* GetKroshMageTank(Player* bot) +{ + Group* group = bot->GetGroup(); + if (!group) + return nullptr; + + // (1) First loop: Return the first assistant Mage (real player or bot) + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { - const char* ogreBossNames[] = - { - "high king maulgar", - "kiggler the crazed", - "krosh firehand", - "olm the summoner", - "blindeye the seer" - }; + Player* member = ref->GetSource(); + if (!member || !member->IsAlive() || member->getClass() != CLASS_MAGE) + continue; - for (const char* name : ogreBossNames) - { - Unit* boss = botAI->GetAiObjectContext()->GetValue("find target", name)->Get(); - if (!boss || !boss->IsAlive()) - continue; - return true; - } + if (group->IsAssistant(member->GetGUID())) + return member; - return false; } - bool IsKroshMageTank(Player* bot) + // (2) Fall back to bot Mage with highest HP + Player* highestHpMage = nullptr; + uint32 highestHp = 0; + + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { - Group* group = bot->GetGroup(); - if (!group) - return false; - - // (1) First loop: Return the first assistant Mage (real player or bot) - for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + Player* member = ref->GetSource(); + if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member) || + member->getClass() != CLASS_MAGE) { - Player* member = ref->GetSource(); - if (!member || !member->IsAlive() || member->getClass() != CLASS_MAGE) - continue; - - if (group->IsAssistant(member->GetGUID())) - return member == bot; + continue; } - // (2) Fall back to bot Mage with highest HP - Player* highestHpMage = nullptr; - uint32 highestHp = 0; - - for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + uint32 hp = member->GetMaxHealth(); + if (!highestHpMage || hp > highestHp) { - Player* member = ref->GetSource(); - if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member) || - member->getClass() != CLASS_MAGE) - continue; - - uint32 hp = member->GetMaxHealth(); - if (!highestHpMage || hp > highestHp) - { - highestHpMage = member; - highestHp = hp; - } + highestHpMage = member; + highestHp = hp; } - - // (3) Return the found Mage tank, or nullptr if none found - return highestHpMage == bot; } - bool IsKigglerMoonkinTank(Player* bot) - { - Group* group = bot->GetGroup(); - if (!group) - return false; - - // (1) First loop: Return the first assistant Moonkin (real player or bot) - for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) - { - Player* member = ref->GetSource(); - if (!member || !member->IsAlive() || member->getClass() != CLASS_DRUID) - continue; - - if (group->IsAssistant(member->GetGUID()) && - AiFactory::GetPlayerSpecTab(member) == DRUID_TAB_BALANCE) - return member == bot; - } - - // (2) Fall back to bot Moonkin with highest HP - Player* highestHpMoonkin = nullptr; - uint32 highestHp = 0; - for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) - { - Player* member = ref->GetSource(); - if (!member || !member->IsAlive() || member->getClass() != CLASS_DRUID || - !GET_PLAYERBOT_AI(member) || AiFactory::GetPlayerSpecTab(member) != DRUID_TAB_BALANCE) - continue; - - uint32 hp = member->GetMaxHealth(); - if (!highestHpMoonkin || hp > highestHp) - { - highestHpMoonkin = member; - highestHp = hp; - } - } - - // (3) Return the found Moonkin tank, or nullptr if none found - return highestHpMoonkin == bot; - } - - bool IsPositionSafe(PlayerbotAI* botAI, Player* bot, Position pos) - { - const float KROSH_SAFE_DISTANCE = 20.0f; - const float MAULGAR_SAFE_DISTANCE = 10.0f; - bool isSafe = true; - - Unit* krosh = botAI->GetAiObjectContext()->GetValue("find target", "krosh firehand")->Get(); - if (krosh && krosh->IsAlive()) - { - float dist = krosh->GetDistance2d(pos.GetPositionX(), pos.GetPositionY()); - if (dist < KROSH_SAFE_DISTANCE) - isSafe = false; - } - - Unit* maulgar = botAI->GetAiObjectContext()->GetValue("find target", "high king maulgar")->Get(); - if (botAI->IsRanged(bot) && maulgar && maulgar->IsAlive()) - { - float dist = maulgar->GetDistance2d(pos.GetPositionX(), pos.GetPositionY()); - if (dist < MAULGAR_SAFE_DISTANCE) - isSafe = false; - } - - return isSafe; - } - - bool TryGetNewSafePosition(PlayerbotAI* botAI, Player* bot, Position& outPos) - { - const float SEARCH_RADIUS = 30.0f; - const uint8 NUM_POSITIONS = 32; - - outPos = { bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ() }; - if (IsPositionSafe(botAI, bot, outPos)) - { - outPos = Position(); - return false; - } - - float bestScore = std::numeric_limits::max(); - bool foundSafeSpot = false; - Position bestPos; - - for (int i = 0; i < NUM_POSITIONS; ++i) - { - float angle = 2 * M_PI * i / NUM_POSITIONS; - Position candidatePos; - candidatePos.Relocate(bot->GetPositionX() + SEARCH_RADIUS * cos(angle), - bot->GetPositionY() + SEARCH_RADIUS * sin(angle), - bot->GetPositionZ()); - - float destX = candidatePos.GetPositionX(); - float destY = candidatePos.GetPositionY(); - float destZ = candidatePos.GetPositionZ(); - if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(), - bot->GetPositionZ(), destX, destY, destZ, true)) - continue; - - if (destX != candidatePos.GetPositionX() || destY != candidatePos.GetPositionY()) - continue; - - candidatePos.Relocate(destX, destY, destZ); - - if (IsPositionSafe(botAI, bot, candidatePos)) - { - float movementDistance = bot->GetDistance2d(destX, destY); - if (movementDistance < bestScore) - { - bestScore = movementDistance; - bestPos = candidatePos; - foundSafeSpot = true; - } - } - } - - if (foundSafeSpot) - { - outPos = bestPos; - return true; - } - - outPos = Position(); - return false; - } + return highestHpMage; +} + +Player* GetKigglerMoonkinTank(Player* bot) +{ + Group* group = bot->GetGroup(); + if (!group) + return nullptr; + + uint8 tab = AiFactory::GetPlayerSpecTab(bot); + + // (1) First loop: Return the first assistant Moonkin (real player or bot) + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member || !member->IsAlive() || member->getClass() != CLASS_DRUID) + continue; + + if (group->IsAssistant(member->GetGUID()) && tab == DRUID_TAB_BALANCE) + return member; + } + + // (2) Fall back to bot Moonkin with highest HP + Player* highestHpMoonkin = nullptr; + uint32 highestHp = 0; + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member || !member->IsAlive() || member->getClass() != CLASS_DRUID || + !GET_PLAYERBOT_AI(member) || tab != DRUID_TAB_BALANCE) + { + continue; + } + + uint32 hp = member->GetMaxHealth(); + if (!highestHpMoonkin || hp > highestHp) + { + highestHpMoonkin = member; + highestHp = hp; + } + } + + return highestHpMoonkin; +} + } diff --git a/src/Ai/Raid/Gruul/GruulHelpers.h b/src/Ai/Raid/Gruul/GruulHelpers.h index f9315565b..9ef913b85 100644 --- a/src/Ai/Raid/Gruul/GruulHelpers.h +++ b/src/Ai/Raid/Gruul/GruulHelpers.h @@ -1,45 +1,44 @@ -#ifndef RAID_GRUULSLAIRHELPERS_H -#define RAID_GRUULSLAIRHELPERS_H +#ifndef PLAYERBOTS_GRUULHELPERS_H +#define PLAYERBOTS_GRUULHELPERS_H #include "PlayerbotAI.h" namespace GruulsLairHelpers { - enum GruulsLairSpells - { - // High King Maulgar - SPELL_WHIRLWIND = 33238, - // Krosh Firehand - SPELL_SPELL_SHIELD = 33054, +enum class GruulsLairSpells : uint32 +{ + // High King Maulgar + SPELL_WHIRLWIND = 33238, - // Hunter - SPELL_MISDIRECTION = 35079, + // Krosh Firehand + SPELL_SPELL_SHIELD = 33054, - // Gruul the Dragonkiller - SPELL_GROUND_SLAM_1 = 33525, - SPELL_GROUND_SLAM_2 = 39187, - }; + // Hunter + SPELL_MISDIRECTION = 35079, - enum GruulsLairNPCs - { - NPC_WILD_FEL_STALKER = 18847, - }; + // Gruul the Dragonkiller + SPELL_GROUND_SLAM_1 = 33525, + SPELL_GROUND_SLAM_2 = 39187, +}; - constexpr uint32 GRUULS_LAIR_MAP_ID = 565; +enum class GruulsLairNpcs : uint32 +{ + NPC_WILD_FEL_STALKER = 18847, +}; - bool IsAnyOgreBossAlive(PlayerbotAI* botAI); - bool IsKroshMageTank(Player* bot); - bool IsKigglerMoonkinTank(Player* bot); - bool IsPositionSafe(PlayerbotAI* botAI, Player* bot, Position pos); - bool TryGetNewSafePosition(PlayerbotAI* botAI, Player* bot, Position& outPos); +constexpr uint32 GRUULS_LAIR_MAP_ID = 565; + +Player* GetKroshMageTank(Player* bot); +Player* GetKigglerMoonkinTank(Player* bot); + +extern const Position MAULGAR_TANK_POSITION; +extern const Position OLM_TANK_POSITION; +extern const Position BLINDEYE_TANK_POSITION; +extern const Position KROSH_TANK_POSITION; +extern const Position MAULGAR_ROOM_CENTER; +extern const Position GRUUL_TANK_POSITION; - extern const Position MAULGAR_TANK_POSITION; - extern const Position OLM_TANK_POSITION; - extern const Position BLINDEYE_TANK_POSITION; - extern const Position KROSH_TANK_POSITION; - extern const Position MAULGAR_ROOM_CENTER; - extern const Position GRUUL_TANK_POSITION; } #endif diff --git a/src/Ai/Raid/Gruul/GruulMultipliers.cpp b/src/Ai/Raid/Gruul/GruulMultipliers.cpp index e5a02698f..f518f869a 100644 --- a/src/Ai/Raid/Gruul/GruulMultipliers.cpp +++ b/src/Ai/Raid/Gruul/GruulMultipliers.cpp @@ -2,44 +2,69 @@ #include "GruulActions.h" #include "GruulHelpers.h" #include "ChooseTargetActions.h" -#include "DruidBearActions.h" -#include "DruidCatActions.h" #include "GenericSpellActions.h" #include "HunterActions.h" -#include "MageActions.h" #include "Playerbots.h" #include "ReachTargetActions.h" -#include "WarriorActions.h" +#include "ShamanActions.h" using namespace GruulsLairHelpers; -float HighKingMaulgarDisableTankAssistMultiplier::GetValue(Action* action) +float HighKingMaulgarDelayBloodlustAndHeroismMultiplier::GetValue(Action* action) { - if (bot->GetVictim() == nullptr) + if (bot->getClass() != CLASS_SHAMAN) return 1.0f; - if (IsAnyOgreBossAlive(botAI) && dynamic_cast(action)) + Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer"); + if (!blindeye || blindeye->GetHealthPct() < 75.0f) + return 1.0f; + + if (dynamic_cast(action) || + dynamic_cast(action)) + { return 0.0f; + } + + return 1.0f; +} + +float HighKingMaulgarControlTankActionsMultiplier::GetValue(Action* action) +{ + if (!botAI->IsTank(bot)) + return 1.0f; + + if (!AI_VALUE2(Unit*, "find target", "high king maulgar")) + return 1.0f; + + if (dynamic_cast(action) || + (bot->GetVictim() != nullptr && dynamic_cast(action))) + { + return 0.0f; + } return 1.0f; } -// Don't run back in during Whirlwind float HighKingMaulgarAvoidWhirlwindMultiplier::GetValue(Action* action) { Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar"); - Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed"); - Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); - Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner"); - Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer"); - - if (maulgar && maulgar->HasAura(SPELL_WHIRLWIND) && - !kiggler && !krosh && !olm && !blindeye) + if (!maulgar || + !maulgar->HasAura(static_cast(GruulsLairSpells::SPELL_WHIRLWIND))) { - if (dynamic_cast(action) || - (dynamic_cast(action) && - !dynamic_cast(action))) - return 0.0f; + return 1.0f; + } + + if (AI_VALUE(Unit*, "current target") != maulgar) + return 1.0f; + + if (botAI->IsMainTank(bot)) + return 1.0f; + + if (dynamic_cast(action) || + (dynamic_cast(action) && + !dynamic_cast(action))) + { + return 0.0f; } return 1.0f; @@ -48,57 +73,83 @@ float HighKingMaulgarAvoidWhirlwindMultiplier::GetValue(Action* action) // Arcane Shot will remove Spell Shield, which the mage tank needs to survive float HighKingMaulgarDisableArcaneShotOnKroshMultiplier::GetValue(Action* action) { + if (bot->getClass() != CLASS_HUNTER) + return 1.0f; + Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); + if (!krosh || AI_VALUE(Unit*, "current target") != krosh) + return 1.0f; - if (krosh && AI_VALUE(Unit*, "current target") == krosh && - dynamic_cast(action)) + if (dynamic_cast(action)) return 0.0f; return 1.0f; } -float HighKingMaulgarDisableMageTankAOEMultiplier::GetValue(Action* action) +float HighKingMaulgarDisableMageTankAoeMultiplier::GetValue(Action* action) { - if (IsKroshMageTank(bot) && - (dynamic_cast(action) || dynamic_cast(action) || - dynamic_cast(action) || dynamic_cast(action) || - dynamic_cast(action) || dynamic_cast(action))) + if (bot->getClass() != CLASS_MAGE) + return 1.0f; + + if (!AI_VALUE2(Unit*, "find target", "krosh firehand")) + return 1.0f; + + auto castSpellAction = dynamic_cast(action); + if (castSpellAction && + castSpellAction->getThreatType() == Action::ActionThreatType::Aoe) + { return 0.0f; - - return 1.0f; -} - -float GruulTheDragonkillerMainTankMovementMultiplier::GetValue(Action* action) -{ - Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); - if (!gruul) - return 1.0f; - - if (botAI->IsMainTank(bot)) - { - if (gruul->GetVictim() == bot && dynamic_cast(action)) - return 0.0f; - - if (dynamic_cast(action)) - return 0.0f; } return 1.0f; } -float GruulTheDragonkillerGroundSlamMultiplier::GetValue(Action* action) +float GruulTheDragonkillerDelayBloodlustAndHeroismMultiplier::GetValue(Action* action) { - Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); - if (!gruul) + if (bot->getClass() != CLASS_SHAMAN) return 1.0f; - if (bot->HasAura(SPELL_GROUND_SLAM_1) || - bot->HasAura(SPELL_GROUND_SLAM_2)) + Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); + if (!gruul || gruul->GetHealthPct() < 95.0f) + return 1.0f; + + if (dynamic_cast(action) || + dynamic_cast(action)) { - if ((dynamic_cast(action) && - !dynamic_cast(action)) || - dynamic_cast(action)) - return 0.0f; + return 0.0f; + } + + return 1.0f; +} + +float GruulTheDragonkillerControlTankMovementMultiplier::GetValue(Action* action) +{ + Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); + if (!gruul || gruul->GetVictim() != bot) + return 1.0f; + + if (dynamic_cast(action) || + dynamic_cast(action)) + { + return 0.0f; + } + + return 1.0f; +} + +float GruulTheDragonkillerStaySpreadForShatterMultiplier::GetValue(Action* action) +{ + if (!bot->HasAura(static_cast(GruulsLairSpells::SPELL_GROUND_SLAM_1)) && + !bot->HasAura(static_cast(GruulsLairSpells::SPELL_GROUND_SLAM_2))) + { + return 1.0f; + } + + if (dynamic_cast(action) || + (dynamic_cast(action) && + !dynamic_cast(action))) + { + return 0.0f; } return 1.0f; diff --git a/src/Ai/Raid/Gruul/GruulMultipliers.h b/src/Ai/Raid/Gruul/GruulMultipliers.h index f64294968..b15f382ad 100644 --- a/src/Ai/Raid/Gruul/GruulMultipliers.h +++ b/src/Ai/Raid/Gruul/GruulMultipliers.h @@ -1,47 +1,69 @@ -#ifndef PLAYERBOTS_RAIDGRUULSLAIRMULTIPLIERS_H -#define PLAYERBOTS_RAIDGRUULSLAIRMULTIPLIERS_H +#ifndef PLAYERBOTS_GRUULMULTIPLIERS_H +#define PLAYERBOTS_GRUULMULTIPLIERS_H #include "Multiplier.h" -class HighKingMaulgarDisableTankAssistMultiplier : public Multiplier +class HighKingMaulgarDelayBloodlustAndHeroismMultiplier : public Multiplier { public: - HighKingMaulgarDisableTankAssistMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar disable tank assist multiplier") {} + HighKingMaulgarDelayBloodlustAndHeroismMultiplier( + PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar delay bloodlust and heroism multiplier") {} + float GetValue(Action* action) override; +}; + +class HighKingMaulgarControlTankActionsMultiplier : public Multiplier +{ +public: + HighKingMaulgarControlTankActionsMultiplier( + PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar control tank actions multiplier") {} float GetValue(Action* action) override; }; class HighKingMaulgarAvoidWhirlwindMultiplier : public Multiplier { public: - HighKingMaulgarAvoidWhirlwindMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar avoid whirlwind multiplier") {} + HighKingMaulgarAvoidWhirlwindMultiplier( + PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar avoid whirlwind multiplier") {} float GetValue(Action* action) override; }; class HighKingMaulgarDisableArcaneShotOnKroshMultiplier : public Multiplier { public: - HighKingMaulgarDisableArcaneShotOnKroshMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar disable arcane shot on krosh multiplier") {} + HighKingMaulgarDisableArcaneShotOnKroshMultiplier( + PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar disable arcane shot on krosh multiplier") {} float GetValue(Action* action) override; }; -class HighKingMaulgarDisableMageTankAOEMultiplier : public Multiplier +class HighKingMaulgarDisableMageTankAoeMultiplier : public Multiplier { public: - HighKingMaulgarDisableMageTankAOEMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar disable mage tank aoe multiplier") {} + HighKingMaulgarDisableMageTankAoeMultiplier( + PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar disable mage tank aoe multiplier") {} float GetValue(Action* action) override; }; -class GruulTheDragonkillerMainTankMovementMultiplier : public Multiplier +class GruulTheDragonkillerDelayBloodlustAndHeroismMultiplier : public Multiplier { public: - GruulTheDragonkillerMainTankMovementMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "gruul the dragonkiller main tank movement multiplier") {} + GruulTheDragonkillerDelayBloodlustAndHeroismMultiplier( + PlayerbotAI* botAI) : Multiplier(botAI, "gruul the dragonkiller delay bloodlust and heroism multiplier") {} float GetValue(Action* action) override; }; -class GruulTheDragonkillerGroundSlamMultiplier : public Multiplier +class GruulTheDragonkillerControlTankMovementMultiplier : public Multiplier { public: - GruulTheDragonkillerGroundSlamMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "gruul the dragonkiller ground slam multiplier") {} + GruulTheDragonkillerControlTankMovementMultiplier( + PlayerbotAI* botAI) : Multiplier(botAI, "gruul the dragonkiller control tank movement multiplier") {} + float GetValue(Action* action) override; +}; + +class GruulTheDragonkillerStaySpreadForShatterMultiplier : public Multiplier +{ +public: + GruulTheDragonkillerStaySpreadForShatterMultiplier( + PlayerbotAI* botAI) : Multiplier(botAI, "gruul the dragonkiller stay spread for shatter multiplier") {} float GetValue(Action* action) override; }; diff --git a/src/Ai/Raid/Gruul/GruulStrategy.cpp b/src/Ai/Raid/Gruul/GruulStrategy.cpp index 4f4297650..8cac48f32 100644 --- a/src/Ai/Raid/Gruul/GruulStrategy.cpp +++ b/src/Ai/Raid/Gruul/GruulStrategy.cpp @@ -4,35 +4,35 @@ void RaidGruulsLairStrategy::InitTriggers(std::vector& triggers) { // High King Maulgar - triggers.push_back(new TriggerNode("high king maulgar is main tank", { + triggers.push_back(new TriggerNode("high king maulgar boss engaged by main tank", { NextAction("high king maulgar main tank attack maulgar", ACTION_RAID + 1) })); - triggers.push_back(new TriggerNode("high king maulgar is first assist tank", { + triggers.push_back(new TriggerNode("high king maulgar olm engaged by first assist tank", { NextAction("high king maulgar first assist tank attack olm", ACTION_RAID + 1) })); - triggers.push_back(new TriggerNode("high king maulgar is second assist tank", { + triggers.push_back(new TriggerNode("high king maulgar blindeye engaged by second assist tank", { NextAction("high king maulgar second assist tank attack blindeye", ACTION_RAID + 1) })); - triggers.push_back(new TriggerNode("high king maulgar is mage tank", { + triggers.push_back(new TriggerNode("high king maulgar krosh engaged by mage tank", { NextAction("high king maulgar mage tank attack krosh", ACTION_RAID + 1) })); - triggers.push_back(new TriggerNode("high king maulgar is moonkin tank", { + triggers.push_back(new TriggerNode("high king maulgar kiggler engaged by moonkin tank", { NextAction("high king maulgar moonkin tank attack kiggler", ACTION_RAID + 1) })); triggers.push_back(new TriggerNode("high king maulgar determining kill order", { NextAction("high king maulgar assign dps priority", ACTION_RAID + 1) })); - triggers.push_back(new TriggerNode("high king maulgar healer in danger", { - NextAction("high king maulgar healer find safe position", ACTION_RAID + 1) })); - triggers.push_back(new TriggerNode("high king maulgar boss channeling whirlwind", { - NextAction("high king maulgar run away from whirlwind", ACTION_EMERGENCY + 6) })); + NextAction("high king maulgar run away from whirlwind", ACTION_EMERGENCY + 7) })); - triggers.push_back(new TriggerNode("high king maulgar wild felstalker spawned", { - NextAction("high king maulgar banish felstalker", ACTION_RAID + 2) })); + triggers.push_back(new TriggerNode("high king maulgar krosh casts blast wave", { + NextAction("high king maulgar move away from blast nova danger", ACTION_EMERGENCY + 6) })); - triggers.push_back(new TriggerNode("high king maulgar pulling olm and blindeye", { - NextAction("high king maulgar misdirect olm and blindeye", ACTION_RAID + 2) })); + triggers.push_back(new TriggerNode("high king maulgar wild fel stalker spawned", { + NextAction("high king maulgar banish fel stalker", ACTION_RAID + 2) })); + + triggers.push_back(new TriggerNode("high king maulgar pulling ogre council", { + NextAction("high king maulgar misdirect ogres to tanks", ACTION_RAID + 2) })); // Gruul the Dragonkiller triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by tanks", { @@ -47,10 +47,15 @@ void RaidGruulsLairStrategy::InitTriggers(std::vector& triggers) void RaidGruulsLairStrategy::InitMultipliers(std::vector& multipliers) { - multipliers.push_back(new HighKingMaulgarDisableTankAssistMultiplier(botAI)); + // High King Maulgar + multipliers.push_back(new HighKingMaulgarDelayBloodlustAndHeroismMultiplier(botAI)); + multipliers.push_back(new HighKingMaulgarControlTankActionsMultiplier(botAI)); multipliers.push_back(new HighKingMaulgarAvoidWhirlwindMultiplier(botAI)); multipliers.push_back(new HighKingMaulgarDisableArcaneShotOnKroshMultiplier(botAI)); - multipliers.push_back(new HighKingMaulgarDisableMageTankAOEMultiplier(botAI)); - multipliers.push_back(new GruulTheDragonkillerMainTankMovementMultiplier(botAI)); - multipliers.push_back(new GruulTheDragonkillerGroundSlamMultiplier(botAI)); + multipliers.push_back(new HighKingMaulgarDisableMageTankAoeMultiplier(botAI)); + + // Gruul the Dragonkiller + multipliers.push_back(new GruulTheDragonkillerDelayBloodlustAndHeroismMultiplier(botAI)); + multipliers.push_back(new GruulTheDragonkillerControlTankMovementMultiplier(botAI)); + multipliers.push_back(new GruulTheDragonkillerStaySpreadForShatterMultiplier(botAI)); } diff --git a/src/Ai/Raid/Gruul/GruulStrategy.h b/src/Ai/Raid/Gruul/GruulStrategy.h index a494d5c20..2c233b910 100644 --- a/src/Ai/Raid/Gruul/GruulStrategy.h +++ b/src/Ai/Raid/Gruul/GruulStrategy.h @@ -1,5 +1,5 @@ -#ifndef PLAYERBOTS_RAIDGRUULSLAIRSTRATEGY_H -#define PLAYERBOTS_RAIDGRUULSLAIRSTRATEGY_H +#ifndef PLAYERBOTS_GRUULSTRATEGY_H +#define PLAYERBOTS_GRUULSTRATEGY_H #include "Strategy.h" diff --git a/src/Ai/Raid/Gruul/GruulTriggerContext.h b/src/Ai/Raid/Gruul/GruulTriggerContext.h index b1adf8dec..0989ee5e9 100644 --- a/src/Ai/Raid/Gruul/GruulTriggerContext.h +++ b/src/Ai/Raid/Gruul/GruulTriggerContext.h @@ -1,5 +1,5 @@ -#ifndef PLAYERBOTS_RAIDGRUULSLAIRTRIGGERCONTEXT_H -#define PLAYERBOTS_RAIDGRUULSLAIRTRIGGERCONTEXT_H +#ifndef PLAYERBOTS_GRUULTRIGGERCONTEXT_H +#define PLAYERBOTS_GRUULTRIGGERCONTEXT_H #include "GruulTriggers.h" #include "NamedObjectContext.h" @@ -10,40 +10,101 @@ public: RaidGruulsLairTriggerContext() : NamedObjectContext() { // High King Maulgar - creators["high king maulgar is main tank"] = &RaidGruulsLairTriggerContext::high_king_maulgar_is_main_tank; - creators["high king maulgar is first assist tank"] = &RaidGruulsLairTriggerContext::high_king_maulgar_is_first_assist_tank; - creators["high king maulgar is second assist tank"] = &RaidGruulsLairTriggerContext::high_king_maulgar_is_second_assist_tank; - creators["high king maulgar is mage tank"] = &RaidGruulsLairTriggerContext::high_king_maulgar_is_mage_tank; - creators["high king maulgar is moonkin tank"] = &RaidGruulsLairTriggerContext::high_king_maulgar_is_moonkin_tank; - creators["high king maulgar determining kill order"] = &RaidGruulsLairTriggerContext::high_king_maulgar_determining_kill_order; - creators["high king maulgar healer in danger"] = &RaidGruulsLairTriggerContext::high_king_maulgar_healer_in_danger; - creators["high king maulgar boss channeling whirlwind"] = &RaidGruulsLairTriggerContext::high_king_maulgar_boss_channeling_whirlwind; - creators["high king maulgar wild felstalker spawned"] = &RaidGruulsLairTriggerContext::high_king_maulgar_wild_felstalker_spawned; - creators["high king maulgar pulling olm and blindeye"] = &RaidGruulsLairTriggerContext::high_king_maulgar_pulling_olm_and_blindeye; + creators["high king maulgar boss engaged by main tank"] = + &RaidGruulsLairTriggerContext::high_king_maulgar_boss_engaged_by_main_tank; + + creators["high king maulgar olm engaged by first assist tank"] = + &RaidGruulsLairTriggerContext::high_king_maulgar_olm_engaged_by_first_assist_tank; + + creators["high king maulgar blindeye engaged by second assist tank"] = + &RaidGruulsLairTriggerContext::high_king_maulgar_blindeye_engaged_by_second_assist_tank; + + creators["high king maulgar krosh engaged by mage tank"] = + &RaidGruulsLairTriggerContext::high_king_maulgar_krosh_engaged_by_mage_tank; + + creators["high king maulgar kiggler engaged by moonkin tank"] = + &RaidGruulsLairTriggerContext::high_king_maulgar_kiggler_engaged_by_moonkin_tank; + + creators["high king maulgar determining kill order"] = + &RaidGruulsLairTriggerContext::high_king_maulgar_determining_kill_order; + + creators["high king maulgar boss channeling whirlwind"] = + &RaidGruulsLairTriggerContext::high_king_maulgar_boss_channeling_whirlwind; + + creators["high king maulgar krosh casts blast wave"] = + &RaidGruulsLairTriggerContext::high_king_maulgar_krosh_casts_blast_wave; + + creators["high king maulgar wild fel stalker spawned"] = + &RaidGruulsLairTriggerContext::high_king_maulgar_wild_fel_stalker_spawned; + + creators["high king maulgar pulling ogre council"] = + &RaidGruulsLairTriggerContext::high_king_maulgar_pulling_ogre_council; // Gruul the Dragonkiller - creators["gruul the dragonkiller boss engaged by tanks"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_tanks; - creators["gruul the dragonkiller boss engaged by ranged"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_ranged; - creators["gruul the dragonkiller incoming shatter"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_incoming_shatter; + creators["gruul the dragonkiller boss engaged by tanks"] = + &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_tanks; + + creators["gruul the dragonkiller boss engaged by ranged"] = + &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_ranged; + + creators["gruul the dragonkiller incoming shatter"] = + &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_incoming_shatter; } private: // High King Maulgar - static Trigger* high_king_maulgar_is_main_tank(PlayerbotAI* botAI) { return new HighKingMaulgarIsMainTankTrigger(botAI); } - static Trigger* high_king_maulgar_is_first_assist_tank(PlayerbotAI* botAI) { return new HighKingMaulgarIsFirstAssistTankTrigger(botAI); } - static Trigger* high_king_maulgar_is_second_assist_tank(PlayerbotAI* botAI) { return new HighKingMaulgarIsSecondAssistTankTrigger(botAI); } - static Trigger* high_king_maulgar_is_mage_tank(PlayerbotAI* botAI) { return new HighKingMaulgarIsMageTankTrigger(botAI); } - static Trigger* high_king_maulgar_is_moonkin_tank(PlayerbotAI* botAI) { return new HighKingMaulgarIsMoonkinTankTrigger(botAI); } - static Trigger* high_king_maulgar_determining_kill_order(PlayerbotAI* botAI) { return new HighKingMaulgarDeterminingKillOrderTrigger(botAI); } - static Trigger* high_king_maulgar_healer_in_danger(PlayerbotAI* botAI) { return new HighKingMaulgarHealerInDangerTrigger(botAI); } - static Trigger* high_king_maulgar_boss_channeling_whirlwind(PlayerbotAI* botAI) { return new HighKingMaulgarBossChannelingWhirlwindTrigger(botAI); } - static Trigger* high_king_maulgar_wild_felstalker_spawned(PlayerbotAI* botAI) { return new HighKingMaulgarWildFelstalkerSpawnedTrigger(botAI); } - static Trigger* high_king_maulgar_pulling_olm_and_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarPullingOlmAndBlindeyeTrigger(botAI); } + static Trigger* high_king_maulgar_boss_engaged_by_main_tank(PlayerbotAI* botAI) { + return new HighKingMaulgarBossEngagedByMainTankTrigger(botAI); + } + + static Trigger* high_king_maulgar_olm_engaged_by_first_assist_tank(PlayerbotAI* botAI) { + return new HighKingMaulgarOlmEngagedByFirstAssistTankTrigger(botAI); + } + + static Trigger* high_king_maulgar_blindeye_engaged_by_second_assist_tank(PlayerbotAI* botAI) { + return new HighKingMaulgarBlindeyeEngagedBySecondAssistTankTrigger(botAI); + } + + static Trigger* high_king_maulgar_krosh_engaged_by_mage_tank(PlayerbotAI* botAI) { + return new HighKingMaulgarKroshEngagedByMageTankTrigger(botAI); + } + + static Trigger* high_king_maulgar_kiggler_engaged_by_moonkin_tank(PlayerbotAI* botAI) { + return new HighKingMaulgarKigglerEngagedByMoonkinTankTrigger(botAI); + } + + static Trigger* high_king_maulgar_determining_kill_order(PlayerbotAI* botAI) { + return new HighKingMaulgarDeterminingKillOrderTrigger(botAI); + } + + static Trigger* high_king_maulgar_boss_channeling_whirlwind(PlayerbotAI* botAI) { + return new HighKingMaulgarBossChannelingWhirlwindTrigger(botAI); + } + + static Trigger* high_king_maulgar_krosh_casts_blast_wave(PlayerbotAI* botAI) { + return new HighKingMaulgarKroshCastsBlastWaveTrigger(botAI); + } + + static Trigger* high_king_maulgar_wild_fel_stalker_spawned(PlayerbotAI* botAI) { + return new HighKingMaulgarWildFelStalkerSpawnedTrigger(botAI); + } + + static Trigger* high_king_maulgar_pulling_ogre_council(PlayerbotAI* botAI) { + return new HighKingMaulgarPullingOgreCouncilTrigger(botAI); + } // Gruul the Dragonkiller - static Trigger* gruul_the_dragonkiller_boss_engaged_by_tanks(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByTanksTrigger(botAI); } - static Trigger* gruul_the_dragonkiller_boss_engaged_by_ranged(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByRangedTrigger(botAI); } - static Trigger* gruul_the_dragonkiller_incoming_shatter(PlayerbotAI* botAI) { return new GruulTheDragonkillerIncomingShatterTrigger(botAI); } + static Trigger* gruul_the_dragonkiller_boss_engaged_by_tanks(PlayerbotAI* botAI) { + return new GruulTheDragonkillerBossEngagedByTanksTrigger(botAI); + } + + static Trigger* gruul_the_dragonkiller_boss_engaged_by_ranged(PlayerbotAI* botAI) { + return new GruulTheDragonkillerBossEngagedByRangedTrigger(botAI); + } + + static Trigger* gruul_the_dragonkiller_incoming_shatter(PlayerbotAI* botAI) { + return new GruulTheDragonkillerIncomingShatterTrigger(botAI); + } }; #endif diff --git a/src/Ai/Raid/Gruul/GruulTriggers.cpp b/src/Ai/Raid/Gruul/GruulTriggers.cpp index 82c3e18ac..419f486c8 100644 --- a/src/Ai/Raid/Gruul/GruulTriggers.cpp +++ b/src/Ai/Raid/Gruul/GruulTriggers.cpp @@ -6,154 +6,113 @@ using namespace GruulsLairHelpers; // High King Maulgar Triggers -bool HighKingMaulgarIsMainTankTrigger::IsActive() +bool HighKingMaulgarBossEngagedByMainTankTrigger::IsActive() { - Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar"); - - return botAI->IsMainTank(bot) && maulgar; + return botAI->IsMainTank(bot) && + AI_VALUE2(Unit*, "find target", "high king maulgar"); } -bool HighKingMaulgarIsFirstAssistTankTrigger::IsActive() +bool HighKingMaulgarOlmEngagedByFirstAssistTankTrigger::IsActive() { - Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner"); - - return botAI->IsAssistTankOfIndex(bot, 0, false) && olm; + return botAI->IsAssistTankOfIndex(bot, 0, false) && + AI_VALUE2(Unit*, "find target", "olm the summoner"); } -bool HighKingMaulgarIsSecondAssistTankTrigger::IsActive() +bool HighKingMaulgarBlindeyeEngagedBySecondAssistTankTrigger::IsActive() { - Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer"); - - return botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye; + return botAI->IsAssistTankOfIndex(bot, 1, false) && + AI_VALUE2(Unit*, "find target", "blindeye the seer"); } -bool HighKingMaulgarIsMageTankTrigger::IsActive() +bool HighKingMaulgarKroshEngagedByMageTankTrigger::IsActive() { - Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); - - return IsKroshMageTank(bot) && krosh; + return bot->getClass() == CLASS_MAGE && + AI_VALUE2(Unit*, "find target", "krosh firehand") && + GetKroshMageTank(bot) == bot; } -bool HighKingMaulgarIsMoonkinTankTrigger::IsActive() +bool HighKingMaulgarKigglerEngagedByMoonkinTankTrigger::IsActive() { - Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed"); - - return IsKigglerMoonkinTank(bot) && kiggler; + return bot->getClass() == CLASS_DRUID && + AI_VALUE2(Unit*, "find target", "kiggler the crazed") && + GetKigglerMoonkinTank(bot) == bot; } bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive() { + if (botAI->IsHeal(bot) || botAI->IsMainTank(bot)) + return false; + Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar"); - Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed"); - Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner"); - Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer"); - Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); + if (!maulgar) + return false; - return (botAI->IsDps(bot) || botAI->IsTank(bot)) && - !(botAI->IsMainTank(bot) && maulgar) && - !(botAI->IsAssistTankOfIndex(bot, 0, false) && olm) && - !(botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye) && - !(IsKroshMageTank(bot) && krosh) && - !(IsKigglerMoonkinTank(bot) && kiggler); -} + if (botAI->IsAssistTankOfIndex(bot, 0, false)) + return !AI_VALUE2(Unit*, "find target", "olm the summoner"); -bool HighKingMaulgarHealerInDangerTrigger::IsActive() -{ - return botAI->IsHeal(bot) && IsAnyOgreBossAlive(botAI); + if (botAI->IsAssistTankOfIndex(bot, 1, false)) + return !AI_VALUE2(Unit*, "find target", "blindeye the seer"); + + if (bot->getClass() == CLASS_MAGE && GetKroshMageTank(bot) == bot) + return !AI_VALUE2(Unit*, "find target", "krosh firehand"); + + if (bot->getClass() == CLASS_DRUID && GetKigglerMoonkinTank(bot) == bot) + return !AI_VALUE2(Unit*, "find target", "kiggler the crazed"); + + return true; } bool HighKingMaulgarBossChannelingWhirlwindTrigger::IsActive() { Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar"); - - return maulgar && maulgar->HasAura(SPELL_WHIRLWIND) && - !botAI->IsMainTank(bot); -} - -bool HighKingMaulgarWildFelstalkerSpawnedTrigger::IsActive() -{ - Unit* felStalker = AI_VALUE2(Unit*, "find target", "wild fel stalker"); - - return felStalker && bot->getClass() == CLASS_WARLOCK; -} - -bool HighKingMaulgarPullingOlmAndBlindeyeTrigger::IsActive() -{ - Group* group = bot->GetGroup(); - if (!group || bot->getClass() != CLASS_HUNTER) - return false; - - std::vector hunters; - for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + if (!maulgar || + !maulgar->HasAura(static_cast(GruulsLairSpells::SPELL_WHIRLWIND))) { - Player* member = ref->GetSource(); - if (member && member->IsAlive() && member->getClass() == CLASS_HUNTER && GET_PLAYERBOT_AI(member)) - hunters.push_back(member); + return false; } - int hunterIndex = -1; - for (size_t i = 0; i < hunters.size(); ++i) - { - if (hunters[i] == bot) - { - hunterIndex = static_cast(i); - break; - } - } - if (hunterIndex == -1 || hunterIndex > 1) + return !botAI->IsMainTank(bot); +} + +bool HighKingMaulgarKroshCastsBlastWaveTrigger::IsActive() +{ + if (!AI_VALUE2(Unit*, "find target", "krosh firehand")) + return false; + + return !botAI->IsTank(bot) && GetKroshMageTank(bot) != bot; +} + +bool HighKingMaulgarWildFelStalkerSpawnedTrigger::IsActive() +{ + return bot->getClass() == CLASS_WARLOCK && + AI_VALUE2(Unit*, "find target", "wild fel stalker"); +} + +bool HighKingMaulgarPullingOgreCouncilTrigger::IsActive() +{ + if (bot->getClass() != CLASS_HUNTER) return false; - Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner"); Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer"); - Player* olmTank = nullptr; - Player* blindeyeTank = nullptr; - - for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) - { - Player* member = ref->GetSource(); - if (!member || !member->IsAlive()) - continue; - else if (botAI->IsAssistTankOfIndex(member, 0)) olmTank = member; - else if (botAI->IsAssistTankOfIndex(member, 1)) blindeyeTank = member; - } - - switch (hunterIndex) - { - case 0: - return olm && olm->GetHealthPct() > 98.0f && - olmTank && botAI->CanCastSpell("misdirection", olmTank); - - case 1: - return blindeye && blindeye->GetHealthPct() > 90.0f && - blindeyeTank && botAI->CanCastSpell("misdirection", blindeyeTank); - - default: - break; - } - - return false; + return blindeye && blindeye->GetHealthPct() > 80.0f; } // Gruul the Dragonkiller Triggers bool GruulTheDragonkillerBossEngagedByTanksTrigger::IsActive() { - Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); - - return gruul && botAI->IsTank(bot); + return botAI->IsTank(bot) && + AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); } bool GruulTheDragonkillerBossEngagedByRangedTrigger::IsActive() { - Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); - - return gruul && botAI->IsRanged(bot); + return botAI->IsRanged(bot) && + AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); } bool GruulTheDragonkillerIncomingShatterTrigger::IsActive() { - Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); - - return gruul && (bot->HasAura(SPELL_GROUND_SLAM_1) || - bot->HasAura(SPELL_GROUND_SLAM_2)); + return bot->HasAura(static_cast(GruulsLairSpells::SPELL_GROUND_SLAM_1)) || + bot->HasAura(static_cast(GruulsLairSpells::SPELL_GROUND_SLAM_2)); } diff --git a/src/Ai/Raid/Gruul/GruulTriggers.h b/src/Ai/Raid/Gruul/GruulTriggers.h index 6a30fd857..2a86c9328 100644 --- a/src/Ai/Raid/Gruul/GruulTriggers.h +++ b/src/Ai/Raid/Gruul/GruulTriggers.h @@ -1,96 +1,109 @@ -#ifndef PLAYERBOTS_RAIDGRUULSLAIRTRIGGERS_H -#define PLAYERBOTS_RAIDGRUULSLAIRTRIGGERS_H +#ifndef PLAYERBOTS_GRUULTRIGGERS_H +#define PLAYERBOTS_GRUULTRIGGERS_H #include "Trigger.h" -class HighKingMaulgarIsMainTankTrigger : public Trigger +class HighKingMaulgarBossEngagedByMainTankTrigger : public Trigger { public: - HighKingMaulgarIsMainTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar is main tank") {} + HighKingMaulgarBossEngagedByMainTankTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar engaged by main tank") {} bool IsActive() override; }; -class HighKingMaulgarIsFirstAssistTankTrigger : public Trigger +class HighKingMaulgarOlmEngagedByFirstAssistTankTrigger : public Trigger { public: - HighKingMaulgarIsFirstAssistTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar is first assist tank") {} + HighKingMaulgarOlmEngagedByFirstAssistTankTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar olm engaged by first assist tank") {} bool IsActive() override; }; -class HighKingMaulgarIsSecondAssistTankTrigger : public Trigger +class HighKingMaulgarBlindeyeEngagedBySecondAssistTankTrigger : public Trigger { public: - HighKingMaulgarIsSecondAssistTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar is second assist tank") {} + HighKingMaulgarBlindeyeEngagedBySecondAssistTankTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar blindeye engaged by second assist tank") {} bool IsActive() override; }; -class HighKingMaulgarIsMageTankTrigger : public Trigger +class HighKingMaulgarKroshEngagedByMageTankTrigger : public Trigger { public: - HighKingMaulgarIsMageTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar is mage tank") {} + HighKingMaulgarKroshEngagedByMageTankTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar krosh engaged by mage tank") {} bool IsActive() override; }; -class HighKingMaulgarIsMoonkinTankTrigger : public Trigger +class HighKingMaulgarKigglerEngagedByMoonkinTankTrigger : public Trigger { public: - HighKingMaulgarIsMoonkinTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar is moonkin tank") {} + HighKingMaulgarKigglerEngagedByMoonkinTankTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar kiggler engaged by moonkin tank") {} bool IsActive() override; }; class HighKingMaulgarDeterminingKillOrderTrigger : public Trigger { public: - HighKingMaulgarDeterminingKillOrderTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar determining kill order") {} - bool IsActive() override; -}; - -class HighKingMaulgarHealerInDangerTrigger : public Trigger -{ -public: - HighKingMaulgarHealerInDangerTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar healers in danger") {} + HighKingMaulgarDeterminingKillOrderTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar determining kill order") {} bool IsActive() override; }; class HighKingMaulgarBossChannelingWhirlwindTrigger : public Trigger { public: - HighKingMaulgarBossChannelingWhirlwindTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar boss channeling whirlwind") {} + HighKingMaulgarBossChannelingWhirlwindTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar boss channeling whirlwind") {} bool IsActive() override; }; -class HighKingMaulgarWildFelstalkerSpawnedTrigger : public Trigger +class HighKingMaulgarKroshCastsBlastWaveTrigger : public Trigger { public: - HighKingMaulgarWildFelstalkerSpawnedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar wild felstalker spawned") {} + HighKingMaulgarKroshCastsBlastWaveTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar krosh casts blast wave") {} bool IsActive() override; }; -class HighKingMaulgarPullingOlmAndBlindeyeTrigger : public Trigger +class HighKingMaulgarWildFelStalkerSpawnedTrigger : public Trigger { public: - HighKingMaulgarPullingOlmAndBlindeyeTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar pulling olm and blindeye") {} + HighKingMaulgarWildFelStalkerSpawnedTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar wild fel stalker spawned") {} + bool IsActive() override; +}; + +class HighKingMaulgarPullingOgreCouncilTrigger : public Trigger +{ +public: + HighKingMaulgarPullingOgreCouncilTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar pulling ogre council") {} bool IsActive() override; }; class GruulTheDragonkillerBossEngagedByTanksTrigger : public Trigger { public: - GruulTheDragonkillerBossEngagedByTanksTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by tanks") {} + GruulTheDragonkillerBossEngagedByTanksTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by tanks") {} bool IsActive() override; }; class GruulTheDragonkillerBossEngagedByRangedTrigger : public Trigger { public: - GruulTheDragonkillerBossEngagedByRangedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by ranged") {} + GruulTheDragonkillerBossEngagedByRangedTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by ranged") {} bool IsActive() override; }; class GruulTheDragonkillerIncomingShatterTrigger : public Trigger { public: - GruulTheDragonkillerIncomingShatterTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller incoming shatter") {} + GruulTheDragonkillerIncomingShatterTrigger( + PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller incoming shatter") {} bool IsActive() override; };