diff --git a/src/Ai/Raid/GruulsLair/Action/RaidGruulsLairActions.cpp b/src/Ai/Raid/GruulsLair/Action/RaidGruulsLairActions.cpp index 1a98135c..2af82ebe 100644 --- a/src/Ai/Raid/GruulsLair/Action/RaidGruulsLairActions.cpp +++ b/src/Ai/Raid/GruulsLair/Action/RaidGruulsLairActions.cpp @@ -2,6 +2,7 @@ #include "RaidGruulsLairHelpers.h" #include "CreatureAI.h" #include "Playerbots.h" +#include "RaidBossHelpers.h" #include "Unit.h" using namespace GruulsLairHelpers; @@ -12,6 +13,8 @@ using namespace GruulsLairHelpers; bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event event) { Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar"); + if (!maulgar) + return false; MarkTargetWithSquare(bot, maulgar); SetRtiTarget(botAI, "square", maulgar); @@ -21,31 +24,20 @@ bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event event) if (maulgar->GetVictim() == bot) { - const Location& tankPosition = GruulsLairLocations::MaulgarTankPosition; + const Position& position = MAULGAR_TANK_POSITION; const float maxDistance = 3.0f; - float distanceToTankPosition = bot->GetExactDist2d(tankPosition.x, tankPosition.y); + float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - if (distanceToTankPosition > maxDistance) + if (distanceToPosition > maxDistance) { - float dX = tankPosition.x - bot->GetPositionX(); - float dY = tankPosition.y - bot->GetPositionY(); - float dist = sqrt(dX * dX + dY * dY); - float moveX = bot->GetPositionX() + (dX / dist) * maxDistance; - float moveY = bot->GetPositionY() + (dY / dist) * maxDistance; - return MoveTo(bot->GetMapId(), moveX, moveY, tankPosition.z, false, false, false, false, - MovementPriority::MOVEMENT_COMBAT, true, false); + 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); } - - float orientation = atan2(maulgar->GetPositionY() - bot->GetPositionY(), - maulgar->GetPositionX() - bot->GetPositionX()); - bot->SetFacingTo(orientation); - } - else if (!bot->IsWithinMeleeRange(maulgar)) - { - return MoveTo(maulgar->GetMapId(), maulgar->GetPositionX(), maulgar->GetPositionY(), - maulgar->GetPositionZ(), false, false, false, false, - MovementPriority::MOVEMENT_COMBAT, true, false); } return false; @@ -55,6 +47,8 @@ bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event event) bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event event) { Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner"); + if (!olm) + return false; MarkTargetWithCircle(bot, olm); SetRtiTarget(botAI, "circle", olm); @@ -64,29 +58,22 @@ bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event event) if (olm->GetVictim() == bot) { - const Location& tankPosition = GruulsLairLocations::OlmTankPosition; + const Position& position = OLM_TANK_POSITION; const float maxDistance = 3.0f; const float olmTankLeeway = 30.0f; - float distanceOlmToTankPosition = olm->GetExactDist2d(tankPosition.x, tankPosition.y); + float distanceOlmToPosition = olm->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - if (distanceOlmToTankPosition > olmTankLeeway) + if (distanceOlmToPosition > olmTankLeeway) { - float dX = tankPosition.x - bot->GetPositionX(); - float dY = tankPosition.y - bot->GetPositionY(); - float dist = sqrt(dX * dX + dY * dY); - float moveX = bot->GetPositionX() + (dX / dist) * maxDistance; - float moveY = bot->GetPositionY() + (dY / dist) * maxDistance; - return MoveTo(bot->GetMapId(), moveX, moveY, tankPosition.z, false, false, false, false, + 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); } } - else if (!bot->IsWithinMeleeRange(olm)) - { - return MoveTo(olm->GetMapId(), olm->GetPositionX(), olm->GetPositionY(), - olm->GetPositionZ(), false, false, false, false, - MovementPriority::MOVEMENT_COMBAT, true, false); - } return false; } @@ -95,6 +82,8 @@ bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event event) bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event event) { Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer"); + if (!blindeye) + return false; MarkTargetWithStar(bot, blindeye); SetRtiTarget(botAI, "star", blindeye); @@ -104,31 +93,20 @@ bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event event) if (blindeye->GetVictim() == bot) { - const Location& tankPosition = GruulsLairLocations::BlindeyeTankPosition; + const Position& position = BLINDEYE_TANK_POSITION; const float maxDistance = 3.0f; - float distanceToTankPosition = bot->GetExactDist2d(tankPosition.x, tankPosition.y); + float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - if (distanceToTankPosition > maxDistance) + if (distanceToPosition > maxDistance) { - float dX = tankPosition.x - bot->GetPositionX(); - float dY = tankPosition.y - bot->GetPositionY(); - float dist = sqrt(dX * dX + dY * dY); - float moveX = bot->GetPositionX() + (dX / dist) * maxDistance; - float moveY = bot->GetPositionY() + (dY / dist) * maxDistance; - return MoveTo(bot->GetMapId(), moveX, moveY, tankPosition.z, false, false, false, false, + 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); } - - float orientation = atan2(blindeye->GetPositionY() - bot->GetPositionY(), - blindeye->GetPositionX() - bot->GetPositionX()); - bot->SetFacingTo(orientation); - } - else if (!bot->IsWithinMeleeRange(blindeye)) - { - return MoveTo(blindeye->GetMapId(), blindeye->GetPositionX(), blindeye->GetPositionY(), - blindeye->GetPositionZ(), false, false, false, false, - MovementPriority::MOVEMENT_COMBAT, true, false); } return false; @@ -138,6 +116,8 @@ bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event event) bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event) { Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); + if (!krosh) + return false; MarkTargetWithTriangle(bot, krosh); SetRtiTarget(botAI, "triangle", krosh); @@ -149,25 +129,22 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event) return botAI->CastSpell("fire ward", bot); if (bot->GetTarget() != krosh->GetGUID()) - { - bot->SetSelection(krosh->GetGUID()); - return true; - } + return Attack(krosh); if (krosh->GetVictim() == bot) { - const Location& tankPosition = GruulsLairLocations::KroshTankPosition; - float distanceToKrosh = krosh->GetExactDist2d(tankPosition.x, tankPosition.y); + 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; if (distanceToKrosh > minDistance && distanceToKrosh < maxDistance) { - if (!bot->IsWithinDist2d(tankPosition.x, tankPosition.y, tankPositionLeeway)) + if (!bot->IsWithinDist2d(position.GetPositionX(), position.GetPositionY(), tankPositionLeeway)) { - return MoveTo(bot->GetMapId(), tankPosition.x, tankPosition.y, tankPosition.z, false, - false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); + 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(), @@ -179,7 +156,7 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event) Position safePos; if (TryGetNewSafePosition(botAI, bot, safePos)) { - return MoveTo(krosh->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ, + return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } } @@ -192,20 +169,19 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event event) bool HighKingMaulgarMoonkinTankAttackKigglerAction::Execute(Event event) { Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed"); + if (!kiggler) + return false; MarkTargetWithDiamond(bot, kiggler); SetRtiTarget(botAI, "diamond", kiggler); if (bot->GetTarget() != kiggler->GetGUID()) - { - bot->SetSelection(kiggler->GetGUID()); - return true; - } + return Attack(kiggler); Position safePos; if (TryGetNewSafePosition(botAI, bot, safePos)) { - return MoveTo(kiggler->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ, + return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } @@ -216,120 +192,105 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event event) { // Target priority 1: Blindeye Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer"); - if (blindeye && blindeye->IsAlive()) + if (blindeye) { Position safePos; if (TryGetNewSafePosition(botAI, bot, safePos)) { bot->AttackStop(); bot->InterruptNonMeleeSpells(false); - return MoveTo(blindeye->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ, + return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } SetRtiTarget(botAI, "star", blindeye); if (bot->GetTarget() != blindeye->GetGUID()) - { - bot->SetSelection(blindeye->GetGUID()); return Attack(blindeye); - } return false; } // Target priority 2: Olm Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner"); - if (olm && olm->IsAlive()) + if (olm) { Position safePos; if (TryGetNewSafePosition(botAI, bot, safePos)) { bot->AttackStop(); bot->InterruptNonMeleeSpells(false); - return MoveTo(olm->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ, + return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } SetRtiTarget(botAI, "circle", olm); if (bot->GetTarget() != olm->GetGUID()) - { - bot->SetSelection(olm->GetGUID()); return Attack(olm); - } return false; } // Target priority 3a: Krosh (ranged only) Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); - if (krosh && krosh->IsAlive() && botAI->IsRanged(bot)) + if (krosh && botAI->IsRanged(bot)) { Position safePos; if (TryGetNewSafePosition(botAI, bot, safePos)) { bot->AttackStop(); bot->InterruptNonMeleeSpells(false); - return MoveTo(krosh->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ, + return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } SetRtiTarget(botAI, "triangle", krosh); if (bot->GetTarget() != krosh->GetGUID()) - { - bot->SetSelection(krosh->GetGUID()); return Attack(krosh); - } return false; } // Target priority 3b: Kiggler Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed"); - if (kiggler && kiggler->IsAlive()) + if (kiggler) { Position safePos; if (TryGetNewSafePosition(botAI, bot, safePos)) { bot->AttackStop(); bot->InterruptNonMeleeSpells(false); - return MoveTo(kiggler->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ, + return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } SetRtiTarget(botAI, "diamond", kiggler); if (bot->GetTarget() != kiggler->GetGUID()) - { - bot->SetSelection(kiggler->GetGUID()); return Attack(kiggler); - } return false; } // Target priority 4: Maulgar Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar"); - if (maulgar && maulgar->IsAlive()) + if (maulgar) { Position safePos; if (TryGetNewSafePosition(botAI, bot, safePos)) { bot->AttackStop(); bot->InterruptNonMeleeSpells(false); - return MoveTo(maulgar->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ, + return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } SetRtiTarget(botAI, "square", maulgar); if (bot->GetTarget() != maulgar->GetGUID()) - { - bot->SetSelection(maulgar->GetGUID()); return Attack(maulgar); - } } return false; @@ -338,22 +299,22 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event event) // Avoid Whirlwind and Blast Wave and generally try to stay near the center of the room bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event event) { - const Location& fightCenter = GruulsLairLocations::MaulgarRoomCenter; - const float maxDistanceFromFight = 50.0f; - float distToFight = bot->GetExactDist2d(fightCenter.x, fightCenter.y); + const Position& center = MAULGAR_ROOM_CENTER; + const float maxDistanceFromCenter = 50.0f; + float distToCenter = bot->GetExactDist2d(center.GetPositionX(), center.GetPositionY()); - if (distToFight > maxDistanceFromFight) + if (distToCenter > maxDistanceFromCenter) { - float angle = atan2(bot->GetPositionY() - fightCenter.y, bot->GetPositionX() - fightCenter.x); - float destX = fightCenter.x + 40.0f * cos(angle); - float destY = fightCenter.y + 40.0f * sin(angle); - float destZ = fightCenter.z; + 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(bot->GetMapId(), destX, destY, destZ, false, false, false, false, + return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } @@ -362,7 +323,7 @@ bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event event) { bot->AttackStop(); bot->InterruptNonMeleeSpells(false); - return MoveTo(bot->GetMapId(), safePos.m_positionX, safePos.m_positionY, safePos.m_positionZ, + return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } @@ -373,6 +334,8 @@ bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event event) 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); @@ -395,7 +358,7 @@ bool HighKingMaulgarRunAwayFromWhirlwindAction::Execute(Event event) { bot->AttackStop(); bot->InterruptNonMeleeSpells(true); - return MoveTo(maulgar->GetMapId(), destX, destY, destZ, false, false, false, false, + return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } } @@ -439,7 +402,7 @@ bool HighKingMaulgarBanishFelstalkerAction::Execute(Event event) if (warlockIndex >= 0 && warlockIndex < felStalkers.size()) { Unit* assignedFelStalker = felStalkers[warlockIndex]; - if (!assignedFelStalker->HasAura(SPELL_BANISH) && botAI->CanCastSpell(SPELL_BANISH, assignedFelStalker, true)) + if (!botAI->HasAura("banish", assignedFelStalker) && botAI->CanCastSpell("banish", assignedFelStalker)) return botAI->CastSpell("banish", assignedFelStalker); } @@ -528,40 +491,33 @@ bool HighKingMaulgarMisdirectOlmAndBlindeyeAction::Execute(Event event) // Gruul the Dragonkiller Actions // Position in center of the room -bool GruulTheDragonkillerMainTankPositionBossAction::Execute(Event event) +bool GruulTheDragonkillerTanksPositionBossAction::Execute(Event event) { Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); + if (!gruul) + return false; if (bot->GetVictim() != gruul) return Attack(gruul); if (gruul->GetVictim() == bot) { - const Location& tankPosition = GruulsLairLocations::GruulTankPosition; - const float maxDistance = 3.0f; + const Position& position = GRUUL_TANK_POSITION; + const float maxDistance = 5.0f; - float dX = tankPosition.x - bot->GetPositionX(); - float dY = tankPosition.y - bot->GetPositionY(); - float distanceToTankPosition = bot->GetExactDist2d(tankPosition.x, tankPosition.y); + float dX = position.GetPositionX() - bot->GetPositionX(); + float dY = position.GetPositionY() - bot->GetPositionY(); + float distanceToTankPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); if (distanceToTankPosition > maxDistance) { float step = std::min(maxDistance, distanceToTankPosition); float moveX = bot->GetPositionX() + (dX / distanceToTankPosition) * maxDistance; float moveY = bot->GetPositionY() + (dY / distanceToTankPosition) * maxDistance; - const float moveZ = tankPosition.z; - return MoveTo(bot->GetMapId(), moveX, moveY, moveZ, false, false, false, false, + const float moveZ = position.GetPositionZ(); + return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, moveZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } - - float orientation = atan2(gruul->GetPositionY() - bot->GetPositionY(), - gruul->GetPositionX() - bot->GetPositionX()); - bot->SetFacingTo(orientation); - } - else if (!bot->IsWithinMeleeRange(gruul)) - { - return MoveTo(gruul->GetMapId(), gruul->GetPositionX(), gruul->GetPositionY(), gruul->GetPositionZ(), - false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } return false; @@ -579,16 +535,16 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event event) static std::unordered_map hasReachedInitialPosition; Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); - if (gruul && gruul->IsAlive() && gruul->GetHealth() == gruul->GetMaxHealth()) + if (gruul && gruul->GetHealth() == gruul->GetMaxHealth()) { - initialPositions.clear(); - hasReachedInitialPosition.clear(); + initialPositions.erase(bot->GetGUID()); + hasReachedInitialPosition.erase(bot->GetGUID()); } - const Location& tankPosition = GruulsLairLocations::GruulTankPosition; - const float centerX = tankPosition.x; - const float centerY = tankPosition.y; - float centerZ = bot->GetPositionZ(); + 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; @@ -642,7 +598,7 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event event) bot->GetPositionY(), bot->GetPositionZ(), destX, destY, destZ)) return false; - return MoveTo(bot->GetMapId(), destX, destY, destZ, false, false, false, false, + return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } diff --git a/src/Ai/Raid/GruulsLair/Action/RaidGruulsLairActions.h b/src/Ai/Raid/GruulsLair/Action/RaidGruulsLairActions.h index 6faf7ed3..525e0ee6 100644 --- a/src/Ai/Raid/GruulsLair/Action/RaidGruulsLairActions.h +++ b/src/Ai/Raid/GruulsLair/Action/RaidGruulsLairActions.h @@ -85,10 +85,10 @@ public: bool Execute(Event event) override; }; -class GruulTheDragonkillerMainTankPositionBossAction : public AttackAction +class GruulTheDragonkillerTanksPositionBossAction : public AttackAction { public: - GruulTheDragonkillerMainTankPositionBossAction(PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller main tank 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; }; diff --git a/src/Ai/Raid/GruulsLair/Multiplier/RaidGruulsLairMultipliers.cpp b/src/Ai/Raid/GruulsLair/Multiplier/RaidGruulsLairMultipliers.cpp index 5ca2de93..6604fc52 100644 --- a/src/Ai/Raid/GruulsLair/Multiplier/RaidGruulsLairMultipliers.cpp +++ b/src/Ai/Raid/GruulsLair/Multiplier/RaidGruulsLairMultipliers.cpp @@ -8,18 +8,11 @@ #include "HunterActions.h" #include "MageActions.h" #include "Playerbots.h" +#include "ReachTargetActions.h" #include "WarriorActions.h" using namespace GruulsLairHelpers; -static bool IsChargeAction(Action* action) -{ - return dynamic_cast(action) || - dynamic_cast(action) || - dynamic_cast(action) || - dynamic_cast(action); -} - float HighKingMaulgarDisableTankAssistMultiplier::GetValue(Action* action) { if (IsAnyOgreBossAlive(botAI) && dynamic_cast(action)) @@ -38,12 +31,10 @@ float HighKingMaulgarAvoidWhirlwindMultiplier::GetValue(Action* action) Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer"); if (maulgar && maulgar->HasAura(SPELL_WHIRLWIND) && - (!kiggler || !kiggler->IsAlive()) && - (!krosh || !krosh->IsAlive()) && - (!olm || !olm->IsAlive()) && - (!blindeye || !blindeye->IsAlive())) + !kiggler && !krosh && !olm && !blindeye) { - if (IsChargeAction(action) || (dynamic_cast(action) && + if (dynamic_cast(action) || + (dynamic_cast(action) && !dynamic_cast(action))) return 0.0f; } @@ -57,7 +48,8 @@ float HighKingMaulgarDisableArcaneShotOnKroshMultiplier::GetValue(Action* action Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); Unit* target = AI_VALUE(Unit*, "current target"); - if (krosh && target && target->GetGUID() == krosh->GetGUID() && dynamic_cast(action)) + if (krosh && target && target->GetGUID() == krosh->GetGUID() && + dynamic_cast(action)) return 0.0f; return 1.0f; @@ -101,8 +93,9 @@ float GruulTheDragonkillerGroundSlamMultiplier::GetValue(Action* action) if (bot->HasAura(SPELL_GROUND_SLAM_1) || bot->HasAura(SPELL_GROUND_SLAM_2)) { - if ((dynamic_cast(action) && !dynamic_cast(action)) || - IsChargeAction(action)) + if ((dynamic_cast(action) && + !dynamic_cast(action)) || + dynamic_cast(action)) return 0.0f; } diff --git a/src/Ai/Raid/GruulsLair/RaidGruulsLairActionContext.h b/src/Ai/Raid/GruulsLair/RaidGruulsLairActionContext.h index 809fadf0..3850f58c 100644 --- a/src/Ai/Raid/GruulsLair/RaidGruulsLairActionContext.h +++ b/src/Ai/Raid/GruulsLair/RaidGruulsLairActionContext.h @@ -22,7 +22,7 @@ public: creators["high king maulgar misdirect olm and blindeye"] = &RaidGruulsLairActionContext::high_king_maulgar_misdirect_olm_and_blindeye; // Gruul the Dragonkiller - creators["gruul the dragonkiller main tank position boss"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_main_tank_position_boss; + 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; } @@ -41,7 +41,7 @@ private: static Action* high_king_maulgar_misdirect_olm_and_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarMisdirectOlmAndBlindeyeAction(botAI); } // Gruul the Dragonkiller - static Action* gruul_the_dragonkiller_main_tank_position_boss(PlayerbotAI* botAI) { return new GruulTheDragonkillerMainTankPositionBossAction(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); } }; diff --git a/src/Ai/Raid/GruulsLair/RaidGruulsLairTriggerContext.h b/src/Ai/Raid/GruulsLair/RaidGruulsLairTriggerContext.h index fa8e76f5..d12b0ce4 100644 --- a/src/Ai/Raid/GruulsLair/RaidGruulsLairTriggerContext.h +++ b/src/Ai/Raid/GruulsLair/RaidGruulsLairTriggerContext.h @@ -22,8 +22,8 @@ public: creators["high king maulgar pulling olm and blindeye"] = &RaidGruulsLairTriggerContext::high_king_maulgar_pulling_olm_and_blindeye; // Gruul the Dragonkiller - creators["gruul the dragonkiller boss engaged by main tank"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_main_tank; - creators["gruul the dragonkiller boss engaged by range"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_range; + 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; } @@ -41,8 +41,8 @@ private: static Trigger* high_king_maulgar_pulling_olm_and_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarPullingOlmAndBlindeyeTrigger(botAI); } // Gruul the Dragonkiller - static Trigger* gruul_the_dragonkiller_boss_engaged_by_main_tank(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByMainTankTrigger(botAI); } - static Trigger* gruul_the_dragonkiller_boss_engaged_by_range(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByRangeTrigger(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); } }; diff --git a/src/Ai/Raid/GruulsLair/Strategy/RaidGruulsLairStrategy.cpp b/src/Ai/Raid/GruulsLair/Strategy/RaidGruulsLairStrategy.cpp index 9ec264ea..249c8e8a 100644 --- a/src/Ai/Raid/GruulsLair/Strategy/RaidGruulsLairStrategy.cpp +++ b/src/Ai/Raid/GruulsLair/Strategy/RaidGruulsLairStrategy.cpp @@ -35,10 +35,10 @@ void RaidGruulsLairStrategy::InitTriggers(std::vector& triggers) NextAction("high king maulgar misdirect olm and blindeye", ACTION_RAID + 2) })); // Gruul the Dragonkiller - triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by main tank", { - NextAction("gruul the dragonkiller main tank position boss", ACTION_RAID + 1) })); + triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by tanks", { + NextAction("gruul the dragonkiller tanks position boss", ACTION_RAID + 1) })); - triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by range", { + triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by ranged", { NextAction("gruul the dragonkiller spread ranged", ACTION_RAID + 1) })); triggers.push_back(new TriggerNode("gruul the dragonkiller incoming shatter", { diff --git a/src/Ai/Raid/GruulsLair/Trigger/RaidGruulsLairTriggers.cpp b/src/Ai/Raid/GruulsLair/Trigger/RaidGruulsLairTriggers.cpp index 35d9f9a1..4bc5efe9 100644 --- a/src/Ai/Raid/GruulsLair/Trigger/RaidGruulsLairTriggers.cpp +++ b/src/Ai/Raid/GruulsLair/Trigger/RaidGruulsLairTriggers.cpp @@ -10,35 +10,35 @@ bool HighKingMaulgarIsMainTankTrigger::IsActive() { Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar"); - return botAI->IsMainTank(bot) && maulgar && maulgar->IsAlive(); + return botAI->IsMainTank(bot) && maulgar; } bool HighKingMaulgarIsFirstAssistTankTrigger::IsActive() { Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner"); - return botAI->IsAssistTankOfIndex(bot, 0) && olm && olm->IsAlive(); + return botAI->IsAssistTankOfIndex(bot, 0, false) && olm; } bool HighKingMaulgarIsSecondAssistTankTrigger::IsActive() { Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer"); - return botAI->IsAssistTankOfIndex(bot, 1) && blindeye && blindeye->IsAlive(); + return botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye; } bool HighKingMaulgarIsMageTankTrigger::IsActive() { Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); - return IsKroshMageTank(botAI, bot) && krosh && krosh->IsAlive(); + return IsKroshMageTank(botAI, bot) && krosh; } bool HighKingMaulgarIsMoonkinTankTrigger::IsActive() { Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed"); - return IsKigglerMoonkinTank(botAI, bot) && kiggler && kiggler->IsAlive(); + return IsKigglerMoonkinTank(botAI, bot) && kiggler; } bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive() @@ -50,11 +50,11 @@ bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive() Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand"); return (botAI->IsDps(bot) || botAI->IsTank(bot)) && - !(botAI->IsMainTank(bot) && maulgar && maulgar->IsAlive()) && - !(botAI->IsAssistTankOfIndex(bot, 0) && olm && olm->IsAlive()) && - !(botAI->IsAssistTankOfIndex(bot, 1) && blindeye && blindeye->IsAlive()) && - !(IsKroshMageTank(botAI, bot) && krosh && krosh->IsAlive()) && - !(IsKigglerMoonkinTank(botAI, bot) && kiggler && kiggler->IsAlive()); + !(botAI->IsMainTank(bot) && maulgar) && + !(botAI->IsAssistTankOfIndex(bot, 0, false) && olm) && + !(botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye) && + !(IsKroshMageTank(botAI, bot) && krosh) && + !(IsKigglerMoonkinTank(botAI, bot) && kiggler); } bool HighKingMaulgarHealerInDangerTrigger::IsActive() @@ -66,7 +66,7 @@ bool HighKingMaulgarBossChannelingWhirlwindTrigger::IsActive() { Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar"); - return maulgar && maulgar->IsAlive() && maulgar->HasAura(SPELL_WHIRLWIND) && + return maulgar && maulgar->HasAura(SPELL_WHIRLWIND) && !botAI->IsMainTank(bot); } @@ -74,7 +74,7 @@ bool HighKingMaulgarWildFelstalkerSpawnedTrigger::IsActive() { Unit* felStalker = AI_VALUE2(Unit*, "find target", "wild fel stalker"); - return felStalker && felStalker->IsAlive() && bot->getClass() == CLASS_WARLOCK; + return felStalker && bot->getClass() == CLASS_WARLOCK; } bool HighKingMaulgarPullingOlmAndBlindeyeTrigger::IsActive() @@ -120,12 +120,12 @@ bool HighKingMaulgarPullingOlmAndBlindeyeTrigger::IsActive() switch (hunterIndex) { case 0: - return olm && olm->IsAlive() && olm->GetHealthPct() > 98.0f && - olmTank && olmTank->IsAlive() && botAI->CanCastSpell("misdirection", olmTank); + return olm && olm->GetHealthPct() > 98.0f && + olmTank && botAI->CanCastSpell("misdirection", olmTank); case 1: - return blindeye && blindeye->IsAlive() && blindeye->GetHealthPct() > 90.0f && - blindeyeTank && blindeyeTank->IsAlive() && botAI->CanCastSpell("misdirection", blindeyeTank); + return blindeye && blindeye->GetHealthPct() > 90.0f && + blindeyeTank && botAI->CanCastSpell("misdirection", blindeyeTank); default: break; @@ -136,25 +136,24 @@ bool HighKingMaulgarPullingOlmAndBlindeyeTrigger::IsActive() // Gruul the Dragonkiller Triggers -bool GruulTheDragonkillerBossEngagedByMainTankTrigger::IsActive() +bool GruulTheDragonkillerBossEngagedByTanksTrigger::IsActive() { Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); - return gruul && gruul->IsAlive() && botAI->IsMainTank(bot); + return gruul && botAI->IsTank(bot); } -bool GruulTheDragonkillerBossEngagedByRangeTrigger::IsActive() +bool GruulTheDragonkillerBossEngagedByRangedTrigger::IsActive() { Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); - return gruul && gruul->IsAlive() && botAI->IsRanged(bot); + return gruul && botAI->IsRanged(bot); } bool GruulTheDragonkillerIncomingShatterTrigger::IsActive() { Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller"); - return gruul && gruul->IsAlive() && - (bot->HasAura(SPELL_GROUND_SLAM_1) || - bot->HasAura(SPELL_GROUND_SLAM_2)); + return gruul && (bot->HasAura(SPELL_GROUND_SLAM_1) || + bot->HasAura(SPELL_GROUND_SLAM_2)); } diff --git a/src/Ai/Raid/GruulsLair/Trigger/RaidGruulsLairTriggers.h b/src/Ai/Raid/GruulsLair/Trigger/RaidGruulsLairTriggers.h index f3f32853..583b8b75 100644 --- a/src/Ai/Raid/GruulsLair/Trigger/RaidGruulsLairTriggers.h +++ b/src/Ai/Raid/GruulsLair/Trigger/RaidGruulsLairTriggers.h @@ -73,17 +73,17 @@ public: bool IsActive() override; }; -class GruulTheDragonkillerBossEngagedByMainTankTrigger : public Trigger +class GruulTheDragonkillerBossEngagedByTanksTrigger : public Trigger { public: - GruulTheDragonkillerBossEngagedByMainTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by main tank") {} + GruulTheDragonkillerBossEngagedByTanksTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by tanks") {} bool IsActive() override; }; -class GruulTheDragonkillerBossEngagedByRangeTrigger : public Trigger +class GruulTheDragonkillerBossEngagedByRangedTrigger : public Trigger { public: - GruulTheDragonkillerBossEngagedByRangeTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by range") {} + GruulTheDragonkillerBossEngagedByRangedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by ranged") {} bool IsActive() override; }; diff --git a/src/Ai/Raid/GruulsLair/Util/RaidGruulsLairHelpers.cpp b/src/Ai/Raid/GruulsLair/Util/RaidGruulsLairHelpers.cpp index 0c8a23a1..27c703ae 100644 --- a/src/Ai/Raid/GruulsLair/Util/RaidGruulsLairHelpers.cpp +++ b/src/Ai/Raid/GruulsLair/Util/RaidGruulsLairHelpers.cpp @@ -6,19 +6,16 @@ namespace GruulsLairHelpers { - namespace GruulsLairLocations - { - // 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 Location MaulgarTankPosition = { 90.686f, 167.047f, -13.234f }; - const Location OlmTankPosition = { 87.485f, 234.942f, -3.635f }; - const Location BlindeyeTankPosition = { 99.681f, 213.989f, -10.345f }; - const Location KroshTankPosition = { 116.880f, 166.208f, -14.231f }; - const Location MaulgarRoomCenter = { 88.754f, 150.759f, -11.569f }; - const Location GruulTankPosition = { 241.238f, 365.025f, -4.220f }; - } + // 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) { @@ -42,84 +39,43 @@ namespace GruulsLairHelpers return false; } - void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId) - { - Group* group = bot->GetGroup(); - if (!target || !group) - return; - - ObjectGuid currentGuid = group->GetTargetIcon(iconId); - if (currentGuid != target->GetGUID()) - { - group->SetTargetIcon(iconId, bot->GetGUID(), target->GetGUID()); - } - } - - void MarkTargetWithSquare(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::squareIndex); - } - - void MarkTargetWithStar(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::starIndex); - } - - void MarkTargetWithCircle(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::circleIndex); - } - - void MarkTargetWithDiamond(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::diamondIndex); - } - - void MarkTargetWithTriangle(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::triangleIndex); - } - - void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target) - { - if (!target) - return; - - std::string currentRti = botAI->GetAiObjectContext()->GetValue("rti")->Get(); - Unit* currentTarget = botAI->GetAiObjectContext()->GetValue("rti target")->Get(); - - if (currentRti != rtiName || currentTarget != target) - { - botAI->GetAiObjectContext()->GetValue("rti")->Set(rtiName); - botAI->GetAiObjectContext()->GetValue("rti target")->Set(target); - } - } - bool IsKroshMageTank(PlayerbotAI* botAI, Player* bot) { Group* group = bot->GetGroup(); if (!group) return false; - Player* highestHpMage = nullptr; - uint32 highestHp = 0; + // (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)) + if (!member || !member->IsAlive() || member->getClass() != CLASS_MAGE) continue; - if (member->getClass() == CLASS_MAGE) + if (group->IsAssistant(member->GetGUID())) + return member == 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()) + { + 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) { - 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; } @@ -129,30 +85,37 @@ namespace GruulsLairHelpers if (!group) return false; - Player* highestHpMoonkin = nullptr; - uint32 highestHp = 0; - + // (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() || !GET_PLAYERBOT_AI(member)) + if (!member || !member->IsAlive() || member->getClass() != CLASS_DRUID) continue; - if (member->getClass() == CLASS_DRUID) + 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) { - int tab = AiFactory::GetPlayerSpecTab(member); - if (tab == DRUID_TAB_BALANCE) - { - uint32 hp = member->GetMaxHealth(); - if (!highestHpMoonkin || hp > highestHp) - { - highestHpMoonkin = member; - highestHp = hp; - } - } + highestHpMoonkin = member; + highestHp = hp; } } + // (3) Return the found Moonkin tank, or nullptr if none found return highestHpMoonkin == bot; } diff --git a/src/Ai/Raid/GruulsLair/Util/RaidGruulsLairHelpers.h b/src/Ai/Raid/GruulsLair/Util/RaidGruulsLairHelpers.h index c7becc83..4615a9b7 100644 --- a/src/Ai/Raid/GruulsLair/Util/RaidGruulsLairHelpers.h +++ b/src/Ai/Raid/GruulsLair/Util/RaidGruulsLairHelpers.h @@ -2,23 +2,19 @@ #define RAID_GRUULSLAIRHELPERS_H #include "PlayerbotAI.h" -#include "RtiTargetValue.h" namespace GruulsLairHelpers { enum GruulsLairSpells { // High King Maulgar - SPELL_WHIRLWIND = 33238, + SPELL_WHIRLWIND = 33238, // Krosh Firehand - SPELL_SPELL_SHIELD = 33054, + SPELL_SPELL_SHIELD = 33054, // Hunter - SPELL_MISDIRECTION = 35079, - - // Warlock - SPELL_BANISH = 18647, // Rank 2 + SPELL_MISDIRECTION = 35079, // Gruul the Dragonkiller SPELL_GROUND_SLAM_1 = 33525, @@ -30,33 +26,20 @@ namespace GruulsLairHelpers NPC_WILD_FEL_STALKER = 18847, }; + constexpr uint32 GRUULS_LAIR_MAP_ID = 565; + bool IsAnyOgreBossAlive(PlayerbotAI* botAI); - void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId); - void MarkTargetWithSquare(Player* bot, Unit* target); - void MarkTargetWithStar(Player* bot, Unit* target); - void MarkTargetWithCircle(Player* bot, Unit* target); - void MarkTargetWithDiamond(Player* bot, Unit* target); - void MarkTargetWithTriangle(Player* bot, Unit* target); - void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target); bool IsKroshMageTank(PlayerbotAI* botAI, Player* bot); bool IsKigglerMoonkinTank(PlayerbotAI* botAI, Player* bot); bool IsPositionSafe(PlayerbotAI* botAI, Player* bot, Position pos); bool TryGetNewSafePosition(PlayerbotAI* botAI, Player* bot, Position& outPos); - struct Location - { - float x, y, z; - }; - - namespace GruulsLairLocations - { - extern const Location MaulgarTankPosition; - extern const Location OlmTankPosition; - extern const Location BlindeyeTankPosition; - extern const Location KroshTankPosition; - extern const Location MaulgarRoomCenter; - extern const Location GruulTankPosition; - } + 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/Icecrown/RaidIccScripts.h b/src/Ai/Raid/Icecrown/Util/RaidIccScripts.h similarity index 100% rename from src/Ai/Raid/Icecrown/RaidIccScripts.h rename to src/Ai/Raid/Icecrown/Util/RaidIccScripts.h diff --git a/src/Ai/Raid/Karazhan/Action/RaidKarazhanActions.cpp b/src/Ai/Raid/Karazhan/Action/RaidKarazhanActions.cpp index adf0eac4..4d40a9ee 100644 --- a/src/Ai/Raid/Karazhan/Action/RaidKarazhanActions.cpp +++ b/src/Ai/Raid/Karazhan/Action/RaidKarazhanActions.cpp @@ -2,6 +2,7 @@ #include "RaidKarazhanHelpers.h" #include "Playerbots.h" #include "PlayerbotTextMgr.h" +#include "RaidBossHelpers.h" using namespace KarazhanHelpers; @@ -44,7 +45,7 @@ bool AttumenTheHuntsmanMarkTargetAction::Execute(Event event) Unit* attumenMounted = GetFirstAliveUnitByEntry(botAI, NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED); if (attumenMounted) { - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) MarkTargetWithStar(bot, attumenMounted); SetRtiTarget(botAI, "star", attumenMounted); @@ -57,7 +58,7 @@ bool AttumenTheHuntsmanMarkTargetAction::Execute(Event event) } else if (Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight")) { - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) MarkTargetWithStar(bot, midnight); if (!botAI->IsAssistTankOfIndex(bot, 0)) @@ -180,7 +181,7 @@ bool MoroesMarkTargetAction::Execute(Event event) if (target) { - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) MarkTargetWithSkull(bot, target); SetRtiTarget(botAI, "skull", target); @@ -405,7 +406,7 @@ bool TheCuratorMarkAstralFlareAction::Execute(Event event) if (!flare) return false; - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) MarkTargetWithSkull(bot, flare); SetRtiTarget(botAI, "skull", flare); @@ -469,11 +470,11 @@ bool TheCuratorSpreadRangedAction::Execute(Event event) // Prioritize (1) Demon Chains, (2) Kil'rek, (3) Illhoof bool TerestianIllhoofMarkTargetAction::Execute(Event event) { - Unit* demonChains = AI_VALUE2(Unit*, "find target", "demon chains"); - Unit* kilrek = AI_VALUE2(Unit*, "find target", "kil'rek"); + Unit* demonChains = GetFirstAliveUnitByEntry(botAI, NPC_DEMON_CHAINS); + Unit* kilrek = GetFirstAliveUnitByEntry(botAI, NPC_KILREK); Unit* illhoof = AI_VALUE2(Unit*, "find target", "terestian illhoof"); - Unit* target = GetFirstAliveUnit({demonChains, kilrek, illhoof}); + Unit* target = GetFirstAliveUnit({demonChains, kilrek, illhoof}); if (target) MarkTargetWithSkull(bot, target); @@ -1007,7 +1008,7 @@ bool NetherspiteManageTimersAndTrackersAction::Execute(Event event) if (netherspite->GetHealth() == netherspite->GetMaxHealth() && !netherspite->HasAura(SPELL_GREEN_BEAM_HEAL)) { - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) netherspiteDpsWaitTimer.insert_or_assign(instanceId, now); if (botAI->IsTank(bot) && !bot->HasAura(SPELL_RED_BEAM_DEBUFF)) @@ -1018,7 +1019,7 @@ bool NetherspiteManageTimersAndTrackersAction::Execute(Event event) } else if (netherspite->HasAura(SPELL_NETHERSPITE_BANISHED)) { - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) netherspiteDpsWaitTimer.erase(instanceId); if (botAI->IsTank(bot)) @@ -1029,7 +1030,7 @@ bool NetherspiteManageTimersAndTrackersAction::Execute(Event event) } else if (!netherspite->HasAura(SPELL_NETHERSPITE_BANISHED)) { - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) netherspiteDpsWaitTimer.try_emplace(instanceId, now); if (botAI->IsTank(bot) && bot->HasAura(SPELL_RED_BEAM_DEBUFF)) @@ -1458,7 +1459,7 @@ bool NightbaneManageTimersAndTrackersAction::Execute(Event event) if (botAI->IsRanged(bot)) nightbaneRangedStep.erase(botGuid); - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) nightbaneDpsWaitTimer.erase(instanceId); } // Erase flight phase timer and Rain of Bones tracker on ground phase and start DPS wait timer @@ -1466,7 +1467,7 @@ bool NightbaneManageTimersAndTrackersAction::Execute(Event event) { nightbaneRainOfBonesHit.erase(botGuid); - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) { nightbaneFlightPhaseStartTimer.erase(instanceId); nightbaneDpsWaitTimer.try_emplace(instanceId, now); @@ -1482,7 +1483,7 @@ bool NightbaneManageTimersAndTrackersAction::Execute(Event event) if (botAI->IsRanged(bot)) nightbaneRangedStep.erase(botGuid); - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) { nightbaneDpsWaitTimer.erase(instanceId); nightbaneFlightPhaseStartTimer.try_emplace(instanceId, now); diff --git a/src/Ai/Raid/Karazhan/Multiplier/RaidKarazhanMultipliers.cpp b/src/Ai/Raid/Karazhan/Multiplier/RaidKarazhanMultipliers.cpp index 117a17f3..06a3335c 100644 --- a/src/Ai/Raid/Karazhan/Multiplier/RaidKarazhanMultipliers.cpp +++ b/src/Ai/Raid/Karazhan/Multiplier/RaidKarazhanMultipliers.cpp @@ -10,6 +10,7 @@ #include "MageActions.h" #include "Playerbots.h" #include "PriestActions.h" +#include "RaidBossHelpers.h" #include "ReachTargetActions.h" #include "RogueActions.h" #include "ShamanActions.h" @@ -242,6 +243,9 @@ float PrinceMalchezaarEnfeebleKeepDistanceMultiplier::GetValue(Action* action) if (bot->HasAura(SPELL_ENFEEBLE)) { + if (dynamic_cast(action)) + return 0.0f; + if (dynamic_cast(action) && !dynamic_cast(action)) return 0.0f; diff --git a/src/Ai/Raid/Karazhan/Trigger/RaidKarazhanTriggers.cpp b/src/Ai/Raid/Karazhan/Trigger/RaidKarazhanTriggers.cpp index 2fb7d5af..3c43aa89 100644 --- a/src/Ai/Raid/Karazhan/Trigger/RaidKarazhanTriggers.cpp +++ b/src/Ai/Raid/Karazhan/Trigger/RaidKarazhanTriggers.cpp @@ -2,6 +2,7 @@ #include "RaidKarazhanHelpers.h" #include "RaidKarazhanActions.h" #include "Playerbots.h" +#include "RaidBossHelpers.h" using namespace KarazhanHelpers; @@ -40,7 +41,7 @@ bool AttumenTheHuntsmanAttumenIsMountedTrigger::IsActive() bool AttumenTheHuntsmanBossWipesAggroWhenMountingTrigger::IsActive() { - if (!IsInstanceTimerManager(botAI, bot)) + if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) return false; Unit* midnight = AI_VALUE2(Unit*, "find target", "midnight"); @@ -110,7 +111,7 @@ bool BigBadWolfBossIsChasingLittleRedRidingHoodTrigger::IsActive() bool RomuloAndJulianneBothBossesRevivedTrigger::IsActive() { - if (!IsInstanceTimerManager(botAI, bot)) + if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) return false; Unit* romulo = AI_VALUE2(Unit*, "find target", "romulo"); @@ -126,7 +127,7 @@ bool RomuloAndJulianneBothBossesRevivedTrigger::IsActive() bool WizardOfOzNeedTargetPriorityTrigger::IsActive() { - if (!IsInstanceTimerManager(botAI, bot)) + if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) return false; Unit* dorothee = AI_VALUE2(Unit*, "find target", "dorothee"); @@ -178,7 +179,7 @@ bool TheCuratorBossAstralFlaresCastArcingSearTrigger::IsActive() bool TerestianIllhoofNeedTargetPriorityTrigger::IsActive() { - if (!IsInstanceTimerManager(botAI, bot)) + if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) return false; Unit* illhoof = AI_VALUE2(Unit*, "find target", "terestian illhoof"); @@ -202,7 +203,7 @@ bool ShadeOfAranFlameWreathIsActiveTrigger::IsActive() // Exclusion of Banish is so the player may Banish elementals if they wish bool ShadeOfAranConjuredElementalsSummonedTrigger::IsActive() { - if (!IsInstanceTimerManager(botAI, bot)) + if (!IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) return false; Unit* elemental = AI_VALUE2(Unit*, "find target", "conjured elemental"); @@ -279,7 +280,7 @@ bool NetherspiteBossIsBanishedTrigger::IsActive() bool NetherspiteNeedToManageTimersAndTrackersTrigger::IsActive() { - if (!botAI->IsTank(bot) && !IsInstanceTimerManager(botAI, bot)) + if (!botAI->IsTank(bot) && !IsMechanicTrackerBot(botAI, bot, KARAZHAN_MAP_ID, nullptr)) return false; Unit* netherspite = AI_VALUE2(Unit*, "find target", "netherspite"); diff --git a/src/Ai/Raid/Karazhan/Util/RaidKarazhanHelpers.cpp b/src/Ai/Raid/Karazhan/Util/RaidKarazhanHelpers.cpp index 821cc670..ea989dcf 100644 --- a/src/Ai/Raid/Karazhan/Util/RaidKarazhanHelpers.cpp +++ b/src/Ai/Raid/Karazhan/Util/RaidKarazhanHelpers.cpp @@ -1,7 +1,6 @@ #include "RaidKarazhanHelpers.h" #include "RaidKarazhanActions.h" #include "Playerbots.h" -#include "RtiTargetValue.h" namespace KarazhanHelpers { @@ -52,75 +51,6 @@ namespace KarazhanHelpers const Position NIGHTBANE_FLIGHT_STACK_POSITION = { -11159.555f, -1893.526f, 91.473f }; // Broken Barrel const Position NIGHTBANE_RAIN_OF_BONES_POSITION = { -11165.233f, -1911.123f, 91.473f }; - void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId) - { - if (!target) - return; - - if (Group* group = bot->GetGroup()) - { - ObjectGuid currentGuid = group->GetTargetIcon(iconId); - if (currentGuid != target->GetGUID()) - group->SetTargetIcon(iconId, bot->GetGUID(), target->GetGUID()); - } - } - - void MarkTargetWithSkull(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::skullIndex); - } - - void MarkTargetWithSquare(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::squareIndex); - } - - void MarkTargetWithStar(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::starIndex); - } - - void MarkTargetWithCircle(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::circleIndex); - } - - void MarkTargetWithMoon(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::moonIndex); - } - - void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target) - { - if (!target) - return; - - std::string currentRti = botAI->GetAiObjectContext()->GetValue("rti")->Get(); - Unit* currentTarget = botAI->GetAiObjectContext()->GetValue("rti target")->Get(); - - if (currentRti != rtiName || currentTarget != target) - { - botAI->GetAiObjectContext()->GetValue("rti")->Set(rtiName); - botAI->GetAiObjectContext()->GetValue("rti target")->Set(target); - } - } - - // Only one bot is needed to set/reset instance-wide timers - bool IsInstanceTimerManager(PlayerbotAI* botAI, Player* bot) - { - if (Group* group = bot->GetGroup()) - { - for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) - { - Player* member = ref->GetSource(); - if (member && member->IsAlive() && botAI->IsDps(member) && GET_PLAYERBOT_AI(member)) - return member == bot; - } - } - - return false; - } - Unit* GetFirstAliveUnit(const std::vector& units) { for (Unit* unit : units) @@ -132,44 +62,6 @@ namespace KarazhanHelpers return nullptr; } - Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry) - { - const GuidVector npcs = botAI->GetAiObjectContext()->GetValue("nearest hostile npcs")->Get(); - for (auto const& npcGuid : npcs) - { - Unit* unit = botAI->GetUnit(npcGuid); - if (unit && unit->IsAlive() && unit->GetEntry() == entry) - return unit; - } - - return nullptr; - } - - Unit* GetNearestPlayerInRadius(Player* bot, float radius) - { - Unit* nearestPlayer = nullptr; - float nearestDistance = radius; - - if (Group* group = bot->GetGroup()) - { - for (GroupReference* ref = group->GetFirstMember(); ref != nullptr; ref = ref->next()) - { - Player* member = ref->GetSource(); - if (!member || !member->IsAlive() || member == bot) - continue; - - float distance = bot->GetExactDist2d(member); - if (distance < nearestDistance) - { - nearestDistance = distance; - nearestPlayer = member; - } - } - } - - return nearestPlayer; - } - bool IsFlameWreathActive(PlayerbotAI* botAI, Player* bot) { Unit* aran = botAI->GetAiObjectContext()->GetValue("find target", "shade of aran")->Get(); diff --git a/src/Ai/Raid/Karazhan/Util/RaidKarazhanHelpers.h b/src/Ai/Raid/Karazhan/Util/RaidKarazhanHelpers.h index 394693b2..ad7e8c3d 100644 --- a/src/Ai/Raid/Karazhan/Util/RaidKarazhanHelpers.h +++ b/src/Ai/Raid/Karazhan/Util/RaidKarazhanHelpers.h @@ -61,6 +61,11 @@ namespace KarazhanHelpers NPC_ATTUMEN_THE_HUNTSMAN = 15550, NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED = 16152, + // Terestian Illhoof + NPC_TERESTIAN_ILLHOOF = 15688, + NPC_DEMON_CHAINS = 17248, + NPC_KILREK = 17229, + // Shade of Aran NPC_CONJURED_ELEMENTAL = 17167, @@ -74,8 +79,8 @@ namespace KarazhanHelpers NPC_NETHERSPITE_INFERNAL = 17646, }; - const uint32 KARAZHAN_MAP_ID = 532; - const float NIGHTBANE_FLIGHT_Z = 95.0f; + constexpr uint32 KARAZHAN_MAP_ID = 532; + constexpr float NIGHTBANE_FLIGHT_Z = 95.0f; // Attumen the Huntsman extern std::unordered_map attumenDpsWaitTimer; @@ -105,17 +110,7 @@ namespace KarazhanHelpers extern const Position NIGHTBANE_FLIGHT_STACK_POSITION; extern const Position NIGHTBANE_RAIN_OF_BONES_POSITION; - void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId); - void MarkTargetWithSkull(Player* bot, Unit* target); - void MarkTargetWithSquare(Player* bot, Unit* target); - void MarkTargetWithStar(Player* bot, Unit* target); - void MarkTargetWithCircle(Player* bot, Unit* target); - void MarkTargetWithMoon(Player* bot, Unit* target); - void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target); - bool IsInstanceTimerManager(PlayerbotAI* botAI, Player* bot); Unit* GetFirstAliveUnit(const std::vector& units); - Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry); - Unit* GetNearestPlayerInRadius(Player* bot, float radius); bool IsFlameWreathActive(PlayerbotAI* botAI, Player* bot); std::vector GetRedBlockers(PlayerbotAI* botAI, Player* bot); std::vector GetBlueBlockers(PlayerbotAI* botAI, Player* bot); diff --git a/src/Ai/Raid/Magtheridon/Action/RaidMagtheridonActions.cpp b/src/Ai/Raid/Magtheridon/Action/RaidMagtheridonActions.cpp index 69fc8624..dab7efab 100644 --- a/src/Ai/Raid/Magtheridon/Action/RaidMagtheridonActions.cpp +++ b/src/Ai/Raid/Magtheridon/Action/RaidMagtheridonActions.cpp @@ -4,6 +4,7 @@ #include "ObjectAccessor.h" #include "ObjectGuid.h" #include "Playerbots.h" +#include "RaidBossHelpers.h" using namespace MagtheridonHelpers; @@ -14,46 +15,45 @@ bool MagtheridonMainTankAttackFirstThreeChannelersAction::Execute(Event event) return false; Creature* channelerSquare = GetChanneler(bot, SOUTH_CHANNELER); - if (channelerSquare && channelerSquare->IsAlive()) + if (channelerSquare) MarkTargetWithSquare(bot, channelerSquare); Creature* channelerStar = GetChanneler(bot, WEST_CHANNELER); - if (channelerStar && channelerStar->IsAlive()) + if (channelerStar) MarkTargetWithStar(bot, channelerStar); Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER); - if (channelerCircle && channelerCircle->IsAlive()) + if (channelerCircle) MarkTargetWithCircle(bot, channelerCircle); // After first three channelers are dead, wait for Magtheridon to activate - if ((!channelerSquare || !channelerSquare->IsAlive()) && - (!channelerStar || !channelerStar->IsAlive()) && - (!channelerCircle || !channelerCircle->IsAlive())) + if (!channelerSquare && !channelerStar && !channelerCircle) { - const Location& position = MagtheridonsLairLocations::WaitingForMagtheridonPosition; - if (!bot->IsWithinDist2d(position.x, position.y, 2.0f)) + const Position& position = WAITING_FOR_MAGTHERIDON_POSITION; + if (!bot->IsWithinDist2d(position.GetPositionX(), position.GetPositionY(), 2.0f)) { - return MoveTo(bot->GetMapId(), position.x, position.y, position.z, false, false, false, false, + return MoveTo(MAGTHERIDON_MAP_ID, position.GetPositionX(), position.GetPositionY(), + position.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } - bot->SetFacingTo(position.orientation); + bot->SetFacingTo(position.GetOrientation()); return true; } Creature* currentTarget = nullptr; std::string rtiName; - if (channelerSquare && channelerSquare->IsAlive()) + if (channelerSquare) { currentTarget = channelerSquare; rtiName = "square"; } - else if (channelerStar && channelerStar->IsAlive()) + else if (channelerStar) { currentTarget = channelerStar; rtiName = "star"; } - else if (channelerCircle && channelerCircle->IsAlive()) + else if (channelerCircle) { currentTarget = channelerCircle; rtiName = "circle"; @@ -70,7 +70,7 @@ bool MagtheridonMainTankAttackFirstThreeChannelersAction::Execute(Event event) bool MagtheridonFirstAssistTankAttackNWChannelerAction::Execute(Event event) { Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER); - if (!channelerDiamond || !channelerDiamond->IsAlive()) + if (!channelerDiamond) return false; MarkTargetWithDiamond(bot, channelerDiamond); @@ -81,18 +81,18 @@ bool MagtheridonFirstAssistTankAttackNWChannelerAction::Execute(Event event) if (channelerDiamond->GetVictim() == bot) { - const Location& position = MagtheridonsLairLocations::NWChannelerTankPosition; + const Position& position = NW_CHANNELER_TANK_POSITION; const float maxDistance = 3.0f; + float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - if (bot->GetExactDist2d(position.x, position.y) > maxDistance) + if (distanceToPosition > maxDistance) { - float dX = position.x - bot->GetPositionX(); - float dY = position.y - bot->GetPositionY(); - float dist = sqrt(dX * dX + dY * dY); - float moveX = bot->GetPositionX() + (dX / dist) * maxDistance; - float moveY = bot->GetPositionY() + (dY / dist) * maxDistance; + 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(bot->GetMapId(), moveX, moveY, position.z, false, false, false, false, + return MoveTo(MAGTHERIDON_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } } @@ -103,7 +103,7 @@ bool MagtheridonFirstAssistTankAttackNWChannelerAction::Execute(Event event) bool MagtheridonSecondAssistTankAttackNEChannelerAction::Execute(Event event) { Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER); - if (!channelerTriangle || !channelerTriangle->IsAlive()) + if (!channelerTriangle) return false; MarkTargetWithTriangle(bot, channelerTriangle); @@ -114,18 +114,18 @@ bool MagtheridonSecondAssistTankAttackNEChannelerAction::Execute(Event event) if (channelerTriangle->GetVictim() == bot) { - const Location& position = MagtheridonsLairLocations::NEChannelerTankPosition; + const Position& position = NE_CHANNELER_TANK_POSITION; const float maxDistance = 3.0f; + float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - if (bot->GetExactDist2d(position.x, position.y) > maxDistance) + if (distanceToPosition > maxDistance) { - float dX = position.x - bot->GetPositionX(); - float dY = position.y - bot->GetPositionY(); - float dist = sqrt(dX * dX + dY * dY); - float moveX = bot->GetPositionX() + (dX / dist) * maxDistance; - float moveY = bot->GetPositionY() + (dY / dist) * maxDistance; + 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(bot->GetMapId(), moveX, moveY, position.z, false, false, false, false, + return MoveTo(MAGTHERIDON_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } } @@ -175,7 +175,7 @@ bool MagtheridonMisdirectHellfireChannelers::Execute(Event event) switch (hunterIndex) { case 0: - if (mainTank && channelerStar && channelerStar->IsAlive() && + if (mainTank && channelerStar && channelerStar->GetVictim() != mainTank) { if (botAI->CanCastSpell("misdirection", mainTank)) @@ -190,7 +190,7 @@ bool MagtheridonMisdirectHellfireChannelers::Execute(Event event) break; case 1: - if (mainTank && channelerCircle && channelerCircle->IsAlive() && + if (mainTank && channelerCircle && channelerCircle->GetVictim() != mainTank) { if (botAI->CanCastSpell("misdirection", mainTank)) @@ -215,90 +215,69 @@ bool MagtheridonAssignDPSPriorityAction::Execute(Event event) { // Listed in order of priority Creature* channelerSquare = GetChanneler(bot, SOUTH_CHANNELER); - if (channelerSquare && channelerSquare->IsAlive()) + if (channelerSquare) { SetRtiTarget(botAI, "square", channelerSquare); if (bot->GetTarget() != channelerSquare->GetGUID()) - { - bot->SetSelection(channelerSquare->GetGUID()); return Attack(channelerSquare); - } return false; } Creature* channelerStar = GetChanneler(bot, WEST_CHANNELER); - if (channelerStar && channelerStar->IsAlive()) + if (channelerStar) { SetRtiTarget(botAI, "star", channelerStar); if (bot->GetTarget() != channelerStar->GetGUID()) - { - bot->SetSelection(channelerStar->GetGUID()); return Attack(channelerStar); - } return false; } Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER); - if (channelerCircle && channelerCircle->IsAlive()) + if (channelerCircle) { SetRtiTarget(botAI, "circle", channelerCircle); if (bot->GetTarget() != channelerCircle->GetGUID()) - { - bot->SetSelection(channelerCircle->GetGUID()); return Attack(channelerCircle); - } return false; } Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER); - if (channelerDiamond && channelerDiamond->IsAlive()) + if (channelerDiamond) { SetRtiTarget(botAI, "diamond", channelerDiamond); if (bot->GetTarget() != channelerDiamond->GetGUID()) - { - bot->SetSelection(channelerDiamond->GetGUID()); return Attack(channelerDiamond); - } return false; } Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER); - if (channelerTriangle && channelerTriangle->IsAlive()) + if (channelerTriangle) { SetRtiTarget(botAI, "triangle", channelerTriangle); if (bot->GetTarget() != channelerTriangle->GetGUID()) - { - bot->SetSelection(channelerTriangle->GetGUID()); return Attack(channelerTriangle); - } return false; } Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon"); if (magtheridon && !magtheridon->HasAura(SPELL_SHADOW_CAGE) && - (!channelerSquare || !channelerSquare->IsAlive()) && - (!channelerStar || !channelerStar->IsAlive()) && - (!channelerCircle || !channelerCircle->IsAlive()) && - (!channelerDiamond || !channelerDiamond->IsAlive()) && - (!channelerTriangle || !channelerTriangle->IsAlive())) + !channelerSquare && !channelerStar && !channelerCircle && + !channelerDiamond && !channelerTriangle) { SetRtiTarget(botAI, "cross", magtheridon); if (bot->GetTarget() != magtheridon->GetGUID()) - { - bot->SetSelection(magtheridon->GetGUID()); return Attack(magtheridon); - } } return false; @@ -343,15 +322,15 @@ bool MagtheridonWarlockCCBurningAbyssalAction::Execute(Event event) if (warlockIndex >= 0 && warlockIndex < abyssals.size()) { Unit* assignedAbyssal = abyssals[warlockIndex]; - if (!assignedAbyssal->HasAura(SPELL_BANISH) && botAI->CanCastSpell(SPELL_BANISH, assignedAbyssal, true)) + if (!botAI->HasAura("banish", assignedAbyssal) && botAI->CanCastSpell("banish", assignedAbyssal)) return botAI->CastSpell("banish", assignedAbyssal); } for (size_t i = warlocks.size(); i < abyssals.size(); ++i) { Unit* excessAbyssal = abyssals[i]; - if (!excessAbyssal->HasAura(SPELL_BANISH) && !excessAbyssal->HasAura(SPELL_FEAR) && - botAI->CanCastSpell(SPELL_FEAR, excessAbyssal, true)) + if (!botAI->HasAura("banish", excessAbyssal) && !botAI->HasAura("fear", excessAbyssal) && + botAI->CanCastSpell("fear", excessAbyssal)) return botAI->CastSpell("fear", excessAbyssal); } @@ -373,22 +352,20 @@ bool MagtheridonMainTankPositionBossAction::Execute(Event event) if (magtheridon->GetVictim() == bot) { - const Location& position = MagtheridonsLairLocations::MagtheridonTankPosition; + const Position& position = MAGTHERIDON_TANK_POSITION; const float maxDistance = 2.0f; + float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()); - if (bot->GetExactDist2d(position.x, position.y) > maxDistance) + if (distanceToPosition > maxDistance) { - float dX = position.x - bot->GetPositionX(); - float dY = position.y - bot->GetPositionY(); - float dist = sqrt(dX * dX + dY * dY); - float moveX = bot->GetPositionX() + (dX / dist) * maxDistance; - float moveY = bot->GetPositionY() + (dY / dist) * maxDistance; + 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(bot->GetMapId(), moveX, moveY, position.z, false, false, false, false, + return MoveTo(MAGTHERIDON_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, true); } - - bot->SetFacingTo(position.orientation); } return false; @@ -440,13 +417,13 @@ bool MagtheridonSpreadRangedAction::Execute(Event event) } bool isHealer = botAI->IsHeal(bot); - const Location& center = isHealer - ? MagtheridonsLairLocations::HealerSpreadPosition - : MagtheridonsLairLocations::RangedSpreadPosition; + const Position& center = isHealer + ? HEALER_SPREAD_POSITION + : RANGED_SPREAD_POSITION; float maxSpreadRadius = isHealer ? 15.0f : 20.0f; - float centerX = center.x; - float centerY = center.y; - float centerZ = bot->GetPositionZ(); + float centerX = center.GetPositionX(); + float centerY = center.GetPositionY(); + float centerZ = center.GetPositionZ(); const float radiusBuffer = 3.0f; if (!initialPositions.count(bot->GetGUID())) @@ -479,7 +456,7 @@ bool MagtheridonSpreadRangedAction::Execute(Event event) bot->AttackStop(); bot->InterruptNonMeleeSpells(false); - return MoveTo(bot->GetMapId(), destX, destY, destZ, false, false, false, false, + return MoveTo(MAGTHERIDON_MAP_ID, destX, destY, destZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } hasReachedInitialPosition[bot->GetGUID()] = true; @@ -499,7 +476,7 @@ bool MagtheridonSpreadRangedAction::Execute(Event event) { bot->AttackStop(); bot->InterruptNonMeleeSpells(false); - return MoveTo(bot->GetMapId(), targetX, targetY, centerZ, false, false, false, false, + return MoveTo(MAGTHERIDON_MAP_ID, targetX, targetY, centerZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } } @@ -593,7 +570,7 @@ bool MagtheridonUseManticronCubeAction::HandleWaitingPhase(const CubeInfo& cubeI { bot->AttackStop(); bot->InterruptNonMeleeSpells(true); - return MoveTo(bot->GetMapId(), targetX, targetY, targetZ, false, false, false, false, + return MoveTo(MAGTHERIDON_MAP_ID, targetX, targetY, targetZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } } @@ -603,7 +580,7 @@ bool MagtheridonUseManticronCubeAction::HandleWaitingPhase(const CubeInfo& cubeI float fallbackY = cubeInfo.y + sin(angle) * safeWaitDistance; float fallbackZ = bot->GetPositionZ(); - return MoveTo(bot->GetMapId(), fallbackX, fallbackY, fallbackZ, false, false, false, false, + return MoveTo(MAGTHERIDON_MAP_ID, fallbackX, fallbackY, fallbackZ, false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); } @@ -638,7 +615,7 @@ bool MagtheridonUseManticronCubeAction::HandleCubeInteraction(const CubeInfo& cu bot->AttackStop(); bot->InterruptNonMeleeSpells(true); - return MoveTo(bot->GetMapId(), targetX, targetY, targetZ, false, false, false, false, + return MoveTo(MAGTHERIDON_MAP_ID, targetX, targetY, targetZ, false, false, false, false, MovementPriority::MOVEMENT_FORCED, true, false); } @@ -663,14 +640,14 @@ bool MagtheridonManageTimersAndAssignmentsAction::Execute(Event event) magtheridon->FindCurrentSpellBySpellId(SPELL_BLAST_NOVA); bool lastBlastNova = lastBlastNovaState[instanceId]; - if (lastBlastNova && !blastNovaActive && IsInstanceTimerManager(botAI, bot)) + if (lastBlastNova && !blastNovaActive && IsMechanicTrackerBot(botAI, bot, MAGTHERIDON_MAP_ID, nullptr)) blastNovaTimer[instanceId] = now; lastBlastNovaState[instanceId] = blastNovaActive; if (!magtheridon->HasAura(SPELL_SHADOW_CAGE)) { - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, MAGTHERIDON_MAP_ID, nullptr)) { spreadWaitTimer.try_emplace(instanceId, now); blastNovaTimer.try_emplace(instanceId, now); @@ -679,11 +656,12 @@ bool MagtheridonManageTimersAndAssignmentsAction::Execute(Event event) } else { - MagtheridonSpreadRangedAction::initialPositions.clear(); - MagtheridonSpreadRangedAction::hasReachedInitialPosition.clear(); - botToCubeAssignment.clear(); + ObjectGuid guid = bot->GetGUID(); + MagtheridonSpreadRangedAction::initialPositions.erase(guid); + MagtheridonSpreadRangedAction::hasReachedInitialPosition.erase(guid); + botToCubeAssignment.erase(guid); - if (IsInstanceTimerManager(botAI, bot)) + if (IsMechanicTrackerBot(botAI, bot, MAGTHERIDON_MAP_ID, nullptr)) { spreadWaitTimer.erase(instanceId); blastNovaTimer.erase(instanceId); diff --git a/src/Ai/Raid/Magtheridon/Action/RaidMagtheridonActions.h b/src/Ai/Raid/Magtheridon/Action/RaidMagtheridonActions.h index 6c4ed84c..d47d0645 100644 --- a/src/Ai/Raid/Magtheridon/Action/RaidMagtheridonActions.h +++ b/src/Ai/Raid/Magtheridon/Action/RaidMagtheridonActions.h @@ -6,8 +6,6 @@ #include "AttackAction.h" #include "MovementActions.h" -using namespace MagtheridonHelpers; - class MagtheridonMainTankAttackFirstThreeChannelersAction : public AttackAction { public: @@ -85,8 +83,8 @@ public: private: bool HandleCubeRelease(Unit* magtheridon, GameObject* cube); bool ShouldActivateCubeLogic(Unit* magtheridon); - bool HandleWaitingPhase(const CubeInfo& cubeInfo); - bool HandleCubeInteraction(const CubeInfo& cubeInfo, GameObject* cube); + bool HandleWaitingPhase(const MagtheridonHelpers::CubeInfo& cubeInfo); + bool HandleCubeInteraction(const MagtheridonHelpers::CubeInfo& cubeInfo, GameObject* cube); }; class MagtheridonManageTimersAndAssignmentsAction : public Action diff --git a/src/Ai/Raid/Magtheridon/Multiplier/RaidMagtheridonMultipliers.cpp b/src/Ai/Raid/Magtheridon/Multiplier/RaidMagtheridonMultipliers.cpp index 9580fd92..55aaf90e 100644 --- a/src/Ai/Raid/Magtheridon/Multiplier/RaidMagtheridonMultipliers.cpp +++ b/src/Ai/Raid/Magtheridon/Multiplier/RaidMagtheridonMultipliers.cpp @@ -8,6 +8,7 @@ #include "GenericSpellActions.h" #include "Playerbots.h" #include "WarlockActions.h" +#include "WipeAction.h" using namespace MagtheridonHelpers; @@ -24,10 +25,10 @@ float MagtheridonUseManticronCubeMultiplier::GetValue(Action* action) auto it = botToCubeAssignment.find(bot->GetGUID()); if (it != botToCubeAssignment.end()) { - if (dynamic_cast(action)) + if (dynamic_cast(action)) return 1.0f; - - return 0.0f; + else if (!dynamic_cast(action)) + return 0.0f; } } @@ -41,28 +42,31 @@ float MagtheridonWaitToAttackMultiplier::GetValue(Action* action) if (!magtheridon || magtheridon->HasAura(SPELL_SHADOW_CAGE)) return 1.0f; + if (botAI->IsMainTank(bot)) + return 1.0f; + const uint8 dpsWaitSeconds = 6; auto it = dpsWaitTimer.find(magtheridon->GetMap()->GetInstanceId()); if (it == dpsWaitTimer.end() || (time(nullptr) - it->second) < dpsWaitSeconds) { - if (!botAI->IsMainTank(bot) && (dynamic_cast(action) || - (!botAI->IsHeal(bot) && dynamic_cast(action)))) + if (dynamic_cast(action) || + (!botAI->IsHeal(bot) && dynamic_cast(action))) return 0.0f; } return 1.0f; } -// No tank assist for offtanks during the channeler phase -// So they don't try to pull channelers from each other or the main tank float MagtheridonDisableOffTankAssistMultiplier::GetValue(Action* action) { Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon"); - Unit* channeler = AI_VALUE2(Unit*, "find target", "hellfire channeler"); if (!magtheridon) return 1.0f; + if (bot->GetVictim() == nullptr) + return 1.0f; + if ((botAI->IsAssistTankOfIndex(bot, 0) || botAI->IsAssistTankOfIndex(bot, 1)) && dynamic_cast(action)) return 0.0f; diff --git a/src/Ai/Raid/Magtheridon/Trigger/RaidMagtheridonTriggers.cpp b/src/Ai/Raid/Magtheridon/Trigger/RaidMagtheridonTriggers.cpp index 35442df6..43aa3361 100644 --- a/src/Ai/Raid/Magtheridon/Trigger/RaidMagtheridonTriggers.cpp +++ b/src/Ai/Raid/Magtheridon/Trigger/RaidMagtheridonTriggers.cpp @@ -18,7 +18,7 @@ bool MagtheridonNWChannelerEngagedByFirstAssistTankTrigger::IsActive() Creature* channelerDiamond = GetChanneler(bot, NORTHWEST_CHANNELER); return magtheridon && botAI->IsAssistTankOfIndex(bot, 0) && - channelerDiamond && channelerDiamond->IsAlive(); + channelerDiamond; } bool MagtheridonNEChannelerEngagedBySecondAssistTankTrigger::IsActive() @@ -27,7 +27,7 @@ bool MagtheridonNEChannelerEngagedBySecondAssistTankTrigger::IsActive() Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER); return magtheridon && botAI->IsAssistTankOfIndex(bot, 1) && - channelerTriangle && channelerTriangle->IsAlive(); + channelerTriangle; } bool MagtheridonPullingWestAndEastChannelersTrigger::IsActive() @@ -38,8 +38,7 @@ bool MagtheridonPullingWestAndEastChannelersTrigger::IsActive() Creature* channelerCircle = GetChanneler(bot, EAST_CHANNELER); return magtheridon && bot->getClass() == CLASS_HUNTER && - ((channelerStar && channelerStar->IsAlive()) || - (channelerCircle && channelerCircle->IsAlive())); + (channelerStar || channelerCircle); } bool MagtheridonDeterminingKillOrderTrigger::IsActive() @@ -51,12 +50,11 @@ bool MagtheridonDeterminingKillOrderTrigger::IsActive() Creature* channelerTriangle = GetChanneler(bot, NORTHEAST_CHANNELER); if (!magtheridon || botAI->IsHeal(bot) || botAI->IsMainTank(bot) || - (botAI->IsAssistTankOfIndex(bot, 0) && channelerDiamond && channelerDiamond->IsAlive()) || - (botAI->IsAssistTankOfIndex(bot, 1) && channelerTriangle && channelerTriangle->IsAlive())) + (botAI->IsAssistTankOfIndex(bot, 0) && channelerDiamond) || + (botAI->IsAssistTankOfIndex(bot, 1) && channelerTriangle)) return false; - return (channeler && channeler->IsAlive()) || (magtheridon && - !magtheridon->HasAura(SPELL_SHADOW_CAGE)); + return channeler || (magtheridon && !magtheridon->HasAura(SPELL_SHADOW_CAGE)); } bool MagtheridonBurningAbyssalSpawnedTrigger::IsActive() @@ -84,10 +82,8 @@ bool MagtheridonBossEngagedByMainTankTrigger::IsActive() bool MagtheridonBossEngagedByRangedTrigger::IsActive() { Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon"); - Unit* channeler = AI_VALUE2(Unit*, "find target", "hellfire channeler"); - return magtheridon && botAI->IsRanged(bot) && - !(channeler && channeler->IsAlive()); + return magtheridon && !magtheridon->HasAura(SPELL_SHADOW_CAGE) && botAI->IsRanged(bot); } bool MagtheridonIncomingBlastNovaTrigger::IsActive() @@ -122,7 +118,5 @@ bool MagtheridonIncomingBlastNovaTrigger::IsActive() bool MagtheridonNeedToManageTimersAndAssignmentsTrigger::IsActive() { - Unit* magtheridon = AI_VALUE2(Unit*, "find target", "magtheridon"); - - return magtheridon; + return AI_VALUE2(Unit*, "find target", "magtheridon"); } diff --git a/src/Ai/Raid/Magtheridon/Util/RaidMagtheridonHelpers.cpp b/src/Ai/Raid/Magtheridon/Util/RaidMagtheridonHelpers.cpp index dc88d2a1..a56d4b85 100644 --- a/src/Ai/Raid/Magtheridon/Util/RaidMagtheridonHelpers.cpp +++ b/src/Ai/Raid/Magtheridon/Util/RaidMagtheridonHelpers.cpp @@ -1,22 +1,18 @@ #include "RaidMagtheridonHelpers.h" #include "Creature.h" #include "GameObject.h" -#include "GroupReference.h" #include "Map.h" #include "ObjectGuid.h" #include "Playerbots.h" namespace MagtheridonHelpers { - namespace MagtheridonsLairLocations - { - const Location WaitingForMagtheridonPosition = { 1.359f, 2.048f, -0.406f, 3.135f }; - const Location MagtheridonTankPosition = { 22.827f, 2.105f, -0.406f, 3.135f }; - const Location NWChannelerTankPosition = { -11.764f, 30.818f, -0.411f, 0.0f }; - const Location NEChannelerTankPosition = { -12.490f, -26.211f, -0.411f, 0.0f }; - const Location RangedSpreadPosition = { -14.890f, 1.995f, -0.406f, 0.0f }; - const Location HealerSpreadPosition = { -2.265f, 1.874f, -0.404f, 0.0f }; - } + const Position WAITING_FOR_MAGTHERIDON_POSITION = { 1.359f, 2.048f, -0.406f, 3.135f }; + const Position MAGTHERIDON_TANK_POSITION = { 22.827f, 2.105f, -0.406f, 3.135f }; + const Position NW_CHANNELER_TANK_POSITION = { -11.764f, 30.818f, -0.411f, 0.0f }; + const Position NE_CHANNELER_TANK_POSITION = { -12.490f, -26.211f, -0.411f, 0.0f }; + const Position RANGED_SPREAD_POSITION = { -14.890f, 1.995f, -0.406f, 0.0f }; + const Position HEALER_SPREAD_POSITION = { -2.265f, 1.874f, -0.404f, 0.0f }; // Identify channelers by their database GUIDs Creature* GetChanneler(Player* bot, uint32 dbGuid) @@ -29,63 +25,11 @@ namespace MagtheridonHelpers if (it == map->GetCreatureBySpawnIdStore().end()) return nullptr; - return it->second; - } + Creature* channeler = it->second; + if (!channeler->IsAlive()) + return nullptr; - void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId) - { - Group* group = bot->GetGroup(); - if (!target || !group) - return; - - ObjectGuid currentGuid = group->GetTargetIcon(iconId); - if (currentGuid != target->GetGUID()) - group->SetTargetIcon(iconId, bot->GetGUID(), target->GetGUID()); - } - - void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target) - { - if (!target) - return; - - std::string currentRti = botAI->GetAiObjectContext()->GetValue("rti")->Get(); - Unit* currentTarget = botAI->GetAiObjectContext()->GetValue("rti target")->Get(); - - if (currentRti != rtiName || currentTarget != target) - { - botAI->GetAiObjectContext()->GetValue("rti")->Set(rtiName); - botAI->GetAiObjectContext()->GetValue("rti target")->Set(target); - } - } - - void MarkTargetWithSquare(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::squareIndex); - } - - void MarkTargetWithStar(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::starIndex); - } - - void MarkTargetWithCircle(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::circleIndex); - } - - void MarkTargetWithDiamond(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::diamondIndex); - } - - void MarkTargetWithTriangle(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::triangleIndex); - } - - void MarkTargetWithCross(Player* bot, Unit* target) - { - MarkTargetWithIcon(bot, target, RtiTargetValue::crossIndex); + return channeler; } const std::vector MANTICRON_CUBE_DB_GUIDS = { 43157, 43158, 43159, 43160, 43161 }; @@ -208,19 +152,4 @@ namespace MagtheridonHelpers return true; } - - bool IsInstanceTimerManager(PlayerbotAI* botAI, Player* bot) - { - if (Group* group = bot->GetGroup()) - { - for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) - { - Player* member = ref->GetSource(); - if (member && member->IsAlive() && botAI->IsDps(member) && GET_PLAYERBOT_AI(member)) - return member == bot; - } - } - - return true; - } } diff --git a/src/Ai/Raid/Magtheridon/Util/RaidMagtheridonHelpers.h b/src/Ai/Raid/Magtheridon/Util/RaidMagtheridonHelpers.h index f9f514de..1335aff4 100644 --- a/src/Ai/Raid/Magtheridon/Util/RaidMagtheridonHelpers.h +++ b/src/Ai/Raid/Magtheridon/Util/RaidMagtheridonHelpers.h @@ -8,7 +8,6 @@ #include "Group.h" #include "ObjectGuid.h" #include "PlayerbotAI.h" -#include "RtiTargetValue.h" namespace MagtheridonHelpers { @@ -19,10 +18,6 @@ namespace MagtheridonHelpers SPELL_BLAST_NOVA = 30616, SPELL_SHADOW_GRASP = 30410, - // Warlock - SPELL_BANISH = 18647, - SPELL_FEAR = 6215, - // Hunter SPELL_MISDIRECTION = 35079, }; @@ -38,6 +33,7 @@ namespace MagtheridonHelpers GO_BLAZE = 181832, }; + constexpr uint32 MAGTHERIDON_MAP_ID = 544; constexpr uint32 SOUTH_CHANNELER = 90978; constexpr uint32 WEST_CHANNELER = 90979; constexpr uint32 NORTHWEST_CHANNELER = 90980; @@ -45,31 +41,14 @@ namespace MagtheridonHelpers constexpr uint32 NORTHEAST_CHANNELER = 90981; Creature* GetChanneler(Player* bot, uint32 dbGuid); - void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId); - void MarkTargetWithSquare(Player* bot, Unit* target); - void MarkTargetWithStar(Player* bot, Unit* target); - void MarkTargetWithCircle(Player* bot, Unit* target); - void MarkTargetWithDiamond(Player* bot, Unit* target); - void MarkTargetWithTriangle(Player* bot, Unit* target); - void MarkTargetWithCross(Player* bot, Unit* target); - void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target); bool IsSafeFromMagtheridonHazards(PlayerbotAI* botAI, Player* bot, float x, float y, float z); - bool IsInstanceTimerManager(PlayerbotAI* botAI, Player* bot); - struct Location - { - float x, y, z, orientation; - }; - - namespace MagtheridonsLairLocations - { - extern const Location WaitingForMagtheridonPosition; - extern const Location MagtheridonTankPosition; - extern const Location NWChannelerTankPosition; - extern const Location NEChannelerTankPosition; - extern const Location RangedSpreadPosition; - extern const Location HealerSpreadPosition; - } + extern const Position WAITING_FOR_MAGTHERIDON_POSITION; + extern const Position MAGTHERIDON_TANK_POSITION; + extern const Position NW_CHANNELER_TANK_POSITION; + extern const Position NE_CHANNELER_TANK_POSITION; + extern const Position RANGED_SPREAD_POSITION; + extern const Position HEALER_SPREAD_POSITION; struct CubeInfo { diff --git a/src/Ai/Raid/MoltenCore/RaidMcActionContext.h b/src/Ai/Raid/MoltenCore/RaidMcActionContext.h index 79a4a95a..aaccb80d 100644 --- a/src/Ai/Raid/MoltenCore/RaidMcActionContext.h +++ b/src/Ai/Raid/MoltenCore/RaidMcActionContext.h @@ -2,6 +2,7 @@ #define _PLAYERBOT_RAIDMCACTIONCONTEXT_H #include "Action.h" +#include "BossAuraActions.h" #include "NamedObjectContext.h" #include "RaidMcActions.h" diff --git a/src/Ai/Raid/MoltenCore/RaidMcTriggerContext.h b/src/Ai/Raid/MoltenCore/RaidMcTriggerContext.h index b7495891..a62d851d 100644 --- a/src/Ai/Raid/MoltenCore/RaidMcTriggerContext.h +++ b/src/Ai/Raid/MoltenCore/RaidMcTriggerContext.h @@ -2,6 +2,7 @@ #define _PLAYERBOT_RAIDMCTRIGGERCONTEXT_H #include "AiObjectContext.h" +#include "BossAuraTriggers.h" #include "NamedObjectContext.h" #include "RaidMcTriggers.h" diff --git a/src/Ai/Raid/MoltenCore/RaidMcHelpers.h b/src/Ai/Raid/MoltenCore/Util/RaidMcHelpers.h similarity index 100% rename from src/Ai/Raid/MoltenCore/RaidMcHelpers.h rename to src/Ai/Raid/MoltenCore/Util/RaidMcHelpers.h diff --git a/src/Ai/Raid/RaidBossHelpers.cpp b/src/Ai/Raid/RaidBossHelpers.cpp new file mode 100644 index 00000000..bcb48294 --- /dev/null +++ b/src/Ai/Raid/RaidBossHelpers.cpp @@ -0,0 +1,142 @@ +#include "RaidBossHelpers.h" +#include "Playerbots.h" +#include "RtiTargetValue.h" + +// Functions to mark targets with raid target icons +// Note that these functions do not allow the player to change the icon during the encounter +void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId) +{ + if (!target) + return; + + if (Group* group = bot->GetGroup()) + { + ObjectGuid currentGuid = group->GetTargetIcon(iconId); + if (currentGuid != target->GetGUID()) + group->SetTargetIcon(iconId, bot->GetGUID(), target->GetGUID()); + } +} + +void MarkTargetWithSkull(Player* bot, Unit* target) +{ + MarkTargetWithIcon(bot, target, RtiTargetValue::skullIndex); +} + +void MarkTargetWithSquare(Player* bot, Unit* target) +{ + MarkTargetWithIcon(bot, target, RtiTargetValue::squareIndex); +} + +void MarkTargetWithStar(Player* bot, Unit* target) +{ + MarkTargetWithIcon(bot, target, RtiTargetValue::starIndex); +} + +void MarkTargetWithCircle(Player* bot, Unit* target) +{ + MarkTargetWithIcon(bot, target, RtiTargetValue::circleIndex); +} + +void MarkTargetWithDiamond(Player* bot, Unit* target) +{ + MarkTargetWithIcon(bot, target, RtiTargetValue::diamondIndex); +} + +void MarkTargetWithTriangle(Player* bot, Unit* target) +{ + MarkTargetWithIcon(bot, target, RtiTargetValue::triangleIndex); +} + +void MarkTargetWithCross(Player* bot, Unit* target) +{ + MarkTargetWithIcon(bot, target, RtiTargetValue::crossIndex); +} + +void MarkTargetWithMoon(Player* bot, Unit* target) +{ + MarkTargetWithIcon(bot, target, RtiTargetValue::moonIndex); +} + +// For bots to set their raid target icon to the specified icon on the specified target +void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target) +{ + if (!target) + return; + + std::string currentRti = botAI->GetAiObjectContext()->GetValue("rti")->Get(); + Unit* currentTarget = botAI->GetAiObjectContext()->GetValue("rti target")->Get(); + + if (currentRti != rtiName || currentTarget != target) + { + botAI->GetAiObjectContext()->GetValue("rti")->Set(rtiName); + botAI->GetAiObjectContext()->GetValue("rti target")->Set(target); + } +} + +// Return the first alive DPS bot in the specified instance map, excluding any specified bot +// Intended for purposes of storing and erasing timers and trackers in associative containers +bool IsMechanicTrackerBot(PlayerbotAI* botAI, Player* bot, uint32 mapId, Player* exclude) +{ + if (Group* group = bot->GetGroup()) + { + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member || !member->IsAlive() || member->GetMapId() != mapId || + !GET_PLAYERBOT_AI(member) || !botAI->IsDps(member)) + continue; + + if (member != exclude) + return member == bot; + } + } + + return false; +} + +// Return the first matching alive unit from a cell search of nearby npcs +// More responsive than "find target," but performance cost is much higher +// Re: using the third parameter (false by default), some units are never considered +// to be in combat (e.g., totems) +Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry, bool requireInCombat) +{ + auto const& npcs = + botAI->GetAiObjectContext()->GetValue("nearest npcs")->Get(); + for (auto const& npcGuid : npcs) + { + Unit* unit = botAI->GetUnit(npcGuid); + if (unit && unit->IsAlive() && unit->GetEntry() == entry) + { + if (!requireInCombat || unit->IsInCombat()) + return unit; + } + } + + return nullptr; +} + +// Return the nearest alive player (human or bot) within the specified radius +Unit* GetNearestPlayerInRadius(Player* bot, float radius) +{ + Unit* nearestPlayer = nullptr; + float nearestDistance = radius; + + if (Group* group = bot->GetGroup()) + { + for (GroupReference* ref = group->GetFirstMember(); ref != nullptr; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member || !member->IsAlive() || member == bot) + continue; + + float distance = bot->GetExactDist2d(member); + if (distance < nearestDistance) + { + nearestDistance = distance; + nearestPlayer = member; + } + } + } + + return nearestPlayer; +} diff --git a/src/Ai/Raid/RaidBossHelpers.h b/src/Ai/Raid/RaidBossHelpers.h new file mode 100644 index 00000000..15c60353 --- /dev/null +++ b/src/Ai/Raid/RaidBossHelpers.h @@ -0,0 +1,21 @@ +#ifndef _PLAYERBOT_RAIDBOSSHELPERS_H_ +#define _PLAYERBOT_RAIDBOSSHELPERS_H_ + +#include "AiObject.h" +#include "Unit.h" + +void MarkTargetWithIcon(Player* bot, Unit* target, uint8 iconId); +void MarkTargetWithSkull(Player* bot, Unit* target); +void MarkTargetWithSquare(Player* bot, Unit* target); +void MarkTargetWithStar(Player* bot, Unit* target); +void MarkTargetWithCircle(Player* bot, Unit* target); +void MarkTargetWithDiamond(Player* bot, Unit* target); +void MarkTargetWithTriangle(Player* bot, Unit* target); +void MarkTargetWithCross(Player* bot, Unit* target); +void MarkTargetWithMoon(Player* bot, Unit* target); +void SetRtiTarget(PlayerbotAI* botAI, const std::string& rtiName, Unit* target); +bool IsMechanicTrackerBot(PlayerbotAI* botAI, Player* bot, uint32 mapId, Player* exclude = nullptr); +Unit* GetFirstAliveUnitByEntry(PlayerbotAI* botAI, uint32 entry, bool requireInCombat = false); +Unit* GetNearestPlayerInRadius(Player* bot, float radius); + +#endif diff --git a/src/Ai/Raid/RaidStrategyContext.h b/src/Ai/Raid/RaidStrategyContext.h index 4f7a63c7..3c7971fb 100644 --- a/src/Ai/Raid/RaidStrategyContext.h +++ b/src/Ai/Raid/RaidStrategyContext.h @@ -29,7 +29,7 @@ public: creators["wotlk-os"] = &RaidStrategyContext::wotlk_os; creators["wotlk-eoe"] = &RaidStrategyContext::wotlk_eoe; creators["voa"] = &RaidStrategyContext::voa; - creators["uld"] = &RaidStrategyContext::uld; + creators["ulduar"] = &RaidStrategyContext::ulduar; creators["onyxia"] = &RaidStrategyContext::onyxia; creators["icc"] = &RaidStrategyContext::icc; } @@ -45,7 +45,7 @@ private: static Strategy* wotlk_eoe(PlayerbotAI* botAI) { return new RaidEoEStrategy(botAI); } static Strategy* voa(PlayerbotAI* botAI) { return new RaidVoAStrategy(botAI); } static Strategy* onyxia(PlayerbotAI* botAI) { return new RaidOnyxiaStrategy(botAI); } - static Strategy* uld(PlayerbotAI* botAI) { return new RaidUlduarStrategy(botAI); } + static Strategy* ulduar(PlayerbotAI* botAI) { return new RaidUlduarStrategy(botAI); } static Strategy* icc(PlayerbotAI* botAI) { return new RaidIccStrategy(botAI); } }; diff --git a/src/Ai/Raid/Ulduar/Action/RaidUlduarActions.cpp b/src/Ai/Raid/Ulduar/Action/RaidUlduarActions.cpp index b20425d2..f7eca38d 100644 --- a/src/Ai/Raid/Ulduar/Action/RaidUlduarActions.cpp +++ b/src/Ai/Raid/Ulduar/Action/RaidUlduarActions.cpp @@ -11,7 +11,6 @@ #include "GameObject.h" #include "Group.h" #include "LastMovementValue.h" -#include "ObjectDefines.h" #include "ObjectGuid.h" #include "PlayerbotAI.h" #include "PlayerbotAIConfig.h" @@ -19,11 +18,9 @@ #include "Position.h" #include "RaidUlduarBossHelper.h" #include "RaidUlduarScripts.h" -#include "RaidUlduarStrategy.h" #include "RtiValue.h" #include "ScriptedCreature.h" #include "ServerFacade.h" -#include "SharedDefines.h" #include "Unit.h" #include "Vehicle.h" #include diff --git a/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.cpp b/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.cpp deleted file mode 100644 index 0a51ca40..00000000 --- a/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "RaidUlduarMultipliers.h" - -#include "ChooseTargetActions.h" -#include "DKActions.h" -#include "DruidActions.h" -#include "DruidBearActions.h" -#include "FollowActions.h" -#include "GenericActions.h" -#include "GenericSpellActions.h" -#include "HunterActions.h" -#include "MageActions.h" -#include "MovementActions.h" -#include "PaladinActions.h" -#include "PriestActions.h" -#include "RaidUlduarActions.h" -#include "ReachTargetActions.h" -#include "RogueActions.h" -#include "ScriptedCreature.h" -#include "ShamanActions.h" -#include "UseMeetingStoneAction.h" -#include "WarriorActions.h" - -float FlameLeviathanMultiplier::GetValue(Action* action) -{ - // if (dynamic_cast(action)) - // return 0.0f; - return 1.0f; -} diff --git a/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.h b/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.h deleted file mode 100644 index 6c9a468f..00000000 --- a/src/Ai/Raid/Ulduar/Multiplier/RaidUlduarMultipliers.h +++ /dev/null @@ -1,17 +0,0 @@ - -#ifndef _PLAYERRBOT_RAIDULDUARMULTIPLIERS_H_ -#define _PLAYERRBOT_RAIDULDUARMULTIPLIERS_H_ - -#include "Multiplier.h" -#include "Ai/Raid/Ulduar/RaidUlduarBossHelper.h" - -class FlameLeviathanMultiplier : public Multiplier -{ -public: - FlameLeviathanMultiplier(PlayerbotAI* ai) : Multiplier(ai, "flame leviathan") {} - -public: - virtual float GetValue(Action* action); -}; - -#endif diff --git a/src/Ai/Raid/Ulduar/RaidUlduarBossHelper.h b/src/Ai/Raid/Ulduar/RaidUlduarBossHelper.h deleted file mode 100644 index 592fbc80..00000000 --- a/src/Ai/Raid/Ulduar/RaidUlduarBossHelper.h +++ /dev/null @@ -1,169 +0,0 @@ -#ifndef _PLAYERBOT_RAIDULDUARBOSSHELPER_H -#define _PLAYERBOT_RAIDULDUARBOSSHELPER_H - -#include -#include -#include -#include -#include -#include - -#include "AiObject.h" -#include "AiObjectContext.h" -#include "EventMap.h" -#include "Log.h" -#include "ObjectGuid.h" -#include "Player.h" -#include "PlayerbotAI.h" -#include "Playerbots.h" -#include "ScriptedCreature.h" -#include "SharedDefines.h" - -const uint32 ULDUAR_MAP_ID = 603; - -class RazorscaleBossHelper : public AiObject -{ -public: - // Enums and constants specific to Razorscale - enum RazorscaleUnits : uint32 - { - UNIT_RAZORSCALE = 33186, - UNIT_DARK_RUNE_SENTINEL = 33846, - UNIT_DARK_RUNE_WATCHER = 33453, - UNIT_DARK_RUNE_GUARDIAN = 33388, - UNIT_DEVOURING_FLAME = 34188, - }; - - enum RazorscaleGameObjects : uint32 - { - GO_RAZORSCALE_HARPOON_1 = 194519, - GO_RAZORSCALE_HARPOON_2 = 194541, - GO_RAZORSCALE_HARPOON_3 = 194542, - GO_RAZORSCALE_HARPOON_4 = 194543, - }; - - enum RazorscaleSpells : uint32 - { - SPELL_CHAIN_1 = 49679, - SPELL_CHAIN_2 = 49682, - SPELL_CHAIN_3 = 49683, - SPELL_CHAIN_4 = 49684, - SPELL_SENTINEL_WHIRLWIND = 63806, - SPELL_STUN_AURA = 62794, - SPELL_FUSEARMOR = 64771 - }; - - static constexpr uint32 FUSEARMOR_THRESHOLD = 2; - - // Constants for arena parameters - static constexpr float RAZORSCALE_FLYING_Z_THRESHOLD = 440.0f; - static constexpr float RAZORSCALE_ARENA_CENTER_X = 587.54f; - static constexpr float RAZORSCALE_ARENA_CENTER_Y = -175.04f; - static constexpr float RAZORSCALE_ARENA_RADIUS = 30.0f; - - // Harpoon cooldown (seconds) - static constexpr time_t HARPOON_COOLDOWN_DURATION = 5; - - // Structure for harpoon data - struct HarpoonData - { - uint32 gameObjectEntry; - uint32 chainSpellId; - }; - - explicit RazorscaleBossHelper(PlayerbotAI* botAI) - : AiObject(botAI), _boss(nullptr) {} - - bool UpdateBossAI(); - Unit* GetBoss() const; - - bool IsGroundPhase() const; - bool IsFlyingPhase() const; - - bool IsHarpoonFired(uint32 chainSpellId) const; - static bool IsHarpoonReady(GameObject* harpoonGO); - static void SetHarpoonOnCooldown(GameObject* harpoonGO); - GameObject* FindNearestHarpoon(float x, float y, float z) const; - - static const std::vector& GetHarpoonData(); - - void AssignRolesBasedOnHealth(); - bool AreRolesAssigned() const; - bool CanSwapRoles() const; - -private: - Unit* _boss; - - // A map to track the last role swap *per bot* by their GUID - static std::unordered_map _lastRoleSwapTime; - - // The cooldown that applies to every bot - static const std::time_t _roleSwapCooldown = 10; - - static std::unordered_map _harpoonCooldowns; -}; - -// template -// class GenericBossHelper : public AiObject -// { -// public: -// GenericBossHelper(PlayerbotAI* botAI, std::string name) : AiObject(botAI), _name(name) {} -// virtual bool UpdateBossAI() -// { -// if (!bot->IsInCombat()) -// { -// _unit = nullptr; -// } -// if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive())) -// { -// _unit = nullptr; -// } -// if (!_unit) -// { -// _unit = AI_VALUE2(Unit*, "find target", _name); -// if (!_unit) -// { -// return false; -// } -// _target = _unit->ToCreature(); -// if (!_target) -// { -// return false; -// } -// _ai = dynamic_cast(_target->GetAI()); -// if (!_ai) -// { -// return false; -// } -// _event_map = &_ai->events; -// if (!_event_map) -// { -// return false; -// } -// } -// if (!_event_map) -// { -// return false; -// } -// _timer = _event_map->GetTimer(); -// return true; -// } -// virtual void Reset() -// { -// _unit = nullptr; -// _target = nullptr; -// _ai = nullptr; -// _event_map = nullptr; -// _timer = 0; -// } - -// protected: -// std::string _name; -// Unit* _unit = nullptr; -// Creature* _target = nullptr; -// BossAiType* _ai = nullptr; -// EventMap* _event_map = nullptr; -// uint32 _timer = 0; -// }; - -#endif diff --git a/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.cpp b/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.cpp index 3b9a426c..0a1b76a4 100644 --- a/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.cpp +++ b/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.cpp @@ -1,7 +1,5 @@ #include "RaidUlduarStrategy.h" -#include "RaidUlduarMultipliers.h" - void RaidUlduarStrategy::InitTriggers(std::vector& triggers) { // @@ -316,8 +314,3 @@ void RaidUlduarStrategy::InitTriggers(std::vector& triggers) "yogg-saron phase 3 positioning trigger", { NextAction("yogg-saron phase 3 positioning action", ACTION_RAID) })); } - -void RaidUlduarStrategy::InitMultipliers(std::vector& multipliers) -{ - multipliers.push_back(new FlameLeviathanMultiplier(botAI)); -} diff --git a/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.h b/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.h index 81bb93c3..bb2feefe 100644 --- a/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.h +++ b/src/Ai/Raid/Ulduar/Strategy/RaidUlduarStrategy.h @@ -3,16 +3,14 @@ #define _PLAYERBOT_RAIDULDUARSTRATEGY_H #include "AiObjectContext.h" -#include "Multiplier.h" #include "Strategy.h" class RaidUlduarStrategy : public Strategy { public: RaidUlduarStrategy(PlayerbotAI* ai) : Strategy(ai) {} - virtual std::string const getName() override { return "uld"; } + virtual std::string const getName() override { return "ulduar"; } virtual void InitTriggers(std::vector& triggers) override; - virtual void InitMultipliers(std::vector& multipliers) override; }; #endif diff --git a/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp b/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp index a4bc2cf9..f14a5131 100644 --- a/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp +++ b/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp @@ -1634,7 +1634,7 @@ bool VezaxShadowCrashTrigger::IsActive() return false; } - return botAI->HasAura(SPELL_SHADOW_CRASH, bot); + return botAI->HasAura(SPELL_VEZAX_SHADOW_CRASH, bot); } bool VezaxMarkOfTheFacelessTrigger::IsActive() diff --git a/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.h b/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.h index 129c3d4d..7f8cb51a 100644 --- a/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.h +++ b/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.h @@ -3,187 +3,9 @@ #include "EventMap.h" #include "GenericTriggers.h" -#include "PlayerbotAIConfig.h" #include "RaidUlduarBossHelper.h" #include "Trigger.h" -enum UlduarIDs -{ - // Iron Assembly - SPELL_LIGHTNING_TENDRILS_10_MAN = 61887, - SPELL_LIGHTNING_TENDRILS_25_MAN = 63486, - SPELL_OVERLOAD_10_MAN = 61869, - SPELL_OVERLOAD_25_MAN = 63481, - SPELL_OVERLOAD_10_MAN_2 = 63485, - SPELL_OVERLOAD_25_MAN_2 = 61886, - SPELL_RUNE_OF_POWER = 64320, - - // Kologarn - NPC_RIGHT_ARM = 32934, - NPC_RUBBLE = 33768, - SPELL_CRUNCH_ARMOR = 64002, - - SPELL_FOCUSED_EYEBEAM_10_2 = 63346, - SPELL_FOCUSED_EYEBEAM_10 = 63347, - SPELL_FOCUSED_EYEBEAM_25_2 = 63976, - SPELL_FOCUSED_EYEBEAM_25 = 63977, - - // Hodir - NPC_SNOWPACKED_ICICLE = 33174, - NPC_TOASTY_FIRE = 33342, - SPELL_FLASH_FREEZE = 61968, - 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, - - // Thorim - NPC_DARK_RUNE_ACOLYTE_I = 32886, - NPC_CAPTURED_MERCENARY_SOLDIER_ALLY = 32885, - NPC_CAPTURED_MERCENARY_SOLDIER_HORDE = 32883, - NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY = 32908, - NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE = 32907, - NPC_JORMUNGAR_BEHEMOT = 32882, - NPC_DARK_RUNE_WARBRINGER = 32877, - NPC_DARK_RUNE_EVOKER = 32878, - NPC_DARK_RUNE_CHAMPION = 32876, - NPC_DARK_RUNE_COMMONER = 32904, - NPC_IRON_RING_GUARD = 32874, - NPC_RUNIC_COLOSSUS = 32872, - NPC_ANCIENT_RUNE_GIANT = 32873, - NPC_DARK_RUNE_ACOLYTE_G = 33110, - NPC_IRON_HONOR_GUARD = 32875, - SPELL_UNBALANCING_STRIKE = 62130, - - // Mimiron - NPC_LEVIATHAN_MKII = 33432, - NPC_VX001 = 33651, - NPC_AERIAL_COMMAND_UNIT = 33670, - NPC_BOMB_BOT = 33836, - NPC_ROCKET_STRIKE_N = 34047, - NPC_ASSAULT_BOT = 34057, - NPC_PROXIMITY_MINE = 34362, - SPELL_P3WX2_LASER_BARRAGE_1 = 63293, - SPELL_P3WX2_LASER_BARRAGE_2 = 63297, - SPELL_SPINNING_UP = 63414, - SPELL_SHOCK_BLAST = 63631, - SPELL_P3WX2_LASER_BARRAGE_3 = 64042, - SPELL_P3WX2_LASER_BARRAGE_AURA_1 = 63274, - SPELL_P3WX2_LASER_BARRAGE_AURA_2 = 63300, - - // General Vezax - SPELL_MARK_OF_THE_FACELESS = 63276, - SPELL_SHADOW_CRASH = 63277, - - // Yogg-Saron - ACTION_ILLUSION_DRAGONS = 1, - ACTION_ILLUSION_ICECROWN = 2, - ACTION_ILLUSION_STORMWIND = 3, - NPC_GUARDIAN_OF_YS = 33136, - NPC_YOGG_SARON = 33288, - NPC_OMINOUS_CLOUD = 33292, - NPC_RUBY_CONSORT = 33716, - NPC_AZURE_CONSORT = 33717, - NPC_BRONZE_CONSORT = 33718, - NPC_EMERALD_CONSORT = 33719, - NPC_OBSIDIAN_CONSORT = 33720, - NPC_ALEXTRASZA = 33536, - NPC_MALYGOS_ILLUSION = 33535, - NPC_NELTHARION = 33523, - NPC_YSERA = 33495, - GO_DRAGON_SOUL = 194462, - NPC_SARA_PHASE_1 = 33134, - NPC_LICH_KING_ILLUSION = 33441, - NPC_IMMOLATED_CHAMPION = 33442, - NPC_SUIT_OF_ARMOR = 33433, - NPC_GARONA = 33436, - NPC_KING_LLANE = 33437, - NPC_DEATHSWORN_ZEALOT = 33567, - NPC_INFLUENCE_TENTACLE = 33943, - NPC_DEATH_ORB = 33882, - NPC_BRAIN = 33890, - NPC_CRUSHER_TENTACLE = 33966, - NPC_CONSTRICTOR_TENTACLE = 33983, - NPC_CORRUPTOR_TENTACLE = 33985, - NPC_IMMORTAL_GUARDIAN = 33988, - NPC_LAUGHING_SKULL = 33990, - NPC_SANITY_WELL = 33991, - NPC_DESCEND_INTO_MADNESS = 34072, - NPC_MARKED_IMMORTAL_GUARDIAN = 36064, - SPELL_SANITY = 63050, - SPELL_BRAIN_LINK = 63802, - SPELL_MALADY_OF_THE_MIND = 63830, - SPELL_SHADOW_BARRIER = 63894, - SPELL_TELEPORT_TO_CHAMBER = 63997, - SPELL_TELEPORT_TO_ICECROWN = 63998, - SPELL_TELEPORT_TO_STORMWIND = 63989, - SPELL_TELEPORT_BACK = 63992, - SPELL_CANCEL_ILLUSION_AURA = 63993, - SPELL_INDUCE_MADNESS = 64059, - SPELL_LUNATIC_GAZE_YS = 64163, - GO_FLEE_TO_THE_SURFACE_PORTAL = 194625, - - // Buffs - SPELL_FROST_TRAP = 13809 -}; - -const float ULDUAR_KOLOGARN_AXIS_Z_PATHING_ISSUE_DETECT = 420.0f; -const float ULDUAR_KOLOGARN_EYEBEAM_RADIUS = 3.0f; -const float ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD = 429.6094f; -const float ULDUAR_THORIM_AXIS_Z_PATHING_ISSUE_DETECT = 410.0f; -const float ULDUAR_AURIAYA_AXIS_Z_PATHING_ISSUE_DETECT = 410.0f; -const float ULDUAR_YOGG_SARON_BOSS_ROOM_AXIS_Z_PATHING_ISSUE_DETECT = 300.0f; -const float ULDUAR_YOGG_SARON_BRAIN_ROOM_AXIS_Z_PATHING_ISSUE_DETECT = 200.0f; -const float ULDUAR_YOGG_SARON_STORMWIND_KEEPER_RADIUS = 150.0f; -const float ULDUAR_YOGG_SARON_ICECROWN_CITADEL_RADIUS = 150.0f; -const float ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_RADIUS = 150.0f; -const float ULDUAR_YOGG_SARON_BRAIN_ROOM_RADIUS = 50.0f; - -const Position ULDUAR_THORIM_NEAR_ARENA_CENTER = Position(2134.9854f, -263.11853f, 419.8465f); -const Position ULDUAR_THORIM_NEAR_ENTRANCE_POSITION = Position(2172.4355f, -258.27957f, 418.47162f); -const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_1 = Position(2237.6187f, -265.08844f, 412.17548f); -const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_2 = Position(2237.2498f, -275.81122f, 412.17548f); -const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_5_YARDS_1 = Position(2236.895f, -294.62448f, 412.1348f); -const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_1 = Position(2242.1162f, -310.15308f, 412.1348f); -const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_2 = Position(2242.018f, -318.66003f, 412.1348f); -const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_3 = Position(2242.1904f, -329.0533f, 412.1348f); -const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_1 = Position(2219.5417f, -264.77167f, 412.17548f); -const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_2 = Position(2217.446f, -275.85248f, 412.17548f); -const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_5_YARDS_1 = Position(2217.8877f, -295.01193f, 412.13434f); -const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_1 = Position(2212.193f, -307.44992f, 412.1348f); -const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_2 = Position(2212.1353f, -318.20795f, 412.1348f); -const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_3 = Position(2212.1956f, -328.0144f, 412.1348f); -const Position ULDUAR_THORIM_JUMP_END_POINT = Position(2137.8818f, -278.18942f, 419.66653f); -const Position ULDUAR_THORIM_PHASE2_TANK_SPOT = Position(2134.8572f, -287.0291f, 419.4935f); -const Position ULDUAR_THORIM_PHASE2_RANGE1_SPOT = Position(2112.8752f, -267.69305f, 419.52814f); -const Position ULDUAR_THORIM_PHASE2_RANGE2_SPOT = Position(2134.1296f, -257.3316f, 419.8462f); -const Position ULDUAR_THORIM_PHASE2_RANGE3_SPOT = Position(2156.798f, -267.57434f, 419.52722f); -const Position ULDUAR_MIMIRON_PHASE2_SIDE1RANGE_SPOT = Position(2753.708f, 2583.9617f, 364.31357f); -const Position ULDUAR_MIMIRON_PHASE2_SIDE1MELEE_SPOT = Position(2746.9792f, 2573.6716f, 364.31357f); -const Position ULDUAR_MIMIRON_PHASE2_SIDE2RANGE_SPOT = Position(2727.7224f, 2569.527f, 364.31357f); -const Position ULDUAR_MIMIRON_PHASE2_SIDE2MELEE_SPOT = Position(2739.4746f, 2569.4106f, 364.31357f); -const Position ULDUAR_MIMIRON_PHASE2_SIDE3RANGE_SPOT = Position(2754.1294f, 2553.9954f, 364.31357f); -const Position ULDUAR_MIMIRON_PHASE2_SIDE3MELEE_SPOT = Position(2746.8513f, 2565.4263f, 364.31357f); -const Position ULDUAR_MIMIRON_PHASE4_TANK_SPOT = Position(2744.5754f, 2570.8657f, 364.3138f); -const Position ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT = Position(1913.6501f, 122.93989f, 342.38083f); -const Position ULDUAR_YOGG_SARON_MIDDLE = Position(1980.28f, -25.5868f, 329.397f); -const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE = Position(1927.1511f, 68.507256f, 242.37657f); -const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE = Position(1925.6553f, -121.59296f, 239.98965f); -const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE = Position(2104.5667f, -25.509348f, 242.64679f); -const Position ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE = Position(1980.1971f, -27.854689f, 236.06789f); -const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_ENTRANCE = Position(1954.06f, 21.66f, 239.71f); -const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_ENTRANCE = Position(1950.11f, -79.284f, 239.98982f); -const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_ENTRANCE = Position(2048.63f, -25.5f, 239.72f); -const Position ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT = Position(1998.5377f, -22.90317f, 324.8895f); -const Position ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT = Position(2018.7628f, -18.896868f, 327.07245f); - // // Flame Levi // diff --git a/src/Ai/Raid/Ulduar/RaidUlduarBossHelper.cpp b/src/Ai/Raid/Ulduar/Util/RaidUlduarBossHelper.cpp similarity index 63% rename from src/Ai/Raid/Ulduar/RaidUlduarBossHelper.cpp rename to src/Ai/Raid/Ulduar/Util/RaidUlduarBossHelper.cpp index 72333a07..fd6711cf 100644 --- a/src/Ai/Raid/Ulduar/RaidUlduarBossHelper.cpp +++ b/src/Ai/Raid/Ulduar/Util/RaidUlduarBossHelper.cpp @@ -1,4 +1,3 @@ -#include "ChatHelper.h" #include "RaidUlduarBossHelper.h" #include "ObjectAccessor.h" #include "GameObject.h" @@ -9,6 +8,44 @@ #include "Playerbots.h" #include "World.h" +const Position ULDUAR_THORIM_NEAR_ARENA_CENTER = Position(2134.9854f, -263.11853f, 419.8465f); +const Position ULDUAR_THORIM_NEAR_ENTRANCE_POSITION = Position(2172.4355f, -258.27957f, 418.47162f); +const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_1 = Position(2237.6187f, -265.08844f, 412.17548f); +const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_2 = Position(2237.2498f, -275.81122f, 412.17548f); +const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_5_YARDS_1 = Position(2236.895f, -294.62448f, 412.1348f); +const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_1 = Position(2242.1162f, -310.15308f, 412.1348f); +const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_2 = Position(2242.018f, -318.66003f, 412.1348f); +const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_3 = Position(2242.1904f, -329.0533f, 412.1348f); +const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_1 = Position(2219.5417f, -264.77167f, 412.17548f); +const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_2 = Position(2217.446f, -275.85248f, 412.17548f); +const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_5_YARDS_1 = Position(2217.8877f, -295.01193f, 412.13434f); +const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_1 = Position(2212.193f, -307.44992f, 412.1348f); +const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_2 = Position(2212.1353f, -318.20795f, 412.1348f); +const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_3 = Position(2212.1956f, -328.0144f, 412.1348f); +const Position ULDUAR_THORIM_JUMP_END_POINT = Position(2137.8818f, -278.18942f, 419.66653f); +const Position ULDUAR_THORIM_PHASE2_TANK_SPOT = Position(2134.8572f, -287.0291f, 419.4935f); +const Position ULDUAR_THORIM_PHASE2_RANGE1_SPOT = Position(2112.8752f, -267.69305f, 419.52814f); +const Position ULDUAR_THORIM_PHASE2_RANGE2_SPOT = Position(2134.1296f, -257.3316f, 419.8462f); +const Position ULDUAR_THORIM_PHASE2_RANGE3_SPOT = Position(2156.798f, -267.57434f, 419.52722f); +const Position ULDUAR_MIMIRON_PHASE2_SIDE1RANGE_SPOT = Position(2753.708f, 2583.9617f, 364.31357f); +const Position ULDUAR_MIMIRON_PHASE2_SIDE1MELEE_SPOT = Position(2746.9792f, 2573.6716f, 364.31357f); +const Position ULDUAR_MIMIRON_PHASE2_SIDE2RANGE_SPOT = Position(2727.7224f, 2569.527f, 364.31357f); +const Position ULDUAR_MIMIRON_PHASE2_SIDE2MELEE_SPOT = Position(2739.4746f, 2569.4106f, 364.31357f); +const Position ULDUAR_MIMIRON_PHASE2_SIDE3RANGE_SPOT = Position(2754.1294f, 2553.9954f, 364.31357f); +const Position ULDUAR_MIMIRON_PHASE2_SIDE3MELEE_SPOT = Position(2746.8513f, 2565.4263f, 364.31357f); +const Position ULDUAR_MIMIRON_PHASE4_TANK_SPOT = Position(2744.5754f, 2570.8657f, 364.3138f); +const Position ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT = Position(1913.6501f, 122.93989f, 342.38083f); +const Position ULDUAR_YOGG_SARON_MIDDLE = Position(1980.28f, -25.5868f, 329.397f); +const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE = Position(1927.1511f, 68.507256f, 242.37657f); +const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE = Position(1925.6553f, -121.59296f, 239.98965f); +const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE = Position(2104.5667f, -25.509348f, 242.64679f); +const Position ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE = Position(1980.1971f, -27.854689f, 236.06789f); +const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_ENTRANCE = Position(1954.06f, 21.66f, 239.71f); +const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_ENTRANCE = Position(1950.11f, -79.284f, 239.98982f); +const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_ENTRANCE = Position(2048.63f, -25.5f, 239.72f); +const Position ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT = Position(1998.5377f, -22.90317f, 324.8895f); +const Position ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT = Position(2018.7628f, -18.896868f, 327.07245f); + // Prevent harpoon spam std::unordered_map RazorscaleBossHelper::_harpoonCooldowns; // Prevent role assignment spam diff --git a/src/Ai/Raid/Ulduar/Util/RaidUlduarBossHelper.h b/src/Ai/Raid/Ulduar/Util/RaidUlduarBossHelper.h new file mode 100644 index 00000000..b3d49ff5 --- /dev/null +++ b/src/Ai/Raid/Ulduar/Util/RaidUlduarBossHelper.h @@ -0,0 +1,341 @@ +#ifndef _PLAYERBOT_RAIDULDUARBOSSHELPER_H +#define _PLAYERBOT_RAIDULDUARBOSSHELPER_H + +#include +#include +#include + +#include "AiObject.h" +#include "AiObjectContext.h" +#include "EventMap.h" +#include "ObjectGuid.h" +#include "Player.h" +#include "PlayerbotAI.h" +#include "Playerbots.h" +#include "ScriptedCreature.h" + +constexpr uint32 ULDUAR_MAP_ID = 603; + +enum UlduarIDs +{ + // Iron Assembly + SPELL_LIGHTNING_TENDRILS_10_MAN = 61887, + SPELL_LIGHTNING_TENDRILS_25_MAN = 63486, + SPELL_OVERLOAD_10_MAN = 61869, + SPELL_OVERLOAD_25_MAN = 63481, + SPELL_OVERLOAD_10_MAN_2 = 63485, + SPELL_OVERLOAD_25_MAN_2 = 61886, + SPELL_RUNE_OF_POWER = 64320, + + // Kologarn + NPC_RIGHT_ARM = 32934, + NPC_RUBBLE = 33768, + SPELL_CRUNCH_ARMOR = 64002, + + SPELL_FOCUSED_EYEBEAM_10_2 = 63346, + SPELL_FOCUSED_EYEBEAM_10 = 63347, + SPELL_FOCUSED_EYEBEAM_25_2 = 63976, + SPELL_FOCUSED_EYEBEAM_25 = 63977, + + // Hodir + NPC_SNOWPACKED_ICICLE = 33174, + NPC_TOASTY_FIRE = 33342, + SPELL_FLASH_FREEZE = 61968, + 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, + + // Thorim + NPC_DARK_RUNE_ACOLYTE_I = 32886, + NPC_CAPTURED_MERCENARY_SOLDIER_ALLY = 32885, + NPC_CAPTURED_MERCENARY_SOLDIER_HORDE = 32883, + NPC_CAPTURED_MERCENARY_CAPTAIN_ALLY = 32908, + NPC_CAPTURED_MERCENARY_CAPTAIN_HORDE = 32907, + NPC_JORMUNGAR_BEHEMOT = 32882, + NPC_DARK_RUNE_WARBRINGER = 32877, + NPC_DARK_RUNE_EVOKER = 32878, + NPC_DARK_RUNE_CHAMPION = 32876, + NPC_DARK_RUNE_COMMONER = 32904, + NPC_IRON_RING_GUARD = 32874, + NPC_RUNIC_COLOSSUS = 32872, + NPC_ANCIENT_RUNE_GIANT = 32873, + NPC_DARK_RUNE_ACOLYTE_G = 33110, + NPC_IRON_HONOR_GUARD = 32875, + SPELL_UNBALANCING_STRIKE = 62130, + + // Mimiron + NPC_LEVIATHAN_MKII = 33432, + NPC_VX001 = 33651, + NPC_AERIAL_COMMAND_UNIT = 33670, + NPC_BOMB_BOT = 33836, + NPC_ROCKET_STRIKE_N = 34047, + NPC_ASSAULT_BOT = 34057, + NPC_PROXIMITY_MINE = 34362, + SPELL_P3WX2_LASER_BARRAGE_1 = 63293, + SPELL_P3WX2_LASER_BARRAGE_2 = 63297, + SPELL_SPINNING_UP = 63414, + SPELL_SHOCK_BLAST = 63631, + SPELL_P3WX2_LASER_BARRAGE_3 = 64042, + SPELL_P3WX2_LASER_BARRAGE_AURA_1 = 63274, + SPELL_P3WX2_LASER_BARRAGE_AURA_2 = 63300, + + // General Vezax + SPELL_MARK_OF_THE_FACELESS = 63276, + SPELL_VEZAX_SHADOW_CRASH = 63277, + + // Yogg-Saron + ACTION_ILLUSION_DRAGONS = 1, + ACTION_ILLUSION_ICECROWN = 2, + ACTION_ILLUSION_STORMWIND = 3, + NPC_GUARDIAN_OF_YS = 33136, + NPC_YOGG_SARON = 33288, + NPC_OMINOUS_CLOUD = 33292, + NPC_RUBY_CONSORT = 33716, + NPC_AZURE_CONSORT = 33717, + NPC_BRONZE_CONSORT = 33718, + NPC_EMERALD_CONSORT = 33719, + NPC_OBSIDIAN_CONSORT = 33720, + NPC_ALEXTRASZA = 33536, + NPC_MALYGOS_ILLUSION = 33535, + NPC_NELTHARION = 33523, + NPC_YSERA = 33495, + GO_DRAGON_SOUL = 194462, + NPC_SARA_PHASE_1 = 33134, + NPC_LICH_KING_ILLUSION = 33441, + NPC_IMMOLATED_CHAMPION = 33442, + NPC_SUIT_OF_ARMOR = 33433, + NPC_GARONA = 33436, + NPC_KING_LLANE = 33437, + NPC_DEATHSWORN_ZEALOT = 33567, + NPC_INFLUENCE_TENTACLE = 33943, + NPC_DEATH_ORB = 33882, + NPC_BRAIN = 33890, + NPC_CRUSHER_TENTACLE = 33966, + NPC_CONSTRICTOR_TENTACLE = 33983, + NPC_CORRUPTOR_TENTACLE = 33985, + NPC_IMMORTAL_GUARDIAN = 33988, + NPC_LAUGHING_SKULL = 33990, + NPC_SANITY_WELL = 33991, + NPC_DESCEND_INTO_MADNESS = 34072, + NPC_MARKED_IMMORTAL_GUARDIAN = 36064, + SPELL_SANITY = 63050, + SPELL_BRAIN_LINK = 63802, + SPELL_MALADY_OF_THE_MIND = 63830, + SPELL_SHADOW_BARRIER = 63894, + SPELL_TELEPORT_TO_CHAMBER = 63997, + SPELL_TELEPORT_TO_ICECROWN = 63998, + SPELL_TELEPORT_TO_STORMWIND = 63989, + SPELL_TELEPORT_BACK = 63992, + SPELL_CANCEL_ILLUSION_AURA = 63993, + SPELL_INDUCE_MADNESS = 64059, + SPELL_LUNATIC_GAZE_YS = 64163, + GO_FLEE_TO_THE_SURFACE_PORTAL = 194625, + + // Buffs + SPELL_FROST_TRAP = 13809 +}; + +constexpr float ULDUAR_KOLOGARN_AXIS_Z_PATHING_ISSUE_DETECT = 420.0f; +constexpr float ULDUAR_KOLOGARN_EYEBEAM_RADIUS = 3.0f; +constexpr float ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD = 429.6094f; +constexpr float ULDUAR_THORIM_AXIS_Z_PATHING_ISSUE_DETECT = 410.0f; +constexpr float ULDUAR_AURIAYA_AXIS_Z_PATHING_ISSUE_DETECT = 410.0f; +constexpr float ULDUAR_YOGG_SARON_BOSS_ROOM_AXIS_Z_PATHING_ISSUE_DETECT = 300.0f; +constexpr float ULDUAR_YOGG_SARON_BRAIN_ROOM_AXIS_Z_PATHING_ISSUE_DETECT = 200.0f; +constexpr float ULDUAR_YOGG_SARON_STORMWIND_KEEPER_RADIUS = 150.0f; +constexpr float ULDUAR_YOGG_SARON_ICECROWN_CITADEL_RADIUS = 150.0f; +constexpr float ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_RADIUS = 150.0f; +constexpr float ULDUAR_YOGG_SARON_BRAIN_ROOM_RADIUS = 50.0f; + +extern const Position ULDUAR_THORIM_NEAR_ARENA_CENTER; +extern const Position ULDUAR_THORIM_NEAR_ENTRANCE_POSITION; +extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_1; +extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_6_YARDS_2; +extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_5_YARDS_1; +extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_1; +extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_2; +extern const Position ULDUAR_THORIM_GAUNTLET_LEFT_SIDE_10_YARDS_3; +extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_1; +extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_6_YARDS_2; +extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_5_YARDS_1; +extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_1; +extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_2; +extern const Position ULDUAR_THORIM_GAUNTLET_RIGHT_SIDE_10_YARDS_3; +extern const Position ULDUAR_THORIM_JUMP_END_POINT; +extern const Position ULDUAR_THORIM_PHASE2_TANK_SPOT; +extern const Position ULDUAR_THORIM_PHASE2_RANGE1_SPOT; +extern const Position ULDUAR_THORIM_PHASE2_RANGE2_SPOT; +extern const Position ULDUAR_THORIM_PHASE2_RANGE3_SPOT; +extern const Position ULDUAR_MIMIRON_PHASE2_SIDE1RANGE_SPOT; +extern const Position ULDUAR_MIMIRON_PHASE2_SIDE1MELEE_SPOT; +extern const Position ULDUAR_MIMIRON_PHASE2_SIDE2RANGE_SPOT; +extern const Position ULDUAR_MIMIRON_PHASE2_SIDE2MELEE_SPOT; +extern const Position ULDUAR_MIMIRON_PHASE2_SIDE3RANGE_SPOT; +extern const Position ULDUAR_MIMIRON_PHASE2_SIDE3MELEE_SPOT; +extern const Position ULDUAR_MIMIRON_PHASE4_TANK_SPOT; +extern const Position ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT; +extern const Position ULDUAR_YOGG_SARON_MIDDLE; +extern const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE; +extern const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE; +extern const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE; +extern const Position ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE; +extern const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_ENTRANCE; +extern const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_ENTRANCE; +extern const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_ENTRANCE; +extern const Position ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT; +extern const Position ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT; + +class RazorscaleBossHelper : public AiObject +{ +public: + // Enums and constants specific to Razorscale + enum RazorscaleUnits : uint32 + { + UNIT_RAZORSCALE = 33186, + UNIT_DARK_RUNE_SENTINEL = 33846, + UNIT_DARK_RUNE_WATCHER = 33453, + UNIT_DARK_RUNE_GUARDIAN = 33388, + UNIT_DEVOURING_FLAME = 34188, + }; + + enum RazorscaleGameObjects : uint32 + { + GO_RAZORSCALE_HARPOON_1 = 194519, + GO_RAZORSCALE_HARPOON_2 = 194541, + GO_RAZORSCALE_HARPOON_3 = 194542, + GO_RAZORSCALE_HARPOON_4 = 194543, + }; + + enum RazorscaleSpells : uint32 + { + SPELL_CHAIN_1 = 49679, + SPELL_CHAIN_2 = 49682, + SPELL_CHAIN_3 = 49683, + SPELL_CHAIN_4 = 49684, + SPELL_SENTINEL_WHIRLWIND = 63806, + SPELL_STUN_AURA = 62794, + SPELL_FUSEARMOR = 64771 + }; + + static constexpr uint32 FUSEARMOR_THRESHOLD = 2; + + // Constants for arena parameters + static constexpr float RAZORSCALE_FLYING_Z_THRESHOLD = 440.0f; + static constexpr float RAZORSCALE_ARENA_CENTER_X = 587.54f; + static constexpr float RAZORSCALE_ARENA_CENTER_Y = -175.04f; + static constexpr float RAZORSCALE_ARENA_RADIUS = 30.0f; + + // Harpoon cooldown (seconds) + static constexpr time_t HARPOON_COOLDOWN_DURATION = 5; + + // Structure for harpoon data + struct HarpoonData + { + uint32 gameObjectEntry; + uint32 chainSpellId; + }; + + explicit RazorscaleBossHelper(PlayerbotAI* botAI) + : AiObject(botAI), _boss(nullptr) {} + + bool UpdateBossAI(); + Unit* GetBoss() const; + + bool IsGroundPhase() const; + bool IsFlyingPhase() const; + + bool IsHarpoonFired(uint32 chainSpellId) const; + static bool IsHarpoonReady(GameObject* harpoonGO); + static void SetHarpoonOnCooldown(GameObject* harpoonGO); + GameObject* FindNearestHarpoon(float x, float y, float z) const; + + static const std::vector& GetHarpoonData(); + + void AssignRolesBasedOnHealth(); + bool AreRolesAssigned() const; + bool CanSwapRoles() const; + +private: + Unit* _boss; + + // A map to track the last role swap *per bot* by their GUID + static std::unordered_map _lastRoleSwapTime; + + // The cooldown that applies to every bot + static const std::time_t _roleSwapCooldown = 10; + + static std::unordered_map _harpoonCooldowns; +}; + +// template +// class GenericBossHelper : public AiObject +// { +// public: +// GenericBossHelper(PlayerbotAI* botAI, std::string name) : AiObject(botAI), _name(name) {} +// virtual bool UpdateBossAI() +// { +// if (!bot->IsInCombat()) +// { +// _unit = nullptr; +// } +// if (_unit && (!_unit->IsInWorld() || !_unit->IsAlive())) +// { +// _unit = nullptr; +// } +// if (!_unit) +// { +// _unit = AI_VALUE2(Unit*, "find target", _name); +// if (!_unit) +// { +// return false; +// } +// _target = _unit->ToCreature(); +// if (!_target) +// { +// return false; +// } +// _ai = dynamic_cast(_target->GetAI()); +// if (!_ai) +// { +// return false; +// } +// _event_map = &_ai->events; +// if (!_event_map) +// { +// return false; +// } +// } +// if (!_event_map) +// { +// return false; +// } +// _timer = _event_map->GetTimer(); +// return true; +// } +// virtual void Reset() +// { +// _unit = nullptr; +// _target = nullptr; +// _ai = nullptr; +// _event_map = nullptr; +// _timer = 0; +// } + +// protected: +// std::string _name; +// Unit* _unit = nullptr; +// Creature* _target = nullptr; +// BossAiType* _ai = nullptr; +// EventMap* _event_map = nullptr; +// uint32 _timer = 0; +// }; + +#endif diff --git a/src/Ai/Raid/Ulduar/RaidUlduarScripts.h b/src/Ai/Raid/Ulduar/Util/RaidUlduarScripts.h similarity index 100% rename from src/Ai/Raid/Ulduar/RaidUlduarScripts.h rename to src/Ai/Raid/Ulduar/Util/RaidUlduarScripts.h diff --git a/src/Ai/Raid/VaultOfArchavon/RaidVoAActionContext.h b/src/Ai/Raid/VaultOfArchavon/RaidVoAActionContext.h index b304826b..263d03d9 100644 --- a/src/Ai/Raid/VaultOfArchavon/RaidVoAActionContext.h +++ b/src/Ai/Raid/VaultOfArchavon/RaidVoAActionContext.h @@ -7,6 +7,7 @@ #define _PLAYERBOT_RAIDVOAACTIONCONTEXT_H #include "Action.h" +#include "BossAuraActions.h" #include "NamedObjectContext.h" #include "RaidVoAActions.h" #include "PlayerbotAI.h" diff --git a/src/Ai/Raid/VaultOfArchavon/RaidVoATriggerContext.h b/src/Ai/Raid/VaultOfArchavon/RaidVoATriggerContext.h index 9fe078f8..6566793f 100644 --- a/src/Ai/Raid/VaultOfArchavon/RaidVoATriggerContext.h +++ b/src/Ai/Raid/VaultOfArchavon/RaidVoATriggerContext.h @@ -7,6 +7,7 @@ #define _PLAYERBOT_RAIDVOATRIGGERCONTEXT_H #include "AiObjectContext.h" +#include "BossAuraTriggers.h" #include "NamedObjectContext.h" #include "RaidVoATriggers.h" diff --git a/src/Bot/Engine/AiObjectContext.cpp b/src/Bot/Engine/AiObjectContext.cpp index b6d5f7de..250a3929 100644 --- a/src/Bot/Engine/AiObjectContext.cpp +++ b/src/Bot/Engine/AiObjectContext.cpp @@ -15,8 +15,6 @@ #include "PaladinAiObjectContext.h" #include "Playerbots.h" #include "PriestAiObjectContext.h" -#include "RaidUlduarActionContext.h" -#include "RaidUlduarTriggerContext.h" #include "RogueAiObjectContext.h" #include "ShamanAiObjectContext.h" #include "SharedValueContext.h" @@ -49,6 +47,8 @@ #include "Ai/Raid/VaultOfArchavon/RaidVoATriggerContext.h" #include "Ai/Raid/ObsidianSanctum/RaidOsActionContext.h" #include "Ai/Raid/ObsidianSanctum/RaidOsTriggerContext.h" +#include "Ai/Raid/Ulduar/RaidUlduarActionContext.h" +#include "Ai/Raid/Ulduar/RaidUlduarTriggerContext.h" #include "Ai/Raid/Onyxia/RaidOnyxiaActionContext.h" #include "Ai/Raid/Onyxia/RaidOnyxiaTriggerContext.h" #include "Ai/Raid/Icecrown/RaidIccActionContext.h" diff --git a/src/Bot/PlayerbotAI.cpp b/src/Bot/PlayerbotAI.cpp index 437e62fc..56c2cd39 100644 --- a/src/Bot/PlayerbotAI.cpp +++ b/src/Bot/PlayerbotAI.cpp @@ -1585,7 +1585,7 @@ void PlayerbotAI::ApplyInstanceStrategies(uint32 mapId, bool tellMaster) strategyName = "wotlk-hol"; // Halls of Lightning break; case 603: - strategyName = "uld"; // Ulduar + strategyName = "ulduar"; // Ulduar break; case 604: strategyName = "wotlk-gd"; // Gundrak