mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
ICC BPC major update, fix and improve (#920)
Fixed main tank sometimes not tanking both bosses (vala and talda) Improved marking of current prince Empowered vortex: bots will now spread out when it is being cast, instead of always spreading (ranged). This will make melee also spread better now since bots will calculate and move to optimal positions. Added Kinetic bomb handling. Hunters will take care of bombs, if no hunter is present then any ranged dps will take care of kinetic bombs.
This commit is contained in:
@@ -36,6 +36,7 @@ public:
|
||||
creators["icc bpc nucleus"] = &RaidIccActionContext::icc_bpc_nucleus;
|
||||
creators["icc bpc main tank"] = &RaidIccActionContext::icc_bpc_main_tank;
|
||||
creators["icc bpc empowered vortex"] = &RaidIccActionContext::icc_bpc_empowered_vortex;
|
||||
creators["icc bpc kinetic bomb"] = &RaidIccActionContext::icc_bpc_kinetic_bomb;
|
||||
creators["icc bql tank position"] = &RaidIccActionContext::icc_bql_tank_position;
|
||||
creators["icc bql pact of darkfallen"] = &RaidIccActionContext::icc_bql_pact_of_darkfallen;
|
||||
creators["icc bql vampiric bite"] = &RaidIccActionContext::icc_bql_vampiric_bite;
|
||||
@@ -85,6 +86,7 @@ private:
|
||||
static Action* icc_bpc_nucleus(PlayerbotAI* ai) { return new IccBpcNucleusAction(ai); }
|
||||
static Action* icc_bpc_main_tank(PlayerbotAI* ai) { return new IccBpcMainTankAction(ai); }
|
||||
static Action* icc_bpc_empowered_vortex(PlayerbotAI* ai) { return new IccBpcEmpoweredVortexAction(ai); }
|
||||
static Action* icc_bpc_kinetic_bomb(PlayerbotAI* ai) { return new IccBpcKineticBombAction(ai); }
|
||||
static Action* icc_bql_tank_position(PlayerbotAI* ai) { return new IccBqlTankPositionAction(ai); }
|
||||
static Action* icc_bql_pact_of_darkfallen(PlayerbotAI* ai) { return new IccBqlPactOfDarkfallenAction(ai); }
|
||||
static Action* icc_bql_vampiric_bite(PlayerbotAI* ai) { return new IccBqlVampiricBiteAction(ai); }
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include "RaidIccActions.h"
|
||||
#include "strategy/values/NearestNpcsValue.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "RaidIccStrategy.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Timer.h"
|
||||
@@ -1426,22 +1428,23 @@ bool IccBpcMainTankAction::Execute(Event event)
|
||||
if (bot->GetExactDist2d(ICC_BPC_MT_POSITION) > 20.0f)
|
||||
return MoveTo(bot->GetMapId(), ICC_BPC_MT_POSITION.GetPositionX(),
|
||||
ICC_BPC_MT_POSITION.GetPositionY(), ICC_BPC_MT_POSITION.GetPositionZ(),
|
||||
false, true, false, true, MovementPriority::MOVEMENT_COMBAT);
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT);
|
||||
|
||||
Unit* valanar = AI_VALUE2(Unit*, "find target", "prince valanar");
|
||||
Unit* taldaram = AI_VALUE2(Unit*, "find target", "prince taldaram");
|
||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||
|
||||
// Keep current prince if we have one
|
||||
if (currentTarget && (currentTarget == valanar || currentTarget == taldaram))
|
||||
return Attack(currentTarget);
|
||||
|
||||
// Pick a new prince that isn't targeting us
|
||||
if (valanar && (!valanar->GetVictim() || valanar->GetVictim() != bot))
|
||||
// Attack any prince that's not targeting us
|
||||
if (valanar && valanar->IsAlive() && (!valanar->GetVictim() || valanar->GetVictim() != bot))
|
||||
return Attack(valanar);
|
||||
if (taldaram && (!taldaram->GetVictim() || taldaram->GetVictim() != bot))
|
||||
if (taldaram && taldaram->IsAlive() && (!taldaram->GetVictim() || taldaram->GetVictim() != bot))
|
||||
return Attack(taldaram);
|
||||
|
||||
// If both princes are targeting us or dead, maintain current target
|
||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||
if (currentTarget && currentTarget->IsAlive() &&
|
||||
(currentTarget == valanar || currentTarget == taldaram))
|
||||
return Attack(currentTarget);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1450,23 +1453,6 @@ bool IccBpcMainTankAction::Execute(Event event)
|
||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||
|
||||
// First check if skull-marked target is a valid empowered prince
|
||||
Unit* skullTarget = nullptr;
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
if (ObjectGuid skullGuid = group->GetTargetIcon(7)) // 7 = skull
|
||||
{
|
||||
skullTarget = botAI->GetUnit(skullGuid);
|
||||
if (skullTarget && skullTarget->IsAlive() && skullTarget->HasAura(71596) &&
|
||||
(skullTarget->GetEntry() == 37972 || // Keleseth
|
||||
skullTarget->GetEntry() == 37973 || // Taldaram
|
||||
skullTarget->GetEntry() == 37970)) // Valanar
|
||||
{
|
||||
return Attack(skullTarget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no valid skull target, search for empowered prince
|
||||
Unit* empoweredPrince = nullptr;
|
||||
for (auto i = targets.begin(); i != targets.end(); ++i)
|
||||
@@ -1483,80 +1469,200 @@ bool IccBpcMainTankAction::Execute(Event event)
|
||||
{
|
||||
empoweredPrince = unit;
|
||||
|
||||
// Mark empowered prince with skull if in group
|
||||
// Mark empowered prince with skull if in group and not already marked
|
||||
if (Group* group = bot->GetGroup())
|
||||
{
|
||||
ObjectGuid currentSkullGuid = group->GetTargetIcon(7);
|
||||
if (currentSkullGuid.IsEmpty() || currentSkullGuid != unit->GetGUID())
|
||||
{
|
||||
group->SetTargetIcon(7, bot->GetGUID(), unit->GetGUID()); // 7 = skull
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attack empowered prince if found and current target doesn't have aura
|
||||
if (empoweredPrince)
|
||||
{
|
||||
// Only switch if current target doesn't have the aura
|
||||
if (!currentTarget || !currentTarget->HasAura(71596))
|
||||
{
|
||||
return Attack(empoweredPrince);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Attack(currentTarget);
|
||||
}
|
||||
}
|
||||
|
||||
// Keep current prince target if no empowered prince found
|
||||
if (currentTarget && (currentTarget->GetEntry() == 37972 || // Keleseth
|
||||
currentTarget->GetEntry() == 37973 || // Taldaram
|
||||
currentTarget->GetEntry() == 37970)) // Valanar
|
||||
{
|
||||
return Attack(currentTarget);
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IccBpcEmpoweredVortexAction::Execute(Event event)
|
||||
{
|
||||
// Double check that we're not a tank
|
||||
if (botAI->IsMainTank(bot) || botAI->IsAssistTank(bot) || botAI->IsTank(bot))
|
||||
return false;
|
||||
|
||||
Unit* valanar = AI_VALUE2(Unit*, "find target", "prince valanar");
|
||||
if (!valanar)
|
||||
if (!valanar || !valanar->HasUnitState(UNIT_STATE_CASTING))
|
||||
return false;
|
||||
|
||||
float radius = 12.0f;
|
||||
GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||
float const MIN_SPREAD = 12.0f;
|
||||
float const MOVE_INCREMENT = 10.0f;
|
||||
|
||||
// Use MT position as reference point to move away from
|
||||
Position const* mtPos = &ICC_BPC_MT_POSITION;
|
||||
float centerX = mtPos->GetPositionX();
|
||||
float centerY = mtPos->GetPositionY();
|
||||
float centerZ = mtPos->GetPositionZ();
|
||||
|
||||
for (auto& member : members)
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
// Get all alive group members and sort by GUID for consistent movement directions
|
||||
std::vector<std::pair<ObjectGuid, Player*>> sortedMembers;
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(member);
|
||||
if (!unit || !unit->IsAlive() || unit == bot)
|
||||
continue;
|
||||
Player* member = itr->GetSource();
|
||||
if (member && member->IsAlive() && !botAI->IsTank(member))
|
||||
{
|
||||
sortedMembers.push_back(std::make_pair(member->GetGUID(), member));
|
||||
}
|
||||
}
|
||||
std::sort(sortedMembers.begin(), sortedMembers.end());
|
||||
|
||||
float dist = bot->GetExactDist2d(unit);
|
||||
if (dist < radius)
|
||||
{
|
||||
float moveDistance = radius - dist + 1.0f;
|
||||
|
||||
// Calculate potential new position
|
||||
float angle = bot->GetAngle(unit);
|
||||
float newX = bot->GetPositionX() + cos(angle + M_PI) * moveDistance;
|
||||
float newY = bot->GetPositionY() + sin(angle + M_PI) * moveDistance;
|
||||
|
||||
// Only move if we have line of sight
|
||||
if (bot->IsWithinLOS(newX, newY, bot->GetPositionZ()))
|
||||
// Find this bot's index to determine movement direction
|
||||
int botIndex = -1;
|
||||
for (size_t i = 0; i < sortedMembers.size(); ++i)
|
||||
{
|
||||
if (sortedMembers[i].first == bot->GetGUID())
|
||||
{
|
||||
botIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (botIndex == -1)
|
||||
return false;
|
||||
|
||||
// Calculate base angle based on bot index (split into 12 directions)
|
||||
float baseAngle = botIndex * (2.0f * M_PI / 12.0f);
|
||||
|
||||
// Calculate current distance from MT position
|
||||
float currentDist = bot->GetDistance2d(centerX, centerY);
|
||||
|
||||
// If too close to others, move further out
|
||||
bool needToMove = false;
|
||||
if (currentDist < MIN_SPREAD)
|
||||
needToMove = true;
|
||||
else
|
||||
{
|
||||
// Check distance to other players
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (!member || !member->IsAlive() || member == bot)
|
||||
continue;
|
||||
|
||||
if (bot->GetDistance2d(member) < MIN_SPREAD)
|
||||
{
|
||||
return FleePosition(unit->GetPosition(), moveDistance);
|
||||
// return MoveAway(unit, moveDistance);
|
||||
needToMove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!needToMove)
|
||||
return false;
|
||||
|
||||
// Calculate new position further out in our assigned direction
|
||||
float moveDistance = std::max(MOVE_INCREMENT, currentDist + MOVE_INCREMENT);
|
||||
float targetX = centerX + cos(baseAngle) * moveDistance;
|
||||
float targetY = centerY + sin(baseAngle) * moveDistance;
|
||||
float targetZ = centerZ;
|
||||
|
||||
// Update Z coordinate and check LOS
|
||||
bot->UpdateAllowedPositionZ(targetX, targetY, targetZ);
|
||||
if (!bot->IsWithinLOS(targetX, targetY, targetZ))
|
||||
{
|
||||
// Try adjusting angle if LOS fails
|
||||
for (float angleAdjust = -M_PI/6; angleAdjust <= M_PI/6; angleAdjust += M_PI/12)
|
||||
{
|
||||
if (angleAdjust == 0)
|
||||
continue;
|
||||
|
||||
float newX = centerX + cos(baseAngle + angleAdjust) * moveDistance;
|
||||
float newY = centerY + sin(baseAngle + angleAdjust) * moveDistance;
|
||||
float newZ = centerZ;
|
||||
|
||||
bot->UpdateAllowedPositionZ(newX, newY, newZ);
|
||||
if (bot->IsWithinLOS(newX, newY, newZ))
|
||||
{
|
||||
targetX = newX;
|
||||
targetY = newY;
|
||||
targetZ = newZ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MoveTo(bot->GetMapId(), targetX, targetY, targetZ,
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
bool IccBpcKineticBombAction::Execute(Event event)
|
||||
{
|
||||
// Only allow ranged DPS to handle bombs
|
||||
if (!botAI->IsRangedDps(bot))
|
||||
return false;
|
||||
|
||||
//for some reason they sometimes decide to move up in the air when they attack the kinetic bomb and that will make everyone tp to entrance...
|
||||
if (bot->GetPositionZ() > 371.16473f)
|
||||
return bot->TeleportTo(bot->GetMapId(), bot->GetPositionX(),
|
||||
bot->GetPositionY(), 366.16473f, bot->GetOrientation());
|
||||
|
||||
Unit* currentTarget = AI_VALUE(Unit*, "current target");
|
||||
|
||||
// If we're already attacking a bomb and it's still in range, stick with it
|
||||
if (currentTarget && currentTarget->IsAlive() && currentTarget->GetName() == "Kinetic Bomb")
|
||||
{
|
||||
float heightDiff = currentTarget->GetPositionZ() - bot->GetPositionZ();
|
||||
if (heightDiff < 25.0f)
|
||||
return false; // Continue current attack
|
||||
}
|
||||
|
||||
GuidVector targets = AI_VALUE(GuidVector, "possible targets");
|
||||
|
||||
// Find the lowest reachable bomb
|
||||
Unit* bestBomb = nullptr;
|
||||
float lowestHeightDiff = 25.0f; // Maximum height we care about
|
||||
|
||||
for (auto& guid : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (!unit || !unit->IsAlive() || unit->GetName() != "Kinetic Bomb")
|
||||
continue;
|
||||
|
||||
float heightDiff = unit->GetPositionZ() - bot->GetPositionZ();
|
||||
if (heightDiff < lowestHeightDiff)
|
||||
{
|
||||
// Check if any closer ranged DPS is already attacking this bomb
|
||||
bool alreadyHandled = false;
|
||||
Group* group = bot->GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (!member || member == bot || !member->IsAlive() || !botAI->IsRangedDps(member))
|
||||
continue;
|
||||
|
||||
if (member->GetTarget() == unit->GetGUID() && member->GetDistance(unit) < bot->GetDistance(unit))
|
||||
{
|
||||
alreadyHandled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadyHandled)
|
||||
{
|
||||
bestBomb = unit;
|
||||
lowestHeightDiff = heightDiff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attack the lowest unhandled bomb if found
|
||||
if (bestBomb)
|
||||
return Attack(bestBomb);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -270,7 +270,6 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
//BPC Vortex
|
||||
class IccBpcEmpoweredVortexAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
@@ -279,6 +278,14 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class IccBpcKineticBombAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
IccBpcKineticBombAction(PlayerbotAI* botAI)
|
||||
: AttackAction(botAI, "icc bpc kinetic bomb") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
//Blood Queen Lana'thel
|
||||
class IccBqlTankPositionAction : public AttackAction
|
||||
{
|
||||
|
||||
@@ -323,6 +323,48 @@ float IccBpcAssistMultiplier::GetValue(Action* action)
|
||||
}
|
||||
}
|
||||
|
||||
Unit* Valanar = AI_VALUE2(Unit*, "find target", "prince valanar");
|
||||
if (!Valanar || !Valanar->IsAlive())
|
||||
return 1.0f;
|
||||
|
||||
Aura* auraValanar = botAI->GetAura("Invocation of Blood", Valanar);
|
||||
|
||||
if (!botAI->IsTank(bot) && auraValanar && Valanar->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
if (dynamic_cast<IccBpcEmpoweredVortexAction*>(action))
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<AttackRtiTargetAction*>(action) ||
|
||||
dynamic_cast<TankAssistAction*>(action) ||
|
||||
dynamic_cast<DpsAssistAction*>(action) ||
|
||||
dynamic_cast<IccBpcMainTankAction*>(action) ||
|
||||
dynamic_cast<CombatFormationMoveAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (botAI->IsRangedDps(bot))
|
||||
{
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (unit)
|
||||
{
|
||||
if (unit->GetName() == "Kinetic Bomb" && ((unit->GetPositionZ() - bot->GetPositionZ()) < 25.0f))
|
||||
{
|
||||
if (dynamic_cast<IccBpcKineticBombAction*>(action))
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<AttackRtiTargetAction*>(action) ||
|
||||
dynamic_cast<TankAssistAction*>(action) ||
|
||||
dynamic_cast<DpsAssistAction*>(action) ||
|
||||
dynamic_cast<IccBpcMainTankAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For assist tank during BPC fight
|
||||
if (botAI->IsAssistTank(bot))
|
||||
{
|
||||
|
||||
@@ -98,10 +98,13 @@ void RaidIccStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
NextAction::array(0, new NextAction("icc bpc nucleus", ACTION_RAID + 2), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc bpc main tank",
|
||||
NextAction::array(0, new NextAction("icc bpc main tank", ACTION_RAID + 4), nullptr)));
|
||||
NextAction::array(0, new NextAction("icc bpc main tank", ACTION_RAID + 3), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc bpc empowered vortex",
|
||||
NextAction::array(0, new NextAction("icc bpc empowered vortex", ACTION_RAID + 3), nullptr)));
|
||||
NextAction::array(0, new NextAction("icc bpc empowered vortex", ACTION_RAID + 4), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("icc bpc kinetic bomb",
|
||||
NextAction::array(0, new NextAction("icc bpc kinetic bomb", ACTION_RAID + 6), nullptr)));
|
||||
|
||||
//BQL
|
||||
triggers.push_back(new TriggerNode("icc bql tank position",
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
creators["icc bpc nucleus"] = &RaidIccTriggerContext::icc_bpc_nucleus;
|
||||
creators["icc bpc main tank"] = &RaidIccTriggerContext::icc_bpc_main_tank;
|
||||
creators["icc bpc empowered vortex"] = &RaidIccTriggerContext::icc_bpc_empowered_vortex;
|
||||
creators["icc bpc kinetic bomb"] = &RaidIccTriggerContext::icc_bpc_kinetic_bomb;
|
||||
creators["icc bql tank position"] = &RaidIccTriggerContext::icc_bql_tank_position;
|
||||
creators["icc bql pact of darkfallen"] = &RaidIccTriggerContext::icc_bql_pact_of_darkfallen;
|
||||
creators["icc bql vampiric bite"] = &RaidIccTriggerContext::icc_bql_vampiric_bite;
|
||||
@@ -94,6 +95,7 @@ private:
|
||||
static Trigger* icc_bpc_nucleus(PlayerbotAI* ai) { return new IccBpcNucleusTrigger(ai); }
|
||||
static Trigger* icc_bpc_main_tank(PlayerbotAI* ai) { return new IccBpcMainTankTrigger(ai); }
|
||||
static Trigger* icc_bpc_empowered_vortex(PlayerbotAI* ai) { return new IccBpcEmpoweredVortexTrigger(ai); }
|
||||
static Trigger* icc_bpc_kinetic_bomb(PlayerbotAI* ai) { return new IccBpcKineticBombTrigger(ai); }
|
||||
static Trigger* icc_bql_tank_position(PlayerbotAI* ai) { return new IccBqlTankPositionTrigger(ai); }
|
||||
static Trigger* icc_bql_pact_of_darkfallen(PlayerbotAI* ai) { return new IccBqlPactOfDarkfallenTrigger(ai); }
|
||||
static Trigger* icc_bql_vampiric_bite(PlayerbotAI* ai) { return new IccBqlVampiricBiteTrigger(ai); }
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "RaidIccTriggers.h"
|
||||
#include "RaidIccActions.h"
|
||||
|
||||
#include "strategy/values/NearestNpcsValue.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "GenericTriggers.h"
|
||||
#include "DungeonStrategyUtils.h"
|
||||
#include "EventMap.h"
|
||||
@@ -463,7 +464,7 @@ bool IccBpcEmpoweredVortexTrigger::IsActive()
|
||||
return false;
|
||||
|
||||
Unit* valanar = AI_VALUE2(Unit*, "find target", "prince valanar");
|
||||
if (!valanar || !valanar->IsAlive())
|
||||
if (!valanar)
|
||||
return false;
|
||||
|
||||
Aura* aura = botAI->GetAura("Shadow Prison", bot, false, true);
|
||||
@@ -471,20 +472,61 @@ bool IccBpcEmpoweredVortexTrigger::IsActive()
|
||||
if (aura->GetStackAmount() > 12)
|
||||
return false;
|
||||
|
||||
Aura* auraValanar = botAI->GetAura("Invocation of Blood", valanar);
|
||||
if (!auraValanar)
|
||||
return false;
|
||||
|
||||
// For ranged, spread whenever Valanar is empowered
|
||||
if (botAI->IsRanged(bot))
|
||||
return valanar->HasAura(71596); // Invocation of Blood
|
||||
//if (botAI->IsRanged(bot) && auraValanar)
|
||||
//return true;
|
||||
|
||||
// For melee, only spread during vortex cast
|
||||
if (valanar->HasAura(71596) && valanar->HasUnitState(UNIT_STATE_CASTING) && valanar->FindCurrentSpellBySpellId(72039))
|
||||
{
|
||||
if (auraValanar && valanar->HasUnitState(UNIT_STATE_CASTING))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//BQL
|
||||
bool IccBpcKineticBombTrigger::IsActive()
|
||||
{
|
||||
GuidVector npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
|
||||
// Check for hunters first
|
||||
bool hasHunter = false;
|
||||
Group* group = bot->GetGroup();
|
||||
if (group)
|
||||
{
|
||||
for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
|
||||
{
|
||||
Player* member = itr->GetSource();
|
||||
if (member && member->getClass() == CLASS_HUNTER && member->IsAlive())
|
||||
{
|
||||
hasHunter = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& npc : npcs)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (unit && unit->GetName() == "Kinetic Bomb" &&
|
||||
((unit->GetPositionZ() - bot->GetPositionZ()) < 25.0f))
|
||||
{
|
||||
if (hasHunter)
|
||||
{
|
||||
return bot->getClass() == CLASS_HUNTER; // Only hunters can handle bombs
|
||||
}
|
||||
else if (botAI->IsRangedDps(bot))
|
||||
{
|
||||
return true; // If no hunters, any ranged DPS can handle bombs
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//BQL
|
||||
bool IccBqlTankPositionTrigger::IsActive()
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "blood-queen lana'thel");
|
||||
|
||||
@@ -226,6 +226,13 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class IccBpcKineticBombTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
IccBpcKineticBombTrigger(PlayerbotAI* botAI) : Trigger(botAI, "icc bpc kinetic bomb") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
//Bql
|
||||
class IccBqlTankPositionTrigger : public Trigger
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user