resolve some comments + more

Formatting edits and improved Malchezaar
This commit is contained in:
crow
2025-09-26 10:01:12 -05:00
parent 22d1cc9d57
commit e8954f6cba
5 changed files with 283 additions and 170 deletions

View File

@@ -18,7 +18,7 @@ namespace
bool KarazhanAttumenTheHuntsmanStackBehindAction::Execute(Event event) bool KarazhanAttumenTheHuntsmanStackBehindAction::Execute(Event event)
{ {
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
Unit* boss = karazhanHelper.GetFirstAliveUnitByEntry(NPC_ATTUMEN_THE_HUNTSMAN); Unit* boss = karazhanHelper.GetFirstAliveUnitByEntry(NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
float distance = 5.0f; float distance = 5.0f;
float orientation = boss->GetOrientation() + M_PI; float orientation = boss->GetOrientation() + M_PI;
@@ -34,12 +34,9 @@ bool KarazhanAttumenTheHuntsmanStackBehindAction::Execute(Event event)
bool KarazhanAttumenTheHuntsmanStackBehindAction::isUseful() bool KarazhanAttumenTheHuntsmanStackBehindAction::isUseful()
{ {
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
Unit* boss = karazhanHelper.GetFirstAliveUnitByEntry(NPC_ATTUMEN_THE_HUNTSMAN); Unit* boss = karazhanHelper.GetFirstAliveUnitByEntry(NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
if (boss && botAI->IsTank(bot) && botAI->HasAggro(boss) && boss->GetVictim() == bot) return boss && !(botAI->IsTank(bot) && botAI->HasAggro(boss) && boss->GetVictim() == bot);
return false;
return boss != nullptr;
} }
bool KarazhanMoroesMarkTargetAction::Execute(Event event) bool KarazhanMoroesMarkTargetAction::Execute(Event event)
@@ -70,7 +67,9 @@ bool KarazhanMaidenOfVirtuePositionBossAction::Execute(Event event)
{ {
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member || !member->IsAlive() || !botAI->IsHeal(member) || !member->HasAura(SPELL_REPENTANCE)) if (!member || !member->IsAlive() || !botAI->IsHeal(member) || !member->HasAura(SPELL_REPENTANCE))
{
continue; continue;
}
healer = member; healer = member;
break; break;
} }
@@ -82,9 +81,10 @@ bool KarazhanMaidenOfVirtuePositionBossAction::Execute(Event event)
float targetX = healer->GetPositionX() + cos(angle) * 6.0f; float targetX = healer->GetPositionX() + cos(angle) * 6.0f;
float targetY = healer->GetPositionY() + sin(angle) * 6.0f; float targetY = healer->GetPositionY() + sin(angle) * 6.0f;
float targetZ = healer->GetPositionZ(); float targetZ = healer->GetPositionZ();
{
return MoveTo(bot->GetMapId(), targetX, targetY, targetZ, false, false, false, true, return MoveTo(bot->GetMapId(), targetX, targetY, targetZ, false, false, false, true,
MovementPriority::MOVEMENT_COMBAT); MovementPriority::MOVEMENT_COMBAT);
}
} }
const float maxDistance = 3.0f; const float maxDistance = 3.0f;
@@ -96,9 +96,10 @@ bool KarazhanMaidenOfVirtuePositionBossAction::Execute(Event event)
float dY = KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION.GetPositionY() - boss->GetPositionY(); float dY = KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION.GetPositionY() - boss->GetPositionY();
float mX = KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION.GetPositionX() + (dX / distanceToBossPosition) * maxDistance; float mX = KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION.GetPositionX() + (dX / distanceToBossPosition) * maxDistance;
float mY = KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION.GetPositionY() + (dY / distanceToBossPosition) * maxDistance; float mY = KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION.GetPositionY() + (dY / distanceToBossPosition) * maxDistance;
{
return MoveTo(bot->GetMapId(), mX, mY, return MoveTo(bot->GetMapId(), mX, mY,
bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
}
} }
return false; return false;
} }
@@ -121,8 +122,10 @@ bool KarazhanMaidenOfVirtuePositionRangedAction::Execute(Event event)
{ {
Unit* member = botAI->GetUnit(memberGuid); Unit* member = botAI->GetUnit(memberGuid);
if (!member || !botAI->IsRanged(member->ToPlayer())) if (!member || !botAI->IsRanged(member->ToPlayer()))
{
continue; continue;
}
if (member == bot) if (member == bot)
break; break;
@@ -137,12 +140,12 @@ bool KarazhanMaidenOfVirtuePositionRangedAction::Execute(Event event)
float distance = bot->GetExactDist2d(KARAZHAN_MAIDEN_OF_VIRTUE_RANGED_POSITION[index]); float distance = bot->GetExactDist2d(KARAZHAN_MAIDEN_OF_VIRTUE_RANGED_POSITION[index]);
const float maxDistance = 2.0f; const float maxDistance = 2.0f;
if (distance > maxDistance) if (distance > maxDistance)
{
return MoveTo(bot->GetMapId(), KARAZHAN_MAIDEN_OF_VIRTUE_RANGED_POSITION[index].GetPositionX(), return MoveTo(bot->GetMapId(), KARAZHAN_MAIDEN_OF_VIRTUE_RANGED_POSITION[index].GetPositionX(),
KARAZHAN_MAIDEN_OF_VIRTUE_RANGED_POSITION[index].GetPositionY(), bot->GetPositionZ(), false, KARAZHAN_MAIDEN_OF_VIRTUE_RANGED_POSITION[index].GetPositionY(), bot->GetPositionZ(), false,
false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false); false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
}
return false; return false;
} }
@@ -173,11 +176,9 @@ bool KarazhanBigBadWolfPositionBossAction::Execute(Event event)
{ {
return false; return false;
} }
return MoveTo(bot->GetMapId(), mX, mY, bot->GetPositionZ(), false, false, false, false, return MoveTo(bot->GetMapId(), mX, mY, bot->GetPositionZ(), false, false, false, false,
MovementPriority::MOVEMENT_COMBAT, true, false); MovementPriority::MOVEMENT_COMBAT, true, false);
} }
return false; return false;
} }
@@ -200,7 +201,6 @@ bool KarazhanBigBadWolfRunAwayAction::Execute(Event event)
currentIndex = (currentIndex + 1) % 4; currentIndex = (currentIndex + 1) % 4;
target = KARAZHAN_BIG_BAD_WOLF_RUN_POSITION[currentIndex]; target = KARAZHAN_BIG_BAD_WOLF_RUN_POSITION[currentIndex];
} }
return MoveTo(bot->GetMapId(), target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), return MoveTo(bot->GetMapId(), target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(),
false, false, false, true, MovementPriority::MOVEMENT_FORCED); false, false, false, true, MovementPriority::MOVEMENT_FORCED);
} }
@@ -220,11 +220,17 @@ bool KarazhanRomuloAndJulianneMarkTargetAction::Execute(Event event)
const int maxPctDifference = 10; const int maxPctDifference = 10;
if (julianne->GetHealthPct() + maxPctDifference < romulo->GetHealthPct() || julianne->GetHealthPct() < 1.0f) if (julianne->GetHealthPct() + maxPctDifference < romulo->GetHealthPct() || julianne->GetHealthPct() < 1.0f)
{
target = romulo; target = romulo;
}
else if (romulo->GetHealthPct() + maxPctDifference < julianne->GetHealthPct() || romulo->GetHealthPct() < 1.0f) else if (romulo->GetHealthPct() + maxPctDifference < julianne->GetHealthPct() || romulo->GetHealthPct() < 1.0f)
{
target = julianne; target = julianne;
}
if (!target) if (!target)
{
return false; return false;
}
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
karazhanHelper.MarkTargetWithSkull(target); karazhanHelper.MarkTargetWithSkull(target);
@@ -252,25 +258,33 @@ bool KarazhanWizardOfOzScorchStrawmanAction::Execute(Event event)
{ {
Unit* strawman = AI_VALUE2(Unit*, "find target", "strawman"); Unit* strawman = AI_VALUE2(Unit*, "find target", "strawman");
if (!strawman || !strawman->IsAlive()) if (!strawman || !strawman->IsAlive())
{
return false; return false;
}
Group* group = bot->GetGroup(); Group* group = bot->GetGroup();
if (!group) if (!group)
{
return false; return false;
}
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
{ {
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member || !member->IsAlive()) if (!member || !member->IsAlive())
{
continue; continue;
}
if (member->getClass() != CLASS_MAGE) if (member->getClass() != CLASS_MAGE)
{
continue; continue;
}
PlayerbotAI* mageAI = sPlayerbotsMgr->GetPlayerbotAI(member); PlayerbotAI* mageAI = sPlayerbotsMgr->GetPlayerbotAI(member);
if (!mageAI) if (!mageAI)
{
continue; continue;
}
if (mageAI->CanCastSpell("scorch", strawman)) if (mageAI->CanCastSpell("scorch", strawman))
{ {
mageAI->CastSpell("scorch", strawman); mageAI->CastSpell("scorch", strawman);
@@ -283,7 +297,9 @@ bool KarazhanTheCuratorMarkTargetAction::Execute(Event event)
{ {
Unit* target = AI_VALUE2(Unit*, "find target", "astral flare"); Unit* target = AI_VALUE2(Unit*, "find target", "astral flare");
if (!target || !target->IsAlive()) if (!target || !target->IsAlive())
{
return false; return false;
}
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
karazhanHelper.MarkTargetWithSkull(target); karazhanHelper.MarkTargetWithSkull(target);
@@ -294,7 +310,6 @@ bool KarazhanTheCuratorMarkTargetAction::Execute(Event event)
bool KarazhanTheCuratorPositionBossAction::Execute(Event event) bool KarazhanTheCuratorPositionBossAction::Execute(Event event)
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "the curator"); Unit* boss = AI_VALUE2(Unit*, "find target", "the curator");
const float maxDistance = 3.0f; const float maxDistance = 3.0f;
const float distanceToBossPosition = boss->GetExactDist2d(KARAZHAN_THE_CURATOR_BOSS_POSITION); const float distanceToBossPosition = boss->GetExactDist2d(KARAZHAN_THE_CURATOR_BOSS_POSITION);
@@ -302,13 +317,13 @@ bool KarazhanTheCuratorPositionBossAction::Execute(Event event)
{ {
float dX = KARAZHAN_THE_CURATOR_BOSS_POSITION.GetPositionX() - boss->GetPositionX(); float dX = KARAZHAN_THE_CURATOR_BOSS_POSITION.GetPositionX() - boss->GetPositionX();
float dY = KARAZHAN_THE_CURATOR_BOSS_POSITION.GetPositionY() - boss->GetPositionY(); float dY = KARAZHAN_THE_CURATOR_BOSS_POSITION.GetPositionY() - boss->GetPositionY();
float mX = KARAZHAN_THE_CURATOR_BOSS_POSITION.GetPositionX() + (dX / distanceToBossPosition) * maxDistance; float mX = KARAZHAN_THE_CURATOR_BOSS_POSITION.GetPositionX() + (dX / distanceToBossPosition) * maxDistance;
float mY = KARAZHAN_THE_CURATOR_BOSS_POSITION.GetPositionY() + (dY / distanceToBossPosition) * maxDistance; float mY = KARAZHAN_THE_CURATOR_BOSS_POSITION.GetPositionY() + (dY / distanceToBossPosition) * maxDistance;
{
return MoveTo(bot->GetMapId(), mX, mY, return MoveTo(bot->GetMapId(), mX, mY,
bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true,
false); false);
}
} }
return false; return false;
} }
@@ -327,8 +342,9 @@ bool KarazhanTheCuratorSpreadRangedAction::Execute(Event event)
Unit* nearestPlayer = karazhanHelper.GetNearestPlayerInRadius(minDistance); Unit* nearestPlayer = karazhanHelper.GetNearestPlayerInRadius(minDistance);
if (nearestPlayer) if (nearestPlayer)
{
return FleePosition(nearestPlayer->GetPosition(), minDistance); return FleePosition(nearestPlayer->GetPosition(), minDistance);
}
return false; return false;
} }
@@ -343,11 +359,12 @@ bool KarazhanTerestianIllhoofMarkTargetAction::Execute(Event event)
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "terestian illhoof"); Unit* boss = AI_VALUE2(Unit*, "find target", "terestian illhoof");
if (!boss) if (!boss)
{
return false; return false;
}
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
Unit* target = karazhanHelper.GetFirstAliveUnitByEntry(NPC_DEMON_CHAINS); Unit* target = karazhanHelper.GetFirstAliveUnitByEntry(NPC_DEMON_CHAINS);
if (!target || !target->IsAlive()) if (!target || !target->IsAlive())
{ {
target = karazhanHelper.GetFirstAliveUnitByEntry(NPC_KILREK); target = karazhanHelper.GetFirstAliveUnitByEntry(NPC_KILREK);
@@ -374,17 +391,15 @@ bool KarazhanShadeOfAranArcaneExplosionRunAwayAction::Execute(Event event)
{ {
return MoveAway(boss, safeDistance - distance); return MoveAway(boss, safeDistance - distance);
} }
return false; return false;
} }
bool KarazhanShadeOfAranArcaneExplosionRunAwayAction::isUseful() bool KarazhanShadeOfAranArcaneExplosionRunAwayAction::isUseful()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran"); Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran");
if (!boss || !boss->IsAlive())
return false;
return boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION); return boss && boss->IsAlive() && boss->HasUnitState(UNIT_STATE_CASTING) &&
boss->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION);
} }
bool KarazhanShadeOfAranFlameWreathStopMovementAction::Execute(Event event) bool KarazhanShadeOfAranFlameWreathStopMovementAction::Execute(Event event)
@@ -395,8 +410,9 @@ bool KarazhanShadeOfAranFlameWreathStopMovementAction::Execute(Event event)
AI_VALUE(LastMovement&, "last movement").Set(nullptr); AI_VALUE(LastMovement&, "last movement").Set(nullptr);
bot->GetMotionMaster()->Clear(); bot->GetMotionMaster()->Clear();
if (bot->isMoving()) if (bot->isMoving())
{
bot->StopMoving(); bot->StopMoving();
}
return true; return true;
} }
return false; return false;
@@ -407,8 +423,9 @@ bool KarazhanShadeOfAranMarkConjuredElementalAction::Execute(Event event)
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran"); Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran");
if (!boss || !boss->IsAlive()) if (!boss || !boss->IsAlive())
{
return false; return false;
}
Unit* target = karazhanHelper.GetFirstAliveUnitByEntry(NPC_CONJURED_ELEMENTAL); Unit* target = karazhanHelper.GetFirstAliveUnitByEntry(NPC_CONJURED_ELEMENTAL);
if (!target || !target->IsAlive() || target->HasAura(SPELL_WARLOCK_BANISH)) if (!target || !target->IsAlive() || target->HasAura(SPELL_WARLOCK_BANISH))
{ {
@@ -430,23 +447,23 @@ bool KarazhanShadeOfAranSpreadRangedAction::Execute(Event event)
float dX = bot->GetPositionX() - boss->GetPositionX(); float dX = bot->GetPositionX() - boss->GetPositionX();
float dY = bot->GetPositionY() - boss->GetPositionY(); float dY = bot->GetPositionY() - boss->GetPositionY();
float length = std::sqrt(dX * dX + dY * dY); float length = std::sqrt(dX * dX + dY * dY);
dX /= length; dX /= length;
dY /= length; dY /= length;
float tX = boss->GetPositionX() + dX * maxBossDistance; float tX = boss->GetPositionX() + dX * maxBossDistance;
float tY = boss->GetPositionY() + dY * maxBossDistance; float tY = boss->GetPositionY() + dY * maxBossDistance;
{
return MoveTo(bot->GetMapId(), tX, tY, bot->GetPositionZ(), false, false, false, true, return MoveTo(bot->GetMapId(), tX, tY, bot->GetPositionZ(), false, false, false, true,
MovementPriority::MOVEMENT_COMBAT); MovementPriority::MOVEMENT_COMBAT);
}
} }
const float minDistance = 5.0f; const float minDistance = 5.0f;
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
Unit* nearestPlayer = karazhanHelper.GetNearestPlayerInRadius(minDistance); Unit* nearestPlayer = karazhanHelper.GetNearestPlayerInRadius(minDistance);
if (nearestPlayer) if (nearestPlayer)
{
return FleePosition(nearestPlayer->GetPosition(), minDistance); return FleePosition(nearestPlayer->GetPosition(), minDistance);
}
return false; return false;
} }
@@ -454,7 +471,9 @@ bool KarazhanShadeOfAranSpreadRangedAction::isUseful()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran"); Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran");
if (!boss || !boss->IsAlive()) if (!boss || !boss->IsAlive())
{
return false; return false;
}
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
@@ -471,19 +490,27 @@ bool KarazhanNetherspiteBlockRedBeamAction::Execute(Event event)
Group* group = bot->GetGroup(); Group* group = bot->GetGroup();
if (!group) if (!group)
{
return false; return false;
}
Player* eligibleTank = nullptr; Player* eligibleTank = nullptr;
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next()) for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
{ {
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member || !member->IsAlive()) if (!member || !member->IsAlive())
{
continue; continue;
}
PlayerbotAI* memberAI = sPlayerbotsMgr->GetPlayerbotAI(member); PlayerbotAI* memberAI = sPlayerbotsMgr->GetPlayerbotAI(member);
if (!memberAI || !memberAI->IsTank(member)) if (!memberAI || !memberAI->IsTank(member))
{
continue; continue;
}
if (member->HasAura(SPELL_NETHER_EXHAUSTION_RED)) if (member->HasAura(SPELL_NETHER_EXHAUSTION_RED))
{
continue; continue;
}
eligibleTank = member; eligibleTank = member;
break; break;
} }
@@ -522,8 +549,9 @@ bool KarazhanNetherspiteBlockRedBeamAction::Execute(Event event)
float dy = py - by; float dy = py - by;
float length = sqrt(dx*dx + dy*dy); float length = sqrt(dx*dx + dy*dy);
if (length == 0.0f) if (length == 0.0f)
{
return false; return false;
}
dx /= length; dx /= length;
dy /= length; dy /= length;
float perpDx = -dy; float perpDx = -dy;
@@ -549,8 +577,9 @@ bool KarazhanNetherspiteBlockRedBeamAction::isUseful()
bool bossIsBanished = boss && boss->HasAura(SPELL_NETHERSPITE_BANISHED); bool bossIsBanished = boss && boss->HasAura(SPELL_NETHERSPITE_BANISHED);
if (!boss || !redPortal) if (!boss || !redPortal)
{
return false; return false;
}
if (lastBossBanishState[botGuid] != bossIsBanished) if (lastBossBanishState[botGuid] != bossIsBanished)
{ {
if (!bossIsBanished) if (!bossIsBanished)
@@ -560,10 +589,10 @@ bool KarazhanNetherspiteBlockRedBeamAction::isUseful()
} }
lastBossBanishState[botGuid] = bossIsBanished; lastBossBanishState[botGuid] = bossIsBanished;
} }
if (bossIsBanished) if (bossIsBanished)
{
return false; return false;
}
return true; return true;
} }
@@ -606,7 +635,9 @@ bool KarazhanNetherspiteBlockBlueBeamAction::Execute(Event event)
float dy = py - by; float dy = py - by;
float length = sqrt(dx*dx + dy*dy); float length = sqrt(dx*dx + dy*dy);
if (length == 0.0f) if (length == 0.0f)
{
return false; return false;
}
dx /= length; dx /= length;
dy /= length; dy /= length;
@@ -630,8 +661,9 @@ bool KarazhanNetherspiteBlockBlueBeamAction::Execute(Event event)
} }
} }
if (!outsideAllVoidZones) if (!outsideAllVoidZones)
{
continue; continue;
}
float distToIdeal = fabs(dist - 18.0f); float distToIdeal = fabs(dist - 18.0f);
if (!found || distToIdeal < bestDist) if (!found || distToIdeal < bestDist)
{ {
@@ -698,8 +730,9 @@ bool KarazhanNetherspiteBlockGreenBeamAction::Execute(Event event)
float dy = py - by; float dy = py - by;
float length = sqrt(dx*dx + dy*dy); float length = sqrt(dx*dx + dy*dy);
if (length == 0.0f) if (length == 0.0f)
{
return false; return false;
}
dx /= length; dx /= length;
dy /= length; dy /= length;
float bestDist = 150.0f; float bestDist = 150.0f;
@@ -722,8 +755,9 @@ bool KarazhanNetherspiteBlockGreenBeamAction::Execute(Event event)
} }
} }
if (!outsideAllVoidZones) if (!outsideAllVoidZones)
{
continue; continue;
}
float distToIdeal = fabs(dist - 18.0f); float distToIdeal = fabs(dist - 18.0f);
if (!found || distToIdeal < bestDist) if (!found || distToIdeal < bestDist)
{ {
@@ -771,27 +805,30 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event)
break; break;
} }
} }
struct BeamAvoid { Unit* portal; float minDist, maxDist; }; struct BeamAvoid { Unit* portal; float minDist, maxDist; };
std::vector<BeamAvoid> beams; std::vector<BeamAvoid> beams;
Unit* redPortal = bot->FindNearestCreature(NPC_RED_PORTAL, 150.0f); Unit* redPortal = bot->FindNearestCreature(NPC_RED_PORTAL, 150.0f);
Unit* bluePortal = bot->FindNearestCreature(NPC_BLUE_PORTAL, 150.0f); Unit* bluePortal = bot->FindNearestCreature(NPC_BLUE_PORTAL, 150.0f);
Unit* greenPortal = bot->FindNearestCreature(NPC_GREEN_PORTAL, 150.0f); Unit* greenPortal = bot->FindNearestCreature(NPC_GREEN_PORTAL, 150.0f);
if (redPortal)
if (redPortal) { {
float bx = boss->GetPositionX(), by = boss->GetPositionY(); float bx = boss->GetPositionX(), by = boss->GetPositionY();
float px = redPortal->GetPositionX(), py = redPortal->GetPositionY(); float px = redPortal->GetPositionX(), py = redPortal->GetPositionY();
float dx = px - bx, dy = py - by; float dx = px - bx, dy = py - by;
float length = sqrt(dx*dx + dy*dy); float length = sqrt(dx*dx + dy*dy);
beams.push_back({redPortal, 0.0f, length}); beams.push_back({redPortal, 0.0f, length});
} }
if (bluePortal) { if (bluePortal)
{
float bx = boss->GetPositionX(), by = boss->GetPositionY(); float bx = boss->GetPositionX(), by = boss->GetPositionY();
float px = bluePortal->GetPositionX(), py = bluePortal->GetPositionY(); float px = bluePortal->GetPositionX(), py = bluePortal->GetPositionY();
float dx = px - bx, dy = py - by; float dx = px - bx, dy = py - by;
float length = sqrt(dx*dx + dy*dy); float length = sqrt(dx*dx + dy*dy);
beams.push_back({bluePortal, 0.0f, length}); beams.push_back({bluePortal, 0.0f, length});
} }
if (greenPortal) { if (greenPortal)
{
float bx = boss->GetPositionX(), by = boss->GetPositionY(); float bx = boss->GetPositionX(), by = boss->GetPositionY();
float px = greenPortal->GetPositionX(), py = greenPortal->GetPositionY(); float px = greenPortal->GetPositionX(), py = greenPortal->GetPositionY();
float dx = px - bx, dy = py - by; float dx = px - bx, dy = py - by;
@@ -806,8 +843,10 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event)
float px = beam.portal->GetPositionX(), py = beam.portal->GetPositionY(); float px = beam.portal->GetPositionX(), py = beam.portal->GetPositionY();
float dx = px - bx, dy = py - by; float dx = px - bx, dy = py - by;
float length = sqrt(dx*dx + dy*dy); float length = sqrt(dx*dx + dy*dy);
if (length == 0.0f) continue; if (length == 0.0f)
{continue;
continue;
}
dx /= length; dy /= length; dx /= length; dy /= length;
float botdx = bot->GetPositionX() - bx, botdy = bot->GetPositionY() - by; float botdx = bot->GetPositionX() - bx, botdy = bot->GetPositionY() - by;
float t = (botdx * dx + botdy * dy); float t = (botdx * dx + botdy * dy);
@@ -821,7 +860,9 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event)
} }
if (!nearVoidZone && !nearBeam) if (!nearVoidZone && !nearBeam)
{
return false; return false;
}
const float minMoveDist = 3.0f, maxSearchDist = 20.0f, stepAngle = M_PI/18.0f, stepDist = 0.5f; const float minMoveDist = 3.0f, maxSearchDist = 20.0f, stepAngle = M_PI/18.0f, stepDist = 0.5f;
float bossZ = boss->GetPositionZ(); float bossZ = boss->GetPositionZ();
@@ -836,8 +877,9 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event)
float cy = bot->GetPositionY() + sin(angle) * dist; float cy = bot->GetPositionY() + sin(angle) * dist;
float cz = bossZ; float cz = bossZ;
if (std::any_of(voidZones.begin(), voidZones.end(), [&](Unit* vz){ return Position(cx, cy, cz).GetExactDist2d(vz) < 4.0f; })) if (std::any_of(voidZones.begin(), voidZones.end(), [&](Unit* vz){ return Position(cx, cy, cz).GetExactDist2d(vz) < 4.0f; }))
{
continue; continue;
}
bool tooCloseToBeam = false; bool tooCloseToBeam = false;
for (const auto& beam : beams) for (const auto& beam : beams)
{ {
@@ -845,7 +887,10 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event)
float px = beam.portal->GetPositionX(), py = beam.portal->GetPositionY(); float px = beam.portal->GetPositionX(), py = beam.portal->GetPositionY();
float dx = px - bx, dy = py - by; float dx = px - bx, dy = py - by;
float length = sqrt(dx*dx + dy*dy); float length = sqrt(dx*dx + dy*dy);
if (length == 0.0f) continue; if (length == 0.0f)
{
continue;
}
dx /= length; dy /= length; dx /= length; dy /= length;
float botdx = cx - bx, botdy = cy - by; float botdx = cx - bx, botdy = cy - by;
float t = (botdx * dx + botdy * dy); float t = (botdx * dx + botdy * dy);
@@ -857,11 +902,15 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event)
break; break;
} }
} }
if (tooCloseToBeam) continue; if (tooCloseToBeam)
{
continue;
}
float moveDist = sqrt(pow(cx - bot->GetPositionX(), 2) + pow(cy - bot->GetPositionY(), 2)); float moveDist = sqrt(pow(cx - bot->GetPositionX(), 2) + pow(cy - bot->GetPositionY(), 2));
if (moveDist < minMoveDist) continue; if (moveDist < minMoveDist)
{
continue;
}
if (!found || moveDist < bestDist) if (!found || moveDist < bestDist)
{ {
bestCandidate = Position(cx, cy, cz); bestCandidate = Position(cx, cy, cz);
@@ -873,9 +922,10 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event)
if (found && karazhanHelper.IsSafePosition(bestCandidate.GetPositionX(), if (found && karazhanHelper.IsSafePosition(bestCandidate.GetPositionX(),
bestCandidate.GetPositionY(), bestCandidate.GetPositionZ(), bestCandidate.GetPositionY(), bestCandidate.GetPositionZ(),
voidZones, 4.0f)) voidZones, 4.0f))
{
return MoveTo(bot->GetMapId(), bestCandidate.GetPositionX(), bestCandidate.GetPositionY(), return MoveTo(bot->GetMapId(), bestCandidate.GetPositionX(), bestCandidate.GetPositionY(),
bestCandidate.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT); bestCandidate.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT);
}
return false; return false;
} }
@@ -883,13 +933,15 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::isUseful()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite"); Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite");
if (!boss || boss->HasAura(SPELL_NETHERSPITE_BANISHED)) if (!boss || boss->HasAura(SPELL_NETHERSPITE_BANISHED))
{
return false; return false;
}
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
auto [redBlocker, greenBlocker, blueBlocker] = karazhanHelper.GetCurrentBeamBlockers(); auto [redBlocker, greenBlocker, blueBlocker] = karazhanHelper.GetCurrentBeamBlockers();
if (bot == redBlocker || bot == blueBlocker || bot == greenBlocker) if (bot == redBlocker || bot == blueBlocker || bot == greenBlocker)
{
return false; return false;
}
return true; return true;
} }
@@ -901,7 +953,9 @@ bool KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction::Execute(Event event)
for (Unit* vz : voidZones) for (Unit* vz : voidZones)
{ {
if (vz->GetEntry() == NPC_VOID_ZONE && bot->GetExactDist2d(vz) < 4.0f) if (vz->GetEntry() == NPC_VOID_ZONE && bot->GetExactDist2d(vz) < 4.0f)
{
return FleePosition(vz->GetPosition(), 4.0f); return FleePosition(vz->GetPosition(), 4.0f);
}
} }
return false; return false;
} }
@@ -910,19 +964,21 @@ bool KarazhanNetherspiteBanishPhaseAvoidVoidZoneAction::isUseful()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite"); Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite");
if (!boss || !boss->HasAura(SPELL_NETHERSPITE_BANISHED)) if (!boss || !boss->HasAura(SPELL_NETHERSPITE_BANISHED))
{
return false; return false;
}
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
std::vector<Unit*> voidZones = karazhanHelper.GetAllVoidZones(); std::vector<Unit*> voidZones = karazhanHelper.GetAllVoidZones();
for (Unit* vz : voidZones) for (Unit* vz : voidZones)
{ {
if (bot->GetExactDist2d(vz) < 4.0f) if (bot->GetExactDist2d(vz) < 4.0f)
{
return true; return true;
}
} }
return false; return false;
} }
// For Enfeebled bots to avoid Shadow Nova and all non-tank bots to avoid infernals
bool KarazhanPrinceMalchezaarNonTankAvoidHazardAction::Execute(Event event) bool KarazhanPrinceMalchezaarNonTankAvoidHazardAction::Execute(Event event)
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar"); Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar");
@@ -957,7 +1013,9 @@ bool KarazhanPrinceMalchezaarNonTankAvoidHazardAction::Execute(Event event)
float y = bossY + dy * dist; float y = bossY + dy * dist;
float destZ = bossZ; float destZ = bossZ;
if (!bot->IsWithinLOS(x, y, destZ)) if (!bot->IsWithinLOS(x, y, destZ))
{
continue; continue;
}
bool pathSafe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, destZ), bool pathSafe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, destZ),
infernals, safeInfernalDistance, stepSize); infernals, safeInfernalDistance, stepSize);
float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2)); float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2));
@@ -1011,7 +1069,9 @@ bool KarazhanPrinceMalchezaarNonTankAvoidHazardAction::Execute(Event event)
float y = bossY + dy * dist; float y = bossY + dy * dist;
float destZ = bossZ; float destZ = bossZ;
if (!bot->IsWithinLOS(x, y, destZ)) if (!bot->IsWithinLOS(x, y, destZ))
{
continue; continue;
}
bool pathSafe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, destZ), bool pathSafe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, destZ),
infernals, safeInfernalDistance, stepSize); infernals, safeInfernalDistance, stepSize);
float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2)); float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2));
@@ -1029,7 +1089,9 @@ bool KarazhanPrinceMalchezaarNonTankAvoidHazardAction::Execute(Event event)
Position arcPoint = karazhanHelper.CalculateArcPoint(Position(bx, by, bz), Position(x, y, destZ), Position arcPoint = karazhanHelper.CalculateArcPoint(Position(bx, by, bz), Position(x, y, destZ),
Position(bossX, bossY, bossZ)); Position(bossX, bossY, bossZ));
if (!bot->IsWithinLOS(arcPoint.GetPositionX(), arcPoint.GetPositionY(), arcPoint.GetPositionZ())) if (!bot->IsWithinLOS(arcPoint.GetPositionX(), arcPoint.GetPositionY(), arcPoint.GetPositionZ()))
{
continue; continue;
}
bool arcSafe = true; bool arcSafe = true;
for (Unit* infernal : infernals) for (Unit* infernal : infernals)
{ {
@@ -1075,7 +1137,6 @@ bool KarazhanPrinceMalchezaarNonTankAvoidHazardAction::isUseful()
return boss && !(botAI->IsTank(bot) && botAI->HasAggro(boss) && boss->GetVictim() == bot); return boss && !(botAI->IsTank(bot) && botAI->HasAggro(boss) && boss->GetVictim() == bot);
} }
// For tank to avoid infernals (with buffer distance)
bool KarazhanPrinceMalchezaarTankAvoidHazardAction::Execute(Event event) bool KarazhanPrinceMalchezaarTankAvoidHazardAction::Execute(Event event)
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar"); Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar");
@@ -1117,7 +1178,9 @@ bool KarazhanPrinceMalchezaarTankAvoidHazardAction::Execute(Event event)
float y = by + dy * dist; float y = by + dy * dist;
float z = bz; float z = bz;
if (!bot->IsWithinLOS(x, y, z)) if (!bot->IsWithinLOS(x, y, z))
{
continue; continue;
}
bool safe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, z), bool safe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, z),
infernals, safeInfernalDistance, stepSize); infernals, safeInfernalDistance, stepSize);
float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2)); float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2));
@@ -1134,8 +1197,14 @@ bool KarazhanPrinceMalchezaarTankAvoidHazardAction::Execute(Event event)
{ {
Position arcPoint = karazhanHelper.CalculateArcPoint(Position(bx, by, bz), Position(x, y, z), Position arcPoint = karazhanHelper.CalculateArcPoint(Position(bx, by, bz), Position(x, y, z),
Position(bx, by, bz)); Position(bx, by, bz));
if (!bot->IsWithinLOS(arcPoint.GetPositionX(), arcPoint.GetPositionY(), arcPoint.GetPositionZ())) float arcX = arcPoint.GetPositionX();
float arcY = arcPoint.GetPositionY();
float arcZ = arcPoint.GetPositionZ();
float arcDestX = arcX, arcDestY = arcY, arcDestZ = arcZ;
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bx, by, bz, arcDestX, arcDestY, arcDestZ))
{
continue; continue;
}
bool arcSafe = true; bool arcSafe = true;
for (Unit* infernal : infernals) for (Unit* infernal : infernals)
{ {
@@ -1164,6 +1233,7 @@ bool KarazhanPrinceMalchezaarTankAvoidHazardAction::Execute(Event event)
{ {
bot->AttackStop(); bot->AttackStop();
bot->InterruptNonMeleeSpells(false); bot->InterruptNonMeleeSpells(false);
return MoveTo(bot->GetMapId(), bestDestX, bestDestY, bestDestZ, false, false, false, true, return MoveTo(bot->GetMapId(), bestDestX, bestDestY, bestDestZ, false, false, false, true,
MovementPriority::MOVEMENT_COMBAT); MovementPriority::MOVEMENT_COMBAT);
} }

View File

@@ -35,7 +35,9 @@ const Position KARAZHAN_THE_CURATOR_BOSS_POSITION = Position(-11139.463f, -1884.
void RaidKarazhanHelpers::MarkTargetWithSkull(Unit* target) void RaidKarazhanHelpers::MarkTargetWithSkull(Unit* target)
{ {
if (!target) if (!target)
{
return; return;
}
if (Group* group = bot->GetGroup()) if (Group* group = bot->GetGroup())
{ {
@@ -43,15 +45,21 @@ void RaidKarazhanHelpers::MarkTargetWithSkull(Unit* target)
ObjectGuid skullGuid = group->GetTargetIcon(skullIconId); ObjectGuid skullGuid = group->GetTargetIcon(skullIconId);
if (skullGuid != target->GetGUID()) if (skullGuid != target->GetGUID())
{
group->SetTargetIcon(skullIconId, bot->GetGUID(), target->GetGUID()); group->SetTargetIcon(skullIconId, bot->GetGUID(), target->GetGUID());
}
} }
} }
Unit* RaidKarazhanHelpers::GetFirstAliveUnit(const std::vector<Unit*>& units) Unit* RaidKarazhanHelpers::GetFirstAliveUnit(const std::vector<Unit*>& units)
{ {
for (Unit* unit : units) for (Unit* unit : units)
{
if (unit && unit->IsAlive()) if (unit && unit->IsAlive())
{
return unit; return unit;
}
}
return nullptr; return nullptr;
} }
@@ -65,8 +73,11 @@ Unit* RaidKarazhanHelpers::GetFirstAliveUnitByEntry(uint32 entry)
Unit* unit = botAI->GetUnit(npcGuid); Unit* unit = botAI->GetUnit(npcGuid);
if (unit && unit->IsAlive() && unit->GetEntry() == entry) if (unit && unit->IsAlive() && unit->GetEntry() == entry)
{
return unit; return unit;
}
} }
return nullptr; return nullptr;
} }
@@ -79,10 +90,14 @@ Unit* RaidKarazhanHelpers::GetNearestPlayerInRadius(float radius)
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member || !member->IsAlive() || member == bot) if (!member || !member->IsAlive() || member == bot)
{
continue; continue;
}
if (bot->GetExactDist2d(member) < radius) if (bot->GetExactDist2d(member) < radius)
{
return member; return member;
}
} }
} }
return nullptr; return nullptr;
@@ -92,12 +107,13 @@ bool RaidKarazhanHelpers::IsFlameWreathActive()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran"); Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran");
if (!boss) if (!boss)
{
return false; return false;
}
Spell* currentSpell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL); Spell* currentSpell = boss->GetCurrentSpell(CURRENT_GENERIC_SPELL);
if (currentSpell && currentSpell->m_spellInfo && currentSpell->m_spellInfo->Id == SPELL_FLAME_WREATH) if (currentSpell && currentSpell->m_spellInfo && currentSpell->m_spellInfo->Id == SPELL_FLAME_WREATH)
{ {
bot->Yell("I will not move when Flame Wreath is cast or the raid blows up.", LANG_UNIVERSAL);
return true; return true;
} }
@@ -107,9 +123,13 @@ bool RaidKarazhanHelpers::IsFlameWreathActive()
{ {
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member || !member->IsAlive()) if (!member || !member->IsAlive())
{
continue; continue;
}
if (member->HasAura(SPELL_AURA_FLAME_WREATH)) if (member->HasAura(SPELL_AURA_FLAME_WREATH))
{
return true; return true;
}
} }
} }
return false; return false;
@@ -125,7 +145,9 @@ std::vector<Player*> RaidKarazhanHelpers::GetBlueBlockers()
{ {
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member)) if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
{
continue; continue;
}
bool isDps = botAI->IsDps(member); bool isDps = botAI->IsDps(member);
bool isWarrior = member->getClass() == CLASS_WARRIOR; bool isWarrior = member->getClass() == CLASS_WARRIOR;
@@ -155,7 +177,9 @@ std::vector<Player*> RaidKarazhanHelpers::GetGreenBlockers()
{ {
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member)) if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member))
{
continue; continue;
}
bool hasExhaustion = member->HasAura(SPELL_NETHER_EXHAUSTION_GREEN); bool hasExhaustion = member->HasAura(SPELL_NETHER_EXHAUSTION_GREEN);
Aura* greenBuff = member->GetAura(SPELL_GREEN_BEAM_DEBUFF); Aura* greenBuff = member->GetAura(SPELL_GREEN_BEAM_DEBUFF);
@@ -188,7 +212,9 @@ Position RaidKarazhanHelpers::GetPositionOnBeam(Unit* boss, Unit* portal, float
float length = sqrt(dx*dx + dy*dy); float length = sqrt(dx*dx + dy*dy);
if (length == 0.0f) if (length == 0.0f)
{
return Position(bx, by, bz); return Position(bx, by, bz);
}
dx /= length; dx /= length;
dy /= length; dy /= length;
@@ -213,26 +239,37 @@ std::tuple<Player*, Player*, Player*> RaidKarazhanHelpers::GetCurrentBeamBlocker
{ {
Player* member = itr->GetSource(); Player* member = itr->GetSource();
if (!member || !member->IsAlive()) if (!member || !member->IsAlive())
{
continue; continue;
PlayerbotAI* memberAI = sPlayerbotsMgr->GetPlayerbotAI(member); }
if (!memberAI || !memberAI->IsTank(member)) if (!botAI->IsTank(member))
{
continue; continue;
}
if (member->HasAura(SPELL_NETHER_EXHAUSTION_RED)) if (member->HasAura(SPELL_NETHER_EXHAUSTION_RED))
{
continue; continue;
}
redBlockers.push_back(member); redBlockers.push_back(member);
} }
} }
if (!redBlockers.empty()) if (!redBlockers.empty())
{
redBlocker = redBlockers.front(); redBlocker = redBlockers.front();
}
std::vector<Player*> greenBlockers = GetGreenBlockers(); std::vector<Player*> greenBlockers = GetGreenBlockers();
if (!greenBlockers.empty()) if (!greenBlockers.empty())
{
greenBlocker = greenBlockers.front(); greenBlocker = greenBlockers.front();
}
std::vector<Player*> blueBlockers = GetBlueBlockers(); std::vector<Player*> blueBlockers = GetBlueBlockers();
if (!blueBlockers.empty()) if (!blueBlockers.empty())
{
blueBlocker = blueBlockers.front(); blueBlocker = blueBlockers.front();
}
return std::make_tuple(redBlocker, greenBlocker, blueBlocker); return std::make_tuple(redBlocker, greenBlocker, blueBlocker);
} }
@@ -246,7 +283,9 @@ std::vector<Unit*> RaidKarazhanHelpers::GetAllVoidZones()
{ {
Unit* unit = botAI->GetUnit(npcGuid); Unit* unit = botAI->GetUnit(npcGuid);
if (!unit || unit->GetEntry() != NPC_VOID_ZONE) if (!unit || unit->GetEntry() != NPC_VOID_ZONE)
{
continue; continue;
}
float dist = bot->GetExactDist2d(unit); float dist = bot->GetExactDist2d(unit);
if (dist < radius) if (dist < radius)
@@ -265,7 +304,9 @@ bool RaidKarazhanHelpers::IsSafePosition(float x, float y, float z,
float dist = std::sqrt(std::pow(x - hazard->GetPositionX(), 2) + std::pow(y - hazard->GetPositionY(), 2)); float dist = std::sqrt(std::pow(x - hazard->GetPositionX(), 2) + std::pow(y - hazard->GetPositionY(), 2));
if (dist < hazardRadius) if (dist < hazardRadius)
{
return false; return false;
}
} }
return true; return true;
} }
@@ -280,7 +321,9 @@ std::vector<Unit*> RaidKarazhanHelpers::GetSpawnedInfernals() const
Unit* unit = botAI->GetUnit(npcGuid); Unit* unit = botAI->GetUnit(npcGuid);
if (unit && unit->GetEntry() == NPC_NETHERSPITE_INFERNAL) if (unit && unit->GetEntry() == NPC_NETHERSPITE_INFERNAL)
{
infernals.push_back(unit); infernals.push_back(unit);
}
} }
return infernals; return infernals;
} }
@@ -295,7 +338,10 @@ bool RaidKarazhanHelpers::IsStraightPathSafe(const Position& start, const Positi
float tz = target.GetPositionZ(); float tz = target.GetPositionZ();
float totalDist = std::sqrt(std::pow(tx - sx, 2) + std::pow(ty - sy, 2)); float totalDist = std::sqrt(std::pow(tx - sx, 2) + std::pow(ty - sy, 2));
if (totalDist == 0.0f) if (totalDist == 0.0f)
{
return true; return true;
}
for (float checkDist = 0.0f; checkDist <= totalDist; checkDist += stepSize) for (float checkDist = 0.0f; checkDist <= totalDist; checkDist += stepSize)
{ {
float t = checkDist / totalDist; float t = checkDist / totalDist;
@@ -306,56 +352,54 @@ bool RaidKarazhanHelpers::IsStraightPathSafe(const Position& start, const Positi
{ {
float hazardDist = std::sqrt(std::pow(checkX - hazard->GetPositionX(), 2) + std::pow(checkY - hazard->GetPositionY(), 2)); float hazardDist = std::sqrt(std::pow(checkX - hazard->GetPositionX(), 2) + std::pow(checkY - hazard->GetPositionY(), 2));
if (hazardDist < hazardRadius) if (hazardDist < hazardRadius)
{
return false; return false;
}
} }
} }
return true; return true;
} }
Position RaidKarazhanHelpers::CalculateArcPoint(const Position& current, const Position& target, const Position& center) Position RaidKarazhanHelpers::CalculateArcPoint(const Position& current, const Position& target, const Position& center)
{ {
float arcFraction = 0.25f; float arcFraction = 0.25f;
// Calculate vectors from center to current position and target
float currentX = current.GetPositionX() - center.GetPositionX(); float currentX = current.GetPositionX() - center.GetPositionX();
float currentY = current.GetPositionY() - center.GetPositionY(); float currentY = current.GetPositionY() - center.GetPositionY();
float targetX = target.GetPositionX() - center.GetPositionX(); float targetX = target.GetPositionX() - center.GetPositionX();
float targetY = target.GetPositionY() - center.GetPositionY(); float targetY = target.GetPositionY() - center.GetPositionY();
// Calculate distances
float currentDist = std::sqrt(currentX * currentX + currentY * currentY); float currentDist = std::sqrt(currentX * currentX + currentY * currentY);
float targetDist = std::sqrt(targetX * targetX + targetY * targetY); float targetDist = std::sqrt(targetX * targetX + targetY * targetY);
if (currentDist == 0.0f || targetDist == 0.0f) if (currentDist == 0.0f || targetDist == 0.0f)
{
return current; return current;
}
// Normalize vectors
currentX /= currentDist; currentX /= currentDist;
currentY /= currentDist; currentY /= currentDist;
targetX /= targetDist; targetX /= targetDist;
targetY /= targetDist; targetY /= targetDist;
// Calculate dot product to find the angle between vectors
float dotProduct = currentX * targetX + currentY * targetY; float dotProduct = currentX * targetX + currentY * targetY;
dotProduct = std::max(-1.0f, std::min(1.0f, dotProduct)); // Clamp to [-1, 1] dotProduct = std::max(-1.0f, std::min(1.0f, dotProduct));
float angle = std::acos(dotProduct); float angle = std::acos(dotProduct);
// Determine rotation direction (clockwise or counterclockwise)
float crossProduct = currentX * targetY - currentY * targetX; float crossProduct = currentX * targetY - currentY * targetX;
float stepAngle = angle * arcFraction; // Move arcFraction along the arc float stepAngle = angle * arcFraction;
if (crossProduct < 0) if (crossProduct < 0)
stepAngle = -stepAngle; // Clockwise {
stepAngle = -stepAngle;
}
// Calculate rotation matrix components
float cos_a = std::cos(stepAngle); float cos_a = std::cos(stepAngle);
float sin_a = std::sin(stepAngle); float sin_a = std::sin(stepAngle);
// Rotate current vector
float rotatedX = currentX * cos_a - currentY * sin_a; float rotatedX = currentX * cos_a - currentY * sin_a;
float rotatedY = currentX * sin_a + currentY * cos_a; float rotatedY = currentX * sin_a + currentY * cos_a;
// Smoothing: blend current and target radius
float desiredDist = currentDist * 0.9f + targetDist * 0.1f; float desiredDist = currentDist * 0.9f + targetDist * 0.1f;
// Calculate the new position
return Position(center.GetPositionX() + rotatedX * desiredDist, return Position(center.GetPositionX() + rotatedX * desiredDist,
center.GetPositionY() + rotatedY * desiredDist, center.GetPositionY() + rotatedY * desiredDist,
current.GetPositionZ()); current.GetPositionZ());

View File

@@ -8,49 +8,49 @@
enum KarazhanSpells enum KarazhanSpells
{ {
// Maiden of Virtue // Maiden of Virtue
SPELL_REPENTANCE = 29511, SPELL_REPENTANCE = 29511,
// Opera Event // Opera Event
SPELL_LITTLE_RED_RIDING_HOOD = 30756, SPELL_LITTLE_RED_RIDING_HOOD = 30756,
// Shade of Aran // Shade of Aran
SPELL_FLAME_WREATH = 30004, SPELL_FLAME_WREATH = 30004,
SPELL_AURA_FLAME_WREATH = 29946, SPELL_AURA_FLAME_WREATH = 29946,
SPELL_ARCANE_EXPLOSION = 29973, SPELL_ARCANE_EXPLOSION = 29973,
SPELL_WARLOCK_BANISH = 18647, // Rank 2 SPELL_WARLOCK_BANISH = 18647, // Rank 2
// Netherspite // Netherspite
SPELL_GREEN_BEAM_DEBUFF = 30422, SPELL_GREEN_BEAM_DEBUFF = 30422,
SPELL_BLUE_BEAM_DEBUFF = 30423, SPELL_BLUE_BEAM_DEBUFF = 30423,
SPELL_NETHER_EXHAUSTION_RED = 38637, SPELL_NETHER_EXHAUSTION_RED = 38637,
SPELL_NETHER_EXHAUSTION_GREEN = 38638, SPELL_NETHER_EXHAUSTION_GREEN = 38638,
SPELL_NETHER_EXHAUSTION_BLUE = 38639, SPELL_NETHER_EXHAUSTION_BLUE = 38639,
SPELL_NETHERSPITE_BANISHED = 39833, SPELL_NETHERSPITE_BANISHED = 39833,
// Prince Malchezaar // Prince Malchezaar
SPELL_ENFEEBLE = 30843, SPELL_ENFEEBLE = 30843,
}; };
enum KarazhanNpcs enum KarazhanNpcs
{ {
// Attumen the Huntsman // Attumen the Huntsman
NPC_ATTUMEN_THE_HUNTSMAN = 16152, // Mounted ID NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED = 16152,
// Terestian Illhoof // Terestian Illhoof
NPC_KILREK = 17229, NPC_KILREK = 17229,
NPC_DEMON_CHAINS = 17248, NPC_DEMON_CHAINS = 17248,
// Shade of Aran // Shade of Aran
NPC_CONJURED_ELEMENTAL = 17167, NPC_CONJURED_ELEMENTAL = 17167,
// Netherspite // Netherspite
NPC_VOID_ZONE = 16697, NPC_VOID_ZONE = 16697,
NPC_RED_PORTAL = 17369, NPC_RED_PORTAL = 17369,
NPC_BLUE_PORTAL = 17368, NPC_BLUE_PORTAL = 17368,
NPC_GREEN_PORTAL = 17367, NPC_GREEN_PORTAL = 17367,
// Prince Malchezaar // Prince Malchezaar
NPC_NETHERSPITE_INFERNAL = 17646, NPC_NETHERSPITE_INFERNAL = 17646,
}; };
extern const Position KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION; extern const Position KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION;

View File

@@ -19,13 +19,17 @@ float KarazhanBigBadWolfMultiplier::GetValue(Action* action)
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "the big bad wolf"); Unit* boss = AI_VALUE2(Unit*, "find target", "the big bad wolf");
if (!boss) if (!boss)
{
return 1.0f; return 1.0f;
}
if (bot->HasAura(SPELL_LITTLE_RED_RIDING_HOOD)) if (bot->HasAura(SPELL_LITTLE_RED_RIDING_HOOD))
{ {
if ((dynamic_cast<MovementAction*>(action) && !dynamic_cast<KarazhanBigBadWolfRunAwayAction*>(action)) || if ((dynamic_cast<MovementAction*>(action) && !dynamic_cast<KarazhanBigBadWolfRunAwayAction*>(action)) ||
(dynamic_cast<AttackAction*>(action))) (dynamic_cast<AttackAction*>(action)))
return 0.0f; {
return 0.0f;
}
} }
return 1.0f; return 1.0f;
} }
@@ -34,18 +38,24 @@ float KarazhanShadeOfAranMultiplier::GetValue(Action* action)
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran"); Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran");
if (!boss) if (!boss)
{
return 1.0f; return 1.0f;
}
if (boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION)) if (boss->HasUnitState(UNIT_STATE_CASTING) && boss->FindCurrentSpellBySpellId(SPELL_ARCANE_EXPLOSION))
{ {
if (IsChargeAction(action)) if (IsChargeAction(action))
{
return 0.0f; return 0.0f;
}
if (dynamic_cast<MovementAction*>(action)) if (dynamic_cast<MovementAction*>(action))
{ {
const float safeDistance = 20.0f; const float safeDistance = 20.0f;
if (bot->GetDistance2d(boss) >= safeDistance) if (bot->GetDistance2d(boss) >= safeDistance)
{
return 0.0f; return 0.0f;
}
} }
} }
@@ -67,7 +77,9 @@ float KarazhanShadeOfAranMultiplier::GetValue(Action* action)
if (flameWreathActive) if (flameWreathActive)
{ {
if (dynamic_cast<MovementAction*>(action) || IsChargeAction(action)) if (dynamic_cast<MovementAction*>(action) || IsChargeAction(action))
{
return 0.0f; return 0.0f;
}
} }
return 1.0f; return 1.0f;
} }
@@ -76,7 +88,9 @@ float KarazhanNetherspiteBlueAndGreenBeamMultiplier::GetValue(Action* action)
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite"); Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite");
if (!boss || !boss->IsAlive()) if (!boss || !boss->IsAlive())
{
return 1.0f; return 1.0f;
}
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
auto [redBlocker /*unused*/, greenBlocker, blueBlocker] = karazhanHelper.GetCurrentBeamBlockers(); auto [redBlocker /*unused*/, greenBlocker, blueBlocker] = karazhanHelper.GetCurrentBeamBlockers();
@@ -88,18 +102,25 @@ float KarazhanNetherspiteBlueAndGreenBeamMultiplier::GetValue(Action* action)
bool inBeam = false; bool inBeam = false;
for (Unit* portal : {bluePortal, greenPortal}) { for (Unit* portal : {bluePortal, greenPortal}) {
if (!portal) continue; if (!portal)
{
continue;
}
float bx = boss->GetPositionX(), by = boss->GetPositionY(); float bx = boss->GetPositionX(), by = boss->GetPositionY();
float px = portal->GetPositionX(), py = portal->GetPositionY(); float px = portal->GetPositionX(), py = portal->GetPositionY();
float dx = px - bx, dy = py - by; float dx = px - bx, dy = py - by;
float length = sqrt(dx*dx + dy*dy); float length = sqrt(dx*dx + dy*dy);
if (length == 0.0f) continue; if (length == 0.0f)
{
continue;
}
dx /= length; dy /= length; dx /= length; dy /= length;
float botdx = bot->GetPositionX() - bx, botdy = bot->GetPositionY() - by; float botdx = bot->GetPositionX() - bx, botdy = bot->GetPositionY() - by;
float t = (botdx * dx + botdy * dy); float t = (botdx * dx + botdy * dy);
float beamX = bx + dx * t, beamY = by + dy * t; float beamX = bx + dx * t, beamY = by + dy * t;
float distToBeam = sqrt(pow(bot->GetPositionX() - beamX, 2) + pow(bot->GetPositionY() - beamY, 2)); float distToBeam = sqrt(pow(bot->GetPositionX() - beamX, 2) + pow(bot->GetPositionY() - beamY, 2));
if (distToBeam < 5.0f && t > 0.0f && t < length) { if (distToBeam < 5.0f && t > 0.0f && t < length)
{
inBeam = true; inBeam = true;
break; break;
} }
@@ -118,7 +139,9 @@ float KarazhanNetherspiteBlueAndGreenBeamMultiplier::GetValue(Action* action)
if (!inVoidZone) if (!inVoidZone)
{ {
if (dynamic_cast<MovementAction*>(action) || IsChargeAction(action)) if (dynamic_cast<MovementAction*>(action) || IsChargeAction(action))
{
return 0.0f; return 0.0f;
}
} }
} }
} }
@@ -129,7 +152,9 @@ float KarazhanNetherspiteRedBeamMultiplier::GetValue(Action* action)
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite"); Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite");
if (!boss || !boss->IsAlive()) if (!boss || !boss->IsAlive())
{
return 1.0f; return 1.0f;
}
RaidKarazhanHelpers karazhanHelper(botAI); RaidKarazhanHelpers karazhanHelper(botAI);
auto [redBlocker, greenBlocker /*unused*/, blueBlocker /*unused*/] = karazhanHelper.GetCurrentBeamBlockers(); auto [redBlocker, greenBlocker /*unused*/, blueBlocker /*unused*/] = karazhanHelper.GetCurrentBeamBlockers();
@@ -177,7 +202,9 @@ float KarazhanNetherspiteRedBeamMultiplier::GetValue(Action* action)
if (distToTarget < positionTolerance) if (distToTarget < positionTolerance)
{ {
if (dynamic_cast<MovementAction*>(action) || IsChargeAction(action)) if (dynamic_cast<MovementAction*>(action) || IsChargeAction(action))
{
return 0.0f; return 0.0f;
}
} }
} }
} }
@@ -187,13 +214,14 @@ float KarazhanNetherspiteRedBeamMultiplier::GetValue(Action* action)
float KarazhanPrinceMalchezaarMultiplier::GetValue(Action* action) float KarazhanPrinceMalchezaarMultiplier::GetValue(Action* action)
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar"); Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar");
if (!boss)
return 1.0f;
if (boss && bot->HasAura(SPELL_ENFEEBLE)) if (boss && botAI->IsMelee(bot) && bot->HasAura(SPELL_ENFEEBLE))
{ {
if (IsChargeAction(action)) if (dynamic_cast<KarazhanPrinceMalchezaarNonTankAvoidHazardAction*>(action))
return 0.0f; {
return 1.0f;
}
return 0.0f;
} }
return 1.0f; return 1.0f;
} }

