mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Various corrections
This commit is contained in:
@@ -29,7 +29,12 @@ bool KarazhanAttumenTheHuntsmanStackBehindAction::Execute(Event event)
|
||||
float rx = x + cos(orientation) * distance;
|
||||
float ry = y + sin(orientation) * distance;
|
||||
|
||||
return MoveTo(bot->GetMapId(), rx, ry, z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
if (bot->GetExactDist2d(rx, ry) > 1.0f)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), rx, ry, z, false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KarazhanAttumenTheHuntsmanStackBehindAction::isUseful()
|
||||
@@ -83,6 +88,9 @@ bool KarazhanMaidenOfVirtuePositionBossAction::Execute(Event event)
|
||||
float targetY = healer->GetPositionY() + sin(angle) * 6.0f;
|
||||
float targetZ = healer->GetPositionZ();
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
|
||||
return MoveTo(bot->GetMapId(), targetX, targetY, targetZ, false, false, false, true,
|
||||
MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
@@ -98,6 +106,9 @@ bool KarazhanMaidenOfVirtuePositionBossAction::Execute(Event event)
|
||||
float mX = KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION.GetPositionX() + (dX / distanceToBossPosition) * maxDistance;
|
||||
float mY = KARAZHAN_MAIDEN_OF_VIRTUE_BOSS_POSITION.GetPositionY() + (dY / distanceToBossPosition) * maxDistance;
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
|
||||
return MoveTo(bot->GetMapId(), mX, mY,
|
||||
bot->GetPositionZ(), false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
@@ -144,6 +155,9 @@ bool KarazhanMaidenOfVirtuePositionRangedAction::Execute(Event event)
|
||||
const float maxDistance = 2.0f;
|
||||
if (distance > maxDistance)
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
|
||||
return MoveTo(bot->GetMapId(), KARAZHAN_MAIDEN_OF_VIRTUE_RANGED_POSITION[index].GetPositionX(),
|
||||
KARAZHAN_MAIDEN_OF_VIRTUE_RANGED_POSITION[index].GetPositionY(), bot->GetPositionZ(), false,
|
||||
false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
@@ -206,6 +220,9 @@ bool KarazhanBigBadWolfRunAwayAction::Execute(Event event)
|
||||
target = KARAZHAN_BIG_BAD_WOLF_RUN_POSITION[currentIndex];
|
||||
}
|
||||
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
|
||||
return MoveTo(bot->GetMapId(), target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(),
|
||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
}
|
||||
@@ -326,6 +343,9 @@ bool KarazhanTheCuratorSpreadRangedAction::Execute(Event event)
|
||||
|
||||
if (nearestPlayer)
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
|
||||
return FleePosition(nearestPlayer->GetPosition(), minDistance);
|
||||
}
|
||||
|
||||
@@ -368,11 +388,11 @@ bool KarazhanShadeOfAranArcaneExplosionRunAwayAction::Execute(Event event)
|
||||
const float safeDistance = 20.0f;
|
||||
const float distance = bot->GetDistance2d(boss);
|
||||
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
|
||||
if (distance < safeDistance)
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
|
||||
return MoveAway(boss, safeDistance - distance);
|
||||
}
|
||||
|
||||
@@ -469,36 +489,27 @@ bool KarazhanNetherspiteBlockRedBeamAction::Execute(Event event)
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "netherspite");
|
||||
Unit* redPortal = bot->FindNearestCreature(NPC_RED_PORTAL, 150.0f);
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Player* eligibleTank = nullptr;
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (!member || !member->IsAlive() || !botAI->IsTank(member) || !GET_PLAYERBOT_AI(member) ||
|
||||
member->HasAura(SPELL_NETHER_EXHAUSTION_RED))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
eligibleTank = member;
|
||||
break;
|
||||
}
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
static std::map<ObjectGuid, bool> wasBlockingRedBeam;
|
||||
ObjectGuid botGuid = bot->GetGUID();
|
||||
auto [redBlocker, greenBlocker, blueBlocker] = karazhanHelper.GetCurrentBeamBlockers();
|
||||
bool isBlockingNow = (bot == redBlocker);
|
||||
bool wasBlocking = wasBlockingRedBeam[botGuid];
|
||||
|
||||
Position beamPos = karazhanHelper.GetPositionOnBeam(boss, redPortal, 18.0f);
|
||||
|
||||
if (bot == eligibleTank)
|
||||
if (isBlockingNow)
|
||||
{
|
||||
std::map<std::string, std::string> ph;
|
||||
ph["%player"] = bot->GetName();
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"netherspite_beam_blocking_red", "%player is moving to block the red beam!", ph);
|
||||
bot->Yell(text, LANG_UNIVERSAL);
|
||||
if (!wasBlocking)
|
||||
{
|
||||
std::map<std::string, std::string> ph;
|
||||
ph["%player"] = bot->GetName();
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"netherspite_beam_blocking_red", "%player is moving to block the red beam!", ph);
|
||||
bot->Yell(text, LANG_UNIVERSAL);
|
||||
}
|
||||
wasBlockingRedBeam[botGuid] = true;
|
||||
|
||||
ObjectGuid botGuid = bot->GetGUID();
|
||||
uint32 intervalSecs = 5;
|
||||
|
||||
if (beamMoveTimes[botGuid] == 0)
|
||||
@@ -516,7 +527,6 @@ bool KarazhanNetherspiteBlockRedBeamAction::Execute(Event event)
|
||||
return MoveTo(bot->GetMapId(), beamPos.GetPositionX(), beamPos.GetPositionY(), beamPos.GetPositionZ(),
|
||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
float bx = boss->GetPositionX();
|
||||
@@ -544,6 +554,7 @@ bool KarazhanNetherspiteBlockRedBeamAction::Execute(Event event)
|
||||
}
|
||||
}
|
||||
|
||||
wasBlockingRedBeam[botGuid] = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -556,11 +567,6 @@ bool KarazhanNetherspiteBlockRedBeamAction::isUseful()
|
||||
static std::map<ObjectGuid, bool> lastBossBanishState;
|
||||
bool bossIsBanished = boss && boss->HasAura(SPELL_NETHERSPITE_BANISHED);
|
||||
|
||||
if (!boss || !redPortal || bossIsBanished)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lastBossBanishState[botGuid] != bossIsBanished)
|
||||
{
|
||||
if (!bossIsBanished)
|
||||
@@ -571,10 +577,10 @@ bool KarazhanNetherspiteBlockRedBeamAction::isUseful()
|
||||
lastBossBanishState[botGuid] = bossIsBanished;
|
||||
}
|
||||
|
||||
return true;
|
||||
return boss && redPortal && !bossIsBanished;
|
||||
}
|
||||
|
||||
// Two non-Rogue/Warrior DPS bots will block the blue beam for each phase (swap at 25 debuff stacks)
|
||||
// Two non-Rogue/Warrior DPS bots will block the blue beam for each phase (swap at 26 debuff stacks)
|
||||
// When avoiding void zones, blocking bots will move along the beam to continue blocking
|
||||
bool KarazhanNetherspiteBlockBlueBeamAction::Execute(Event event)
|
||||
{
|
||||
@@ -582,11 +588,10 @@ bool KarazhanNetherspiteBlockBlueBeamAction::Execute(Event event)
|
||||
Unit* bluePortal = bot->FindNearestCreature(NPC_BLUE_PORTAL, 150.0f);
|
||||
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
std::vector<Player*> blueBlockers = karazhanHelper.GetBlueBlockers();
|
||||
static std::map<ObjectGuid, bool> wasBlockingBlueBeam;
|
||||
ObjectGuid botGuid = bot->GetGUID();
|
||||
Player* assignedBlueBlocker = blueBlockers.empty() ? nullptr : blueBlockers.front();
|
||||
bool isBlockingNow = (bot == assignedBlueBlocker);
|
||||
auto [redBlocker, greenBlocker, blueBlocker] = karazhanHelper.GetCurrentBeamBlockers();
|
||||
bool isBlockingNow = (bot == blueBlocker);
|
||||
bool wasBlocking = wasBlockingBlueBeam[botGuid];
|
||||
|
||||
if (wasBlocking && !isBlockingNow)
|
||||
@@ -596,8 +601,8 @@ bool KarazhanNetherspiteBlockBlueBeamAction::Execute(Event event)
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"netherspite_beam_leaving_blue", "%player is leaving the blue beam--next blocker up!", ph);
|
||||
bot->Yell(text, LANG_UNIVERSAL);
|
||||
|
||||
wasBlockingBlueBeam[botGuid] = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -632,7 +637,7 @@ bool KarazhanNetherspiteBlockBlueBeamAction::Execute(Event event)
|
||||
float bestDist = 150.0f;
|
||||
Position bestPos;
|
||||
bool found = false;
|
||||
for (float dist = 18.0f; dist <= 25.0f; dist += 0.5f)
|
||||
for (float dist = 18.0f; dist <= 30.0f; dist += 0.5f)
|
||||
{
|
||||
float candidateX = bx + dx * dist;
|
||||
float candidateY = by + dy * dist;
|
||||
@@ -662,6 +667,9 @@ bool KarazhanNetherspiteBlockBlueBeamAction::Execute(Event event)
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
|
||||
return MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(),
|
||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
}
|
||||
@@ -681,7 +689,7 @@ bool KarazhanNetherspiteBlockBlueBeamAction::isUseful()
|
||||
return boss && bluePortal && !boss->HasAura(SPELL_NETHERSPITE_BANISHED);
|
||||
}
|
||||
|
||||
// Two healer bots will block the green beam for each phase (swap at 25 debuff stacks)
|
||||
// Two healer bots will block the green beam for each phase (swap at 26 debuff stacks)
|
||||
// OR one rogue or DPS warrior bot will block the green beam for an entire phase (if they begin the phase as the blocker)
|
||||
// When avoiding void zones, blocking bots will move along the beam to continue blocking
|
||||
bool KarazhanNetherspiteBlockGreenBeamAction::Execute(Event event)
|
||||
@@ -690,11 +698,10 @@ bool KarazhanNetherspiteBlockGreenBeamAction::Execute(Event event)
|
||||
Unit* greenPortal = bot->FindNearestCreature(NPC_GREEN_PORTAL, 150.0f);
|
||||
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
std::vector<Player*> greenBlockers = karazhanHelper.GetGreenBlockers();
|
||||
static std::map<ObjectGuid, bool> wasBlockingGreenBeam;
|
||||
ObjectGuid botGuid = bot->GetGUID();
|
||||
Player* assignedGreenBlocker = greenBlockers.empty() ? nullptr : greenBlockers.front();
|
||||
bool isBlockingNow = (bot == assignedGreenBlocker);
|
||||
auto [redBlocker, greenBlocker, blueBlocker] = karazhanHelper.GetCurrentBeamBlockers();
|
||||
bool isBlockingNow = (bot == greenBlocker);
|
||||
bool wasBlocking = wasBlockingGreenBeam[botGuid];
|
||||
|
||||
if (wasBlocking && !isBlockingNow)
|
||||
@@ -704,8 +711,8 @@ bool KarazhanNetherspiteBlockGreenBeamAction::Execute(Event event)
|
||||
std::string text = sPlayerbotTextMgr->GetBotTextOrDefault(
|
||||
"netherspite_beam_leaving_green", "%player is leaving the green beam--next blocker up!", ph);
|
||||
bot->Yell(text, LANG_UNIVERSAL);
|
||||
|
||||
wasBlockingGreenBeam[botGuid] = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -740,7 +747,7 @@ bool KarazhanNetherspiteBlockGreenBeamAction::Execute(Event event)
|
||||
float bestDist = 150.0f;
|
||||
Position bestPos;
|
||||
bool found = false;
|
||||
for (float dist = 18.0f; dist <= 25.0f; dist += 0.5f)
|
||||
for (float dist = 18.0f; dist <= 30.0f; dist += 0.5f)
|
||||
{
|
||||
float candidateX = bx + dx * dist;
|
||||
float candidateY = by + dy * dist;
|
||||
@@ -770,6 +777,9 @@ bool KarazhanNetherspiteBlockGreenBeamAction::Execute(Event event)
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
|
||||
return MoveTo(bot->GetMapId(), bestPos.GetPositionX(), bestPos.GetPositionY(), bestPos.GetPositionZ(),
|
||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED);
|
||||
}
|
||||
@@ -796,7 +806,6 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event)
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
auto [redBlocker, greenBlocker, blueBlocker] = karazhanHelper.GetCurrentBeamBlockers();
|
||||
std::vector<Unit*> voidZones = karazhanHelper.GetAllVoidZones();
|
||||
|
||||
bool nearVoidZone = false;
|
||||
for (Unit* vz : voidZones)
|
||||
{
|
||||
@@ -806,7 +815,6 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct BeamAvoid { Unit* portal; float minDist, maxDist; };
|
||||
std::vector<BeamAvoid> beams;
|
||||
Unit* redPortal = bot->FindNearestCreature(NPC_RED_PORTAL, 150.0f);
|
||||
@@ -863,14 +871,14 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event)
|
||||
return false;
|
||||
}
|
||||
|
||||
const float minMoveDist = 3.0f, maxSearchDist = 20.0f, stepAngle = M_PI/18.0f, stepDist = 0.5f;
|
||||
const float minMoveDist = 2.0f, maxSearchDist = 30.0f, stepAngle = M_PI/18.0f, stepDist = 0.5f;
|
||||
float bossZ = boss->GetPositionZ();
|
||||
Position bestCandidate;
|
||||
float bestDist = 0.0f;
|
||||
bool found = false;
|
||||
for (float angle = 0; angle < 2 * M_PI; angle += stepAngle)
|
||||
{
|
||||
for (float dist = 5.0f; dist <= maxSearchDist; dist += stepDist)
|
||||
for (float dist = 2.0f; dist <= maxSearchDist; dist += stepDist)
|
||||
{
|
||||
float cx = bot->GetPositionX() + cos(angle) * dist;
|
||||
float cy = bot->GetPositionY() + sin(angle) * dist;
|
||||
@@ -922,9 +930,13 @@ bool KarazhanNetherspiteAvoidBeamAndVoidZoneAction::Execute(Event event)
|
||||
bestCandidate.GetPositionY(), bestCandidate.GetPositionZ(),
|
||||
voidZones, 4.0f))
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
|
||||
return MoveTo(bot->GetMapId(), bestCandidate.GetPositionX(), bestCandidate.GetPositionY(),
|
||||
bestCandidate.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -989,9 +1001,9 @@ bool KarazhanPrinceMalchezaarNonTankAvoidHazardAction::Execute(Event event)
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
std::vector<Unit*> infernals = karazhanHelper.GetSpawnedInfernals();
|
||||
|
||||
const float minSafeBossDistance = 35.0f;
|
||||
const float maxSafeBossDistance = 40.0f;
|
||||
const float safeInfernalDistance = 22.0f;
|
||||
const float minSafeBossDistance = 34.0f;
|
||||
const float maxSafeBossDistance = 60.0f;
|
||||
const float safeInfernalDistance = 23.0f;
|
||||
const float stepSize = 0.5f;
|
||||
const int numAngles = 64;
|
||||
float bx = bot->GetPositionX();
|
||||
@@ -1016,19 +1028,25 @@ bool KarazhanPrinceMalchezaarNonTankAvoidHazardAction::Execute(Event event)
|
||||
float x = bossX + dx * dist;
|
||||
float y = bossY + dy * dist;
|
||||
float destZ = bossZ;
|
||||
if (!bot->IsWithinLOS(x, y, destZ))
|
||||
float destX = x, destY = y, destZ2 = destZ;
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bx, by, bz, destX, destY, destZ2, true))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
bool pathSafe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, destZ),
|
||||
float distFromBoss = sqrt(pow(destX - bossX, 2) + pow(destY - bossY, 2));
|
||||
if (distFromBoss < minSafeBossDistance)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
bool pathSafe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(destX, destY, destZ2),
|
||||
infernals, safeInfernalDistance, stepSize);
|
||||
float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2));
|
||||
float moveDist = sqrt(pow(destX - bx, 2) + pow(destY - by, 2));
|
||||
if (pathSafe && moveDist < bestMoveDist)
|
||||
{
|
||||
bestMoveDist = moveDist;
|
||||
bestDestX = x;
|
||||
bestDestY = y;
|
||||
bestDestZ = destZ;
|
||||
bestDestX = destX;
|
||||
bestDestY = destY;
|
||||
bestDestZ = destZ2;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
@@ -1062,63 +1080,41 @@ bool KarazhanPrinceMalchezaarNonTankAvoidHazardAction::Execute(Event event)
|
||||
float bestMoveDist = std::numeric_limits<float>::max();
|
||||
float bestDestX = bx, bestDestY = by, bestDestZ = bz;
|
||||
bool found = false;
|
||||
bool usedArc = false;
|
||||
for (int i = 0; i < numAngles; ++i)
|
||||
{
|
||||
float angle = (2 * M_PI * i) / numAngles;
|
||||
float dx = cos(angle);
|
||||
float dy = sin(angle);
|
||||
for (float dist = stepSize; dist <= 35.0f; dist += stepSize)
|
||||
for (float dist = stepSize; dist <= maxSafeBossDistance; dist += stepSize)
|
||||
{
|
||||
float x = bossX + dx * dist;
|
||||
float y = bossY + dy * dist;
|
||||
float destZ = bossZ;
|
||||
if (!bot->IsWithinLOS(x, y, destZ))
|
||||
float destX = x, destY = y, destZ2 = destZ;
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bossX, bossY, bossZ, destX, destY, destZ2, true))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
bool pathSafe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, destZ),
|
||||
infernals, safeInfernalDistance, stepSize);
|
||||
float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2));
|
||||
if (pathSafe && moveDist < bestMoveDist)
|
||||
bool destSafe = true;
|
||||
for (Unit* infernal : infernals)
|
||||
{
|
||||
float infernalDist = sqrt(pow(destX - infernal->GetPositionX(), 2) + pow(destY - infernal->GetPositionY(), 2));
|
||||
if (infernalDist < safeInfernalDistance)
|
||||
{
|
||||
destSafe = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!destSafe)
|
||||
continue;
|
||||
float moveDist = sqrt(pow(destX - bx, 2) + pow(destY - by, 2));
|
||||
if (moveDist < bestMoveDist)
|
||||
{
|
||||
bestMoveDist = moveDist;
|
||||
bestDestX = x;
|
||||
bestDestY = y;
|
||||
bestDestZ = destZ;
|
||||
bestDestX = destX;
|
||||
bestDestY = destY;
|
||||
bestDestZ = destZ2;
|
||||
found = true;
|
||||
usedArc = false;
|
||||
}
|
||||
if (!pathSafe)
|
||||
{
|
||||
Position arcPoint = karazhanHelper.CalculateArcPoint(Position(bx, by, bz), Position(x, y, destZ),
|
||||
Position(bossX, bossY, bossZ));
|
||||
if (!bot->IsWithinLOS(arcPoint.GetPositionX(), arcPoint.GetPositionY(), arcPoint.GetPositionZ()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
bool arcSafe = true;
|
||||
for (Unit* infernal : infernals)
|
||||
{
|
||||
float infernalDist = sqrt(pow(arcPoint.GetPositionX() - infernal->GetPositionX(), 2) +
|
||||
pow(arcPoint.GetPositionY() - infernal->GetPositionY(), 2));
|
||||
if (infernalDist < safeInfernalDistance)
|
||||
{
|
||||
arcSafe = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
float arcMoveDist = sqrt(pow(arcPoint.GetPositionX() - bx, 2) +
|
||||
pow(arcPoint.GetPositionY() - by, 2));
|
||||
if (arcSafe && arcMoveDist < bestMoveDist)
|
||||
{
|
||||
bestMoveDist = arcMoveDist;
|
||||
bestDestX = arcPoint.GetPositionX();
|
||||
bestDestY = arcPoint.GetPositionY();
|
||||
bestDestZ = arcPoint.GetPositionZ();
|
||||
found = true;
|
||||
usedArc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1149,17 +1145,13 @@ bool KarazhanPrinceMalchezaarTankAvoidHazardAction::Execute(Event event)
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
std::vector<Unit*> infernals = karazhanHelper.GetSpawnedInfernals();
|
||||
|
||||
const float safeInfernalDistance = 30.0f;
|
||||
const float safeInfernalDistance = 28.0f;
|
||||
const float stepSize = 0.5f;
|
||||
const int numAngles = 64;
|
||||
const float maxSampleDist = 60.0f;
|
||||
float bx = bot->GetPositionX();
|
||||
float by = bot->GetPositionY();
|
||||
float bz = bot->GetPositionZ();
|
||||
float bestMoveDist = std::numeric_limits<float>::max();
|
||||
float bestDestX = bx, bestDestY = by, bestDestZ = bz;
|
||||
bool found = false;
|
||||
bool usedArc = false;
|
||||
|
||||
bool nearInfernal = false;
|
||||
for (Unit* infernal : infernals)
|
||||
@@ -1172,6 +1164,10 @@ bool KarazhanPrinceMalchezaarTankAvoidHazardAction::Execute(Event event)
|
||||
}
|
||||
}
|
||||
|
||||
float bestMoveDist = std::numeric_limits<float>::max();
|
||||
float bestDestX = bx, bestDestY = by, bestDestZ = bz;
|
||||
bool found = false;
|
||||
|
||||
if (nearInfernal)
|
||||
{
|
||||
for (int i = 0; i < numAngles; ++i)
|
||||
@@ -1184,54 +1180,72 @@ bool KarazhanPrinceMalchezaarTankAvoidHazardAction::Execute(Event event)
|
||||
float x = bx + dx * dist;
|
||||
float y = by + dy * dist;
|
||||
float z = bz;
|
||||
if (!bot->IsWithinLOS(x, y, z))
|
||||
{
|
||||
|
||||
float destX = x, destY = y, destZ = z;
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bx, by, bz, destX, destY, destZ, true))
|
||||
continue;
|
||||
|
||||
bool destSafe = true;
|
||||
for (Unit* infernal : infernals)
|
||||
{
|
||||
float infernalDist = sqrt(pow(destX - infernal->GetPositionX(), 2) + pow(destY - infernal->GetPositionY(), 2));
|
||||
if (infernalDist < safeInfernalDistance)
|
||||
{
|
||||
destSafe = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool safe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(x, y, z),
|
||||
infernals, safeInfernalDistance, stepSize);
|
||||
float moveDist = sqrt(pow(x - bx, 2) + pow(y - by, 2));
|
||||
if (safe && moveDist < bestMoveDist)
|
||||
if (!destSafe)
|
||||
continue;
|
||||
|
||||
bool pathSafe = karazhanHelper.IsStraightPathSafe(Position(bx, by, bz), Position(destX, destY, destZ),
|
||||
infernals, safeInfernalDistance, stepSize);
|
||||
float moveDist = sqrt(pow(destX - bx, 2) + pow(destY - by, 2));
|
||||
if (pathSafe && moveDist < bestMoveDist)
|
||||
{
|
||||
bestMoveDist = moveDist;
|
||||
bestDestX = x;
|
||||
bestDestY = y;
|
||||
bestDestZ = z;
|
||||
bestDestX = destX;
|
||||
bestDestY = destY;
|
||||
bestDestZ = destZ;
|
||||
found = true;
|
||||
usedArc = false;
|
||||
}
|
||||
if (!safe)
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
for (int i = 0; i < numAngles; ++i)
|
||||
{
|
||||
float angle = (2 * M_PI * i) / numAngles;
|
||||
float dx = cos(angle);
|
||||
float dy = sin(angle);
|
||||
for (float dist = stepSize; dist <= maxSampleDist; dist += stepSize)
|
||||
{
|
||||
Position arcPoint = karazhanHelper.CalculateArcPoint(Position(bx, by, bz), Position(x, y, z),
|
||||
Position(bx, by, bz));
|
||||
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))
|
||||
{
|
||||
float x = bx + dx * dist;
|
||||
float y = by + dy * dist;
|
||||
float z = bz;
|
||||
|
||||
float destX = x, destY = y, destZ = z;
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bx, by, bz, destX, destY, destZ, true))
|
||||
continue;
|
||||
}
|
||||
bool arcSafe = true;
|
||||
|
||||
bool destSafe = true;
|
||||
for (Unit* infernal : infernals)
|
||||
{
|
||||
float infernalDist = sqrt(pow(arcPoint.GetPositionX() - infernal->GetPositionX(), 2) +
|
||||
pow(arcPoint.GetPositionY() - infernal->GetPositionY(), 2));
|
||||
float infernalDist = sqrt(pow(destX - infernal->GetPositionX(), 2) + pow(destY - infernal->GetPositionY(), 2));
|
||||
if (infernalDist < safeInfernalDistance)
|
||||
{
|
||||
arcSafe = false;
|
||||
destSafe = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
float arcMoveDist = sqrt(pow(arcPoint.GetPositionX() - bx, 2) + pow(arcPoint.GetPositionY() - by, 2));
|
||||
if (arcSafe && arcMoveDist < bestMoveDist)
|
||||
float moveDist = sqrt(pow(destX - bx, 2) + pow(destY - by, 2));
|
||||
if (destSafe && moveDist < bestMoveDist)
|
||||
{
|
||||
bestMoveDist = arcMoveDist;
|
||||
bestDestX = arcPoint.GetPositionX();
|
||||
bestDestY = arcPoint.GetPositionY();
|
||||
bestDestZ = arcPoint.GetPositionZ();
|
||||
bestMoveDist = moveDist;
|
||||
bestDestX = destX;
|
||||
bestDestY = destY;
|
||||
bestDestZ = destZ;
|
||||
found = true;
|
||||
usedArc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,28 @@ bool RaidKarazhanHelpers::IsFlameWreathActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
// Blue beam blockers: non-Rogue/Warrior DPS bots, no Nether Exhaustion Blue and <25 stacks of Blue Beam debuff
|
||||
// Red beam blockers: tank bots, no Nether Exhaustion Red
|
||||
std::vector<Player*> RaidKarazhanHelpers::GetRedBlockers()
|
||||
{
|
||||
std::vector<Player*> redBlockers;
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (!member || !member->IsAlive() || !botAI->IsTank(member) || !GET_PLAYERBOT_AI(member) ||
|
||||
member->HasAura(SPELL_NETHER_EXHAUSTION_RED))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
redBlockers.push_back(member);
|
||||
}
|
||||
}
|
||||
|
||||
return redBlockers;
|
||||
}
|
||||
|
||||
// Blue beam blockers: non-Rogue/Warrior DPS bots, no Nether Exhaustion Blue and ≤25 stacks of Blue Beam debuff
|
||||
std::vector<Player*> RaidKarazhanHelpers::GetBlueBlockers()
|
||||
{
|
||||
std::vector<Player*> blueBlockers;
|
||||
@@ -150,7 +171,7 @@ std::vector<Player*> RaidKarazhanHelpers::GetBlueBlockers()
|
||||
bool isRogue = member->getClass() == CLASS_ROGUE;
|
||||
bool hasExhaustion = member->HasAura(SPELL_NETHER_EXHAUSTION_BLUE);
|
||||
Aura* blueBuff = member->GetAura(SPELL_BLUE_BEAM_DEBUFF);
|
||||
bool overStack = blueBuff && blueBuff->GetStackAmount() >= 25;
|
||||
bool overStack = blueBuff && blueBuff->GetStackAmount() >= 26;
|
||||
if (isDps && !isWarrior && !isRogue && !hasExhaustion && !overStack)
|
||||
{
|
||||
blueBlockers.push_back(member);
|
||||
@@ -163,7 +184,7 @@ std::vector<Player*> RaidKarazhanHelpers::GetBlueBlockers()
|
||||
|
||||
// Green beam blockers:
|
||||
// (1) Rogue and non-tank Warrior bots, no Nether Exhaustion Green
|
||||
// (2) Healer bots, no Nether Exhaustion Green and <25 stacks of Green Beam debuff
|
||||
// (2) Healer bots, no Nether Exhaustion Green and ≤25 stacks of Green Beam debuff
|
||||
std::vector<Player*> RaidKarazhanHelpers::GetGreenBlockers()
|
||||
{
|
||||
std::vector<Player*> greenBlockers;
|
||||
@@ -178,7 +199,7 @@ std::vector<Player*> RaidKarazhanHelpers::GetGreenBlockers()
|
||||
}
|
||||
bool hasExhaustion = member->HasAura(SPELL_NETHER_EXHAUSTION_GREEN);
|
||||
Aura* greenBuff = member->GetAura(SPELL_GREEN_BEAM_DEBUFF);
|
||||
bool overStack = greenBuff && greenBuff->GetStackAmount() >= 25;
|
||||
bool overStack = greenBuff && greenBuff->GetStackAmount() >= 26;
|
||||
bool isRogue = member->getClass() == CLASS_ROGUE;
|
||||
bool isDpsWarrior = member->getClass() == CLASS_WARRIOR && botAI->IsDps(member);
|
||||
bool eligibleRogueWarrior = (isRogue || isDpsWarrior) && !hasExhaustion;
|
||||
@@ -221,47 +242,91 @@ Position RaidKarazhanHelpers::GetPositionOnBeam(Unit* boss, Unit* portal, float
|
||||
|
||||
std::tuple<Player*, Player*, Player*> RaidKarazhanHelpers::GetCurrentBeamBlockers()
|
||||
{
|
||||
static ObjectGuid currentRedBlocker;
|
||||
static ObjectGuid currentGreenBlocker;
|
||||
static ObjectGuid currentBlueBlocker;
|
||||
|
||||
Player* redBlocker = nullptr;
|
||||
Player* greenBlocker = nullptr;
|
||||
Player* blueBlocker = nullptr;
|
||||
std::vector<Player*> redBlockers;
|
||||
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (!member || !member->IsAlive() || !botAI->IsTank(member) || !GET_PLAYERBOT_AI(member) ||
|
||||
member->HasAura(SPELL_NETHER_EXHAUSTION_RED))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
redBlockers.push_back(member);
|
||||
}
|
||||
}
|
||||
std::vector<Player*> redBlockers = GetRedBlockers();
|
||||
if (!redBlockers.empty())
|
||||
{
|
||||
redBlocker = redBlockers.front();
|
||||
auto it = std::find_if(redBlockers.begin(), redBlockers.end(), [](Player* p)
|
||||
{
|
||||
return p && p->GetGUID() == currentRedBlocker;
|
||||
});
|
||||
if (it != redBlockers.end())
|
||||
{
|
||||
redBlocker = *it;
|
||||
}
|
||||
else
|
||||
{
|
||||
redBlocker = redBlockers.front();
|
||||
}
|
||||
currentRedBlocker = redBlocker ? redBlocker->GetGUID() : ObjectGuid::Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentRedBlocker = ObjectGuid::Empty;
|
||||
redBlocker = nullptr;
|
||||
}
|
||||
|
||||
std::vector<Player*> greenBlockers = GetGreenBlockers();
|
||||
if (!greenBlockers.empty())
|
||||
{
|
||||
greenBlocker = greenBlockers.front();
|
||||
auto it = std::find_if(greenBlockers.begin(), greenBlockers.end(), [](Player* p)
|
||||
{
|
||||
return p && p->GetGUID() == currentGreenBlocker;
|
||||
});
|
||||
if (it != greenBlockers.end())
|
||||
{
|
||||
greenBlocker = *it;
|
||||
}
|
||||
else
|
||||
{
|
||||
greenBlocker = greenBlockers.front();
|
||||
}
|
||||
currentGreenBlocker = greenBlocker ? greenBlocker->GetGUID() : ObjectGuid::Empty;
|
||||
}
|
||||
std::vector<Player*> blueBlockers = GetBlueBlockers();
|
||||
if (!blueBlockers.empty())
|
||||
else
|
||||
{
|
||||
blueBlocker = blueBlockers.front();
|
||||
currentGreenBlocker = ObjectGuid::Empty;
|
||||
greenBlocker = nullptr;
|
||||
}
|
||||
|
||||
std::vector<Player*> blueBlockers = GetBlueBlockers();
|
||||
if (!blueBlockers.empty())
|
||||
{
|
||||
auto it = std::find_if(blueBlockers.begin(), blueBlockers.end(), [](Player* p)
|
||||
{
|
||||
return p && p->GetGUID() == currentBlueBlocker;
|
||||
});
|
||||
if (it != blueBlockers.end())
|
||||
{
|
||||
blueBlocker = *it;
|
||||
}
|
||||
else
|
||||
{
|
||||
blueBlocker = blueBlockers.front();
|
||||
}
|
||||
currentBlueBlocker = blueBlocker ? blueBlocker->GetGUID() : ObjectGuid::Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentBlueBlocker = ObjectGuid::Empty;
|
||||
blueBlocker = nullptr;
|
||||
}
|
||||
|
||||
return std::make_tuple(redBlocker, greenBlocker, blueBlocker);
|
||||
}
|
||||
|
||||
std::vector<Unit*> RaidKarazhanHelpers::GetAllVoidZones()
|
||||
{
|
||||
std::vector<Unit*> voidZones;
|
||||
const float radius = 15.0f;
|
||||
const GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest hostile npcs")->Get();
|
||||
const float radius = 30.0f;
|
||||
const GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
||||
for (const auto& npcGuid : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npcGuid);
|
||||
@@ -280,7 +345,7 @@ std::vector<Unit*> RaidKarazhanHelpers::GetAllVoidZones()
|
||||
}
|
||||
|
||||
bool RaidKarazhanHelpers::IsSafePosition(float x, float y, float z,
|
||||
const std::vector<Unit*>& hazards, float hazardRadius)
|
||||
const std::vector<Unit*>& hazards, float hazardRadius)
|
||||
{
|
||||
for (Unit* hazard : hazards)
|
||||
{
|
||||
@@ -297,7 +362,7 @@ bool RaidKarazhanHelpers::IsSafePosition(float x, float y, float z,
|
||||
std::vector<Unit*> RaidKarazhanHelpers::GetSpawnedInfernals() const
|
||||
{
|
||||
std::vector<Unit*> infernals;
|
||||
const GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest hostile npcs")->Get();
|
||||
const GuidVector npcs = botAI->GetAiObjectContext()->GetValue<GuidVector>("nearest npcs")->Get();
|
||||
for (const auto& npcGuid : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npcGuid);
|
||||
@@ -342,44 +407,3 @@ bool RaidKarazhanHelpers::IsStraightPathSafe(const Position& start, const Positi
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Position RaidKarazhanHelpers::CalculateArcPoint(const Position& current, const Position& target, const Position& center)
|
||||
{
|
||||
float arcFraction = 0.25f;
|
||||
float currentX = current.GetPositionX() - center.GetPositionX();
|
||||
float currentY = current.GetPositionY() - center.GetPositionY();
|
||||
float targetX = target.GetPositionX() - center.GetPositionX();
|
||||
float targetY = target.GetPositionY() - center.GetPositionY();
|
||||
|
||||
float currentDist = std::sqrt(currentX * currentX + currentY * currentY);
|
||||
float targetDist = std::sqrt(targetX * targetX + targetY * targetY);
|
||||
if (currentDist == 0.0f || targetDist == 0.0f)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
|
||||
currentX /= currentDist;
|
||||
currentY /= currentDist;
|
||||
targetX /= targetDist;
|
||||
targetY /= targetDist;
|
||||
|
||||
float dotProduct = currentX * targetX + currentY * targetY;
|
||||
dotProduct = std::max(-1.0f, std::min(1.0f, dotProduct));
|
||||
float angle = std::acos(dotProduct);
|
||||
float crossProduct = currentX * targetY - currentY * targetX;
|
||||
float stepAngle = angle * arcFraction;
|
||||
if (crossProduct < 0)
|
||||
{
|
||||
stepAngle = -stepAngle;
|
||||
}
|
||||
|
||||
float cos_a = std::cos(stepAngle);
|
||||
float sin_a = std::sin(stepAngle);
|
||||
float rotatedX = currentX * cos_a - currentY * sin_a;
|
||||
float rotatedY = currentX * sin_a + currentY * cos_a;
|
||||
float desiredDist = currentDist * 0.9f + targetDist * 0.1f;
|
||||
|
||||
return Position(center.GetPositionX() + rotatedX * desiredDist,
|
||||
center.GetPositionY() + rotatedY * desiredDist,
|
||||
current.GetPositionZ());
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ public:
|
||||
Unit* GetNearestPlayerInRadius(float /*radius*/ = 5.0f);
|
||||
bool IsFlameWreathActive();
|
||||
Position GetPositionOnBeam(Unit* boss, Unit* portal, float distanceFromBoss);
|
||||
std::vector<Player*> GetRedBlockers();
|
||||
std::vector<Player*> GetBlueBlockers();
|
||||
std::vector<Player*> GetGreenBlockers();
|
||||
std::tuple<Player*, Player*, Player*> GetCurrentBeamBlockers();
|
||||
@@ -79,7 +80,6 @@ public:
|
||||
std::vector<Unit*> GetSpawnedInfernals() const;
|
||||
bool IsStraightPathSafe(const Position& start, const Position& target,
|
||||
const std::vector<Unit*>& hazards, float hazardRadius, float stepSize);
|
||||
Position CalculateArcPoint(const Position& current, const Position& target, const Position& center);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "AttackAction.h"
|
||||
#include "DruidBearActions.h"
|
||||
#include "DruidCatActions.h"
|
||||
#include "RogueActions.h"
|
||||
#include "WarriorActions.h"
|
||||
|
||||
static bool IsChargeAction(Action* action)
|
||||
@@ -15,6 +16,20 @@ static bool IsChargeAction(Action* action)
|
||||
dynamic_cast<CastFeralChargeCatAction*>(action);
|
||||
}
|
||||
|
||||
float KarazhanAttumenTheHuntsmanMultiplier::GetValue(Action* action)
|
||||
{
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
Unit* boss = karazhanHelper.GetFirstAliveUnitByEntry(NPC_ATTUMEN_THE_HUNTSMAN_MOUNTED);
|
||||
if (boss && !(botAI->IsTank(bot) && botAI->HasAggro(boss) && boss->GetVictim() == bot) &&
|
||||
(dynamic_cast<MovementAction*>(action) &&
|
||||
!dynamic_cast<KarazhanAttumenTheHuntsmanStackBehindAction*>(action)))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float KarazhanBigBadWolfMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "the big bad wolf");
|
||||
@@ -61,7 +76,6 @@ float KarazhanShadeOfAranMultiplier::GetValue(Action* action)
|
||||
}
|
||||
|
||||
bool flameWreathActive = boss->HasAura(SPELL_FLAME_WREATH);
|
||||
|
||||
if (!flameWreathActive && bot->GetGroup())
|
||||
{
|
||||
for (GroupReference* itr = bot->GetGroup()->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
@@ -74,7 +88,6 @@ float KarazhanShadeOfAranMultiplier::GetValue(Action* action)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flameWreathActive)
|
||||
{
|
||||
if (dynamic_cast<MovementAction*>(action) || IsChargeAction(action))
|
||||
@@ -94,6 +107,11 @@ float KarazhanNetherspiteBlueAndGreenBeamMultiplier::GetValue(Action* action)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<AvoidAoeAction*>(action) || dynamic_cast<CastKillingSpreeAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
auto [redBlocker /*unused*/, greenBlocker, blueBlocker] = karazhanHelper.GetCurrentBeamBlockers();
|
||||
bool isBlocker = (bot == greenBlocker || bot == blueBlocker);
|
||||
@@ -101,9 +119,9 @@ float KarazhanNetherspiteBlueAndGreenBeamMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* bluePortal = bot->FindNearestCreature(NPC_BLUE_PORTAL, 150.0f);
|
||||
Unit* greenPortal = bot->FindNearestCreature(NPC_GREEN_PORTAL, 150.0f);
|
||||
|
||||
bool inBeam = false;
|
||||
for (Unit* portal : {bluePortal, greenPortal}) {
|
||||
for (Unit* portal : {bluePortal, greenPortal})
|
||||
{
|
||||
if (!portal)
|
||||
{
|
||||
continue;
|
||||
@@ -121,18 +139,18 @@ float KarazhanNetherspiteBlueAndGreenBeamMultiplier::GetValue(Action* action)
|
||||
float t = (botdx * dx + botdy * dy);
|
||||
float beamX = bx + dx * t, beamY = by + dy * t;
|
||||
float distToBeam = sqrt(pow(bot->GetPositionX() - beamX, 2) + pow(bot->GetPositionY() - beamY, 2));
|
||||
if (distToBeam < 5.0f && t > 0.0f && t < length)
|
||||
if (distToBeam < 0.3f && t > 0.0f && t < length)
|
||||
{
|
||||
inBeam = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (inBeam)
|
||||
{
|
||||
std::vector<Unit*> voidZones = karazhanHelper.GetAllVoidZones();
|
||||
bool inVoidZone = false;
|
||||
for (Unit* vz : voidZones) {
|
||||
for (Unit* vz : voidZones)
|
||||
{
|
||||
if (bot->GetExactDist2d(vz) < 4.0f)
|
||||
{
|
||||
inVoidZone = true;
|
||||
@@ -160,9 +178,13 @@ float KarazhanNetherspiteRedBeamMultiplier::GetValue(Action* action)
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<AvoidAoeAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
RaidKarazhanHelpers karazhanHelper(botAI);
|
||||
auto [redBlocker, greenBlocker /*unused*/, blueBlocker /*unused*/] = karazhanHelper.GetCurrentBeamBlockers();
|
||||
|
||||
static std::map<ObjectGuid, uint32> beamMoveTimes;
|
||||
static std::map<ObjectGuid, bool> lastBeamMoveSideways;
|
||||
ObjectGuid botGuid = bot->GetGUID();
|
||||
@@ -198,11 +220,9 @@ float KarazhanNetherspiteRedBeamMultiplier::GetValue(Action* action)
|
||||
lastBeamMoveSideways[botGuid] = !lastBeamMoveSideways[botGuid];
|
||||
beamMoveTimes[botGuid] = time(nullptr);
|
||||
}
|
||||
|
||||
Position targetPos = lastBeamMoveSideways[botGuid] ? sidewaysPos : blockingPos;
|
||||
float distToTarget = bot->GetExactDist2d(targetPos.GetPositionX(), targetPos.GetPositionY());
|
||||
const float positionTolerance = 1.5f;
|
||||
|
||||
if (distToTarget < positionTolerance)
|
||||
{
|
||||
if (dynamic_cast<MovementAction*>(action) || IsChargeAction(action))
|
||||
@@ -219,12 +239,28 @@ float KarazhanNetherspiteRedBeamMultiplier::GetValue(Action* action)
|
||||
float KarazhanPrinceMalchezaarMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "prince malchezaar");
|
||||
if (!boss || !boss->IsAlive())
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (boss && botAI->IsMelee(bot) && bot->HasAura(SPELL_ENFEEBLE) &&
|
||||
if (dynamic_cast<AvoidAoeAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsMelee(bot) && bot->HasAura(SPELL_ENFEEBLE) &&
|
||||
!dynamic_cast<KarazhanPrinceMalchezaarNonTankAvoidHazardAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsRanged(bot) && bot->HasAura(SPELL_ENFEEBLE) &&
|
||||
(dynamic_cast<MovementAction*>(action) &&
|
||||
!dynamic_cast<KarazhanPrinceMalchezaarNonTankAvoidHazardAction*>(action)))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
|
||||
#include "Multiplier.h"
|
||||
|
||||
class KarazhanAttumenTheHuntsmanMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
KarazhanAttumenTheHuntsmanMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "karazhan attumen the huntsman multiplier") {}
|
||||
virtual float GetValue(Action* action);
|
||||
};
|
||||
|
||||
class KarazhanBigBadWolfMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user