mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Yogg-Saron strategy (#1565)
* - wip * - Added Yogg-Saron strategy * - Added Yogg-Saron sanity strategy * - WIP * - WIP * - WIP * - WIP * - Added Yogg-Saron strategy * - code refactoring * - Code fix after pr
This commit is contained in:
@@ -1765,7 +1765,7 @@ bool PlayerbotAI::IsRangedDps(Player* player, bool bySpec) { return IsRanged(pla
|
||||
|
||||
bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
Group* group = player->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
@@ -1777,6 +1777,11 @@ bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index)
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsHeal(member)) // Check if the member is a healer
|
||||
{
|
||||
bool isAssistant = group->IsAssistant(member->GetGUID());
|
||||
@@ -1796,7 +1801,7 @@ bool PlayerbotAI::IsHealAssistantOfIndex(Player* player, int index)
|
||||
|
||||
bool PlayerbotAI::IsRangedDpsAssistantOfIndex(Player* player, int index)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
Group* group = player->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
@@ -1808,6 +1813,11 @@ bool PlayerbotAI::IsRangedDpsAssistantOfIndex(Player* player, int index)
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsRangedDps(member)) // Check if the member is a ranged DPS
|
||||
{
|
||||
bool isAssistant = group->IsAssistant(member->GetGUID());
|
||||
@@ -1840,6 +1850,35 @@ bool PlayerbotAI::HasAggro(Unit* unit)
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 PlayerbotAI::GetAssistTankIndex(Player* player)
|
||||
{
|
||||
Group* group = player->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int counter = 0;
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player == member)
|
||||
{
|
||||
return counter;
|
||||
}
|
||||
if (IsTank(member, true) && group->IsAssistant(member->GetGUID()))
|
||||
{
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 PlayerbotAI::GetGroupSlotIndex(Player* player)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
@@ -1851,6 +1890,12 @@ int32 PlayerbotAI::GetGroupSlotIndex(Player* player)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player == member)
|
||||
{
|
||||
return counter;
|
||||
@@ -1875,6 +1920,12 @@ int32 PlayerbotAI::GetRangedIndex(Player* player)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player == member)
|
||||
{
|
||||
return counter;
|
||||
@@ -1902,6 +1953,12 @@ int32 PlayerbotAI::GetClassIndex(Player* player, uint8 cls)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player == member)
|
||||
{
|
||||
return counter;
|
||||
@@ -1928,6 +1985,12 @@ int32 PlayerbotAI::GetRangedDpsIndex(Player* player)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player == member)
|
||||
{
|
||||
return counter;
|
||||
@@ -1955,6 +2018,12 @@ int32 PlayerbotAI::GetMeleeIndex(Player* player)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (player == member)
|
||||
{
|
||||
return counter;
|
||||
@@ -2126,6 +2195,12 @@ bool PlayerbotAI::IsMainTank(Player* player)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsTank(member) && member->IsAlive())
|
||||
{
|
||||
return player->GetGUID() == member->GetGUID();
|
||||
@@ -2134,6 +2209,62 @@ bool PlayerbotAI::IsMainTank(Player* player)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PlayerbotAI::IsBotMainTank(Player* player)
|
||||
{
|
||||
if (!player->GetSession()->IsBot() || !IsTank(player))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsMainTank(player))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Group* group = player->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return true; // If no group, consider the bot as main tank
|
||||
}
|
||||
|
||||
uint32 botAssistTankIndex = GetAssistTankIndex(player);
|
||||
|
||||
if (botAssistTankIndex == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* member = gref->GetSource();
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 memberAssistTankIndex = GetAssistTankIndex(member);
|
||||
|
||||
if (memberAssistTankIndex == -1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memberAssistTankIndex == botAssistTankIndex && player == member)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (memberAssistTankIndex < botAssistTankIndex && member->GetSession()->IsBot())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 PlayerbotAI::GetGroupTankNum(Player* player)
|
||||
{
|
||||
Group* group = player->GetGroup();
|
||||
@@ -2145,6 +2276,12 @@ uint32 PlayerbotAI::GetGroupTankNum(Player* player)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsTank(member) && member->IsAlive())
|
||||
{
|
||||
result++;
|
||||
@@ -2157,7 +2294,7 @@ bool PlayerbotAI::IsAssistTank(Player* player) { return IsTank(player) && !IsMai
|
||||
|
||||
bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
Group* group = player->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
@@ -2166,6 +2303,12 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
||||
{
|
||||
if (index == counter)
|
||||
@@ -2179,6 +2322,12 @@ bool PlayerbotAI::IsAssistTankOfIndex(Player* player, int index)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!group->IsAssistant(member->GetGUID()) && IsAssistTank(member))
|
||||
{
|
||||
if (index == counter)
|
||||
@@ -2386,6 +2535,11 @@ std::vector<Player*> PlayerbotAI::GetPlayersInGroup()
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
|
||||
if (!member)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GET_PLAYERBOT_AI(member) && !GET_PLAYERBOT_AI(member)->IsRealPlayer())
|
||||
continue;
|
||||
|
||||
|
||||
@@ -423,13 +423,15 @@ public:
|
||||
static bool IsCaster(Player* player, bool bySpec = false);
|
||||
static bool IsRangedDps(Player* player, bool bySpec = false);
|
||||
static bool IsCombo(Player* player);
|
||||
static bool IsBotMainTank(Player* player);
|
||||
static bool IsMainTank(Player* player);
|
||||
static uint32 GetGroupTankNum(Player* player);
|
||||
bool IsAssistTank(Player* player);
|
||||
bool IsAssistTankOfIndex(Player* player, int index);
|
||||
bool IsHealAssistantOfIndex(Player* player, int index);
|
||||
bool IsRangedDpsAssistantOfIndex(Player* player, int index);
|
||||
static bool IsAssistTank(Player* player);
|
||||
static bool IsAssistTankOfIndex(Player* player, int index);
|
||||
static bool IsHealAssistantOfIndex(Player* player, int index);
|
||||
static bool IsRangedDpsAssistantOfIndex(Player* player, int index);
|
||||
bool HasAggro(Unit* unit);
|
||||
static int32 GetAssistTankIndex(Player* player);
|
||||
int32 GetGroupSlotIndex(Player* player);
|
||||
int32 GetRangedIndex(Player* player);
|
||||
int32 GetClassIndex(Player* player, uint8 cls);
|
||||
|
||||
@@ -22,6 +22,7 @@ bool BossFireResistanceAction::Execute(Event event)
|
||||
{
|
||||
PaladinFireResistanceStrategy paladinFireResistanceStrategy(botAI);
|
||||
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + paladinFireResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
||||
botAI->DoSpecificAction("fire resistance aura", Event(), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -35,6 +36,7 @@ bool BossFrostResistanceAction::Execute(Event event)
|
||||
{
|
||||
PaladinFrostResistanceStrategy paladinFrostResistanceStrategy(botAI);
|
||||
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + paladinFrostResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
||||
botAI->DoSpecificAction("frost resistance aura", Event(), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -48,6 +50,7 @@ bool BossNatureResistanceAction::Execute(Event event)
|
||||
{
|
||||
HunterNatureResistanceStrategy hunterNatureResistanceStrategy(botAI);
|
||||
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + hunterNatureResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
||||
botAI->DoSpecificAction("aspect of the wild", Event(), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -61,5 +64,6 @@ bool BossShadowResistanceAction::Execute(Event event)
|
||||
{
|
||||
PaladinShadowResistanceStrategy paladinShadowResistanceStrategy(botAI);
|
||||
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + paladinShadowResistanceStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
||||
botAI->DoSpecificAction("shadow resistance aura", Event(), true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2767,3 +2767,177 @@ bool MoveFromGroupAction::Execute(Event event)
|
||||
distance = 20.0f; // flee distance from config is too small for this
|
||||
return MoveFromGroup(distance);
|
||||
}
|
||||
|
||||
bool MoveAwayFromCreatureAction::Execute(Event event)
|
||||
{
|
||||
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
|
||||
Creature* nearestCreature = bot->FindNearestCreature(creatureId, range, alive);
|
||||
|
||||
// Find all creatures with the specified Id
|
||||
std::vector<Unit*> creatures;
|
||||
for (const auto& guid : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (unit && (alive && unit->IsAlive()) && unit->GetEntry() == creatureId)
|
||||
{
|
||||
creatures.push_back(unit);
|
||||
}
|
||||
}
|
||||
|
||||
if (creatures.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Search for a safe position
|
||||
const int directions = 8;
|
||||
const float increment = 3.0f;
|
||||
float bestX = bot->GetPositionX();
|
||||
float bestY = bot->GetPositionY();
|
||||
float bestZ = bot->GetPositionZ();
|
||||
float maxSafetyScore = -1.0f;
|
||||
|
||||
for (int i = 0; i < directions; ++i)
|
||||
{
|
||||
float angle = (i * 2 * M_PI) / directions;
|
||||
for (float distance = increment; distance <= 30.0f; distance += increment)
|
||||
{
|
||||
float moveX = bot->GetPositionX() + distance * cos(angle);
|
||||
float moveY = bot->GetPositionY() + distance * sin(angle);
|
||||
float moveZ = bot->GetPositionZ();
|
||||
|
||||
// Check creature distance constraints
|
||||
bool isSafeFromCreatures = true;
|
||||
float minCreatureDist = std::numeric_limits<float>::max();
|
||||
for (Unit* creature : creatures)
|
||||
{
|
||||
float dist = creature->GetExactDist2d(moveX, moveY);
|
||||
if (dist < range)
|
||||
{
|
||||
isSafeFromCreatures = false;
|
||||
break;
|
||||
}
|
||||
if (dist < minCreatureDist)
|
||||
{
|
||||
minCreatureDist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSafeFromCreatures && bot->IsWithinLOS(moveX, moveY, moveZ))
|
||||
{
|
||||
// A simple safety score: the minimum distance to any creature. Higher is better.
|
||||
if (minCreatureDist > maxSafetyScore)
|
||||
{
|
||||
maxSafetyScore = minCreatureDist;
|
||||
bestX = moveX;
|
||||
bestY = moveY;
|
||||
bestZ = moveZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move to the best position found
|
||||
if (maxSafetyScore > 0.0f)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), bestX, bestY, bestZ, false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MoveAwayFromCreatureAction::isPossible()
|
||||
{
|
||||
return bot->CanFreeMove();
|
||||
}
|
||||
|
||||
bool MoveAwayFromPlayerWithDebuffAction::Execute(Event event)
|
||||
{
|
||||
Player* closestPlayer = nullptr;
|
||||
float minDistance = 0.0f;
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Player*> debuffedPlayers;
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* player = gref->GetSource();
|
||||
if (player && player->IsAlive() && player->HasAura(spellId))
|
||||
{
|
||||
debuffedPlayers.push_back(player);
|
||||
}
|
||||
}
|
||||
|
||||
if (debuffedPlayers.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Search for a safe position
|
||||
const int directions = 8;
|
||||
const float increment = 3.0f;
|
||||
float bestX = bot->GetPositionX();
|
||||
float bestY = bot->GetPositionY();
|
||||
float bestZ = bot->GetPositionZ();
|
||||
float maxSafetyScore = -1.0f;
|
||||
|
||||
for (int i = 0; i < directions; ++i)
|
||||
{
|
||||
float angle = (i * 2 * M_PI) / directions;
|
||||
for (float distance = increment; distance <= (range + 5.0f); distance += increment)
|
||||
{
|
||||
float moveX = bot->GetPositionX() + distance * cos(angle);
|
||||
float moveY = bot->GetPositionY() + distance * sin(angle);
|
||||
float moveZ = bot->GetPositionZ();
|
||||
|
||||
// Check creature distance constraints
|
||||
bool isSafeFromDebuffedPlayer = true;
|
||||
float minDebuffedPlayerDistance = std::numeric_limits<float>::max();
|
||||
for (Unit* debuffedPlayer : debuffedPlayers)
|
||||
{
|
||||
float dist = debuffedPlayer->GetExactDist2d(moveX, moveY);
|
||||
if (dist < range)
|
||||
{
|
||||
isSafeFromDebuffedPlayer = false;
|
||||
break;
|
||||
}
|
||||
if (dist < minDebuffedPlayerDistance)
|
||||
{
|
||||
minDebuffedPlayerDistance = dist;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSafeFromDebuffedPlayer && bot->IsWithinLOS(moveX, moveY, moveZ))
|
||||
{
|
||||
// A simple safety score: the minimum distance to any debuffed player. Higher is better.
|
||||
if (minDebuffedPlayerDistance > maxSafetyScore)
|
||||
{
|
||||
maxSafetyScore = minDebuffedPlayerDistance;
|
||||
bestX = moveX;
|
||||
bestY = moveY;
|
||||
bestZ = moveZ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move to the best position found
|
||||
if (maxSafetyScore > 0.0f)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), bestX, bestY, bestZ, false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MoveAwayFromPlayerWithDebuffAction::isPossible()
|
||||
{
|
||||
return bot->CanFreeMove();
|
||||
}
|
||||
|
||||
@@ -294,4 +294,34 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class MoveAwayFromCreatureAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
MoveAwayFromCreatureAction(PlayerbotAI* botAI, std::string name, uint32 creatureId, float range, bool alive = true)
|
||||
: MovementAction(botAI, name), creatureId(creatureId), range(range), alive(alive) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isPossible() override;
|
||||
|
||||
private:
|
||||
uint32 creatureId;
|
||||
float range;
|
||||
bool alive;
|
||||
};
|
||||
|
||||
class MoveAwayFromPlayerWithDebuffAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
MoveAwayFromPlayerWithDebuffAction(PlayerbotAI* botAI, std::string name, uint32 spellId, float range)
|
||||
: MovementAction(botAI, name), spellId(spellId), range(range) {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
bool isPossible() override;
|
||||
|
||||
private:
|
||||
uint32 spellId;
|
||||
float range;
|
||||
bool alive;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -65,6 +65,24 @@ public:
|
||||
creators["vezax cheat action"] = &RaidUlduarActionContext::vezax_cheat_action;
|
||||
creators["vezax shadow crash action"] = &RaidUlduarActionContext::vezax_shadow_crash_action;
|
||||
creators["vezax mark of the faceless action"] = &RaidUlduarActionContext::vezax_mark_of_the_faceless_action;
|
||||
creators["vezax shadow resistance action"] = &RaidUlduarActionContext::vezax_shadow_resistance_action;
|
||||
creators["sara shadow resistance action"] = &RaidUlduarActionContext::sara_shadow_resistance_action;
|
||||
creators["yogg-saron shadow resistance action"] = &RaidUlduarActionContext::yogg_saron_shadow_resistance_action;
|
||||
creators["yogg-saron ominous cloud cheat action"] = &RaidUlduarActionContext::yogg_saron_ominous_cloud_cheat_action;
|
||||
creators["yogg-saron guardian positioning action"] = &RaidUlduarActionContext::yogg_saron_guardian_positioning_action;
|
||||
creators["yogg-saron sanity action"] = &RaidUlduarActionContext::yogg_saron_sanity_action;
|
||||
creators["yogg-saron death orb action"] = &RaidUlduarActionContext::yogg_saron_death_orb_action;
|
||||
creators["yogg-saron malady of the mind action"] = &RaidUlduarActionContext::yogg_saron_malady_of_the_mind_action;
|
||||
creators["yogg-saron mark target action"] = &RaidUlduarActionContext::yogg_saron_mark_target_action;
|
||||
creators["yogg-saron brain link action"] = &RaidUlduarActionContext::yogg_saron_brain_link_action;
|
||||
creators["yogg-saron move to enter portal action"] = &RaidUlduarActionContext::yogg_saron_move_to_enter_portal_action;
|
||||
creators["yogg-saron use portal action"] = &RaidUlduarActionContext::yogg_saron_use_portal_action;
|
||||
creators["yogg-saron fall from floor action"] = &RaidUlduarActionContext::yogg_saron_fall_from_floor_action;
|
||||
creators["yogg-saron boss room movement cheat action"] = &RaidUlduarActionContext::yogg_saron_boss_room_movement_cheat_action;
|
||||
creators["yogg-saron illusion room action"] = &RaidUlduarActionContext::yogg_saron_illusion_room_action;
|
||||
creators["yogg-saron move to exit portal action"] = &RaidUlduarActionContext::yogg_saron_move_to_exit_portal_action;
|
||||
creators["yogg-saron lunatic gaze action"] = &RaidUlduarActionContext::yogg_saron_lunatic_gaze_action;
|
||||
creators["yogg-saron phase 3 positioning action"] = &RaidUlduarActionContext::yogg_saron_phase_3_positioning_action;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -117,6 +135,24 @@ private:
|
||||
static Action* vezax_cheat_action(PlayerbotAI* ai) { return new VezaxCheatAction(ai); }
|
||||
static Action* vezax_shadow_crash_action(PlayerbotAI* ai) { return new VezaxShadowCrashAction(ai); }
|
||||
static Action* vezax_mark_of_the_faceless_action(PlayerbotAI* ai) { return new VezaxMarkOfTheFacelessAction(ai); }
|
||||
static Action* vezax_shadow_resistance_action(PlayerbotAI* ai) { return new BossShadowResistanceAction(ai, "general vezax"); }
|
||||
static Action* sara_shadow_resistance_action(PlayerbotAI* ai) { return new BossShadowResistanceAction(ai, "sara"); }
|
||||
static Action* yogg_saron_shadow_resistance_action(PlayerbotAI* ai) { return new BossShadowResistanceAction(ai, "yogg-saron"); }
|
||||
static Action* yogg_saron_ominous_cloud_cheat_action(PlayerbotAI* ai) { return new YoggSaronOminousCloudCheatAction(ai); }
|
||||
static Action* yogg_saron_guardian_positioning_action(PlayerbotAI* ai) { return new YoggSaronGuardianPositioningAction(ai); }
|
||||
static Action* yogg_saron_sanity_action(PlayerbotAI* ai) { return new YoggSaronSanityAction(ai); }
|
||||
static Action* yogg_saron_death_orb_action(PlayerbotAI* ai) { return new YoggSaronDeathOrbAction(ai); }
|
||||
static Action* yogg_saron_malady_of_the_mind_action(PlayerbotAI* ai) { return new YoggSaronMaladyOfTheMindAction(ai); }
|
||||
static Action* yogg_saron_mark_target_action(PlayerbotAI* ai) { return new YoggSaronMarkTargetAction(ai); }
|
||||
static Action* yogg_saron_brain_link_action(PlayerbotAI* ai) { return new YoggSaronBrainLinkAction(ai); }
|
||||
static Action* yogg_saron_move_to_enter_portal_action(PlayerbotAI* ai) { return new YoggSaronMoveToEnterPortalAction(ai); }
|
||||
static Action* yogg_saron_use_portal_action(PlayerbotAI* ai) { return new YoggSaronUsePortalAction(ai); }
|
||||
static Action* yogg_saron_fall_from_floor_action(PlayerbotAI* ai) { return new YoggSaronFallFromFloorAction(ai); }
|
||||
static Action* yogg_saron_boss_room_movement_cheat_action(PlayerbotAI* ai) { return new YoggSaronBossRoomMovementCheatAction(ai); }
|
||||
static Action* yogg_saron_illusion_room_action(PlayerbotAI* ai) { return new YoggSaronIllusionRoomAction(ai); }
|
||||
static Action* yogg_saron_move_to_exit_portal_action(PlayerbotAI* ai) { return new YoggSaronMoveToExitPortalAction(ai); }
|
||||
static Action* yogg_saron_lunatic_gaze_action(PlayerbotAI* ai) { return new YoggSaronLunaticGazeAction(ai); }
|
||||
static Action* yogg_saron_phase_3_positioning_action(PlayerbotAI* ai) { return new YoggSaronPhase3PositioningAction(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -20,13 +20,14 @@
|
||||
#include "RaidUlduarBossHelper.h"
|
||||
#include "RaidUlduarScripts.h"
|
||||
#include "RaidUlduarStrategy.h"
|
||||
#include "RaidUlduarTriggers.h"
|
||||
#include "RtiValue.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ServerFacade.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Unit.h"
|
||||
#include "Vehicle.h"
|
||||
#include <RtiTargetValue.h>
|
||||
#include <TankAssistStrategy.h>
|
||||
|
||||
const std::string ADD_STRATEGY_CHAR = "+";
|
||||
const std::string REMOVE_STRATEGY_CHAR = "-";
|
||||
@@ -42,6 +43,12 @@ const Position ULDUAR_KOLOGARN_RESTORE_POSITION = Position(1764.3749f, -24.02903
|
||||
const Position ULDUAR_KOLOGARN_EYEBEAM_LEFT_POSITION = Position(1781.2051f, 9.34402f, 449.0f, 0.00087690353f);
|
||||
const Position ULDUAR_KOLOGARN_EYEBEAM_RIGHT_POSITION = Position(1763.2561f, -24.44305f, 449.0f, 0.00087690353f);
|
||||
const Position ULDUAR_THORIM_JUMP_START_POINT = Position(2137.137f, -291.19025f, 438.24753f, 1.7059844f);
|
||||
const Position ULDUAR_YOGG_SARON_BOSS_ROOM_RESTORE_POINT = Position(1928.8923f, -24.871964f, 324.88956f, 6.247805f);
|
||||
|
||||
const Position yoggPortalLoc[] = {
|
||||
{1970.48f, -9.75f, 325.5f}, {1992.76f, -10.21f, 325.5f}, {1995.53f, -39.78f, 325.5f}, {1969.25f, -42.00f, 325.5f},
|
||||
{1960.62f, -32.00f, 325.5f}, {1981.98f, -5.69f, 325.5f}, {1982.78f, -45.73f, 325.5f}, {2000.66f, -29.68f, 325.5f},
|
||||
{1999.88f, -19.61f, 325.5f}, {1961.37f, -19.54f, 325.5f}};
|
||||
|
||||
bool FlameLeviathanVehicleAction::Execute(Event event)
|
||||
{
|
||||
@@ -1817,24 +1824,24 @@ bool ThorimMarkDpsTargetAction::Execute(Event event)
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
ObjectGuid currentMoonTarget = group->GetTargetIcon(moonIndex);
|
||||
ObjectGuid currentMoonTarget = group->GetTargetIcon(RtiTargetValue::moonIndex);
|
||||
Unit* currentMoonUnit = botAI->GetUnit(currentMoonTarget);
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "thorim");
|
||||
if (!currentMoonUnit && boss && boss->IsAlive() && boss->GetPositionZ() > ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD)
|
||||
{
|
||||
group->SetTargetIcon(moonIndex, bot->GetGUID(), boss->GetGUID());
|
||||
group->SetTargetIcon(RtiTargetValue::moonIndex, bot->GetGUID(), boss->GetGUID());
|
||||
}
|
||||
|
||||
if (currentMoonUnit && boss && currentMoonUnit->GetEntry() == boss->GetEntry() &&
|
||||
boss->GetPositionZ() < ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD)
|
||||
{
|
||||
group->SetTargetIcon(skullIndex, bot->GetGUID(), boss->GetGUID());
|
||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), boss->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
{
|
||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex);
|
||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
Unit* currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
||||
if (currentSkullUnit && !currentSkullUnit->IsAlive())
|
||||
{
|
||||
@@ -1855,7 +1862,7 @@ bool ThorimMarkDpsTargetAction::Execute(Event event)
|
||||
}
|
||||
else if (botAI->IsAssistTankOfIndex(bot, 0))
|
||||
{
|
||||
ObjectGuid currentCrossTarget = group->GetTargetIcon(crossIndex);
|
||||
ObjectGuid currentCrossTarget = group->GetTargetIcon(RtiTargetValue::crossIndex);
|
||||
Unit* currentCrossUnit = botAI->GetUnit(currentCrossTarget);
|
||||
if (currentCrossUnit && !currentCrossUnit->IsAlive())
|
||||
{
|
||||
@@ -1891,13 +1898,13 @@ bool ThorimMarkDpsTargetAction::Execute(Event event)
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
{
|
||||
group->SetTargetIcon(skullIndex, bot->GetGUID(), targetToMark->GetGUID());
|
||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), targetToMark->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (botAI->IsAssistTankOfIndex(bot, 0))
|
||||
{
|
||||
group->SetTargetIcon(crossIndex, bot->GetGUID(), targetToMark->GetGUID());
|
||||
group->SetTargetIcon(RtiTargetValue::crossIndex, bot->GetGUID(), targetToMark->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2438,20 +2445,20 @@ bool MimironAerialCommandUnitAction::Execute(Event event)
|
||||
|
||||
if (bombBot)
|
||||
{
|
||||
group->SetTargetIcon(crossIndex, bot->GetGUID(), bombBot->GetGUID());
|
||||
group->SetTargetIcon(RtiTargetValue::crossIndex, bot->GetGUID(), bombBot->GetGUID());
|
||||
}
|
||||
else if (boss)
|
||||
{
|
||||
group->SetTargetIcon(crossIndex, bot->GetGUID(), boss->GetGUID());
|
||||
group->SetTargetIcon(RtiTargetValue::crossIndex, bot->GetGUID(), boss->GetGUID());
|
||||
}
|
||||
|
||||
if (assaultBot)
|
||||
{
|
||||
ObjectGuid skullTarget = group->GetTargetIcon(skullIndex);
|
||||
ObjectGuid skullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
Unit* skullUnit = botAI->GetUnit(skullTarget);
|
||||
if (!skullTarget || !skullUnit || !skullUnit->IsAlive())
|
||||
{
|
||||
group->SetTargetIcon(skullIndex, bot->GetGUID(), assaultBot->GetGUID());
|
||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), assaultBot->GetGUID());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2591,7 +2598,7 @@ bool MimironPhase4MarkDpsAction::Execute(Event event)
|
||||
highestHealthUnit = aerialCommandUnit;
|
||||
}
|
||||
|
||||
group->SetTargetIcon(skullIndex, bot->GetGUID(), highestHealthUnit->GetGUID());
|
||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), highestHealthUnit->GetGUID());
|
||||
if (highestHealthUnit == leviathanMkII)
|
||||
{
|
||||
if (AI_VALUE(std::string, "rti") == "skull")
|
||||
@@ -2601,7 +2608,7 @@ bool MimironPhase4MarkDpsAction::Execute(Event event)
|
||||
}
|
||||
else
|
||||
{
|
||||
group->SetTargetIcon(crossIndex, bot->GetGUID(), leviathanMkII->GetGUID());
|
||||
group->SetTargetIcon(RtiTargetValue::crossIndex, bot->GetGUID(), leviathanMkII->GetGUID());
|
||||
if (AI_VALUE(std::string, "rti") != "cross")
|
||||
{
|
||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("cross");
|
||||
@@ -2707,3 +2714,575 @@ bool VezaxMarkOfTheFacelessAction::Execute(Event event)
|
||||
ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionZ(), false, false, false, true,
|
||||
MovementPriority::MOVEMENT_FORCED, true, false);
|
||||
}
|
||||
|
||||
bool YoggSaronOminousCloudCheatAction::Execute(Event event)
|
||||
{
|
||||
YoggSaronTrigger yoggSaronTrigger(botAI);
|
||||
|
||||
Unit* boss = yoggSaronTrigger.GetSaraIfAlive();
|
||||
if (!boss)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Creature* target = boss->FindNearestCreature(NPC_OMINOUS_CLOUD, 25.0f);
|
||||
if (!target || !target->IsAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
target->Kill(bot, target);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YoggSaronGuardianPositioningAction::Execute(Event event)
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), ULDUAR_YOGG_SARON_MIDDLE.GetPositionX(), ULDUAR_YOGG_SARON_MIDDLE.GetPositionY(),
|
||||
ULDUAR_YOGG_SARON_MIDDLE.GetPositionZ(), false, false, false, true,
|
||||
MovementPriority::MOVEMENT_FORCED, true, false);
|
||||
}
|
||||
|
||||
bool YoggSaronSanityAction::Execute(Event event)
|
||||
{
|
||||
Creature* sanityWell = bot->FindNearestCreature(NPC_SANITY_WELL, 200.0f);
|
||||
|
||||
return MoveTo(bot->GetMapId(), sanityWell->GetPositionX(), sanityWell->GetPositionY(), sanityWell->GetPositionZ(),
|
||||
false, false, false, true, MovementPriority::MOVEMENT_FORCED,
|
||||
true, false);
|
||||
}
|
||||
|
||||
bool YoggSaronMarkTargetAction::Execute(Event event)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
YoggSaronTrigger yoggSaronTrigger(botAI);
|
||||
if (yoggSaronTrigger.IsPhase2())
|
||||
{
|
||||
if (botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
Unit* crusherTentacle = bot->FindNearestCreature(NPC_CRUSHER_TENTACLE, 200.0f, true);
|
||||
if (crusherTentacle)
|
||||
{
|
||||
crusherTentacle->Kill(bot, crusherTentacle);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectGuid currentMoonTarget = group->GetTargetIcon(RtiTargetValue::moonIndex);
|
||||
Creature* yogg_saron = bot->FindNearestCreature(NPC_YOGG_SARON, 200.0f, true);
|
||||
if (!currentMoonTarget || currentMoonTarget != yogg_saron->GetGUID())
|
||||
{
|
||||
group->SetTargetIcon(RtiTargetValue::moonIndex, bot->GetGUID(), yogg_saron->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
|
||||
Creature* nextPossibleTarget = bot->FindNearestCreature(NPC_CONSTRICTOR_TENTACLE, 200.0f, true);
|
||||
if (!nextPossibleTarget)
|
||||
{
|
||||
nextPossibleTarget = bot->FindNearestCreature(NPC_CORRUPTOR_TENTACLE, 200.0f, true);
|
||||
if (!nextPossibleTarget)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentSkullTarget)
|
||||
{
|
||||
Unit* currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
||||
|
||||
if (currentSkullUnit && currentSkullUnit->IsAlive() &&
|
||||
currentSkullUnit->GetGUID() == nextPossibleTarget->GetGUID())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), nextPossibleTarget->GetGUID());
|
||||
}
|
||||
else if (yoggSaronTrigger.IsPhase3())
|
||||
{
|
||||
TankFaceStrategy tankFaceStrategy(botAI);
|
||||
if (botAI->HasStrategy(tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + tankFaceStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
||||
}
|
||||
|
||||
TankAssistStrategy tankAssistStrategy(botAI);
|
||||
if (!botAI->HasStrategy(tankAssistStrategy.getName(), BotState::BOT_STATE_COMBAT))
|
||||
{
|
||||
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + tankAssistStrategy.getName(), BotState::BOT_STATE_COMBAT);
|
||||
}
|
||||
|
||||
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
|
||||
|
||||
int lowestHealth = std::numeric_limits<int>::max();
|
||||
Unit* lowestHealthUnit = nullptr;
|
||||
for (const ObjectGuid& guid : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (!unit || !unit->IsAlive())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((unit->GetEntry() == NPC_IMMORTAL_GUARDIAN || unit->GetEntry() == NPC_MARKED_IMMORTAL_GUARDIAN) &&
|
||||
unit->GetHealthPct() > 10)
|
||||
{
|
||||
if (unit->GetHealth() < lowestHealth)
|
||||
{
|
||||
lowestHealth = unit->GetHealth();
|
||||
lowestHealthUnit = unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lowestHealthUnit)
|
||||
{
|
||||
// Added because lunatic gaze freeze all bots and they can't attack
|
||||
// If someone fix it then this cheat can be removed
|
||||
if (botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
lowestHealthUnit->Kill(bot, lowestHealthUnit);
|
||||
}
|
||||
else
|
||||
{
|
||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), lowestHealthUnit->GetGUID());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
Unit* currentSkullUnit = nullptr;
|
||||
if (currentSkullTarget)
|
||||
{
|
||||
currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
||||
}
|
||||
|
||||
if (!currentSkullUnit || currentSkullUnit->GetEntry() != NPC_YOGG_SARON)
|
||||
{
|
||||
Unit* yoggsaron = AI_VALUE2(Unit*, "find target", "yogg-saron");
|
||||
if (yoggsaron && yoggsaron->IsAlive())
|
||||
{
|
||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), yoggsaron->GetGUID());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YoggSaronBrainLinkAction::Execute(Event event)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* player = gref->GetSource();
|
||||
if (player && player->IsAlive() && player->HasAura(SPELL_BRAIN_LINK) && player->GetGUID() != bot->GetGUID())
|
||||
{
|
||||
return MoveNear(player, 10.0f, MovementPriority::MOVEMENT_FORCED);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YoggSaronMoveToEnterPortalAction::Execute(Event event)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isInBrainRoomTeam = false;
|
||||
int portalNumber = 0;
|
||||
int brainRoomTeamCount = 10;
|
||||
if (bot->GetRaidDifficulty() == Difficulty::RAID_DIFFICULTY_10MAN_NORMAL)
|
||||
{
|
||||
brainRoomTeamCount = 4;
|
||||
}
|
||||
|
||||
Player* master = botAI->GetMaster();
|
||||
if (master && !botAI->IsTank(master))
|
||||
{
|
||||
portalNumber++;
|
||||
brainRoomTeamCount--;
|
||||
}
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* member = gref->GetSource();
|
||||
if (!member || !member->IsAlive() || botAI->IsTank(member) || botAI->GetMaster()->GetGUID() == member->GetGUID())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
portalNumber++;
|
||||
if (member->GetGUID() == bot->GetGUID())
|
||||
{
|
||||
isInBrainRoomTeam = true;
|
||||
break;
|
||||
}
|
||||
|
||||
brainRoomTeamCount--;
|
||||
if (brainRoomTeamCount == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isInBrainRoomTeam)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Position assignedPortalPosition = yoggPortalLoc[portalNumber - 1];
|
||||
|
||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("diamond");
|
||||
|
||||
if (botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
return bot->TeleportTo(bot->GetMapId(), assignedPortalPosition.GetPositionX(),
|
||||
assignedPortalPosition.GetPositionY(),
|
||||
assignedPortalPosition.GetPositionZ(), bot->GetOrientation());
|
||||
}
|
||||
else
|
||||
{
|
||||
return MoveNear(bot->GetMapId(), assignedPortalPosition.GetPositionX(),
|
||||
assignedPortalPosition.GetPositionY(),
|
||||
assignedPortalPosition.GetPositionZ(), sPlayerbotAIConfig->contactDistance,
|
||||
MovementPriority::MOVEMENT_FORCED);
|
||||
}
|
||||
}
|
||||
|
||||
bool YoggSaronFallFromFloorAction::Execute(Event event)
|
||||
{
|
||||
std::string rtiMark = AI_VALUE(std::string, "rti");
|
||||
if (rtiMark == "skull")
|
||||
{
|
||||
return bot->TeleportTo(bot->GetMapId(), ULDUAR_YOGG_SARON_BOSS_ROOM_RESTORE_POINT.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_BOSS_ROOM_RESTORE_POINT.GetPositionY(),
|
||||
ULDUAR_YOGG_SARON_BOSS_ROOM_RESTORE_POINT.GetPositionZ(),
|
||||
ULDUAR_YOGG_SARON_BOSS_ROOM_RESTORE_POINT.GetOrientation());
|
||||
}
|
||||
if (rtiMark == "cross")
|
||||
{
|
||||
return bot->TeleportTo(bot->GetMapId(), ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE.GetPositionY(),
|
||||
ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE.GetPositionZ(),
|
||||
bot->GetOrientation());
|
||||
}
|
||||
if (rtiMark == "circle")
|
||||
{
|
||||
return bot->TeleportTo(bot->GetMapId(), ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE.GetPositionY(),
|
||||
ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE.GetPositionZ(), bot->GetOrientation());
|
||||
}
|
||||
if (rtiMark == "star")
|
||||
{
|
||||
return bot->TeleportTo(bot->GetMapId(), ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE.GetPositionY(),
|
||||
ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE.GetPositionZ(), bot->GetOrientation());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YoggSaronBossRoomMovementCheatAction::Execute(Event event)
|
||||
{
|
||||
FollowMasterStrategy followMasterStrategy(botAI);
|
||||
if (botAI->HasStrategy(followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT))
|
||||
{
|
||||
botAI->ChangeStrategy(REMOVE_STRATEGY_CHAR + followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT);
|
||||
}
|
||||
|
||||
if (!botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
|
||||
if (!currentSkullTarget)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit* currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
||||
|
||||
if (!currentSkullUnit || !currentSkullUnit->IsAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return bot->TeleportTo(bot->GetMapId(), currentSkullUnit->GetPositionX(), currentSkullUnit->GetPositionY(),
|
||||
currentSkullUnit->GetPositionZ(), bot->GetOrientation());
|
||||
}
|
||||
|
||||
bool YoggSaronUsePortalAction::Execute(Event event)
|
||||
{
|
||||
Creature* assignedPortal = bot->FindNearestCreature(NPC_DESCEND_INTO_MADNESS, 2.0f, true);
|
||||
if (!assignedPortal)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FollowMasterStrategy followMasterStrategy(botAI);
|
||||
if (botAI->HasStrategy(followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT))
|
||||
{
|
||||
botAI->ChangeStrategy(ADD_STRATEGY_CHAR + followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT);
|
||||
}
|
||||
|
||||
return assignedPortal->HandleSpellClick(bot);
|
||||
}
|
||||
|
||||
bool YoggSaronIllusionRoomAction::Execute(Event event)
|
||||
{
|
||||
YoggSaronTrigger yoggSaronTrigger(botAI);
|
||||
|
||||
bool resultSetRtiMark = SetRtiMark(yoggSaronTrigger);
|
||||
bool resultSetIllusionRtiTarget = SetIllusionRtiTarget(yoggSaronTrigger);
|
||||
bool resultSetBrainRtiTarget = SetBrainRtiTarget(yoggSaronTrigger);
|
||||
|
||||
return resultSetRtiMark || resultSetIllusionRtiTarget || resultSetBrainRtiTarget;
|
||||
}
|
||||
|
||||
bool YoggSaronIllusionRoomAction::SetRtiMark(YoggSaronTrigger yoggSaronTrigger)
|
||||
{
|
||||
if (AI_VALUE(std::string, "rti") == "diamond")
|
||||
{
|
||||
if (yoggSaronTrigger.IsInStormwindKeeperIllusion())
|
||||
{
|
||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("cross");
|
||||
return true;
|
||||
}
|
||||
else if (yoggSaronTrigger.IsInIcecrownKeeperIllusion())
|
||||
{
|
||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("circle");
|
||||
return true;
|
||||
}
|
||||
else if (yoggSaronTrigger.IsInChamberOfTheAspectsIllusion())
|
||||
{
|
||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("star");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YoggSaronIllusionRoomAction::SetIllusionRtiTarget(YoggSaronTrigger yoggSaronTrigger)
|
||||
{
|
||||
Unit* currentRtiTarget = yoggSaronTrigger.GetIllusionRoomRtiTarget();
|
||||
if (currentRtiTarget)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit* nextRtiTarget = yoggSaronTrigger.GetNextIllusionRoomRtiTarget();
|
||||
if (!nextRtiTarget)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If proper adds handling in illusion room will be implemented, then this can be removed
|
||||
if (botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
bot->TeleportTo(bot->GetMapId(), nextRtiTarget->GetPositionX(), nextRtiTarget->GetPositionY(),
|
||||
nextRtiTarget->GetPositionZ(), bot->GetOrientation());
|
||||
|
||||
Unit::DealDamage(bot->GetSession()->GetPlayer(), nextRtiTarget, nextRtiTarget->GetHealth(), nullptr,
|
||||
DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8 rtiIndex = RtiTargetValue::GetRtiIndex(AI_VALUE(std::string, "rti"));
|
||||
group->SetTargetIcon(rtiIndex, bot->GetGUID(), nextRtiTarget->GetGUID());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YoggSaronIllusionRoomAction::SetBrainRtiTarget(YoggSaronTrigger yoggSaronTrigger)
|
||||
{
|
||||
if (AI_VALUE(std::string, "rti") == "square" || !yoggSaronTrigger.IsMasterIsInBrainRoom())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("square");
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Creature* brain = bot->FindNearestCreature(NPC_BRAIN, 200.0f, true);
|
||||
if (!brain)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
group->SetTargetIcon(RtiTargetValue::squareIndex, bot->GetGUID(), brain->GetGUID());
|
||||
|
||||
Position entrancePosition = yoggSaronTrigger.GetIllusionRoomEntrancePosition();
|
||||
|
||||
if (botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
if (Unit const* master = botAI->GetMaster())
|
||||
{
|
||||
Position masterPosition = master->GetPosition();
|
||||
bot->TeleportTo(bot->GetMapId(), masterPosition.GetPositionX(), masterPosition.GetPositionY(),
|
||||
masterPosition.GetPositionZ(), bot->GetOrientation());
|
||||
}
|
||||
else
|
||||
{
|
||||
bot->TeleportTo(bot->GetMapId(), entrancePosition.GetPositionX(), entrancePosition.GetPositionY(),
|
||||
entrancePosition.GetPositionZ(), bot->GetOrientation());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MoveTo(bot->GetMapId(), entrancePosition.GetPositionX(), entrancePosition.GetPositionY(),
|
||||
entrancePosition.GetPositionZ(), false, false, false, true, MovementPriority::MOVEMENT_FORCED, true,
|
||||
false);
|
||||
}
|
||||
|
||||
botAI->DoSpecificAction("attack rti target");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YoggSaronMoveToExitPortalAction::Execute(Event event)
|
||||
{
|
||||
GameObject* portal = bot->FindNearestGameObject(GO_FLEE_TO_THE_SURFACE_PORTAL, 100.0f);
|
||||
if (!portal)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
bot->TeleportTo(bot->GetMapId(), portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(),
|
||||
bot->GetOrientation());
|
||||
}
|
||||
else
|
||||
{
|
||||
MoveTo(bot->GetMapId(), portal->GetPositionX(), portal->GetPositionY(), portal->GetPositionZ(), false,
|
||||
false, false, true, MovementPriority::MOVEMENT_FORCED,
|
||||
true, false);
|
||||
}
|
||||
|
||||
if (bot->GetDistance2d(portal) > 2.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
portal->Use(bot);
|
||||
|
||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("skull");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YoggSaronLunaticGazeAction::Execute(Event event)
|
||||
{
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "yogg-saron");
|
||||
if (!boss || !boss->IsAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
float angle = bot->GetAngle(boss);
|
||||
float newAngle = Position::NormalizeOrientation(angle + M_PI); // Add 180 degrees (PI radians)
|
||||
bot->SetFacingTo(newAngle);
|
||||
|
||||
if (botAI->IsRangedDps(bot))
|
||||
{
|
||||
if (AI_VALUE(std::string, "rti") != "cross")
|
||||
{
|
||||
botAI->GetAiObjectContext()->GetValue<std::string>("rti")->Set("cross");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YoggSaronPhase3PositioningAction::Execute(Event event)
|
||||
{
|
||||
if (botAI->IsRanged(bot))
|
||||
{
|
||||
if (botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
return bot->TeleportTo(bot->GetMapId(), ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionY(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionZ(),
|
||||
bot->GetOrientation());
|
||||
}
|
||||
else
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionY(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionZ(), false,
|
||||
false, false, true, MovementPriority::MOVEMENT_FORCED, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (botAI->IsMelee(bot) && !botAI->IsTank(bot))
|
||||
{
|
||||
if (botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
return bot->TeleportTo(bot->GetMapId(), ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionY(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionZ(), bot->GetOrientation());
|
||||
}
|
||||
else
|
||||
{
|
||||
return MoveTo(bot->GetMapId(), ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionY(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionZ(), false, false, false, true,
|
||||
MovementPriority::MOVEMENT_FORCED, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (botAI->IsTank(bot))
|
||||
{
|
||||
if (bot->GetDistance(ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT) > 30.0f)
|
||||
{
|
||||
if (botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
return bot->TeleportTo(bot->GetMapId(), ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionY(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionZ(), bot->GetOrientation());
|
||||
}
|
||||
}
|
||||
|
||||
return MoveTo(bot->GetMapId(), ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionY(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionZ(), false, false, false, true,
|
||||
MovementPriority::MOVEMENT_FORCED, true, false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "PlayerbotAI.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RaidUlduarBossHelper.h"
|
||||
#include "RaidUlduarTriggers.h"
|
||||
#include "Vehicle.h"
|
||||
|
||||
//
|
||||
@@ -378,4 +379,125 @@ public:
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronOminousCloudCheatAction : public Action
|
||||
{
|
||||
public:
|
||||
YoggSaronOminousCloudCheatAction(PlayerbotAI* ai) : Action(ai, "yogg-saron ominous cloud cheat action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronGuardianPositioningAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
YoggSaronGuardianPositioningAction(PlayerbotAI* ai) : MovementAction(ai, "yogg-saron guardian positioning action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronSanityAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
YoggSaronSanityAction(PlayerbotAI* ai) : MovementAction(ai, "yogg-saron sanity action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronDeathOrbAction : public MoveAwayFromCreatureAction
|
||||
{
|
||||
public:
|
||||
YoggSaronDeathOrbAction(PlayerbotAI* ai) : MoveAwayFromCreatureAction(ai, "yogg-saron death orb action", NPC_DEATH_ORB, 10.0f) {}
|
||||
};
|
||||
|
||||
class YoggSaronMaladyOfTheMindAction : public MoveAwayFromPlayerWithDebuffAction
|
||||
{
|
||||
public:
|
||||
YoggSaronMaladyOfTheMindAction(PlayerbotAI* ai) : MoveAwayFromPlayerWithDebuffAction(ai, "yogg-saron malady of the mind action", SPELL_MALADY_OF_THE_MIND, 15.0f) {}
|
||||
};
|
||||
|
||||
class YoggSaronMarkTargetAction : public Action
|
||||
{
|
||||
public:
|
||||
YoggSaronMarkTargetAction(PlayerbotAI* ai) : Action(ai, "yogg-saron mark target action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronBrainLinkAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
YoggSaronBrainLinkAction(PlayerbotAI* ai) : MovementAction(ai, "yogg-saron brain link action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronMoveToEnterPortalAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
YoggSaronMoveToEnterPortalAction(PlayerbotAI* ai) : MovementAction(ai, "yogg-saron move to enter portal action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronFallFromFloorAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
YoggSaronFallFromFloorAction(PlayerbotAI* ai) : MovementAction(ai, "yogg-saron fall from floor action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronBossRoomMovementCheatAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
YoggSaronBossRoomMovementCheatAction(PlayerbotAI* ai) : MovementAction(ai, "yogg-saron boss room movement cheat action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronUsePortalAction : public Action
|
||||
{
|
||||
public:
|
||||
YoggSaronUsePortalAction(PlayerbotAI* ai) : Action(ai, "yogg-saron use portal action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronIllusionRoomAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
YoggSaronIllusionRoomAction(PlayerbotAI* ai) : MovementAction(ai, "yogg-saron illusion room action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
bool SetRtiMark(YoggSaronTrigger yoggSaronTrigger);
|
||||
bool SetIllusionRtiTarget(YoggSaronTrigger yoggSaronTrigger);
|
||||
bool SetBrainRtiTarget(YoggSaronTrigger yoggSaronTrigger);
|
||||
};
|
||||
|
||||
class YoggSaronMoveToExitPortalAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
YoggSaronMoveToExitPortalAction(PlayerbotAI* ai) : MovementAction(ai, "yogg-saron move to exit portal action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronLunaticGazeAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
YoggSaronLunaticGazeAction(PlayerbotAI* ai) : MovementAction(ai, "yogg-saron lunatic gaze action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class YoggSaronPhase3PositioningAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
YoggSaronPhase3PositioningAction(PlayerbotAI* ai) : MovementAction(ai, "yogg-saron phase 3 positioning action") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -255,6 +255,66 @@ void RaidUlduarStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron shadow resistance trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron shadow resistance action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron ominous cloud cheat trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron ominous cloud cheat action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron guardian positioning trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron guardian positioning action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron sanity trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron sanity action", ACTION_RAID + 1), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron death orb trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron death orb action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron malady of the mind trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron malady of the mind action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron mark target trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron mark target action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron brain link trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron brain link action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron move to enter portal trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron move to enter portal action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron use portal trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron use portal action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron fall from floor trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron fall from floor action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron boss room movement cheat trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron boss room movement cheat action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron illusion room trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron illusion room action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron move to exit portal trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron move to exit portal action", ACTION_RAID), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron lunatic gaze trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron lunatic gaze action", ACTION_EMERGENCY), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"yogg-saron phase 3 positioning trigger",
|
||||
NextAction::array(0, new NextAction("yogg-saron phase 3 positioning action", ACTION_RAID), nullptr)));
|
||||
}
|
||||
|
||||
void RaidUlduarStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
|
||||
@@ -67,6 +67,24 @@ public:
|
||||
creators["vezax cheat trigger"] = &RaidUlduarTriggerContext::vezax_cheat_trigger;
|
||||
creators["vezax shadow crash trigger"] = &RaidUlduarTriggerContext::vezax_shadow_crash_trigger;
|
||||
creators["vezax mark of the faceless trigger"] = &RaidUlduarTriggerContext::vezax_mark_of_the_faceless_trigger;
|
||||
creators["vezax shadow resistance trigger"] = &RaidUlduarTriggerContext::vezax_shadow_resistance_trigger;
|
||||
creators["sara shadow resistance trigger"] = &RaidUlduarTriggerContext::sara_shadow_resistance_trigger;
|
||||
creators["yogg-saron shadow resistance triggerr"] = &RaidUlduarTriggerContext::yogg_saron_shadow_resistance_trigger;
|
||||
creators["yogg-saron ominous cloud cheat trigger"] = &RaidUlduarTriggerContext::yogg_saron_ominous_cloud_cheat_trigger;
|
||||
creators["yogg-saron guardian positioning trigger"] = &RaidUlduarTriggerContext::yogg_saron_guardian_positioning_trigger;
|
||||
creators["yogg-saron sanity trigger"] = &RaidUlduarTriggerContext::yogg_saron_sanity_trigger;
|
||||
creators["yogg-saron death orb trigger"] = &RaidUlduarTriggerContext::yogg_saron_death_orb_trigger;
|
||||
creators["yogg-saron malady of the mind trigger"] = &RaidUlduarTriggerContext::yogg_saron_malady_of_the_mind_trigger;
|
||||
creators["yogg-saron mark target trigger"] = &RaidUlduarTriggerContext::yogg_saron_mark_target_trigger;
|
||||
creators["yogg-saron brain link trigger"] = &RaidUlduarTriggerContext::yogg_saron_brain_link_trigger;
|
||||
creators["yogg-saron move to enter portal trigger"] = &RaidUlduarTriggerContext::yogg_saron_move_to_enter_portal_trigger;
|
||||
creators["yogg-saron use portal trigger"] = &RaidUlduarTriggerContext::yogg_saron_use_portal_trigger;
|
||||
creators["yogg-saron fall from floor trigger"] = &RaidUlduarTriggerContext::yogg_saron_fall_from_floor_trigger;
|
||||
creators["yogg-saron boss room movement cheat trigger"] = &RaidUlduarTriggerContext::yogg_saron_boss_room_movement_cheat_trigger;
|
||||
creators["yogg-saron illusion room trigger"] = &RaidUlduarTriggerContext::yogg_saron_illusion_room_trigger;
|
||||
creators["yogg-saron move to exit portal trigger"] = &RaidUlduarTriggerContext::yogg_saron_move_to_exit_portal_trigger;
|
||||
creators["yogg-saron lunatic gaze trigger"] = &RaidUlduarTriggerContext::yogg_saron_lunatic_gaze_trigger;
|
||||
creators["yogg-saron phase 3 positioning trigger"] = &RaidUlduarTriggerContext::yogg_saron_phase_3_positioning_trigger;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -120,7 +138,25 @@ private:
|
||||
static Trigger* mimiron_cheat_trigger(PlayerbotAI* ai) { return new MimironCheatTrigger(ai); }
|
||||
static Trigger* vezax_cheat_trigger(PlayerbotAI* ai) { return new VezaxCheatTrigger(ai); }
|
||||
static Trigger* vezax_shadow_crash_trigger(PlayerbotAI* ai) { return new VezaxShadowCrashTrigger(ai); }
|
||||
static Trigger* vezax_shadow_resistance_trigger(PlayerbotAI* ai) { return new BossShadowResistanceTrigger(ai, "general vezax"); }
|
||||
static Trigger* sara_shadow_resistance_trigger(PlayerbotAI* ai) { return new BossShadowResistanceTrigger(ai, "sara"); }
|
||||
static Trigger* yogg_saron_shadow_resistance_trigger(PlayerbotAI* ai) { return new BossShadowResistanceTrigger(ai, "yogg-saron"); }
|
||||
static Trigger* vezax_mark_of_the_faceless_trigger(PlayerbotAI* ai) { return new VezaxMarkOfTheFacelessTrigger(ai); }
|
||||
static Trigger* yogg_saron_ominous_cloud_cheat_trigger(PlayerbotAI* ai) { return new YoggSaronOminousCloudCheatTrigger(ai); }
|
||||
static Trigger* yogg_saron_guardian_positioning_trigger(PlayerbotAI* ai) { return new YoggSaronGuardianPositioningTrigger(ai); }
|
||||
static Trigger* yogg_saron_sanity_trigger(PlayerbotAI* ai) { return new YoggSaronSanityTrigger(ai); }
|
||||
static Trigger* yogg_saron_death_orb_trigger(PlayerbotAI* ai) { return new YoggSaronDeathOrbTrigger(ai); }
|
||||
static Trigger* yogg_saron_malady_of_the_mind_trigger(PlayerbotAI* ai) { return new YoggSaronMaladyOfTheMindTrigger(ai); }
|
||||
static Trigger* yogg_saron_mark_target_trigger(PlayerbotAI* ai) { return new YoggSaronMarkTargetTrigger(ai); }
|
||||
static Trigger* yogg_saron_brain_link_trigger(PlayerbotAI* ai) { return new YoggSaronBrainLinkTrigger(ai); }
|
||||
static Trigger* yogg_saron_move_to_enter_portal_trigger(PlayerbotAI* ai) { return new YoggSaronMoveToEnterPortalTrigger(ai); }
|
||||
static Trigger* yogg_saron_use_portal_trigger(PlayerbotAI* ai) { return new YoggSaronUsePortalTrigger(ai); }
|
||||
static Trigger* yogg_saron_fall_from_floor_trigger(PlayerbotAI* ai) { return new YoggSaronFallFromFloorTrigger(ai); }
|
||||
static Trigger* yogg_saron_boss_room_movement_cheat_trigger(PlayerbotAI* ai) { return new YoggSaronBossRoomMovementCheatTrigger(ai); }
|
||||
static Trigger* yogg_saron_illusion_room_trigger(PlayerbotAI* ai) { return new YoggSaronIllusionRoomTrigger(ai); }
|
||||
static Trigger* yogg_saron_move_to_exit_portal_trigger(PlayerbotAI* ai) { return new YoggSaronMoveToExitPortalTrigger(ai); }
|
||||
static Trigger* yogg_saron_lunatic_gaze_trigger(PlayerbotAI* ai) { return new YoggSaronLunaticGazeTrigger(ai); }
|
||||
static Trigger* yogg_saron_phase_3_positioning_trigger(PlayerbotAI* ai) { return new YoggSaronPhase3PositioningTrigger(ai); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -12,11 +12,33 @@
|
||||
#include "Trigger.h"
|
||||
#include "Vehicle.h"
|
||||
#include <MovementActions.h>
|
||||
#include <FollowMasterStrategy.h>
|
||||
#include <RtiTargetValue.h>
|
||||
|
||||
const std::vector<uint32> availableVehicles = {NPC_VEHICLE_CHOPPER, NPC_SALVAGED_DEMOLISHER,
|
||||
NPC_SALVAGED_DEMOLISHER_TURRET, NPC_SALVAGED_SIEGE_ENGINE,
|
||||
NPC_SALVAGED_SIEGE_ENGINE_TURRET};
|
||||
|
||||
const std::vector<uint32> illusionMobs =
|
||||
{
|
||||
NPC_INFLUENCE_TENTACLE,
|
||||
NPC_RUBY_CONSORT,
|
||||
NPC_AZURE_CONSORT,
|
||||
NPC_BRONZE_CONSORT,
|
||||
NPC_EMERALD_CONSORT,
|
||||
NPC_OBSIDIAN_CONSORT,
|
||||
NPC_ALEXTRASZA,
|
||||
NPC_MALYGOS_ILLUSION,
|
||||
NPC_NELTHARION,
|
||||
NPC_YSERA,
|
||||
NPC_DEATHSWORN_ZEALOT,
|
||||
NPC_LICH_KING_ILLUSION,
|
||||
NPC_IMMOLATED_CHAMPION,
|
||||
NPC_SUIT_OF_ARMOR,
|
||||
NPC_GARONA,
|
||||
NPC_KING_LLANE
|
||||
};
|
||||
|
||||
bool FlameLeviathanOnVehicleTrigger::IsActive()
|
||||
{
|
||||
Unit* vehicleBase = bot->GetVehicleBase();
|
||||
@@ -448,8 +470,8 @@ bool KologarnAttackDpsTargetTrigger::IsActive()
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
ObjectGuid skullTarget = group->GetTargetIcon(skullIndex);
|
||||
ObjectGuid crossTarget = group->GetTargetIcon(crossIndex);
|
||||
ObjectGuid skullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
ObjectGuid crossTarget = group->GetTargetIcon(RtiTargetValue::crossIndex);
|
||||
|
||||
if (crossTarget && (botAI->IsMainTank(bot) || botAI->IsAssistTankOfIndex(bot, 0)))
|
||||
{
|
||||
@@ -745,7 +767,7 @@ bool ThorimUnbalancingStrikeTrigger::IsActive()
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "thorim");
|
||||
|
||||
// Check boss and it is alive
|
||||
if (!boss || !boss->IsAlive())
|
||||
if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot))
|
||||
return false;
|
||||
|
||||
return bot->HasAura(SPELL_UNBALANCING_STRIKE);
|
||||
@@ -762,7 +784,7 @@ bool ThorimMarkDpsTargetTrigger::IsActive()
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
{
|
||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(skullIndex);
|
||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
Unit* currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
||||
if (currentSkullUnit && !currentSkullUnit->IsAlive())
|
||||
{
|
||||
@@ -783,13 +805,13 @@ bool ThorimMarkDpsTargetTrigger::IsActive()
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "thorim");
|
||||
|
||||
// Check boss and it is alive
|
||||
if (!boss || !boss->IsAlive())
|
||||
if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot))
|
||||
return false;
|
||||
|
||||
|
||||
if (boss->GetPositionZ() < ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD && (!currentSkullUnit || !currentSkullUnit->IsAlive()))
|
||||
{
|
||||
group->SetTargetIcon(skullIndex, bot->GetGUID(), boss->GetGUID());
|
||||
group->SetTargetIcon(RtiTargetValue::skullIndex, bot->GetGUID(), boss->GetGUID());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -811,7 +833,7 @@ bool ThorimMarkDpsTargetTrigger::IsActive()
|
||||
if (mainTank && bot->GetDistance(mainTank) < 30.0f)
|
||||
return false;
|
||||
|
||||
ObjectGuid currentCrossTarget = group->GetTargetIcon(crossIndex);
|
||||
ObjectGuid currentCrossTarget = group->GetTargetIcon(RtiTargetValue::crossIndex);
|
||||
Unit* currentCrossUnit = botAI->GetUnit(currentCrossTarget);
|
||||
if (currentCrossUnit && !currentCrossUnit->IsAlive())
|
||||
{
|
||||
@@ -963,7 +985,7 @@ bool ThorimArenaPositioningTrigger::IsActive()
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "thorim");
|
||||
|
||||
// Check boss and it is alive
|
||||
if (!boss || !boss->IsAlive())
|
||||
if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot))
|
||||
return false;
|
||||
|
||||
if (boss->GetPositionZ() < ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD)
|
||||
@@ -1061,7 +1083,7 @@ bool ThorimPhase2PositioningTrigger::IsActive()
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", "thorim");
|
||||
|
||||
// Check boss and it is alive
|
||||
if (!boss || !boss->IsAlive())
|
||||
if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot))
|
||||
return false;
|
||||
|
||||
if (boss->GetPositionZ() > ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD)
|
||||
@@ -1408,8 +1430,8 @@ bool MimironAerialCommandUnitTrigger::IsActive()
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectGuid skullTarget = group->GetTargetIcon(skullIndex);
|
||||
ObjectGuid crossTarget = group->GetTargetIcon(crossIndex);
|
||||
ObjectGuid skullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
ObjectGuid crossTarget = group->GetTargetIcon(RtiTargetValue::crossIndex);
|
||||
|
||||
//if (bombBot && bombBot->GetGUID() != crossTarget)
|
||||
//{
|
||||
@@ -1515,7 +1537,7 @@ bool MimironPhase4MarkDpsTrigger::IsActive()
|
||||
highestHealthUnit = aerialCommandUnit;
|
||||
}
|
||||
|
||||
ObjectGuid skullTarget = group->GetTargetIcon(skullIndex);
|
||||
ObjectGuid skullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
if (!skullTarget)
|
||||
{
|
||||
return true;
|
||||
@@ -1619,3 +1641,748 @@ bool VezaxMarkOfTheFacelessTrigger::IsActive()
|
||||
|
||||
return distance > 2.0f;
|
||||
}
|
||||
|
||||
Unit* YoggSaronTrigger::GetSaraIfAlive()
|
||||
{
|
||||
Unit* sara = AI_VALUE2(Unit*, "find target", "sara");
|
||||
if (!sara || !sara->IsAlive())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return sara;
|
||||
}
|
||||
|
||||
bool YoggSaronTrigger::IsPhase2()
|
||||
{
|
||||
Creature* target = bot->FindNearestCreature(NPC_YOGG_SARON, 200.0f, true);
|
||||
|
||||
return target && target->IsAlive() && target->HasAura(SPELL_SHADOW_BARRIER);
|
||||
}
|
||||
|
||||
bool YoggSaronTrigger::IsPhase3()
|
||||
{
|
||||
Creature* target = bot->FindNearestCreature(NPC_YOGG_SARON, 200.0f, true);
|
||||
Creature* guardian = bot->FindNearestCreature(NPC_GUARDIAN_OF_YS, 200.0f, true);
|
||||
|
||||
return target && target->IsAlive() && !target->HasAura(SPELL_SHADOW_BARRIER) && !guardian;
|
||||
}
|
||||
|
||||
bool YoggSaronTrigger::IsInBrainLevel()
|
||||
{
|
||||
return bot->GetPositionZ() > 230.0f && bot->GetPositionZ() < 250.0f;
|
||||
}
|
||||
|
||||
bool YoggSaronTrigger::IsYoggSaronFight()
|
||||
{
|
||||
Unit* sara = AI_VALUE2(Unit*, "find target", "sara");
|
||||
Unit* yoggsaron = AI_VALUE2(Unit*, "find target", "yogg-saron");
|
||||
|
||||
if ((sara && sara->IsAlive()) || (yoggsaron && yoggsaron->IsAlive()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool YoggSaronTrigger::IsInIllusionRoom()
|
||||
{
|
||||
if (!IsInBrainLevel())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsInStormwindKeeperIllusion())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsInIcecrownKeeperIllusion())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsInChamberOfTheAspectsIllusion())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YoggSaronTrigger::IsInStormwindKeeperIllusion()
|
||||
{
|
||||
return bot->GetDistance2d(ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE.GetPositionY()) <
|
||||
ULDUAR_YOGG_SARON_STORMWIND_KEEPER_RADIUS;
|
||||
}
|
||||
|
||||
bool YoggSaronTrigger::IsInIcecrownKeeperIllusion()
|
||||
{
|
||||
return bot->GetDistance2d(ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE.GetPositionY()) <
|
||||
ULDUAR_YOGG_SARON_ICECROWN_CITADEL_RADIUS;
|
||||
}
|
||||
|
||||
bool YoggSaronTrigger::IsInChamberOfTheAspectsIllusion()
|
||||
{
|
||||
return bot->GetDistance2d(ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE.GetPositionY()) <
|
||||
ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_RADIUS;
|
||||
}
|
||||
|
||||
bool YoggSaronTrigger::IsMasterIsInIllusionGroup()
|
||||
{
|
||||
Player* master = botAI->GetMaster();
|
||||
return master && !botAI->IsTank(master);
|
||||
}
|
||||
|
||||
bool YoggSaronTrigger::IsMasterIsInBrainRoom()
|
||||
{
|
||||
Player* master = botAI->GetMaster();
|
||||
|
||||
if (!master)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return master->GetDistance2d(ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE.GetPositionY()) <
|
||||
ULDUAR_YOGG_SARON_BRAIN_ROOM_RADIUS &&
|
||||
master->GetPositionZ() > 230.0f && master->GetPositionZ() < 250.0f;
|
||||
}
|
||||
|
||||
Position YoggSaronTrigger::GetIllusionRoomEntrancePosition()
|
||||
{
|
||||
if (IsInChamberOfTheAspectsIllusion())
|
||||
{
|
||||
return ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_ENTRANCE;
|
||||
}
|
||||
else if (IsInIcecrownKeeperIllusion())
|
||||
{
|
||||
return ULDUAR_YOGG_SARON_ICECROWN_CITADEL_ENTRANCE;
|
||||
}
|
||||
else if (IsInStormwindKeeperIllusion())
|
||||
{
|
||||
return ULDUAR_YOGG_SARON_STORMWIND_KEEPER_ENTRANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Position();
|
||||
}
|
||||
}
|
||||
|
||||
Unit* YoggSaronTrigger::GetIllusionRoomRtiTarget()
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint8 rtiIndex = RtiTargetValue::GetRtiIndex(AI_VALUE(std::string, "rti"));
|
||||
if (rtiIndex == -1)
|
||||
{
|
||||
return nullptr; // Invalid RTI mark
|
||||
}
|
||||
|
||||
ObjectGuid currentRtiTarget = group->GetTargetIcon(rtiIndex);
|
||||
Unit* currentRtiTargetUnit = botAI->GetUnit(currentRtiTarget);
|
||||
if (!currentRtiTargetUnit || !currentRtiTargetUnit->IsAlive())
|
||||
{
|
||||
currentRtiTargetUnit = nullptr;
|
||||
}
|
||||
|
||||
return currentRtiTargetUnit;
|
||||
}
|
||||
|
||||
Unit* YoggSaronTrigger::GetNextIllusionRoomRtiTarget()
|
||||
{
|
||||
float detectionRadius = 0.0f;
|
||||
if (IsInStormwindKeeperIllusion())
|
||||
{
|
||||
detectionRadius = ULDUAR_YOGG_SARON_STORMWIND_KEEPER_RADIUS;
|
||||
}
|
||||
else if (IsInIcecrownKeeperIllusion())
|
||||
{
|
||||
detectionRadius = ULDUAR_YOGG_SARON_ICECROWN_CITADEL_RADIUS;
|
||||
}
|
||||
else if (IsInChamberOfTheAspectsIllusion())
|
||||
{
|
||||
detectionRadius = ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_RADIUS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
|
||||
|
||||
if (botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
for (const ObjectGuid& guid : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (unit && unit->IsAlive() && unit->GetEntry() == NPC_LAUGHING_SKULL)
|
||||
{
|
||||
return unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float nearestDistance = std::numeric_limits<float>::max();
|
||||
Unit* nextIllusionRoomRtiTarget = nullptr;
|
||||
|
||||
for (const uint32& creatureId : illusionMobs)
|
||||
{
|
||||
for (const ObjectGuid& guid : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (unit && unit->IsAlive() && unit->GetEntry() == creatureId)
|
||||
{
|
||||
float distance = bot->GetDistance(unit);
|
||||
if (distance < nearestDistance)
|
||||
{
|
||||
nextIllusionRoomRtiTarget = unit;
|
||||
nearestDistance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nextIllusionRoomRtiTarget)
|
||||
{
|
||||
return nextIllusionRoomRtiTarget;
|
||||
}
|
||||
|
||||
if (IsInStormwindKeeperIllusion())
|
||||
{
|
||||
Creature* target = bot->FindNearestCreature(NPC_SUIT_OF_ARMOR, detectionRadius, true);
|
||||
if (target)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool YoggSaronOminousCloudCheatTrigger::IsActive()
|
||||
{
|
||||
if (!botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit* boss = GetSaraIfAlive();
|
||||
if (!boss)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!botAI->IsBotMainTank(bot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->GetDistance2d(boss->GetPositionX(), boss->GetPositionY()) > 50.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Creature* target = boss->FindNearestCreature(NPC_OMINOUS_CLOUD, 25.0f, true);
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
bool YoggSaronGuardianPositioningTrigger::IsActive()
|
||||
{
|
||||
if (!GetSaraIfAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!botAI->IsTank(bot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
|
||||
bool thereIsAnyGuardian = false;
|
||||
|
||||
for (const ObjectGuid& guid : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (!unit || !unit->IsAlive())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unit->GetEntry() == NPC_GUARDIAN_OF_YS)
|
||||
{
|
||||
thereIsAnyGuardian = true;
|
||||
ObjectGuid unitTargetGuid = unit->GetTarget();
|
||||
Player* targetedPlayer = botAI->GetPlayer(unitTargetGuid);
|
||||
if (!targetedPlayer || !botAI->IsTank(targetedPlayer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return thereIsAnyGuardian &&
|
||||
bot->GetDistance2d(ULDUAR_YOGG_SARON_MIDDLE.GetPositionX(), ULDUAR_YOGG_SARON_MIDDLE.GetPositionY()) > 1.0f;
|
||||
}
|
||||
|
||||
bool YoggSaronSanityTrigger::IsActive()
|
||||
{
|
||||
Aura* sanityAura = bot->GetAura(SPELL_SANITY);
|
||||
|
||||
if (!sanityAura)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int sanityAuraStacks = sanityAura->GetStackAmount();
|
||||
|
||||
Creature* sanityWell = bot->FindNearestCreature(NPC_SANITY_WELL, 200.0f);
|
||||
|
||||
if (!sanityWell)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float distanceToSanityWell = bot->GetDistance(sanityWell);
|
||||
|
||||
return (distanceToSanityWell >= 1.0f && sanityAuraStacks < 40) ||
|
||||
(distanceToSanityWell < 1.0f && sanityAuraStacks < 100);
|
||||
}
|
||||
|
||||
bool YoggSaronDeathOrbTrigger::IsActive()
|
||||
{
|
||||
TooCloseToCreatureTrigger tooCloseToDeathOrbTrigger(botAI);
|
||||
return IsPhase2() && tooCloseToDeathOrbTrigger.TooCloseToCreature(NPC_DEATH_ORB, 10.0f);
|
||||
}
|
||||
|
||||
bool YoggSaronMaladyOfTheMindTrigger::IsActive()
|
||||
{
|
||||
TooCloseToPlayerWithDebuffTrigger tooCloseToPlayerWithDebuffTrigger(botAI);
|
||||
return IsPhase2() && tooCloseToPlayerWithDebuffTrigger.TooCloseToPlayerWithDebuff(SPELL_MALADY_OF_THE_MIND, 15.0f) && botAI->CanMove();
|
||||
}
|
||||
|
||||
bool YoggSaronMarkTargetTrigger::IsActive()
|
||||
{
|
||||
if (!IsYoggSaronFight())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!botAI->IsBotMainTank(bot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsPhase2())
|
||||
{
|
||||
ObjectGuid currentMoonTarget = group->GetTargetIcon(RtiTargetValue::moonIndex);
|
||||
Creature* yogg_saron = bot->FindNearestCreature(NPC_YOGG_SARON, 200.0f, true);
|
||||
if (!currentMoonTarget || currentMoonTarget != yogg_saron->GetGUID())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
|
||||
Creature* nextPossibleTarget = bot->FindNearestCreature(NPC_CONSTRICTOR_TENTACLE, 200.0f, true);
|
||||
if (!nextPossibleTarget)
|
||||
{
|
||||
nextPossibleTarget = bot->FindNearestCreature(NPC_CORRUPTOR_TENTACLE, 200.0f, true);
|
||||
if (!nextPossibleTarget)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentSkullTarget)
|
||||
{
|
||||
Unit* currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
||||
|
||||
if (!currentSkullUnit)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (currentSkullUnit->IsAlive() && currentSkullUnit->GetGUID() == nextPossibleTarget->GetGUID())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (IsPhase3())
|
||||
{
|
||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
Unit* currentSkullUnit = nullptr;
|
||||
if (currentSkullTarget)
|
||||
{
|
||||
currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
||||
}
|
||||
|
||||
if (currentSkullUnit &&
|
||||
(currentSkullUnit->GetEntry() == NPC_IMMORTAL_GUARDIAN ||
|
||||
currentSkullUnit->GetEntry() == NPC_MARKED_IMMORTAL_GUARDIAN) &&
|
||||
currentSkullUnit->GetHealthPct() > 10)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
|
||||
for (const ObjectGuid& guid : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (!unit || !unit->IsAlive())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((unit->GetEntry() == NPC_IMMORTAL_GUARDIAN || unit->GetEntry() == NPC_MARKED_IMMORTAL_GUARDIAN) &&
|
||||
unit->GetHealthPct() > 10)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentSkullUnit || currentSkullUnit->GetEntry() != NPC_YOGG_SARON)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YoggSaronBrainLinkTrigger::IsActive()
|
||||
{
|
||||
TooFarFromPlayerWithAuraTrigger tooFarFromPlayerWithAuraTrigger(botAI);
|
||||
return IsPhase2() && bot->HasAura(SPELL_BRAIN_LINK) &&
|
||||
tooFarFromPlayerWithAuraTrigger.TooFarFromPlayerWithAura(SPELL_BRAIN_LINK, 20.0f, false);
|
||||
}
|
||||
|
||||
bool YoggSaronMoveToEnterPortalTrigger::IsActive()
|
||||
{
|
||||
if (!IsPhase2())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Creature* portal = bot->FindNearestCreature(NPC_DESCEND_INTO_MADNESS, 100.0f, true);
|
||||
if (!portal)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bot->GetDistance2d(portal->GetPositionX(), portal->GetPositionY()) < 2.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AI_VALUE(std::string, "rti") != "skull")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int brainRoomTeamCount = 10;
|
||||
if (bot->GetRaidDifficulty() == Difficulty::RAID_DIFFICULTY_10MAN_NORMAL)
|
||||
{
|
||||
brainRoomTeamCount = 4;
|
||||
}
|
||||
|
||||
if (IsMasterIsInIllusionGroup())
|
||||
{
|
||||
brainRoomTeamCount--;
|
||||
}
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* member = gref->GetSource();
|
||||
if (!member || !member->IsAlive() || botAI->IsTank(member))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (member->GetGUID() == bot->GetGUID())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
brainRoomTeamCount--;
|
||||
if (brainRoomTeamCount == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YoggSaronFallFromFloorTrigger::IsActive()
|
||||
{
|
||||
if (!IsYoggSaronFight())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string rtiMark = AI_VALUE(std::string, "rti");
|
||||
|
||||
if (rtiMark == "skull" && bot->GetPositionZ() < ULDUAR_YOGG_SARON_BOSS_ROOM_AXIS_Z_PATHING_ISSUE_DETECT)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ((rtiMark == "cross" || rtiMark == "circle" || rtiMark == "star") && bot->GetPositionZ() < ULDUAR_YOGG_SARON_BRAIN_ROOM_AXIS_Z_PATHING_ISSUE_DETECT)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YoggSaronBossRoomMovementCheatTrigger::IsActive()
|
||||
{
|
||||
if (!IsYoggSaronFight() || !IsPhase2())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
FollowMasterStrategy followMasterStrategy(botAI);
|
||||
if (botAI->HasStrategy(followMasterStrategy.getName(), BotState::BOT_STATE_NON_COMBAT))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!botAI->HasCheat(BotCheatMask::raid))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AI_VALUE(std::string, "rti") != "skull")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ObjectGuid currentSkullTarget = group->GetTargetIcon(RtiTargetValue::skullIndex);
|
||||
|
||||
if (!currentSkullTarget)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Unit* currentSkullUnit = botAI->GetUnit(currentSkullTarget);
|
||||
|
||||
if (!currentSkullUnit || !currentSkullUnit->IsAlive() || bot->GetDistance2d(currentSkullUnit->GetPositionX(), currentSkullUnit->GetPositionY()) < 40.0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool YoggSaronUsePortalTrigger::IsActive()
|
||||
{
|
||||
if (!IsPhase2())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (AI_VALUE(std::string, "rti") != "diamond")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return bot->FindNearestCreature(NPC_DESCEND_INTO_MADNESS, 2.0f, true) != nullptr;
|
||||
}
|
||||
|
||||
bool YoggSaronIllusionRoomTrigger::IsActive()
|
||||
{
|
||||
if (!IsYoggSaronFight() || !IsInIllusionRoom() || AI_VALUE(std::string, "rti") == "square")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SetRtiMarkRequired())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (SetRtiTargetRequired())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GoToBrainRoomRequired())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YoggSaronIllusionRoomTrigger::GoToBrainRoomRequired()
|
||||
{
|
||||
if (AI_VALUE(std::string, "rti") == "square")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsMasterIsInBrainRoom();
|
||||
}
|
||||
|
||||
bool YoggSaronIllusionRoomTrigger::SetRtiMarkRequired()
|
||||
{
|
||||
return AI_VALUE(std::string, "rti") == "diamond";
|
||||
}
|
||||
|
||||
bool YoggSaronIllusionRoomTrigger::SetRtiTargetRequired()
|
||||
{
|
||||
Unit const* currentRtiTarget = GetIllusionRoomRtiTarget();
|
||||
if (currentRtiTarget != nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetNextIllusionRoomRtiTarget() != nullptr;
|
||||
}
|
||||
|
||||
bool YoggSaronMoveToExitPortalTrigger::IsActive()
|
||||
{
|
||||
if (!IsYoggSaronFight() || !IsInBrainLevel())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Creature const* brain = bot->FindNearestCreature(NPC_BRAIN, 60.0f, true);
|
||||
if (!brain || !brain->IsAlive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (brain->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
Spell* induceMadnessSpell = brain->GetCurrentSpell(CURRENT_GENERIC_SPELL);
|
||||
|
||||
if (induceMadnessSpell && induceMadnessSpell->m_spellInfo->Id == SPELL_INDUCE_MADNESS)
|
||||
{
|
||||
uint32 castingTimeLeft = induceMadnessSpell->GetCastTimeRemaining();
|
||||
if ((botAI->HasCheat(BotCheatMask::raid) && castingTimeLeft < 6000) ||
|
||||
(!botAI->HasCheat(BotCheatMask::raid) && castingTimeLeft < 8000))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (brain->GetHealth() < brain->GetMaxHealth() * 0.3f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YoggSaronLunaticGazeTrigger::IsActive()
|
||||
{
|
||||
Unit* yoggsaron = AI_VALUE2(Unit*, "find target", "yogg-saron");
|
||||
|
||||
if (yoggsaron && yoggsaron->IsAlive() && yoggsaron->HasUnitState(UNIT_STATE_CASTING))
|
||||
{
|
||||
Spell* currentSpell = yoggsaron->GetCurrentSpell(CURRENT_CHANNELED_SPELL);
|
||||
if (currentSpell && currentSpell->m_spellInfo->Id == SPELL_LUNATIC_GAZE_YS)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool YoggSaronPhase3PositioningTrigger::IsActive()
|
||||
{
|
||||
if (!IsYoggSaronFight() || !IsPhase3())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
YoggSaronSanityTrigger sanityTrigger(botAI);
|
||||
if (sanityTrigger.IsActive())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (botAI->IsRanged(bot) && bot->GetDistance2d(ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT.GetPositionY()) > 15.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (botAI->IsMelee(bot) && !botAI->IsTank(bot) &&
|
||||
bot->GetDistance2d(ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionY()) > 15.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (botAI->IsTank(bot))
|
||||
{
|
||||
if (bot->GetDistance(ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT) > 30.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
GuidVector targets = AI_VALUE(GuidVector, "nearest npcs");
|
||||
bool thereIsAnyGuardian = false;
|
||||
|
||||
for (const ObjectGuid& guid : targets)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(guid);
|
||||
if (!unit || !unit->IsAlive())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unit->GetEntry() == NPC_IMMORTAL_GUARDIAN || unit->GetEntry() == NPC_MARKED_IMMORTAL_GUARDIAN)
|
||||
{
|
||||
thereIsAnyGuardian = true;
|
||||
ObjectGuid unitTargetGuid = unit->GetTarget();
|
||||
Player* targetedPlayer = botAI->GetPlayer(unitTargetGuid);
|
||||
if (!targetedPlayer || !botAI->IsTank(targetedPlayer))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (thereIsAnyGuardian && bot->GetDistance2d(ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionX(),
|
||||
ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT.GetPositionY()) > 3.0f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -82,19 +82,69 @@ enum UlduarIDs
|
||||
SPELL_MARK_OF_THE_FACELESS = 63276,
|
||||
SPELL_SHADOW_CRASH = 63277,
|
||||
|
||||
// Yogg-Saron
|
||||
ACTION_ILLUSION_DRAGONS = 1,
|
||||
ACTION_ILLUSION_ICECROWN = 2,
|
||||
ACTION_ILLUSION_STORMWIND = 3,
|
||||
NPC_GUARDIAN_OF_YS = 33136,
|
||||
NPC_YOGG_SARON = 33288,
|
||||
NPC_OMINOUS_CLOUD = 33292,
|
||||
NPC_RUBY_CONSORT = 33716,
|
||||
NPC_AZURE_CONSORT = 33717,
|
||||
NPC_BRONZE_CONSORT = 33718,
|
||||
NPC_EMERALD_CONSORT = 33719,
|
||||
NPC_OBSIDIAN_CONSORT = 33720,
|
||||
NPC_ALEXTRASZA = 33536,
|
||||
NPC_MALYGOS_ILLUSION = 33535,
|
||||
NPC_NELTHARION = 33523,
|
||||
NPC_YSERA = 33495,
|
||||
GO_DRAGON_SOUL = 194462,
|
||||
NPC_SARA_PHASE_1 = 33134,
|
||||
NPC_LICH_KING_ILLUSION = 33441,
|
||||
NPC_IMMOLATED_CHAMPION = 33442,
|
||||
NPC_SUIT_OF_ARMOR = 33433,
|
||||
NPC_GARONA = 33436,
|
||||
NPC_KING_LLANE = 33437,
|
||||
NPC_DEATHSWORN_ZEALOT = 33567,
|
||||
NPC_INFLUENCE_TENTACLE = 33943,
|
||||
NPC_DEATH_ORB = 33882,
|
||||
NPC_BRAIN = 33890,
|
||||
NPC_CRUSHER_TENTACLE = 33966,
|
||||
NPC_CONSTRICTOR_TENTACLE = 33983,
|
||||
NPC_CORRUPTOR_TENTACLE = 33985,
|
||||
NPC_IMMORTAL_GUARDIAN = 33988,
|
||||
NPC_LAUGHING_SKULL = 33990,
|
||||
NPC_SANITY_WELL = 33991,
|
||||
NPC_DESCEND_INTO_MADNESS = 34072,
|
||||
NPC_MARKED_IMMORTAL_GUARDIAN = 36064,
|
||||
SPELL_SANITY = 63050,
|
||||
SPELL_BRAIN_LINK = 63802,
|
||||
SPELL_MALADY_OF_THE_MIND = 63830,
|
||||
SPELL_SHADOW_BARRIER = 63894,
|
||||
SPELL_TELEPORT_TO_CHAMBER = 63997,
|
||||
SPELL_TELEPORT_TO_ICECROWN = 63998,
|
||||
SPELL_TELEPORT_TO_STORMWIND = 63989,
|
||||
SPELL_TELEPORT_BACK = 63992,
|
||||
SPELL_CANCEL_ILLUSION_AURA = 63993,
|
||||
SPELL_INDUCE_MADNESS = 64059,
|
||||
SPELL_LUNATIC_GAZE_YS = 64163,
|
||||
GO_FLEE_TO_THE_SURFACE_PORTAL = 194625,
|
||||
|
||||
// Buffs
|
||||
SPELL_FROST_TRAP = 13809
|
||||
};
|
||||
|
||||
const int8 skullIndex = 7; // Skull
|
||||
const int8 crossIndex = 6; // Cross
|
||||
const int8 moonIndex = 4; // Moon
|
||||
|
||||
const float ULDUAR_KOLOGARN_AXIS_Z_PATHING_ISSUE_DETECT = 420.0f;
|
||||
const float ULDUAR_KOLOGARN_EYEBEAM_RADIUS = 3.0f;
|
||||
const float ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD = 429.6094f;
|
||||
const float ULDUAR_THORIM_AXIS_Z_PATHING_ISSUE_DETECT = 410.0f;
|
||||
const float ULDUAR_AURIAYA_AXIS_Z_PATHING_ISSUE_DETECT = 410.0f;
|
||||
const float ULDUAR_YOGG_SARON_BOSS_ROOM_AXIS_Z_PATHING_ISSUE_DETECT = 300.0f;
|
||||
const float ULDUAR_YOGG_SARON_BRAIN_ROOM_AXIS_Z_PATHING_ISSUE_DETECT = 200.0f;
|
||||
const float ULDUAR_YOGG_SARON_STORMWIND_KEEPER_RADIUS = 150.0f;
|
||||
const float ULDUAR_YOGG_SARON_ICECROWN_CITADEL_RADIUS = 150.0f;
|
||||
const float ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_RADIUS = 150.0f;
|
||||
const float ULDUAR_YOGG_SARON_BRAIN_ROOM_RADIUS = 50.0f;
|
||||
|
||||
const Position ULDUAR_THORIM_NEAR_ARENA_CENTER = Position(2134.9854f, -263.11853f, 419.8465f);
|
||||
const Position ULDUAR_THORIM_NEAR_ENTRANCE_POSITION = Position(2172.4355f, -258.27957f, 418.47162f);
|
||||
@@ -123,6 +173,16 @@ const Position ULDUAR_MIMIRON_PHASE2_SIDE3RANGE_SPOT = Position(2754.1294f, 2553
|
||||
const Position ULDUAR_MIMIRON_PHASE2_SIDE3MELEE_SPOT = Position(2746.8513f, 2565.4263f, 364.31357f);
|
||||
const Position ULDUAR_MIMIRON_PHASE4_TANK_SPOT = Position(2744.5754f, 2570.8657f, 364.3138f);
|
||||
const Position ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT = Position(1913.6501f, 122.93989f, 342.38083f);
|
||||
const Position ULDUAR_YOGG_SARON_MIDDLE = Position(1980.28f, -25.5868f, 329.397f);
|
||||
const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_MIDDLE = Position(1927.1511f, 68.507256f, 242.37657f);
|
||||
const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_MIDDLE = Position(1925.6553f, -121.59296f, 239.98965f);
|
||||
const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_MIDDLE = Position(2104.5667f, -25.509348f, 242.64679f);
|
||||
const Position ULDUAR_YOGG_SARON_BRAIN_ROOM_MIDDLE = Position(1980.1971f, -27.854689f, 236.06789f);
|
||||
const Position ULDUAR_YOGG_SARON_STORMWIND_KEEPER_ENTRANCE = Position(1954.06f, 21.66f, 239.71f);
|
||||
const Position ULDUAR_YOGG_SARON_ICECROWN_CITADEL_ENTRANCE = Position(1950.11f, -79.284f, 239.98982f);
|
||||
const Position ULDUAR_YOGG_SARON_CHAMBER_OF_ASPECTS_ENTRANCE = Position(2048.63f, -25.5f, 239.72f);
|
||||
const Position ULDUAR_YOGG_SARON_PHASE_3_MELEE_SPOT = Position(1998.5377f, -22.90317f, 324.8895f);
|
||||
const Position ULDUAR_YOGG_SARON_PHASE_3_RANGED_SPOT = Position(2018.7628f, -18.896868f, 327.07245f);
|
||||
|
||||
//
|
||||
// Flame Levi
|
||||
@@ -448,4 +508,139 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
//
|
||||
// Yogg-Saron
|
||||
//
|
||||
class YoggSaronTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
YoggSaronTrigger(PlayerbotAI* ai, std::string const name = "yogg saron trigger", int32 checkInteval = 1)
|
||||
: Trigger(ai, name, checkInteval) {}
|
||||
|
||||
bool IsYoggSaronFight();
|
||||
bool IsPhase2();
|
||||
bool IsPhase3();
|
||||
bool IsInBrainLevel();
|
||||
bool IsInIllusionRoom();
|
||||
bool IsInStormwindKeeperIllusion();
|
||||
bool IsInIcecrownKeeperIllusion();
|
||||
bool IsInChamberOfTheAspectsIllusion();
|
||||
bool IsMasterIsInIllusionGroup();
|
||||
bool IsMasterIsInBrainRoom();
|
||||
Position GetIllusionRoomEntrancePosition();
|
||||
Unit* GetIllusionRoomRtiTarget();
|
||||
Unit* GetNextIllusionRoomRtiTarget();
|
||||
Unit* GetSaraIfAlive();
|
||||
};
|
||||
|
||||
class YoggSaronOminousCloudCheatTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronOminousCloudCheatTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron ominous cloud cheat trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronGuardianPositioningTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronGuardianPositioningTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron guardian positioning trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronSanityTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronSanityTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron sanity trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronDeathOrbTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronDeathOrbTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron death orb trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronMaladyOfTheMindTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronMaladyOfTheMindTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron malady of the mind trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronMarkTargetTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronMarkTargetTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron mark target trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronBrainLinkTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronBrainLinkTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron brain link trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronMoveToEnterPortalTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronMoveToEnterPortalTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron move to enter portal trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronFallFromFloorTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronFallFromFloorTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron fall from floor trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronBossRoomMovementCheatTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronBossRoomMovementCheatTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron boss room movement cheat trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronUsePortalTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronUsePortalTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron use portal trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronIllusionRoomTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronIllusionRoomTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron illusion room trigger") {}
|
||||
bool IsActive() override;
|
||||
|
||||
private:
|
||||
bool GoToBrainRoomRequired();
|
||||
bool SetRtiMarkRequired();
|
||||
bool SetRtiTargetRequired();
|
||||
};
|
||||
|
||||
class YoggSaronMoveToExitPortalTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronMoveToExitPortalTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron move to exit portal trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronLunaticGazeTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronLunaticGazeTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron lunatic gaze trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class YoggSaronPhase3PositioningTrigger : public YoggSaronTrigger
|
||||
{
|
||||
public:
|
||||
YoggSaronPhase3PositioningTrigger(PlayerbotAI* ai) : YoggSaronTrigger(ai, "yogg-saron phase 3 positioning trigger") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,7 @@ bool BossFireResistanceTrigger::IsActive()
|
||||
{
|
||||
// Check boss and it is alive
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", bossName);
|
||||
if (!boss || !boss->IsAlive())
|
||||
if (!boss || !boss->IsAlive() || boss->IsFriendlyTo(bot))
|
||||
return false;
|
||||
|
||||
// Check if bot is paladin
|
||||
@@ -68,7 +68,7 @@ bool BossFrostResistanceTrigger::IsActive()
|
||||
{
|
||||
// Check boss and it is alive
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", bossName);
|
||||
if (!boss || !boss->IsAlive())
|
||||
if (!boss || !boss->IsAlive() || boss->IsFriendlyTo(bot))
|
||||
return false;
|
||||
|
||||
// Check if bot is paladin
|
||||
@@ -121,7 +121,7 @@ bool BossNatureResistanceTrigger::IsActive()
|
||||
{
|
||||
// Check boss and it is alive
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", bossName);
|
||||
if (!boss || !boss->IsAlive())
|
||||
if (!boss || !boss->IsAlive() || boss->IsFriendlyTo(bot))
|
||||
return false;
|
||||
|
||||
// Check if bot is alive
|
||||
@@ -176,7 +176,7 @@ bool BossShadowResistanceTrigger::IsActive()
|
||||
{
|
||||
// Check boss and it is alive
|
||||
Unit* boss = AI_VALUE2(Unit*, "find target", bossName);
|
||||
if (!boss || !boss->IsAlive())
|
||||
if (!boss || !boss->IsAlive() || boss->IsFriendlyTo(bot))
|
||||
return false;
|
||||
|
||||
// Check if bot is paladin
|
||||
|
||||
@@ -214,3 +214,84 @@ bool FarFromMasterTrigger::IsActive()
|
||||
{
|
||||
return sServerFacade->IsDistanceGreaterThan(AI_VALUE2(float, "distance", "master target"), distance);
|
||||
}
|
||||
|
||||
bool TooCloseToCreatureTrigger::TooCloseToCreature(uint32 creatureId, float range, bool alive)
|
||||
{
|
||||
Creature* nearestCreature = bot->FindNearestCreature(creatureId, range, alive);
|
||||
return nearestCreature != nullptr;
|
||||
}
|
||||
|
||||
bool TooCloseToPlayerWithDebuffTrigger::TooCloseToPlayerWithDebuff(uint32 spellId, float range)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Player*> debuffedPlayers;
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* player = gref->GetSource();
|
||||
if (player && player->IsAlive() && player->HasAura(spellId))
|
||||
{
|
||||
debuffedPlayers.push_back(player);
|
||||
}
|
||||
}
|
||||
|
||||
if (debuffedPlayers.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Unit* debuffedPlayer : debuffedPlayers)
|
||||
{
|
||||
float dist = debuffedPlayer->GetExactDist2d(bot->GetPositionX(), bot->GetPositionY());
|
||||
if (dist < range)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TooFarFromPlayerWithAuraTrigger::TooFarFromPlayerWithAura(uint32 spellId, float range, bool selfInclude)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Player*> debuffedPlayers;
|
||||
|
||||
for (GroupReference* gref = group->GetFirstMember(); gref; gref = gref->next())
|
||||
{
|
||||
Player* player = gref->GetSource();
|
||||
if (player && player->IsAlive() && player->HasAura(spellId) &&
|
||||
(selfInclude || (!selfInclude && player->GetGUID() != bot->GetGUID())))
|
||||
{
|
||||
debuffedPlayers.push_back(player);
|
||||
}
|
||||
}
|
||||
|
||||
return !debuffedPlayers.empty();
|
||||
|
||||
if (debuffedPlayers.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Unit* debuffedPlayer : debuffedPlayers)
|
||||
{
|
||||
float dist = debuffedPlayer->GetExactDist2d(bot->GetPositionX(), bot->GetPositionY());
|
||||
if (dist > range)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -121,4 +121,28 @@ public:
|
||||
OutOfReactRangeTrigger(PlayerbotAI* botAI) : FarFromMasterTrigger(botAI, "out of react range", 50.0f, 5) {}
|
||||
};
|
||||
|
||||
class TooCloseToCreatureTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
TooCloseToCreatureTrigger(PlayerbotAI* ai) : Trigger(ai, "too close to creature trigger") {}
|
||||
|
||||
bool TooCloseToCreature(uint32 creatureId, float range, bool alive = true);
|
||||
};
|
||||
|
||||
class TooCloseToPlayerWithDebuffTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
TooCloseToPlayerWithDebuffTrigger(PlayerbotAI* ai) : Trigger(ai, "too cloose to player with debuff trigger") {}
|
||||
|
||||
bool TooCloseToPlayerWithDebuff(uint32 spellId, float range);
|
||||
};
|
||||
|
||||
class TooFarFromPlayerWithAuraTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
TooFarFromPlayerWithAuraTrigger(PlayerbotAI* ai) : Trigger(ai, "too far from player with aura trigger") {}
|
||||
|
||||
bool TooFarFromPlayerWithAura(uint32 spellId, float range, bool selfInclude = false);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,6 +21,14 @@ public:
|
||||
|
||||
static int32 GetRtiIndex(std::string const rti);
|
||||
Unit* Calculate() override;
|
||||
static const int8 starIndex = 0;
|
||||
static const int8 circleIndex = 1;
|
||||
static const int8 diamondIndex = 2;
|
||||
static const int8 triangleIndex = 3;
|
||||
static const int8 moonIndex = 4;
|
||||
static const int8 squareIndex = 5;
|
||||
static const int8 crossIndex = 6;
|
||||
static const int8 skullIndex = 7;
|
||||
|
||||
private:
|
||||
std::string const type;
|
||||
|
||||
@@ -556,7 +556,7 @@ private:
|
||||
static UntypedValue* last_flee_timestamp(PlayerbotAI* ai) { return new LastFleeTimestampValue(ai); }
|
||||
static UntypedValue* recently_flee_info(PlayerbotAI* ai) { return new RecentlyFleeInfo(ai); }
|
||||
// -------------------------------------------------------
|
||||
// Flag for cutom glyphs : true when /w bot glyph equip <20>
|
||||
// Flag for cutom glyphs : true when /w bot glyph equip
|
||||
// -------------------------------------------------------
|
||||
static UntypedValue* custom_glyphs(PlayerbotAI* ai)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user