View File

@@ -6,8 +6,9 @@
bool KarazhanAttumenTheHuntsmanTrigger::IsActive() bool KarazhanAttumenTheHuntsmanTrigger::IsActive()
{ {
RaidKarazhanHelpers helpers(botAI); RaidKarazhanHelpers helpers(botAI);
Unit* boss = helpers.GetFirstAliveUnitByEntry(NPC_ATTUMEN_THE_HUNTSMAN); Unit* boss = helpers.GetFirstAliveUnitByEntry(NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
return boss != nullptr;
return boss && boss->IsAlive();
} }
bool KarazhanMoroesTrigger::IsActive() bool KarazhanMoroesTrigger::IsActive()
@@ -20,36 +21,27 @@ bool KarazhanMoroesTrigger::IsActive()
Unit* robin = AI_VALUE2(Unit*, "find target", "lord robin daris"); Unit* robin = AI_VALUE2(Unit*, "find target", "lord robin daris");
Unit* crispin = AI_VALUE2(Unit*, "find target", "lord crispin ference"); Unit* crispin = AI_VALUE2(Unit*, "find target", "lord crispin ference");
if ((!moroes || !moroes->IsAlive()) && return ((moroes && moroes->IsAlive()) ||
(!dorothea || !dorothea->IsAlive()) && (dorothea && dorothea->IsAlive()) ||
(!catriona || !catriona->IsAlive()) && (catriona && catriona->IsAlive()) ||
(!keira || !keira->IsAlive()) && (keira && keira->IsAlive()) ||
(!rafe || !rafe->IsAlive()) && (rafe && rafe->IsAlive()) ||
(!robin || !robin->IsAlive()) && (robin && robin->IsAlive()) ||
(!crispin || !crispin->IsAlive())) (crispin && crispin->IsAlive()));
return false;
return true;
} }
bool KarazhanMaidenOfVirtueTrigger::IsActive() bool KarazhanMaidenOfVirtueTrigger::IsActive()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "maiden of virtue"); Unit* boss = AI_VALUE2(Unit*, "find target", "maiden of virtue");
if (!boss || !boss->IsAlive()) return boss && boss->IsAlive();
return false;
return true;
} }
bool KarazhanBigBadWolfTrigger::IsActive() bool KarazhanBigBadWolfTrigger::IsActive()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "the big bad wolf"); Unit* boss = AI_VALUE2(Unit*, "find target", "the big bad wolf");
if (!boss || !boss->IsAlive()) return boss && boss->IsAlive();
return false;
return true;
} }
bool KarazhanRomuloAndJulianneTrigger::IsActive() bool KarazhanRomuloAndJulianneTrigger::IsActive()
@@ -57,10 +49,7 @@ bool KarazhanRomuloAndJulianneTrigger::IsActive()
Unit* julianne = AI_VALUE2(Unit*, "find target", "julianne"); Unit* julianne = AI_VALUE2(Unit*, "find target", "julianne");
Unit* romulo = AI_VALUE2(Unit*, "find target", "romulo"); Unit* romulo = AI_VALUE2(Unit*, "find target", "romulo");
if (!julianne || !julianne->IsAlive() || !romulo || !romulo->IsAlive()) return julianne && julianne->IsAlive() && romulo && romulo->IsAlive();
return false;
return true;
} }
bool KarazhanWizardOfOzTrigger::IsActive() bool KarazhanWizardOfOzTrigger::IsActive()
@@ -72,63 +61,45 @@ bool KarazhanWizardOfOzTrigger::IsActive()
Unit* tinhead = AI_VALUE2(Unit*, "find target", "tinhead"); Unit* tinhead = AI_VALUE2(Unit*, "find target", "tinhead");
Unit* crone = AI_VALUE2(Unit*, "find target", "the crone"); Unit* crone = AI_VALUE2(Unit*, "find target", "the crone");
if (( !dorothee || !dorothee->IsAlive() ) && return ((dorothee && dorothee->IsAlive()) ||
( !tito || !tito->IsAlive() ) && (tito && tito->IsAlive()) ||
( !roar || !roar->IsAlive() ) && (roar && roar->IsAlive()) ||
( !strawman || !strawman->IsAlive() ) && (strawman && strawman->IsAlive()) ||
( !tinhead || !tinhead->IsAlive() ) && (tinhead && tinhead->IsAlive()) ||
( !crone || !crone->IsAlive() )) (crone && crone->IsAlive()));
return false;
return true;
} }
bool KarazhanTheCuratorTrigger::IsActive() bool KarazhanTheCuratorTrigger::IsActive()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "the curator"); Unit* boss = AI_VALUE2(Unit*, "find target", "the curator");
if (!boss || !boss->IsAlive()) return boss && boss->IsAlive();
return false;
return true;
} }
bool KarazhanTerestianIllhoofTrigger::IsActive() bool KarazhanTerestianIllhoofTrigger::IsActive()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "terestian illhoof"); Unit* boss = AI_VALUE2(Unit*, "find target", "terestian illhoof");
if (!boss || !boss->IsAlive()) return boss && boss->IsAlive();
return false;
return true;
} }
bool KarazhanShadeOfAranTrigger::IsActive() bool KarazhanShadeOfAranTrigger::IsActive()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran"); Unit* boss = AI_VALUE2(Unit*, "find target", "shade of aran");
if (!boss) return boss && boss->IsAlive();
return false;
return true;
} }
bool KarazhanNetherspiteTrigger::IsActive() bool KarazhanNetherspiteTrigger::IsActive()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite"); Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite");
if (!boss || !boss->IsAlive()) return boss && boss->IsAlive();
return false;
return true;
} }
bool KarazhanPrinceMalchezaarTrigger::IsActive() bool KarazhanPrinceMalchezaarTrigger::IsActive()
{ {
Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar"); Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar");
if (!boss || !boss->IsAlive()) return boss && boss->IsAlive();
return false;
return true;
} }