mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
Rewrite Gruul's Lair Strategies (#2473)
<!--
Thank you for contributing to mod-playerbots, please make sure that
you...
1. Submit your PR to the test-staging branch, not master.
2. Read the guidelines below before submitting.
3. Don't delete parts of this template.
DESIGN PHILOSOPHY: We prioritize STABILITY, PERFORMANCE, AND
PREDICTABILITY over behavioral realism.
Every action and decision executes PER BOT AND PER TRIGGER. Small
increases in logic complexity scale
poorly across thousands of bots and negatively affect all. We prioritize
a stable system over a smarter
one. Bots don't need to behave perfectly; believable behavior is the
goal, not human simulation.
Default behavior must be cheap in processing; expensive behavior must be
opt-in.
Before submitting, make sure your changes aligns with these principles.
-->
## Pull Request Description
<!-- Describe what this change does and why it is needed -->
Well, this is what I was doing while I let AI do the buff announcements
PR...
GL was the first strategy I wrote alone (Revision started Karazhan), and
it sucks. Since AC has now fixed Olm to actually chase and Kiggler to no
longer move to within his Arcane Explosion distance, it was a good time
to redo things. Overall, the code should be much simpler and better for
performance.
I also tweaked several strategies. My raid is close to expansion BiS now
so I tested at 20/20 damage/healing IP nerfs. One shot both, and overall
the bot coordination is a lot smoother than I remember when I was
actually running these raids.
Some stuff is still not great, like
GruulTheDragonkillerSpreadRangedAction() is overdone for sure, but I've
spent all the time I'm willing to on this one. I don't want this to
become a longer project.
## Feature Evaluation
<!--
If your PR is very minimal (comment typo, wrong ID reference, etc), and
it is very obvious it will not have
any impact on performance, you may skip these question. If necessary, a
maintainer may ask you for them later.
-->
<!-- Please answer the following: -->
- Describe the **minimum logic** required to achieve the intended
behavior.
- Describe the **processing cost** when this logic executes across many
bots.
Same structure as before. Improved commonly used methods based on
experience since I did the original strategy (e.g., how to do tank
movement or spread bots), threw out some super complicated, bulky
methods in favor of much simpler ones that work better anyway, yadda
yadda.
## How to Test the Changes
<!--
- Step-by-step instructions to test the change.
- Any required setup (e.g. multiple players, number of bots, specific
configuration).
- Expected behavior and how to verify it.
-->
Go fight HKM and Gruul. For HKM, bring three tanks, a mage, and a
boomin. For Gruul, bring an alarm clock.
## Impact Assessment
<!-- As a generic test, before and after measure of pmon (playerbot pmon
tick) can help you here. -->
- Does this change increase per-bot/per-tick processing or risk scaling
poorly with thousands of bots?
- - [x] No, not at all
- - [ ] Minimal impact (**explain below**)
- - [ ] Moderate impact (**explain below**)
- Does this change modify default bot behavior?
- - [x] No
- - [ ] Yes (**explain why**)
- Does this change add new decision branches or increase maintenance
complexity?
- - [x] No
- - [ ] Yes (**explain below**)
## AI Assistance
<!--
AI assistance is allowed, but all submitted code must be fully
understood, reviewed, and owned by the contributor.
We expect contributors to be honest about what they do and do not
understand.
-->
Was AI assistance used while working on this change?
- - [x] No
- - [ ] Yes (**explain below**)
<!--
If yes, please specify:
- Purpose of usage (e.g. brainstorming, refactoring, documentation, code
generation).
- Which parts of the change were influenced or generated, and whether it
was thoroughly reviewed.
-->
<!--
TRANSLATIONS:
Anything new that the bots say in chat must be in a translatable format.
This is done using GetBotTextOrDefault,
which you can search for in the codebase to find examples. Your code
needs to have English as the default fallback,
while the full translations need to be in an SQL update file. The
languages in the file are the nine language
options supported by AzerothCore: English, Korean, French, German,
Chinese, Taiwanese, Spanish, Spanish Mexico, and
Russian. See
data/sql/playerbots/updates/2025_12_27_ai_playerbot_fishing_text.sql as
an example of a translation SQL
update, whose content are called within the codebase at
src/strategy/actions/FishingAction.cpp
-->
## Final Checklist
- - [x] Stability is not compromised.
- - [x] Performance impact is understood, tested, and acceptable.
- - [x] Added logic complexity is justified and explained.
- - [x] Any new bot dialogue lines are translated.
- - [x] Documentation updated if needed (Conf comments, WiKi commands).
## Notes for Reviewers
<!-- Anything else that's helpful to review or test your pull request.
-->
This commit is contained in:
parent
fffbf65738
commit
82b5c7538e
@ -1,5 +1,5 @@
|
||||
#ifndef PLAYERBOTS_RAIDGRUULSLAIRACTIONCONTEXT_H
|
||||
#define PLAYERBOTS_RAIDGRUULSLAIRACTIONCONTEXT_H
|
||||
#ifndef PLAYERBOTS_GRUULACTIONCONTEXT_H
|
||||
#define PLAYERBOTS_GRUULACTIONCONTEXT_H
|
||||
|
||||
#include "GruulActions.h"
|
||||
#include "NamedObjectContext.h"
|
||||
@ -10,40 +10,101 @@ public:
|
||||
RaidGruulsLairActionContext()
|
||||
{
|
||||
// High King Maulgar
|
||||
creators["high king maulgar main tank attack maulgar"] = &RaidGruulsLairActionContext::high_king_maulgar_main_tank_attack_maulgar;
|
||||
creators["high king maulgar first assist tank attack olm"] = &RaidGruulsLairActionContext::high_king_maulgar_first_assist_tank_attack_olm;
|
||||
creators["high king maulgar second assist tank attack blindeye"] = &RaidGruulsLairActionContext::high_king_maulgar_second_assist_tank_attack_blindeye;
|
||||
creators["high king maulgar mage tank attack krosh"] = &RaidGruulsLairActionContext::high_king_maulgar_mage_tank_attack_krosh;
|
||||
creators["high king maulgar moonkin tank attack kiggler"] = &RaidGruulsLairActionContext::high_king_maulgar_moonkin_tank_attack_kiggler;
|
||||
creators["high king maulgar assign dps priority"] = &RaidGruulsLairActionContext::high_king_maulgar_assign_dps_priority;
|
||||
creators["high king maulgar healer find safe position"] = &RaidGruulsLairActionContext::high_king_maulgar_healer_find_safe_position;
|
||||
creators["high king maulgar run away from whirlwind"] = &RaidGruulsLairActionContext::high_king_maulgar_run_away_from_whirlwind;
|
||||
creators["high king maulgar banish felstalker"] = &RaidGruulsLairActionContext::high_king_maulgar_banish_felstalker;
|
||||
creators["high king maulgar misdirect olm and blindeye"] = &RaidGruulsLairActionContext::high_king_maulgar_misdirect_olm_and_blindeye;
|
||||
creators["high king maulgar main tank attack maulgar"] =
|
||||
&RaidGruulsLairActionContext::high_king_maulgar_main_tank_attack_maulgar;
|
||||
|
||||
creators["high king maulgar first assist tank attack olm"] =
|
||||
&RaidGruulsLairActionContext::high_king_maulgar_first_assist_tank_attack_olm;
|
||||
|
||||
creators["high king maulgar second assist tank attack blindeye"] =
|
||||
&RaidGruulsLairActionContext::high_king_maulgar_second_assist_tank_attack_blindeye;
|
||||
|
||||
creators["high king maulgar mage tank attack krosh"] =
|
||||
&RaidGruulsLairActionContext::high_king_maulgar_mage_tank_attack_krosh;
|
||||
|
||||
creators["high king maulgar moonkin tank attack kiggler"] =
|
||||
&RaidGruulsLairActionContext::high_king_maulgar_moonkin_tank_attack_kiggler;
|
||||
|
||||
creators["high king maulgar assign dps priority"] =
|
||||
&RaidGruulsLairActionContext::high_king_maulgar_assign_dps_priority;
|
||||
|
||||
creators["high king maulgar run away from whirlwind"] =
|
||||
&RaidGruulsLairActionContext::high_king_maulgar_run_away_from_whirlwind;
|
||||
|
||||
creators["high king maulgar move away from blast nova danger"] =
|
||||
&RaidGruulsLairActionContext::high_king_maulgar_move_away_from_blast_nova_danger;
|
||||
|
||||
creators["high king maulgar banish fel stalker"] =
|
||||
&RaidGruulsLairActionContext::high_king_maulgar_banish_fel_stalker;
|
||||
|
||||
creators["high king maulgar misdirect ogres to tanks"] =
|
||||
&RaidGruulsLairActionContext::high_king_maulgar_misdirect_ogres_to_tanks;
|
||||
|
||||
// Gruul the Dragonkiller
|
||||
creators["gruul the dragonkiller tanks position boss"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_tanks_position_boss;
|
||||
creators["gruul the dragonkiller spread ranged"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_spread_ranged;
|
||||
creators["gruul the dragonkiller shatter spread"] = &RaidGruulsLairActionContext::gruul_the_dragonkiller_shatter_spread;
|
||||
creators["gruul the dragonkiller tanks position boss"] =
|
||||
&RaidGruulsLairActionContext::gruul_the_dragonkiller_tanks_position_boss;
|
||||
|
||||
creators["gruul the dragonkiller spread ranged"] =
|
||||
&RaidGruulsLairActionContext::gruul_the_dragonkiller_spread_ranged;
|
||||
|
||||
creators["gruul the dragonkiller shatter spread"] =
|
||||
&RaidGruulsLairActionContext::gruul_the_dragonkiller_shatter_spread;
|
||||
}
|
||||
|
||||
private:
|
||||
// High King Maulgar
|
||||
static Action* high_king_maulgar_main_tank_attack_maulgar(PlayerbotAI* botAI) { return new HighKingMaulgarMainTankAttackMaulgarAction(botAI); }
|
||||
static Action* high_king_maulgar_first_assist_tank_attack_olm(PlayerbotAI* botAI) { return new HighKingMaulgarFirstAssistTankAttackOlmAction(botAI); }
|
||||
static Action* high_king_maulgar_second_assist_tank_attack_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarSecondAssistTankAttackBlindeyeAction(botAI); }
|
||||
static Action* high_king_maulgar_mage_tank_attack_krosh(PlayerbotAI* botAI) { return new HighKingMaulgarMageTankAttackKroshAction(botAI); }
|
||||
static Action* high_king_maulgar_moonkin_tank_attack_kiggler(PlayerbotAI* botAI) { return new HighKingMaulgarMoonkinTankAttackKigglerAction(botAI); }
|
||||
static Action* high_king_maulgar_assign_dps_priority(PlayerbotAI* botAI) { return new HighKingMaulgarAssignDPSPriorityAction(botAI); }
|
||||
static Action* high_king_maulgar_healer_find_safe_position(PlayerbotAI* botAI) { return new HighKingMaulgarHealerFindSafePositionAction(botAI); }
|
||||
static Action* high_king_maulgar_run_away_from_whirlwind(PlayerbotAI* botAI) { return new HighKingMaulgarRunAwayFromWhirlwindAction(botAI); }
|
||||
static Action* high_king_maulgar_banish_felstalker(PlayerbotAI* botAI) { return new HighKingMaulgarBanishFelstalkerAction(botAI); }
|
||||
static Action* high_king_maulgar_misdirect_olm_and_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarMisdirectOlmAndBlindeyeAction(botAI); }
|
||||
static Action* high_king_maulgar_main_tank_attack_maulgar(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarMainTankAttackMaulgarAction(botAI);
|
||||
}
|
||||
|
||||
static Action* high_king_maulgar_first_assist_tank_attack_olm(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarFirstAssistTankAttackOlmAction(botAI);
|
||||
}
|
||||
|
||||
static Action* high_king_maulgar_second_assist_tank_attack_blindeye(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarSecondAssistTankAttackBlindeyeAction(botAI);
|
||||
}
|
||||
|
||||
static Action* high_king_maulgar_mage_tank_attack_krosh(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarMageTankAttackKroshAction(botAI);
|
||||
}
|
||||
|
||||
static Action* high_king_maulgar_moonkin_tank_attack_kiggler(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarMoonkinTankAttackKigglerAction(botAI);
|
||||
}
|
||||
|
||||
static Action* high_king_maulgar_assign_dps_priority(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarAssignDPSPriorityAction(botAI);
|
||||
}
|
||||
|
||||
static Action* high_king_maulgar_run_away_from_whirlwind(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarRunAwayFromWhirlwindAction(botAI);
|
||||
}
|
||||
|
||||
static Action* high_king_maulgar_move_away_from_blast_nova_danger(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarMoveAwayFromBlastNovaDangerAction(botAI);
|
||||
}
|
||||
|
||||
static Action* high_king_maulgar_banish_fel_stalker(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarBanishFelStalkerAction(botAI);
|
||||
}
|
||||
|
||||
static Action* high_king_maulgar_misdirect_ogres_to_tanks(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarMisdirectOgresToTanksAction(botAI);
|
||||
}
|
||||
|
||||
// Gruul the Dragonkiller
|
||||
static Action* gruul_the_dragonkiller_tanks_position_boss(PlayerbotAI* botAI) { return new GruulTheDragonkillerTanksPositionBossAction(botAI); }
|
||||
static Action* gruul_the_dragonkiller_spread_ranged(PlayerbotAI* botAI) { return new GruulTheDragonkillerSpreadRangedAction(botAI); }
|
||||
static Action* gruul_the_dragonkiller_shatter_spread(PlayerbotAI* botAI) { return new GruulTheDragonkillerShatterSpreadAction(botAI); }
|
||||
static Action* gruul_the_dragonkiller_tanks_position_boss(PlayerbotAI* botAI) {
|
||||
return new GruulTheDragonkillerTanksPositionBossAction(botAI);
|
||||
}
|
||||
|
||||
static Action* gruul_the_dragonkiller_spread_ranged(PlayerbotAI* botAI) {
|
||||
return new GruulTheDragonkillerSpreadRangedAction(botAI);
|
||||
}
|
||||
|
||||
static Action* gruul_the_dragonkiller_shatter_spread(PlayerbotAI* botAI) {
|
||||
return new GruulTheDragonkillerShatterSpreadAction(botAI);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -25,18 +25,19 @@ bool HighKingMaulgarMainTankAttackMaulgarAction::Execute(Event /*event*/)
|
||||
if (maulgar->GetVictim() == bot)
|
||||
{
|
||||
const Position& position = MAULGAR_TANK_POSITION;
|
||||
const float maxDistance = 3.0f;
|
||||
const float distToPosition =
|
||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
|
||||
float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
|
||||
if (distanceToPosition > maxDistance)
|
||||
if (distToPosition > 3.0f)
|
||||
{
|
||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * maxDistance;
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true, true);
|
||||
const float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
const float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
const float moveDist = std::min(5.0f, distToPosition);
|
||||
const float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
|
||||
const float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
|
||||
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false,
|
||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,19 +60,19 @@ bool HighKingMaulgarFirstAssistTankAttackOlmAction::Execute(Event /*event*/)
|
||||
if (olm->GetVictim() == bot)
|
||||
{
|
||||
const Position& position = OLM_TANK_POSITION;
|
||||
const float maxDistance = 3.0f;
|
||||
const float olmTankLeeway = 30.0f;
|
||||
const float distToPosition =
|
||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
|
||||
float distanceOlmToPosition = olm->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
|
||||
if (distanceOlmToPosition > olmTankLeeway)
|
||||
if (distToPosition > 3.0f)
|
||||
{
|
||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
float moveX = bot->GetPositionX() + (dX / distanceOlmToPosition) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / distanceOlmToPosition) * maxDistance;
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
const float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
const float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
const float moveDist = std::min(5.0f, distToPosition);
|
||||
const float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
|
||||
const float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
|
||||
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false,
|
||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,18 +95,19 @@ bool HighKingMaulgarSecondAssistTankAttackBlindeyeAction::Execute(Event /*event*
|
||||
if (blindeye->GetVictim() == bot)
|
||||
{
|
||||
const Position& position = BLINDEYE_TANK_POSITION;
|
||||
const float maxDistance = 3.0f;
|
||||
const float distToPosition =
|
||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
|
||||
float distanceToPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
|
||||
if (distanceToPosition > maxDistance)
|
||||
if (distToPosition > 3.0f)
|
||||
{
|
||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
float moveX = bot->GetPositionX() + (dX / distanceToPosition) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / distanceToPosition) * maxDistance;
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
const float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
const float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
const float moveDist = std::min(5.0f, distToPosition);
|
||||
const float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
|
||||
const float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
|
||||
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false,
|
||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,11 +124,17 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event /*event*/)
|
||||
MarkTargetWithTriangle(bot, krosh);
|
||||
SetRtiTarget(botAI, "triangle", krosh);
|
||||
|
||||
if (krosh->HasAura(SPELL_SPELL_SHIELD) && botAI->CanCastSpell("spellsteal", krosh))
|
||||
if (krosh->HasAura(static_cast<uint32>(GruulsLairSpells::SPELL_SPELL_SHIELD)) &&
|
||||
botAI->CanCastSpell("spellsteal", krosh))
|
||||
{
|
||||
return botAI->CastSpell("spellsteal", krosh);
|
||||
}
|
||||
|
||||
if (!bot->HasAura(SPELL_SPELL_SHIELD) && botAI->CanCastSpell("fire ward", bot))
|
||||
if (!bot->HasAura(static_cast<uint32>(GruulsLairSpells::SPELL_SPELL_SHIELD)) &&
|
||||
botAI->CanCastSpell("fire ward", bot))
|
||||
{
|
||||
return botAI->CastSpell("fire ward", bot);
|
||||
}
|
||||
|
||||
if (AI_VALUE(Unit*, "current target") != krosh)
|
||||
return Attack(krosh);
|
||||
@ -134,30 +142,27 @@ bool HighKingMaulgarMageTankAttackKroshAction::Execute(Event /*event*/)
|
||||
if (krosh->GetVictim() == bot)
|
||||
{
|
||||
const Position& position = KROSH_TANK_POSITION;
|
||||
float distanceToKrosh = krosh->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
const float minDistance = 16.0f;
|
||||
const float maxDistance = 29.0f;
|
||||
const float tankPositionLeeway = 1.0f;
|
||||
const float distanceKroshToPosition =
|
||||
krosh->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
constexpr float minDistance = 17.0f;
|
||||
constexpr float maxDistance = 30.0f;
|
||||
|
||||
if (distanceToKrosh > minDistance && distanceToKrosh < maxDistance)
|
||||
if (distanceKroshToPosition > minDistance && distanceKroshToPosition < maxDistance &&
|
||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY()) > 1.0f)
|
||||
{
|
||||
if (!bot->IsWithinDist2d(position.GetPositionX(), position.GetPositionY(), tankPositionLeeway))
|
||||
{
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, position.GetPositionX(), position.GetPositionY(), position.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
float orientation = atan2(krosh->GetPositionY() - bot->GetPositionY(),
|
||||
krosh->GetPositionX() - bot->GetPositionX());
|
||||
bot->SetFacingTo(orientation);
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, position.GetPositionX(), position.GetPositionY(),
|
||||
position.GetPositionZ(), false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
constexpr float safeDistance = 15.0f;
|
||||
const float currentDistance = bot->GetDistance2d(krosh);
|
||||
|
||||
if (currentDistance < safeDistance)
|
||||
{
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
botAI->InterruptSpell();
|
||||
return MoveAway(krosh, safeDistance - currentDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -178,11 +183,16 @@ bool HighKingMaulgarMoonkinTankAttackKigglerAction::Execute(Event /*event*/)
|
||||
if (AI_VALUE(Unit*, "current target") != kiggler)
|
||||
return Attack(kiggler);
|
||||
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
if (kiggler->GetVictim() == bot)
|
||||
{
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
constexpr float safeDistance = 28.5f;
|
||||
const float currentDistance = bot->GetDistance2d(kiggler);
|
||||
|
||||
if (currentDistance < safeDistance)
|
||||
{
|
||||
botAI->InterruptSpell();
|
||||
return MoveAway(kiggler, safeDistance - currentDistance);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -194,15 +204,7 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/)
|
||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
if (blindeye)
|
||||
{
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
MarkTargetWithStar(bot, blindeye);
|
||||
SetRtiTarget(botAI, "star", blindeye);
|
||||
|
||||
if (AI_VALUE(Unit*, "current target") != blindeye)
|
||||
@ -215,15 +217,7 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/)
|
||||
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||
if (olm)
|
||||
{
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
MarkTargetWithCircle(bot, olm);
|
||||
SetRtiTarget(botAI, "circle", olm);
|
||||
|
||||
if (AI_VALUE(Unit*, "current target") != olm)
|
||||
@ -236,15 +230,7 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/)
|
||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
if (krosh && botAI->IsRanged(bot))
|
||||
{
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
MarkTargetWithTriangle(bot, krosh);
|
||||
SetRtiTarget(botAI, "triangle", krosh);
|
||||
|
||||
if (AI_VALUE(Unit*, "current target") != krosh)
|
||||
@ -257,15 +243,7 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/)
|
||||
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
||||
if (kiggler)
|
||||
{
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
MarkTargetWithDiamond(bot, kiggler);
|
||||
SetRtiTarget(botAI, "diamond", kiggler);
|
||||
|
||||
if (AI_VALUE(Unit*, "current target") != kiggler)
|
||||
@ -278,15 +256,7 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/)
|
||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||
if (maulgar)
|
||||
{
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
MarkTargetWithSquare(bot, maulgar);
|
||||
SetRtiTarget(botAI, "square", maulgar);
|
||||
|
||||
if (AI_VALUE(Unit*, "current target") != maulgar)
|
||||
@ -296,98 +266,71 @@ bool HighKingMaulgarAssignDPSPriorityAction::Execute(Event /*event*/)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Avoid Whirlwind and Blast Wave and generally try to stay near the center of the room
|
||||
bool HighKingMaulgarHealerFindSafePositionAction::Execute(Event /*event*/)
|
||||
{
|
||||
const Position& center = MAULGAR_ROOM_CENTER;
|
||||
const float maxDistanceFromCenter = 50.0f;
|
||||
float distToCenter = bot->GetExactDist2d(center.GetPositionX(), center.GetPositionY());
|
||||
|
||||
if (distToCenter > maxDistanceFromCenter)
|
||||
{
|
||||
float angle = atan2(bot->GetPositionY() - center.GetPositionY(), bot->GetPositionX() - center.GetPositionX());
|
||||
float destX = center.GetPositionX() + 40.0f * cos(angle);
|
||||
float destY = center.GetPositionY() + 40.0f * sin(angle);
|
||||
float destZ = center.GetPositionZ();
|
||||
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
bot->GetPositionZ(), destX, destY, destZ))
|
||||
return false;
|
||||
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
Position safePos;
|
||||
if (TryGetNewSafePosition(botAI, bot, safePos))
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(false);
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, safePos.GetPositionX(), safePos.GetPositionY(), safePos.GetPositionZ(),
|
||||
false, false, false, false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Run away from Maulgar during Whirlwind (logic for after all other ogres are dead)
|
||||
bool HighKingMaulgarRunAwayFromWhirlwindAction::Execute(Event /*event*/)
|
||||
{
|
||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||
if (!maulgar)
|
||||
return false;
|
||||
|
||||
const float safeDistance = 10.0f;
|
||||
float distance = bot->GetExactDist2d(maulgar);
|
||||
constexpr float safeDistance = 8.0f;
|
||||
const float currentDistance = bot->GetDistance2d(maulgar);
|
||||
|
||||
if (distance < safeDistance)
|
||||
if (currentDistance < safeDistance)
|
||||
{
|
||||
float angle = atan2(bot->GetPositionY() - maulgar->GetPositionY(),
|
||||
bot->GetPositionX() - maulgar->GetPositionX());
|
||||
float destX = maulgar->GetPositionX() + safeDistance * cos(angle);
|
||||
float destY = maulgar->GetPositionY() + safeDistance * sin(angle);
|
||||
float destZ = bot->GetPositionZ();
|
||||
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
bot->GetPositionZ(), destX, destY, destZ))
|
||||
return false;
|
||||
|
||||
float destDist = maulgar->GetExactDist2d(destX, destY);
|
||||
|
||||
if (destDist >= safeDistance - 0.1f)
|
||||
{
|
||||
bot->AttackStop();
|
||||
bot->InterruptNonMeleeSpells(true);
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
botAI->InterruptSpell();
|
||||
return MoveAway(maulgar, safeDistance - currentDistance);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HighKingMaulgarBanishFelstalkerAction::Execute(Event /*event*/)
|
||||
bool HighKingMaulgarMoveAwayFromBlastNovaDangerAction::Execute(Event /*event*/)
|
||||
{
|
||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
if (!krosh)
|
||||
return false;
|
||||
|
||||
constexpr float safeDistance = 20.0f;
|
||||
constexpr uint32 minInterval = 1000;
|
||||
const float currentDistance = bot->GetDistance2d(krosh);
|
||||
|
||||
if (currentDistance < safeDistance)
|
||||
{
|
||||
botAI->InterruptSpell();
|
||||
return FleePosition(krosh->GetPosition(), safeDistance, minInterval);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HighKingMaulgarBanishFelStalkerAction::Execute(Event /*event*/)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
const GuidVector& npcs = AI_VALUE(GuidVector, "nearest hostile npcs");
|
||||
std::vector<Unit*> felStalkers;
|
||||
for (auto const& npc : npcs)
|
||||
std::list<Creature*> creatureList;
|
||||
constexpr float searchRadius = 50.0f;
|
||||
bot->GetCreatureListWithEntryInGrid(
|
||||
creatureList, static_cast<uint32>(GruulsLairNpcs::NPC_WILD_FEL_STALKER), searchRadius);
|
||||
|
||||
for (Creature* creature : creatureList)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(npc);
|
||||
if (unit && unit->GetEntry() == NPC_WILD_FEL_STALKER && unit->IsAlive())
|
||||
felStalkers.push_back(unit);
|
||||
if (creature && creature->IsAlive())
|
||||
felStalkers.push_back(creature);
|
||||
}
|
||||
|
||||
std::vector<Player*> warlocks;
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (member && member->IsAlive() && member->getClass() == CLASS_WARLOCK && GET_PLAYERBOT_AI(member))
|
||||
if (member && member->IsAlive() && member->getClass() == CLASS_WARLOCK &&
|
||||
GET_PLAYERBOT_AI(member))
|
||||
{
|
||||
warlocks.push_back(member);
|
||||
}
|
||||
}
|
||||
|
||||
int warlockIndex = -1;
|
||||
for (size_t i = 0; i < warlocks.size(); ++i)
|
||||
@ -399,21 +342,26 @@ bool HighKingMaulgarBanishFelstalkerAction::Execute(Event /*event*/)
|
||||
}
|
||||
}
|
||||
|
||||
const int64_t felStalkersSize = felStalkers.size();
|
||||
const uint8 felStalkersSize = felStalkers.size();
|
||||
|
||||
if (warlockIndex >= 0 && warlockIndex < felStalkersSize)
|
||||
{
|
||||
Unit* assignedFelStalker = felStalkers[warlockIndex];
|
||||
if (!botAI->HasAura("banish", assignedFelStalker) && botAI->CanCastSpell("banish", assignedFelStalker))
|
||||
if (!botAI->HasAura("banish", assignedFelStalker) &&
|
||||
botAI->CanCastSpell("banish", assignedFelStalker))
|
||||
{
|
||||
return botAI->CastSpell("banish", assignedFelStalker);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Hunter 1: Misdirect Olm to first offtank and have pet attack Blindeye
|
||||
// Hunter 2: Misdirect Blindeye to second offtank
|
||||
bool HighKingMaulgarMisdirectOlmAndBlindeyeAction::Execute(Event /*event*/)
|
||||
// Hunter 1: Misdirect Blindeye to second offtank
|
||||
// Hunter 2: Misdirect Olm to first offtank
|
||||
// Hunter 3: Misdirect Kiggler to Moonkin tank
|
||||
// Hunter 4: Misdirect Krosh to Mage tank
|
||||
bool HighKingMaulgarMisdirectOgresToTanksAction::Execute(Event /*event*/)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
@ -423,68 +371,82 @@ bool HighKingMaulgarMisdirectOlmAndBlindeyeAction::Execute(Event /*event*/)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (member && member->IsAlive() && member->getClass() == CLASS_HUNTER && GET_PLAYERBOT_AI(member))
|
||||
if (member && member->IsAlive() && member->getClass() == CLASS_HUNTER &&
|
||||
GET_PLAYERBOT_AI(member))
|
||||
{
|
||||
hunters.push_back(member);
|
||||
}
|
||||
|
||||
int hunterIndex = -1;
|
||||
if (hunters.size() >= 4)
|
||||
break;
|
||||
}
|
||||
|
||||
int8 hunterIndex = -1;
|
||||
for (size_t i = 0; i < hunters.size(); ++i)
|
||||
{
|
||||
if (hunters[i] == bot)
|
||||
{
|
||||
hunterIndex = static_cast<int>(i);
|
||||
hunterIndex = static_cast<int8>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hunterIndex == -1)
|
||||
return false;
|
||||
|
||||
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
Player* olmTank = nullptr;
|
||||
Player* blindeyeTank = nullptr;
|
||||
|
||||
Unit* ogreTarget = nullptr;
|
||||
Player* tankTarget = nullptr;
|
||||
if (hunterIndex == 0)
|
||||
{
|
||||
ogreTarget = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
tankTarget = GetGroupAssistTank(botAI, bot, 1);
|
||||
}
|
||||
else if (hunterIndex == 1)
|
||||
{
|
||||
ogreTarget = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive())
|
||||
continue;
|
||||
else if (botAI->IsAssistTankOfIndex(member, 0)) olmTank = member;
|
||||
else if (botAI->IsAssistTankOfIndex(member, 1)) blindeyeTank = member;
|
||||
if (Player* member = GetGroupAssistTank(botAI, bot, 0))
|
||||
{
|
||||
tankTarget = member;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hunterIndex == 2)
|
||||
{
|
||||
ogreTarget = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
if (Player* member = GetKigglerMoonkinTank(bot))
|
||||
{
|
||||
tankTarget = member;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (hunterIndex == 3)
|
||||
{
|
||||
ogreTarget = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
if (Player* member = GetKroshMageTank(bot))
|
||||
{
|
||||
tankTarget = member;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (hunterIndex)
|
||||
{
|
||||
case 0:
|
||||
botAI->CastSpell("misdirection", olmTank);
|
||||
if (bot->HasAura(SPELL_MISDIRECTION))
|
||||
{
|
||||
Pet* pet = bot->GetPet();
|
||||
if (pet && pet->IsAlive() && pet->GetVictim() != blindeye)
|
||||
{
|
||||
pet->ClearUnitState(UNIT_STATE_FOLLOW);
|
||||
pet->AttackStop();
|
||||
pet->SetTarget(blindeye->GetGUID());
|
||||
if (pet->GetCharmInfo())
|
||||
{
|
||||
pet->GetCharmInfo()->SetIsCommandAttack(true);
|
||||
pet->GetCharmInfo()->SetIsAtStay(false);
|
||||
pet->GetCharmInfo()->SetIsFollowing(false);
|
||||
pet->GetCharmInfo()->SetIsCommandFollow(false);
|
||||
pet->GetCharmInfo()->SetIsReturning(false);
|
||||
}
|
||||
pet->ToCreature()->AI()->AttackStart(blindeye);
|
||||
}
|
||||
return botAI->CastSpell("steady shot", olm);
|
||||
}
|
||||
break;
|
||||
if (!ogreTarget || !tankTarget || !tankTarget->IsAlive())
|
||||
return false;
|
||||
|
||||
case 1:
|
||||
botAI->CastSpell("misdirection", blindeyeTank);
|
||||
if (bot->HasAura(SPELL_MISDIRECTION))
|
||||
return botAI->CastSpell("steady shot", blindeye);
|
||||
break;
|
||||
if (botAI->CanCastSpell("misdirection", tankTarget))
|
||||
return botAI->CastSpell("misdirection", tankTarget);
|
||||
|
||||
default:
|
||||
break;
|
||||
if (bot->HasAura(static_cast<uint32>(GruulsLairSpells::SPELL_MISDIRECTION)) &&
|
||||
botAI->CanCastSpell("steady shot", ogreTarget))
|
||||
{
|
||||
return botAI->CastSpell("steady shot", ogreTarget);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -505,19 +467,19 @@ bool GruulTheDragonkillerTanksPositionBossAction::Execute(Event /*event*/)
|
||||
if (gruul->GetVictim() == bot)
|
||||
{
|
||||
const Position& position = GRUUL_TANK_POSITION;
|
||||
const float maxDistance = 5.0f;
|
||||
const float distToPosition =
|
||||
bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
|
||||
float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
float distanceToTankPosition = bot->GetExactDist2d(position.GetPositionX(), position.GetPositionY());
|
||||
|
||||
if (distanceToTankPosition > maxDistance)
|
||||
if (distToPosition > 3.0f)
|
||||
{
|
||||
float moveX = bot->GetPositionX() + (dX / distanceToTankPosition) * maxDistance;
|
||||
float moveY = bot->GetPositionY() + (dY / distanceToTankPosition) * maxDistance;
|
||||
const float moveZ = position.GetPositionZ();
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, moveZ, false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
const float dX = position.GetPositionX() - bot->GetPositionX();
|
||||
const float dY = position.GetPositionY() - bot->GetPositionY();
|
||||
const float moveDist = std::min(5.0f, distToPosition);
|
||||
const float moveX = bot->GetPositionX() + (dX / distToPosition) * moveDist;
|
||||
const float moveY = bot->GetPositionY() + (dY / distToPosition) * moveDist;
|
||||
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, moveX, moveY, position.GetPositionZ(), false, false,
|
||||
false, false, MovementPriority::MOVEMENT_COMBAT, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,27 +490,17 @@ bool GruulTheDragonkillerTanksPositionBossAction::Execute(Event /*event*/)
|
||||
// Ranged should spread out 10 yards from each other
|
||||
bool GruulTheDragonkillerSpreadRangedAction::Execute(Event /*event*/)
|
||||
{
|
||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
if (!gruul)
|
||||
return false;
|
||||
|
||||
if (gruul->GetHealth() == gruul->GetMaxHealth())
|
||||
_hasReachedInitialPosition = false;
|
||||
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
static std::unordered_map<ObjectGuid, Position> initialPositions;
|
||||
static std::unordered_map<ObjectGuid, bool> hasReachedInitialPosition;
|
||||
|
||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
if (gruul && gruul->GetHealth() == gruul->GetMaxHealth())
|
||||
{
|
||||
initialPositions.erase(bot->GetGUID());
|
||||
hasReachedInitialPosition.erase(bot->GetGUID());
|
||||
}
|
||||
|
||||
const Position& position = GRUUL_TANK_POSITION;
|
||||
const float centerX = position.GetPositionX();
|
||||
const float centerY = position.GetPositionY();
|
||||
const float centerZ = position.GetPositionZ();
|
||||
const float minRadius = 25.0f;
|
||||
const float maxRadius = 40.0f;
|
||||
|
||||
std::vector<Player*> members;
|
||||
Player* closestMember = nullptr;
|
||||
float closestDist = std::numeric_limits<float>::max();
|
||||
@ -559,6 +511,7 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event /*event*/)
|
||||
continue;
|
||||
|
||||
members.push_back(member);
|
||||
|
||||
if (member != bot)
|
||||
{
|
||||
float dist = bot->GetExactDist2d(member);
|
||||
@ -570,49 +523,53 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event /*event*/)
|
||||
}
|
||||
}
|
||||
|
||||
if (!initialPositions.count(bot->GetGUID()))
|
||||
const Position& position = GRUUL_TANK_POSITION;
|
||||
|
||||
if (_initialPosition.GetPositionX() == 0.0f && _initialPosition.GetPositionY() == 0.0f)
|
||||
{
|
||||
auto it = std::find(members.begin(), members.end(), bot);
|
||||
uint8 botIndex = (it != members.end()) ? std::distance(members.begin(), it) : 0;
|
||||
uint8 count = members.size();
|
||||
|
||||
constexpr float minRadius = 25.0f;
|
||||
constexpr float maxRadius = 40.0f;
|
||||
float angle = 2 * M_PI * botIndex / count;
|
||||
float radius = minRadius + static_cast<float>(rand()) /
|
||||
static_cast<float>(RAND_MAX) * (maxRadius - minRadius);
|
||||
float targetX = centerX + radius * cos(angle);
|
||||
float targetY = centerY + radius * sin(angle);
|
||||
float targetX = position.GetPositionX() + radius * cos(angle);
|
||||
float targetY = position.GetPositionY() + radius * sin(angle);
|
||||
|
||||
initialPositions[bot->GetGUID()] = Position(targetX, targetY, centerZ);
|
||||
hasReachedInitialPosition[bot->GetGUID()] = false;
|
||||
_initialPosition = Position(targetX, targetY, position.GetPositionZ());
|
||||
}
|
||||
|
||||
Position targetPosition = initialPositions[bot->GetGUID()];
|
||||
if (!hasReachedInitialPosition[bot->GetGUID()])
|
||||
if (!_hasReachedInitialPosition)
|
||||
{
|
||||
if (!bot->IsWithinDist2d(targetPosition.GetPositionX(), targetPosition.GetPositionY(), 2.0f))
|
||||
const float distanceToTarget =
|
||||
bot->GetExactDist2d(_initialPosition.GetPositionX(), _initialPosition.GetPositionY());
|
||||
if (distanceToTarget > 2.0f)
|
||||
{
|
||||
float destX = targetPosition.GetPositionX();
|
||||
float destY = targetPosition.GetPositionY();
|
||||
float destZ = targetPosition.GetPositionZ();
|
||||
float destX = _initialPosition.GetPositionX();
|
||||
float destY = _initialPosition.GetPositionY();
|
||||
float destZ = _initialPosition.GetPositionZ();
|
||||
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(),
|
||||
bot->GetPositionY(), bot->GetPositionZ(), destX, destY, destZ))
|
||||
return false;
|
||||
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false, false,
|
||||
MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
hasReachedInitialPosition[bot->GetGUID()] = true;
|
||||
}
|
||||
|
||||
const float minSpreadDistance = 10.0f;
|
||||
const float movementThreshold = 2.0f;
|
||||
|
||||
if (closestMember && closestDist < minSpreadDistance - movementThreshold)
|
||||
{
|
||||
return FleePosition(Position(closestMember->GetPositionX(), closestMember->GetPositionY(),
|
||||
closestMember->GetPositionZ()), minSpreadDistance, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
return MoveTo(GRUULS_LAIR_MAP_ID, destX, destY, destZ, false, false, false,
|
||||
false, MovementPriority::MOVEMENT_COMBAT, true, false);
|
||||
}
|
||||
|
||||
_hasReachedInitialPosition = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr float minSpreadDistance = 10.0f;
|
||||
constexpr uint32 minInterval = 1000;
|
||||
if (closestMember && closestDist < minSpreadDistance)
|
||||
return FleePosition(closestMember->GetPosition(), minSpreadDistance, minInterval);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -621,33 +578,10 @@ bool GruulTheDragonkillerSpreadRangedAction::Execute(Event /*event*/)
|
||||
// Try to get away from other group members when Ground Slam is cast
|
||||
bool GruulTheDragonkillerShatterSpreadAction::Execute(Event /*event*/)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return false;
|
||||
|
||||
GuidVector members = AI_VALUE(GuidVector, "group members");
|
||||
Unit* closestMember = nullptr;
|
||||
float closestDist = std::numeric_limits<float>::max();
|
||||
|
||||
for (auto& member : members)
|
||||
{
|
||||
Unit* unit = botAI->GetUnit(member);
|
||||
if (!unit || bot->GetGUID() == member)
|
||||
continue;
|
||||
|
||||
const float dist = bot->GetExactDist2d(unit);
|
||||
if (dist < closestDist)
|
||||
{
|
||||
closestDist = dist;
|
||||
closestMember = unit;
|
||||
}
|
||||
}
|
||||
|
||||
if (closestMember)
|
||||
{
|
||||
return FleePosition(Position(closestMember->GetPositionX(), closestMember->GetPositionY(),
|
||||
closestMember->GetPositionZ()), 6.0f, 0);
|
||||
}
|
||||
constexpr float safeDistance = 10.0f;
|
||||
constexpr uint32 minInterval = 0;
|
||||
if (Unit* nearestPlayer = GetNearestPlayerInRadius(bot, safeDistance))
|
||||
return FleePosition(nearestPlayer->GetPosition(), safeDistance, minInterval);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef PLAYERBOTS_RAIDGRUULSLAIRACTIONS_H
|
||||
#define PLAYERBOTS_RAIDGRUULSLAIRACTIONS_H
|
||||
#ifndef PLAYERBOTS_GRUULACTIONS_H
|
||||
#define PLAYERBOTS_GRUULACTIONS_H
|
||||
|
||||
#include "Action.h"
|
||||
#include "AttackAction.h"
|
||||
@ -8,104 +8,108 @@
|
||||
class HighKingMaulgarMainTankAttackMaulgarAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarMainTankAttackMaulgarAction(PlayerbotAI* botAI, std::string const name = "high king maulgar main tank attack maulgar") : AttackAction(botAI, name) {};
|
||||
|
||||
HighKingMaulgarMainTankAttackMaulgarAction(
|
||||
PlayerbotAI* botAI, std::string const name = "high king maulgar main tank attack maulgar") : AttackAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarFirstAssistTankAttackOlmAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarFirstAssistTankAttackOlmAction(PlayerbotAI* botAI, std::string const name = "high king maulgar first assist tank attack olm") : AttackAction(botAI, name) {};
|
||||
|
||||
HighKingMaulgarFirstAssistTankAttackOlmAction(
|
||||
PlayerbotAI* botAI, std::string const name = "high king maulgar first assist tank attack olm") : AttackAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarSecondAssistTankAttackBlindeyeAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarSecondAssistTankAttackBlindeyeAction(PlayerbotAI* botAI, std::string const name = "high king maulgar second assist tank attack blindeye") : AttackAction(botAI, name) {};
|
||||
|
||||
HighKingMaulgarSecondAssistTankAttackBlindeyeAction(
|
||||
PlayerbotAI* botAI, std::string const name = "high king maulgar second assist tank attack blindeye") : AttackAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarMageTankAttackKroshAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarMageTankAttackKroshAction(PlayerbotAI* botAI, std::string const name = "high king maulgar mage tank attack krosh") : AttackAction(botAI, name) {};
|
||||
|
||||
HighKingMaulgarMageTankAttackKroshAction(
|
||||
PlayerbotAI* botAI, std::string const name = "high king maulgar mage tank attack krosh") : AttackAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarMoonkinTankAttackKigglerAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarMoonkinTankAttackKigglerAction(PlayerbotAI* botAI, std::string const name = "high king maulgar moonkin tank attack kiggler") : AttackAction(botAI, name) {};
|
||||
|
||||
HighKingMaulgarMoonkinTankAttackKigglerAction(
|
||||
PlayerbotAI* botAI, std::string const name = "high king maulgar moonkin tank attack kiggler") : AttackAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarAssignDPSPriorityAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarAssignDPSPriorityAction(PlayerbotAI* botAI, std::string const name = "high king maulgar assign dps priority") : AttackAction(botAI, name) {};
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarHealerFindSafePositionAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarHealerFindSafePositionAction(PlayerbotAI* botAI, std::string const name = "high king maulgar healer find safe position") : MovementAction(botAI, name) {};
|
||||
|
||||
HighKingMaulgarAssignDPSPriorityAction(
|
||||
PlayerbotAI* botAI, std::string const name = "high king maulgar assign dps priority") : AttackAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarRunAwayFromWhirlwindAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarRunAwayFromWhirlwindAction(PlayerbotAI* botAI, std::string const name = "high king maulgar run away from whirlwind") : MovementAction(botAI, name) {};
|
||||
|
||||
HighKingMaulgarRunAwayFromWhirlwindAction(
|
||||
PlayerbotAI* botAI, std::string const name = "high king maulgar run away from whirlwind") : MovementAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarBanishFelstalkerAction : public AttackAction
|
||||
class HighKingMaulgarMoveAwayFromBlastNovaDangerAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarBanishFelstalkerAction(PlayerbotAI* botAI, std::string const name = "high king maulgar banish felstalker") : AttackAction(botAI, name) {};
|
||||
|
||||
HighKingMaulgarMoveAwayFromBlastNovaDangerAction(
|
||||
PlayerbotAI* botAI, std::string const name = "high king maulgar move away from blast nova danger") : MovementAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarMisdirectOlmAndBlindeyeAction : public AttackAction
|
||||
class HighKingMaulgarBanishFelStalkerAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarMisdirectOlmAndBlindeyeAction(PlayerbotAI* botAI, std::string const name = "high king maulgar misdirect olm and blindeye") : AttackAction(botAI, name) {};
|
||||
HighKingMaulgarBanishFelStalkerAction(
|
||||
PlayerbotAI* botAI, std::string const name = "high king maulgar banish fel stalker") : AttackAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarMisdirectOgresToTanksAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarMisdirectOgresToTanksAction(
|
||||
PlayerbotAI* botAI, std::string const name = "high king maulgar misdirect ogres to tanks") : AttackAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerTanksPositionBossAction : public AttackAction
|
||||
{
|
||||
public:
|
||||
GruulTheDragonkillerTanksPositionBossAction(PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller tanks position boss") : AttackAction(botAI, name) {};
|
||||
|
||||
GruulTheDragonkillerTanksPositionBossAction(
|
||||
PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller tanks position boss") : AttackAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerSpreadRangedAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
GruulTheDragonkillerSpreadRangedAction(PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller spread ranged") : MovementAction(botAI, name) {};
|
||||
|
||||
GruulTheDragonkillerSpreadRangedAction(
|
||||
PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller spread ranged") : MovementAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
|
||||
private:
|
||||
Position _initialPosition;
|
||||
bool _hasReachedInitialPosition = false;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerShatterSpreadAction : public MovementAction
|
||||
{
|
||||
public:
|
||||
GruulTheDragonkillerShatterSpreadAction(PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller shatter spread") : MovementAction(botAI, name) {};
|
||||
|
||||
GruulTheDragonkillerShatterSpreadAction(
|
||||
PlayerbotAI* botAI, std::string const name = "gruul the dragonkiller shatter spread") : MovementAction(botAI, name) {};
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
|
||||
@ -6,44 +6,19 @@
|
||||
|
||||
namespace GruulsLairHelpers
|
||||
{
|
||||
// Olm does not chase properly due to the Core's caster movement issues
|
||||
// Thus, the below "OlmTankPosition" is beyond the actual desired tanking location
|
||||
// It is the spot to which the OlmTank runs to to pull Olm to a decent tanking location
|
||||
// "MaulgarRoomCenter" is to keep healers in a centralized location
|
||||
const Position MAULGAR_TANK_POSITION = { 90.686f, 167.047f, -13.234f };
|
||||
const Position OLM_TANK_POSITION = { 87.485f, 234.942f, -3.635f };
|
||||
const Position BLINDEYE_TANK_POSITION = { 99.681f, 213.989f, -10.345f };
|
||||
const Position KROSH_TANK_POSITION = { 116.880f, 166.208f, -14.231f };
|
||||
const Position MAULGAR_ROOM_CENTER = { 88.754f, 150.759f, -11.569f };
|
||||
const Position GRUUL_TANK_POSITION = { 241.238f, 365.025f, -4.220f };
|
||||
|
||||
bool IsAnyOgreBossAlive(PlayerbotAI* botAI)
|
||||
{
|
||||
const char* ogreBossNames[] =
|
||||
{
|
||||
"high king maulgar",
|
||||
"kiggler the crazed",
|
||||
"krosh firehand",
|
||||
"olm the summoner",
|
||||
"blindeye the seer"
|
||||
};
|
||||
const Position MAULGAR_TANK_POSITION = { 90.686f, 167.047f, -13.234f };
|
||||
const Position OLM_TANK_POSITION = { 101.050f, 219.359f, -9.503f };
|
||||
const Position BLINDEYE_TANK_POSITION = { 99.681f, 213.989f, -10.345f };
|
||||
const Position KROSH_TANK_POSITION = { 116.880f, 166.208f, -14.231f };
|
||||
const Position MAULGAR_ROOM_CENTER = { 88.754f, 150.759f, -11.569f };
|
||||
const Position GRUUL_TANK_POSITION = { 241.238f, 365.025f, -4.220f };
|
||||
|
||||
for (const char* name : ogreBossNames)
|
||||
{
|
||||
Unit* boss = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", name)->Get();
|
||||
if (!boss || !boss->IsAlive())
|
||||
continue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsKroshMageTank(Player* bot)
|
||||
{
|
||||
Player* GetKroshMageTank(Player* bot)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return false;
|
||||
return nullptr;
|
||||
|
||||
// (1) First loop: Return the first assistant Mage (real player or bot)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
@ -53,7 +28,8 @@ namespace GruulsLairHelpers
|
||||
continue;
|
||||
|
||||
if (group->IsAssistant(member->GetGUID()))
|
||||
return member == bot;
|
||||
return member;
|
||||
|
||||
}
|
||||
|
||||
// (2) Fall back to bot Mage with highest HP
|
||||
@ -65,7 +41,9 @@ namespace GruulsLairHelpers
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive() || !GET_PLAYERBOT_AI(member) ||
|
||||
member->getClass() != CLASS_MAGE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 hp = member->GetMaxHealth();
|
||||
if (!highestHpMage || hp > highestHp)
|
||||
@ -75,15 +53,16 @@ namespace GruulsLairHelpers
|
||||
}
|
||||
}
|
||||
|
||||
// (3) Return the found Mage tank, or nullptr if none found
|
||||
return highestHpMage == bot;
|
||||
}
|
||||
return highestHpMage;
|
||||
}
|
||||
|
||||
bool IsKigglerMoonkinTank(Player* bot)
|
||||
{
|
||||
Player* GetKigglerMoonkinTank(Player* bot)
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group)
|
||||
return false;
|
||||
return nullptr;
|
||||
|
||||
uint8 tab = AiFactory::GetPlayerSpecTab(bot);
|
||||
|
||||
// (1) First loop: Return the first assistant Moonkin (real player or bot)
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
@ -92,9 +71,8 @@ namespace GruulsLairHelpers
|
||||
if (!member || !member->IsAlive() || member->getClass() != CLASS_DRUID)
|
||||
continue;
|
||||
|
||||
if (group->IsAssistant(member->GetGUID()) &&
|
||||
AiFactory::GetPlayerSpecTab(member) == DRUID_TAB_BALANCE)
|
||||
return member == bot;
|
||||
if (group->IsAssistant(member->GetGUID()) && tab == DRUID_TAB_BALANCE)
|
||||
return member;
|
||||
}
|
||||
|
||||
// (2) Fall back to bot Moonkin with highest HP
|
||||
@ -104,8 +82,10 @@ namespace GruulsLairHelpers
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive() || member->getClass() != CLASS_DRUID ||
|
||||
!GET_PLAYERBOT_AI(member) || AiFactory::GetPlayerSpecTab(member) != DRUID_TAB_BALANCE)
|
||||
!GET_PLAYERBOT_AI(member) || tab != DRUID_TAB_BALANCE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 hp = member->GetMaxHealth();
|
||||
if (!highestHpMoonkin || hp > highestHp)
|
||||
@ -115,90 +95,7 @@ namespace GruulsLairHelpers
|
||||
}
|
||||
}
|
||||
|
||||
// (3) Return the found Moonkin tank, or nullptr if none found
|
||||
return highestHpMoonkin == bot;
|
||||
}
|
||||
|
||||
bool IsPositionSafe(PlayerbotAI* botAI, Player* bot, Position pos)
|
||||
{
|
||||
const float KROSH_SAFE_DISTANCE = 20.0f;
|
||||
const float MAULGAR_SAFE_DISTANCE = 10.0f;
|
||||
bool isSafe = true;
|
||||
|
||||
Unit* krosh = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "krosh firehand")->Get();
|
||||
if (krosh && krosh->IsAlive())
|
||||
{
|
||||
float dist = krosh->GetDistance2d(pos.GetPositionX(), pos.GetPositionY());
|
||||
if (dist < KROSH_SAFE_DISTANCE)
|
||||
isSafe = false;
|
||||
}
|
||||
|
||||
Unit* maulgar = botAI->GetAiObjectContext()->GetValue<Unit*>("find target", "high king maulgar")->Get();
|
||||
if (botAI->IsRanged(bot) && maulgar && maulgar->IsAlive())
|
||||
{
|
||||
float dist = maulgar->GetDistance2d(pos.GetPositionX(), pos.GetPositionY());
|
||||
if (dist < MAULGAR_SAFE_DISTANCE)
|
||||
isSafe = false;
|
||||
}
|
||||
|
||||
return isSafe;
|
||||
}
|
||||
|
||||
bool TryGetNewSafePosition(PlayerbotAI* botAI, Player* bot, Position& outPos)
|
||||
{
|
||||
const float SEARCH_RADIUS = 30.0f;
|
||||
const uint8 NUM_POSITIONS = 32;
|
||||
|
||||
outPos = { bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ() };
|
||||
if (IsPositionSafe(botAI, bot, outPos))
|
||||
{
|
||||
outPos = Position();
|
||||
return false;
|
||||
}
|
||||
|
||||
float bestScore = std::numeric_limits<float>::max();
|
||||
bool foundSafeSpot = false;
|
||||
Position bestPos;
|
||||
|
||||
for (int i = 0; i < NUM_POSITIONS; ++i)
|
||||
{
|
||||
float angle = 2 * M_PI * i / NUM_POSITIONS;
|
||||
Position candidatePos;
|
||||
candidatePos.Relocate(bot->GetPositionX() + SEARCH_RADIUS * cos(angle),
|
||||
bot->GetPositionY() + SEARCH_RADIUS * sin(angle),
|
||||
bot->GetPositionZ());
|
||||
|
||||
float destX = candidatePos.GetPositionX();
|
||||
float destY = candidatePos.GetPositionY();
|
||||
float destZ = candidatePos.GetPositionZ();
|
||||
if (!bot->GetMap()->CheckCollisionAndGetValidCoords(bot, bot->GetPositionX(), bot->GetPositionY(),
|
||||
bot->GetPositionZ(), destX, destY, destZ, true))
|
||||
continue;
|
||||
|
||||
if (destX != candidatePos.GetPositionX() || destY != candidatePos.GetPositionY())
|
||||
continue;
|
||||
|
||||
candidatePos.Relocate(destX, destY, destZ);
|
||||
|
||||
if (IsPositionSafe(botAI, bot, candidatePos))
|
||||
{
|
||||
float movementDistance = bot->GetDistance2d(destX, destY);
|
||||
if (movementDistance < bestScore)
|
||||
{
|
||||
bestScore = movementDistance;
|
||||
bestPos = candidatePos;
|
||||
foundSafeSpot = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundSafeSpot)
|
||||
{
|
||||
outPos = bestPos;
|
||||
return true;
|
||||
}
|
||||
|
||||
outPos = Position();
|
||||
return false;
|
||||
}
|
||||
return highestHpMoonkin;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
#ifndef RAID_GRUULSLAIRHELPERS_H
|
||||
#define RAID_GRUULSLAIRHELPERS_H
|
||||
#ifndef PLAYERBOTS_GRUULHELPERS_H
|
||||
#define PLAYERBOTS_GRUULHELPERS_H
|
||||
|
||||
#include "PlayerbotAI.h"
|
||||
|
||||
namespace GruulsLairHelpers
|
||||
{
|
||||
enum GruulsLairSpells
|
||||
{
|
||||
|
||||
enum class GruulsLairSpells : uint32
|
||||
{
|
||||
// High King Maulgar
|
||||
SPELL_WHIRLWIND = 33238,
|
||||
|
||||
@ -19,27 +20,25 @@ namespace GruulsLairHelpers
|
||||
// Gruul the Dragonkiller
|
||||
SPELL_GROUND_SLAM_1 = 33525,
|
||||
SPELL_GROUND_SLAM_2 = 39187,
|
||||
};
|
||||
};
|
||||
|
||||
enum GruulsLairNPCs
|
||||
{
|
||||
enum class GruulsLairNpcs : uint32
|
||||
{
|
||||
NPC_WILD_FEL_STALKER = 18847,
|
||||
};
|
||||
};
|
||||
|
||||
constexpr uint32 GRUULS_LAIR_MAP_ID = 565;
|
||||
constexpr uint32 GRUULS_LAIR_MAP_ID = 565;
|
||||
|
||||
bool IsAnyOgreBossAlive(PlayerbotAI* botAI);
|
||||
bool IsKroshMageTank(Player* bot);
|
||||
bool IsKigglerMoonkinTank(Player* bot);
|
||||
bool IsPositionSafe(PlayerbotAI* botAI, Player* bot, Position pos);
|
||||
bool TryGetNewSafePosition(PlayerbotAI* botAI, Player* bot, Position& outPos);
|
||||
Player* GetKroshMageTank(Player* bot);
|
||||
Player* GetKigglerMoonkinTank(Player* bot);
|
||||
|
||||
extern const Position MAULGAR_TANK_POSITION;
|
||||
extern const Position OLM_TANK_POSITION;
|
||||
extern const Position BLINDEYE_TANK_POSITION;
|
||||
extern const Position KROSH_TANK_POSITION;
|
||||
extern const Position MAULGAR_ROOM_CENTER;
|
||||
extern const Position GRUUL_TANK_POSITION;
|
||||
|
||||
extern const Position MAULGAR_TANK_POSITION;
|
||||
extern const Position OLM_TANK_POSITION;
|
||||
extern const Position BLINDEYE_TANK_POSITION;
|
||||
extern const Position KROSH_TANK_POSITION;
|
||||
extern const Position MAULGAR_ROOM_CENTER;
|
||||
extern const Position GRUUL_TANK_POSITION;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -2,43 +2,68 @@
|
||||
#include "GruulActions.h"
|
||||
#include "GruulHelpers.h"
|
||||
#include "ChooseTargetActions.h"
|
||||
#include "DruidBearActions.h"
|
||||
#include "DruidCatActions.h"
|
||||
#include "GenericSpellActions.h"
|
||||
#include "HunterActions.h"
|
||||
#include "MageActions.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ReachTargetActions.h"
|
||||
#include "WarriorActions.h"
|
||||
#include "ShamanActions.h"
|
||||
|
||||
using namespace GruulsLairHelpers;
|
||||
|
||||
float HighKingMaulgarDisableTankAssistMultiplier::GetValue(Action* action)
|
||||
float HighKingMaulgarDelayBloodlustAndHeroismMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (bot->GetVictim() == nullptr)
|
||||
if (bot->getClass() != CLASS_SHAMAN)
|
||||
return 1.0f;
|
||||
|
||||
if (IsAnyOgreBossAlive(botAI) && dynamic_cast<TankAssistAction*>(action))
|
||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
if (!blindeye || blindeye->GetHealthPct() < 75.0f)
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<CastHeroismAction*>(action) ||
|
||||
dynamic_cast<CastBloodlustAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float HighKingMaulgarControlTankActionsMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (!botAI->IsTank(bot))
|
||||
return 1.0f;
|
||||
|
||||
if (!AI_VALUE2(Unit*, "find target", "high king maulgar"))
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
|
||||
(bot->GetVictim() != nullptr && dynamic_cast<TankAssistAction*>(action)))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// Don't run back in during Whirlwind
|
||||
float HighKingMaulgarAvoidWhirlwindMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
|
||||
if (maulgar && maulgar->HasAura(SPELL_WHIRLWIND) &&
|
||||
!kiggler && !krosh && !olm && !blindeye)
|
||||
if (!maulgar ||
|
||||
!maulgar->HasAura(static_cast<uint32>(GruulsLairSpells::SPELL_WHIRLWIND)))
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (AI_VALUE(Unit*, "current target") != maulgar)
|
||||
return 1.0f;
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<CastReachTargetSpellAction*>(action) ||
|
||||
(dynamic_cast<MovementAction*>(action) &&
|
||||
!dynamic_cast<HighKingMaulgarRunAwayFromWhirlwindAction*>(action)))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
@ -48,56 +73,82 @@ float HighKingMaulgarAvoidWhirlwindMultiplier::GetValue(Action* action)
|
||||
// Arcane Shot will remove Spell Shield, which the mage tank needs to survive
|
||||
float HighKingMaulgarDisableArcaneShotOnKroshMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (bot->getClass() != CLASS_HUNTER)
|
||||
return 1.0f;
|
||||
|
||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
if (!krosh || AI_VALUE(Unit*, "current target") != krosh)
|
||||
return 1.0f;
|
||||
|
||||
if (krosh && AI_VALUE(Unit*, "current target") == krosh &&
|
||||
dynamic_cast<CastArcaneShotAction*>(action))
|
||||
if (dynamic_cast<CastArcaneShotAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float HighKingMaulgarDisableMageTankAOEMultiplier::GetValue(Action* action)
|
||||
float HighKingMaulgarDisableMageTankAoeMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (IsKroshMageTank(bot) &&
|
||||
(dynamic_cast<CastFrostNovaAction*>(action) || dynamic_cast<CastBlizzardAction*>(action) ||
|
||||
dynamic_cast<CastConeOfColdAction*>(action) || dynamic_cast<CastFlamestrikeAction*>(action) ||
|
||||
dynamic_cast<CastDragonsBreathAction*>(action) || dynamic_cast<CastBlastWaveAction*>(action)))
|
||||
return 0.0f;
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float GruulTheDragonkillerMainTankMovementMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
if (!gruul)
|
||||
if (bot->getClass() != CLASS_MAGE)
|
||||
return 1.0f;
|
||||
|
||||
if (botAI->IsMainTank(bot))
|
||||
if (!AI_VALUE2(Unit*, "find target", "krosh firehand"))
|
||||
return 1.0f;
|
||||
|
||||
auto castSpellAction = dynamic_cast<CastSpellAction*>(action);
|
||||
if (castSpellAction &&
|
||||
castSpellAction->getThreatType() == Action::ActionThreatType::Aoe)
|
||||
{
|
||||
if (gruul->GetVictim() == bot && dynamic_cast<CombatFormationMoveAction*>(action))
|
||||
return 0.0f;
|
||||
|
||||
if (dynamic_cast<AvoidAoeAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float GruulTheDragonkillerGroundSlamMultiplier::GetValue(Action* action)
|
||||
float GruulTheDragonkillerDelayBloodlustAndHeroismMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
if (!gruul)
|
||||
if (bot->getClass() != CLASS_SHAMAN)
|
||||
return 1.0f;
|
||||
|
||||
if (bot->HasAura(SPELL_GROUND_SLAM_1) ||
|
||||
bot->HasAura(SPELL_GROUND_SLAM_2))
|
||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
if (!gruul || gruul->GetHealthPct() < 95.0f)
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<CastHeroismAction*>(action) ||
|
||||
dynamic_cast<CastBloodlustAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float GruulTheDragonkillerControlTankMovementMultiplier::GetValue(Action* action)
|
||||
{
|
||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
if (!gruul || gruul->GetVictim() != bot)
|
||||
return 1.0f;
|
||||
|
||||
if (dynamic_cast<CombatFormationMoveAction*>(action) ||
|
||||
dynamic_cast<AvoidAoeAction*>(action))
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float GruulTheDragonkillerStaySpreadForShatterMultiplier::GetValue(Action* action)
|
||||
{
|
||||
if (!bot->HasAura(static_cast<uint32>(GruulsLairSpells::SPELL_GROUND_SLAM_1)) &&
|
||||
!bot->HasAura(static_cast<uint32>(GruulsLairSpells::SPELL_GROUND_SLAM_2)))
|
||||
{
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
if (dynamic_cast<CastReachTargetSpellAction*>(action) ||
|
||||
(dynamic_cast<MovementAction*>(action) &&
|
||||
!dynamic_cast<GruulTheDragonkillerShatterSpreadAction*>(action)))
|
||||
{
|
||||
if ((dynamic_cast<MovementAction*>(action) &&
|
||||
!dynamic_cast<GruulTheDragonkillerShatterSpreadAction*>(action)) ||
|
||||
dynamic_cast<CastReachTargetSpellAction*>(action))
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
||||
@ -1,47 +1,69 @@
|
||||
#ifndef PLAYERBOTS_RAIDGRUULSLAIRMULTIPLIERS_H
|
||||
#define PLAYERBOTS_RAIDGRUULSLAIRMULTIPLIERS_H
|
||||
#ifndef PLAYERBOTS_GRUULMULTIPLIERS_H
|
||||
#define PLAYERBOTS_GRUULMULTIPLIERS_H
|
||||
|
||||
#include "Multiplier.h"
|
||||
|
||||
class HighKingMaulgarDisableTankAssistMultiplier : public Multiplier
|
||||
class HighKingMaulgarDelayBloodlustAndHeroismMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarDisableTankAssistMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar disable tank assist multiplier") {}
|
||||
HighKingMaulgarDelayBloodlustAndHeroismMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar delay bloodlust and heroism multiplier") {}
|
||||
float GetValue(Action* action) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarControlTankActionsMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarControlTankActionsMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar control tank actions multiplier") {}
|
||||
float GetValue(Action* action) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarAvoidWhirlwindMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarAvoidWhirlwindMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar avoid whirlwind multiplier") {}
|
||||
HighKingMaulgarAvoidWhirlwindMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar avoid whirlwind multiplier") {}
|
||||
float GetValue(Action* action) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarDisableArcaneShotOnKroshMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarDisableArcaneShotOnKroshMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar disable arcane shot on krosh multiplier") {}
|
||||
HighKingMaulgarDisableArcaneShotOnKroshMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar disable arcane shot on krosh multiplier") {}
|
||||
float GetValue(Action* action) override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarDisableMageTankAOEMultiplier : public Multiplier
|
||||
class HighKingMaulgarDisableMageTankAoeMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarDisableMageTankAOEMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar disable mage tank aoe multiplier") {}
|
||||
HighKingMaulgarDisableMageTankAoeMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "high king maulgar disable mage tank aoe multiplier") {}
|
||||
float GetValue(Action* action) override;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerMainTankMovementMultiplier : public Multiplier
|
||||
class GruulTheDragonkillerDelayBloodlustAndHeroismMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
GruulTheDragonkillerMainTankMovementMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "gruul the dragonkiller main tank movement multiplier") {}
|
||||
GruulTheDragonkillerDelayBloodlustAndHeroismMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "gruul the dragonkiller delay bloodlust and heroism multiplier") {}
|
||||
float GetValue(Action* action) override;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerGroundSlamMultiplier : public Multiplier
|
||||
class GruulTheDragonkillerControlTankMovementMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
GruulTheDragonkillerGroundSlamMultiplier(PlayerbotAI* botAI) : Multiplier(botAI, "gruul the dragonkiller ground slam multiplier") {}
|
||||
GruulTheDragonkillerControlTankMovementMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "gruul the dragonkiller control tank movement multiplier") {}
|
||||
float GetValue(Action* action) override;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerStaySpreadForShatterMultiplier : public Multiplier
|
||||
{
|
||||
public:
|
||||
GruulTheDragonkillerStaySpreadForShatterMultiplier(
|
||||
PlayerbotAI* botAI) : Multiplier(botAI, "gruul the dragonkiller stay spread for shatter multiplier") {}
|
||||
float GetValue(Action* action) override;
|
||||
};
|
||||
|
||||
|
||||
@ -4,35 +4,35 @@
|
||||
void RaidGruulsLairStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
// High King Maulgar
|
||||
triggers.push_back(new TriggerNode("high king maulgar is main tank", {
|
||||
triggers.push_back(new TriggerNode("high king maulgar boss engaged by main tank", {
|
||||
NextAction("high king maulgar main tank attack maulgar", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar is first assist tank", {
|
||||
triggers.push_back(new TriggerNode("high king maulgar olm engaged by first assist tank", {
|
||||
NextAction("high king maulgar first assist tank attack olm", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar is second assist tank", {
|
||||
triggers.push_back(new TriggerNode("high king maulgar blindeye engaged by second assist tank", {
|
||||
NextAction("high king maulgar second assist tank attack blindeye", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar is mage tank", {
|
||||
triggers.push_back(new TriggerNode("high king maulgar krosh engaged by mage tank", {
|
||||
NextAction("high king maulgar mage tank attack krosh", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar is moonkin tank", {
|
||||
triggers.push_back(new TriggerNode("high king maulgar kiggler engaged by moonkin tank", {
|
||||
NextAction("high king maulgar moonkin tank attack kiggler", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar determining kill order", {
|
||||
NextAction("high king maulgar assign dps priority", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar healer in danger", {
|
||||
NextAction("high king maulgar healer find safe position", ACTION_RAID + 1) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar boss channeling whirlwind", {
|
||||
NextAction("high king maulgar run away from whirlwind", ACTION_EMERGENCY + 6) }));
|
||||
NextAction("high king maulgar run away from whirlwind", ACTION_EMERGENCY + 7) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar wild felstalker spawned", {
|
||||
NextAction("high king maulgar banish felstalker", ACTION_RAID + 2) }));
|
||||
triggers.push_back(new TriggerNode("high king maulgar krosh casts blast wave", {
|
||||
NextAction("high king maulgar move away from blast nova danger", ACTION_EMERGENCY + 6) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar pulling olm and blindeye", {
|
||||
NextAction("high king maulgar misdirect olm and blindeye", ACTION_RAID + 2) }));
|
||||
triggers.push_back(new TriggerNode("high king maulgar wild fel stalker spawned", {
|
||||
NextAction("high king maulgar banish fel stalker", ACTION_RAID + 2) }));
|
||||
|
||||
triggers.push_back(new TriggerNode("high king maulgar pulling ogre council", {
|
||||
NextAction("high king maulgar misdirect ogres to tanks", ACTION_RAID + 2) }));
|
||||
|
||||
// Gruul the Dragonkiller
|
||||
triggers.push_back(new TriggerNode("gruul the dragonkiller boss engaged by tanks", {
|
||||
@ -47,10 +47,15 @@ void RaidGruulsLairStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
|
||||
void RaidGruulsLairStrategy::InitMultipliers(std::vector<Multiplier*>& multipliers)
|
||||
{
|
||||
multipliers.push_back(new HighKingMaulgarDisableTankAssistMultiplier(botAI));
|
||||
// High King Maulgar
|
||||
multipliers.push_back(new HighKingMaulgarDelayBloodlustAndHeroismMultiplier(botAI));
|
||||
multipliers.push_back(new HighKingMaulgarControlTankActionsMultiplier(botAI));
|
||||
multipliers.push_back(new HighKingMaulgarAvoidWhirlwindMultiplier(botAI));
|
||||
multipliers.push_back(new HighKingMaulgarDisableArcaneShotOnKroshMultiplier(botAI));
|
||||
multipliers.push_back(new HighKingMaulgarDisableMageTankAOEMultiplier(botAI));
|
||||
multipliers.push_back(new GruulTheDragonkillerMainTankMovementMultiplier(botAI));
|
||||
multipliers.push_back(new GruulTheDragonkillerGroundSlamMultiplier(botAI));
|
||||
multipliers.push_back(new HighKingMaulgarDisableMageTankAoeMultiplier(botAI));
|
||||
|
||||
// Gruul the Dragonkiller
|
||||
multipliers.push_back(new GruulTheDragonkillerDelayBloodlustAndHeroismMultiplier(botAI));
|
||||
multipliers.push_back(new GruulTheDragonkillerControlTankMovementMultiplier(botAI));
|
||||
multipliers.push_back(new GruulTheDragonkillerStaySpreadForShatterMultiplier(botAI));
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef PLAYERBOTS_RAIDGRUULSLAIRSTRATEGY_H
|
||||
#define PLAYERBOTS_RAIDGRUULSLAIRSTRATEGY_H
|
||||
#ifndef PLAYERBOTS_GRUULSTRATEGY_H
|
||||
#define PLAYERBOTS_GRUULSTRATEGY_H
|
||||
|
||||
#include "Strategy.h"
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#ifndef PLAYERBOTS_RAIDGRUULSLAIRTRIGGERCONTEXT_H
|
||||
#define PLAYERBOTS_RAIDGRUULSLAIRTRIGGERCONTEXT_H
|
||||
#ifndef PLAYERBOTS_GRUULTRIGGERCONTEXT_H
|
||||
#define PLAYERBOTS_GRUULTRIGGERCONTEXT_H
|
||||
|
||||
#include "GruulTriggers.h"
|
||||
#include "NamedObjectContext.h"
|
||||
@ -10,40 +10,101 @@ public:
|
||||
RaidGruulsLairTriggerContext() : NamedObjectContext<Trigger>()
|
||||
{
|
||||
// High King Maulgar
|
||||
creators["high king maulgar is main tank"] = &RaidGruulsLairTriggerContext::high_king_maulgar_is_main_tank;
|
||||
creators["high king maulgar is first assist tank"] = &RaidGruulsLairTriggerContext::high_king_maulgar_is_first_assist_tank;
|
||||
creators["high king maulgar is second assist tank"] = &RaidGruulsLairTriggerContext::high_king_maulgar_is_second_assist_tank;
|
||||
creators["high king maulgar is mage tank"] = &RaidGruulsLairTriggerContext::high_king_maulgar_is_mage_tank;
|
||||
creators["high king maulgar is moonkin tank"] = &RaidGruulsLairTriggerContext::high_king_maulgar_is_moonkin_tank;
|
||||
creators["high king maulgar determining kill order"] = &RaidGruulsLairTriggerContext::high_king_maulgar_determining_kill_order;
|
||||
creators["high king maulgar healer in danger"] = &RaidGruulsLairTriggerContext::high_king_maulgar_healer_in_danger;
|
||||
creators["high king maulgar boss channeling whirlwind"] = &RaidGruulsLairTriggerContext::high_king_maulgar_boss_channeling_whirlwind;
|
||||
creators["high king maulgar wild felstalker spawned"] = &RaidGruulsLairTriggerContext::high_king_maulgar_wild_felstalker_spawned;
|
||||
creators["high king maulgar pulling olm and blindeye"] = &RaidGruulsLairTriggerContext::high_king_maulgar_pulling_olm_and_blindeye;
|
||||
creators["high king maulgar boss engaged by main tank"] =
|
||||
&RaidGruulsLairTriggerContext::high_king_maulgar_boss_engaged_by_main_tank;
|
||||
|
||||
creators["high king maulgar olm engaged by first assist tank"] =
|
||||
&RaidGruulsLairTriggerContext::high_king_maulgar_olm_engaged_by_first_assist_tank;
|
||||
|
||||
creators["high king maulgar blindeye engaged by second assist tank"] =
|
||||
&RaidGruulsLairTriggerContext::high_king_maulgar_blindeye_engaged_by_second_assist_tank;
|
||||
|
||||
creators["high king maulgar krosh engaged by mage tank"] =
|
||||
&RaidGruulsLairTriggerContext::high_king_maulgar_krosh_engaged_by_mage_tank;
|
||||
|
||||
creators["high king maulgar kiggler engaged by moonkin tank"] =
|
||||
&RaidGruulsLairTriggerContext::high_king_maulgar_kiggler_engaged_by_moonkin_tank;
|
||||
|
||||
creators["high king maulgar determining kill order"] =
|
||||
&RaidGruulsLairTriggerContext::high_king_maulgar_determining_kill_order;
|
||||
|
||||
creators["high king maulgar boss channeling whirlwind"] =
|
||||
&RaidGruulsLairTriggerContext::high_king_maulgar_boss_channeling_whirlwind;
|
||||
|
||||
creators["high king maulgar krosh casts blast wave"] =
|
||||
&RaidGruulsLairTriggerContext::high_king_maulgar_krosh_casts_blast_wave;
|
||||
|
||||
creators["high king maulgar wild fel stalker spawned"] =
|
||||
&RaidGruulsLairTriggerContext::high_king_maulgar_wild_fel_stalker_spawned;
|
||||
|
||||
creators["high king maulgar pulling ogre council"] =
|
||||
&RaidGruulsLairTriggerContext::high_king_maulgar_pulling_ogre_council;
|
||||
|
||||
// Gruul the Dragonkiller
|
||||
creators["gruul the dragonkiller boss engaged by tanks"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_tanks;
|
||||
creators["gruul the dragonkiller boss engaged by ranged"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_ranged;
|
||||
creators["gruul the dragonkiller incoming shatter"] = &RaidGruulsLairTriggerContext::gruul_the_dragonkiller_incoming_shatter;
|
||||
creators["gruul the dragonkiller boss engaged by tanks"] =
|
||||
&RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_tanks;
|
||||
|
||||
creators["gruul the dragonkiller boss engaged by ranged"] =
|
||||
&RaidGruulsLairTriggerContext::gruul_the_dragonkiller_boss_engaged_by_ranged;
|
||||
|
||||
creators["gruul the dragonkiller incoming shatter"] =
|
||||
&RaidGruulsLairTriggerContext::gruul_the_dragonkiller_incoming_shatter;
|
||||
}
|
||||
|
||||
private:
|
||||
// High King Maulgar
|
||||
static Trigger* high_king_maulgar_is_main_tank(PlayerbotAI* botAI) { return new HighKingMaulgarIsMainTankTrigger(botAI); }
|
||||
static Trigger* high_king_maulgar_is_first_assist_tank(PlayerbotAI* botAI) { return new HighKingMaulgarIsFirstAssistTankTrigger(botAI); }
|
||||
static Trigger* high_king_maulgar_is_second_assist_tank(PlayerbotAI* botAI) { return new HighKingMaulgarIsSecondAssistTankTrigger(botAI); }
|
||||
static Trigger* high_king_maulgar_is_mage_tank(PlayerbotAI* botAI) { return new HighKingMaulgarIsMageTankTrigger(botAI); }
|
||||
static Trigger* high_king_maulgar_is_moonkin_tank(PlayerbotAI* botAI) { return new HighKingMaulgarIsMoonkinTankTrigger(botAI); }
|
||||
static Trigger* high_king_maulgar_determining_kill_order(PlayerbotAI* botAI) { return new HighKingMaulgarDeterminingKillOrderTrigger(botAI); }
|
||||
static Trigger* high_king_maulgar_healer_in_danger(PlayerbotAI* botAI) { return new HighKingMaulgarHealerInDangerTrigger(botAI); }
|
||||
static Trigger* high_king_maulgar_boss_channeling_whirlwind(PlayerbotAI* botAI) { return new HighKingMaulgarBossChannelingWhirlwindTrigger(botAI); }
|
||||
static Trigger* high_king_maulgar_wild_felstalker_spawned(PlayerbotAI* botAI) { return new HighKingMaulgarWildFelstalkerSpawnedTrigger(botAI); }
|
||||
static Trigger* high_king_maulgar_pulling_olm_and_blindeye(PlayerbotAI* botAI) { return new HighKingMaulgarPullingOlmAndBlindeyeTrigger(botAI); }
|
||||
static Trigger* high_king_maulgar_boss_engaged_by_main_tank(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarBossEngagedByMainTankTrigger(botAI);
|
||||
}
|
||||
|
||||
static Trigger* high_king_maulgar_olm_engaged_by_first_assist_tank(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarOlmEngagedByFirstAssistTankTrigger(botAI);
|
||||
}
|
||||
|
||||
static Trigger* high_king_maulgar_blindeye_engaged_by_second_assist_tank(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarBlindeyeEngagedBySecondAssistTankTrigger(botAI);
|
||||
}
|
||||
|
||||
static Trigger* high_king_maulgar_krosh_engaged_by_mage_tank(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarKroshEngagedByMageTankTrigger(botAI);
|
||||
}
|
||||
|
||||
static Trigger* high_king_maulgar_kiggler_engaged_by_moonkin_tank(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarKigglerEngagedByMoonkinTankTrigger(botAI);
|
||||
}
|
||||
|
||||
static Trigger* high_king_maulgar_determining_kill_order(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarDeterminingKillOrderTrigger(botAI);
|
||||
}
|
||||
|
||||
static Trigger* high_king_maulgar_boss_channeling_whirlwind(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarBossChannelingWhirlwindTrigger(botAI);
|
||||
}
|
||||
|
||||
static Trigger* high_king_maulgar_krosh_casts_blast_wave(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarKroshCastsBlastWaveTrigger(botAI);
|
||||
}
|
||||
|
||||
static Trigger* high_king_maulgar_wild_fel_stalker_spawned(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarWildFelStalkerSpawnedTrigger(botAI);
|
||||
}
|
||||
|
||||
static Trigger* high_king_maulgar_pulling_ogre_council(PlayerbotAI* botAI) {
|
||||
return new HighKingMaulgarPullingOgreCouncilTrigger(botAI);
|
||||
}
|
||||
|
||||
// Gruul the Dragonkiller
|
||||
static Trigger* gruul_the_dragonkiller_boss_engaged_by_tanks(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByTanksTrigger(botAI); }
|
||||
static Trigger* gruul_the_dragonkiller_boss_engaged_by_ranged(PlayerbotAI* botAI) { return new GruulTheDragonkillerBossEngagedByRangedTrigger(botAI); }
|
||||
static Trigger* gruul_the_dragonkiller_incoming_shatter(PlayerbotAI* botAI) { return new GruulTheDragonkillerIncomingShatterTrigger(botAI); }
|
||||
static Trigger* gruul_the_dragonkiller_boss_engaged_by_tanks(PlayerbotAI* botAI) {
|
||||
return new GruulTheDragonkillerBossEngagedByTanksTrigger(botAI);
|
||||
}
|
||||
|
||||
static Trigger* gruul_the_dragonkiller_boss_engaged_by_ranged(PlayerbotAI* botAI) {
|
||||
return new GruulTheDragonkillerBossEngagedByRangedTrigger(botAI);
|
||||
}
|
||||
|
||||
static Trigger* gruul_the_dragonkiller_incoming_shatter(PlayerbotAI* botAI) {
|
||||
return new GruulTheDragonkillerIncomingShatterTrigger(botAI);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -6,154 +6,113 @@ using namespace GruulsLairHelpers;
|
||||
|
||||
// High King Maulgar Triggers
|
||||
|
||||
bool HighKingMaulgarIsMainTankTrigger::IsActive()
|
||||
bool HighKingMaulgarBossEngagedByMainTankTrigger::IsActive()
|
||||
{
|
||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||
|
||||
return botAI->IsMainTank(bot) && maulgar;
|
||||
return botAI->IsMainTank(bot) &&
|
||||
AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||
}
|
||||
|
||||
bool HighKingMaulgarIsFirstAssistTankTrigger::IsActive()
|
||||
bool HighKingMaulgarOlmEngagedByFirstAssistTankTrigger::IsActive()
|
||||
{
|
||||
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||
|
||||
return botAI->IsAssistTankOfIndex(bot, 0, false) && olm;
|
||||
return botAI->IsAssistTankOfIndex(bot, 0, false) &&
|
||||
AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||
}
|
||||
|
||||
bool HighKingMaulgarIsSecondAssistTankTrigger::IsActive()
|
||||
bool HighKingMaulgarBlindeyeEngagedBySecondAssistTankTrigger::IsActive()
|
||||
{
|
||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
|
||||
return botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye;
|
||||
return botAI->IsAssistTankOfIndex(bot, 1, false) &&
|
||||
AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
}
|
||||
|
||||
bool HighKingMaulgarIsMageTankTrigger::IsActive()
|
||||
bool HighKingMaulgarKroshEngagedByMageTankTrigger::IsActive()
|
||||
{
|
||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
|
||||
return IsKroshMageTank(bot) && krosh;
|
||||
return bot->getClass() == CLASS_MAGE &&
|
||||
AI_VALUE2(Unit*, "find target", "krosh firehand") &&
|
||||
GetKroshMageTank(bot) == bot;
|
||||
}
|
||||
|
||||
bool HighKingMaulgarIsMoonkinTankTrigger::IsActive()
|
||||
bool HighKingMaulgarKigglerEngagedByMoonkinTankTrigger::IsActive()
|
||||
{
|
||||
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
||||
|
||||
return IsKigglerMoonkinTank(bot) && kiggler;
|
||||
return bot->getClass() == CLASS_DRUID &&
|
||||
AI_VALUE2(Unit*, "find target", "kiggler the crazed") &&
|
||||
GetKigglerMoonkinTank(bot) == bot;
|
||||
}
|
||||
|
||||
bool HighKingMaulgarDeterminingKillOrderTrigger::IsActive()
|
||||
{
|
||||
if (botAI->IsHeal(bot) || botAI->IsMainTank(bot))
|
||||
return false;
|
||||
|
||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||
Unit* kiggler = AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
||||
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
Unit* krosh = AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
if (!maulgar)
|
||||
return false;
|
||||
|
||||
return (botAI->IsDps(bot) || botAI->IsTank(bot)) &&
|
||||
!(botAI->IsMainTank(bot) && maulgar) &&
|
||||
!(botAI->IsAssistTankOfIndex(bot, 0, false) && olm) &&
|
||||
!(botAI->IsAssistTankOfIndex(bot, 1, false) && blindeye) &&
|
||||
!(IsKroshMageTank(bot) && krosh) &&
|
||||
!(IsKigglerMoonkinTank(bot) && kiggler);
|
||||
}
|
||||
if (botAI->IsAssistTankOfIndex(bot, 0, false))
|
||||
return !AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||
|
||||
bool HighKingMaulgarHealerInDangerTrigger::IsActive()
|
||||
{
|
||||
return botAI->IsHeal(bot) && IsAnyOgreBossAlive(botAI);
|
||||
if (botAI->IsAssistTankOfIndex(bot, 1, false))
|
||||
return !AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
|
||||
if (bot->getClass() == CLASS_MAGE && GetKroshMageTank(bot) == bot)
|
||||
return !AI_VALUE2(Unit*, "find target", "krosh firehand");
|
||||
|
||||
if (bot->getClass() == CLASS_DRUID && GetKigglerMoonkinTank(bot) == bot)
|
||||
return !AI_VALUE2(Unit*, "find target", "kiggler the crazed");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HighKingMaulgarBossChannelingWhirlwindTrigger::IsActive()
|
||||
{
|
||||
Unit* maulgar = AI_VALUE2(Unit*, "find target", "high king maulgar");
|
||||
if (!maulgar ||
|
||||
!maulgar->HasAura(static_cast<uint32>(GruulsLairSpells::SPELL_WHIRLWIND)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return maulgar && maulgar->HasAura(SPELL_WHIRLWIND) &&
|
||||
!botAI->IsMainTank(bot);
|
||||
return !botAI->IsMainTank(bot);
|
||||
}
|
||||
|
||||
bool HighKingMaulgarWildFelstalkerSpawnedTrigger::IsActive()
|
||||
bool HighKingMaulgarKroshCastsBlastWaveTrigger::IsActive()
|
||||
{
|
||||
Unit* felStalker = AI_VALUE2(Unit*, "find target", "wild fel stalker");
|
||||
if (!AI_VALUE2(Unit*, "find target", "krosh firehand"))
|
||||
return false;
|
||||
|
||||
return felStalker && bot->getClass() == CLASS_WARLOCK;
|
||||
return !botAI->IsTank(bot) && GetKroshMageTank(bot) != bot;
|
||||
}
|
||||
|
||||
bool HighKingMaulgarPullingOlmAndBlindeyeTrigger::IsActive()
|
||||
bool HighKingMaulgarWildFelStalkerSpawnedTrigger::IsActive()
|
||||
{
|
||||
Group* group = bot->GetGroup();
|
||||
if (!group || bot->getClass() != CLASS_HUNTER)
|
||||
return bot->getClass() == CLASS_WARLOCK &&
|
||||
AI_VALUE2(Unit*, "find target", "wild fel stalker");
|
||||
}
|
||||
|
||||
bool HighKingMaulgarPullingOgreCouncilTrigger::IsActive()
|
||||
{
|
||||
if (bot->getClass() != CLASS_HUNTER)
|
||||
return false;
|
||||
|
||||
std::vector<Player*> hunters;
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (member && member->IsAlive() && member->getClass() == CLASS_HUNTER && GET_PLAYERBOT_AI(member))
|
||||
hunters.push_back(member);
|
||||
}
|
||||
|
||||
int hunterIndex = -1;
|
||||
for (size_t i = 0; i < hunters.size(); ++i)
|
||||
{
|
||||
if (hunters[i] == bot)
|
||||
{
|
||||
hunterIndex = static_cast<int>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hunterIndex == -1 || hunterIndex > 1)
|
||||
return false;
|
||||
|
||||
Unit* olm = AI_VALUE2(Unit*, "find target", "olm the summoner");
|
||||
Unit* blindeye = AI_VALUE2(Unit*, "find target", "blindeye the seer");
|
||||
Player* olmTank = nullptr;
|
||||
Player* blindeyeTank = nullptr;
|
||||
|
||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||
{
|
||||
Player* member = ref->GetSource();
|
||||
if (!member || !member->IsAlive())
|
||||
continue;
|
||||
else if (botAI->IsAssistTankOfIndex(member, 0)) olmTank = member;
|
||||
else if (botAI->IsAssistTankOfIndex(member, 1)) blindeyeTank = member;
|
||||
}
|
||||
|
||||
switch (hunterIndex)
|
||||
{
|
||||
case 0:
|
||||
return olm && olm->GetHealthPct() > 98.0f &&
|
||||
olmTank && botAI->CanCastSpell("misdirection", olmTank);
|
||||
|
||||
case 1:
|
||||
return blindeye && blindeye->GetHealthPct() > 90.0f &&
|
||||
blindeyeTank && botAI->CanCastSpell("misdirection", blindeyeTank);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
return blindeye && blindeye->GetHealthPct() > 80.0f;
|
||||
}
|
||||
|
||||
// Gruul the Dragonkiller Triggers
|
||||
|
||||
bool GruulTheDragonkillerBossEngagedByTanksTrigger::IsActive()
|
||||
{
|
||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
|
||||
return gruul && botAI->IsTank(bot);
|
||||
return botAI->IsTank(bot) &&
|
||||
AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
}
|
||||
|
||||
bool GruulTheDragonkillerBossEngagedByRangedTrigger::IsActive()
|
||||
{
|
||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
|
||||
return gruul && botAI->IsRanged(bot);
|
||||
return botAI->IsRanged(bot) &&
|
||||
AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
}
|
||||
|
||||
bool GruulTheDragonkillerIncomingShatterTrigger::IsActive()
|
||||
{
|
||||
Unit* gruul = AI_VALUE2(Unit*, "find target", "gruul the dragonkiller");
|
||||
|
||||
return gruul && (bot->HasAura(SPELL_GROUND_SLAM_1) ||
|
||||
bot->HasAura(SPELL_GROUND_SLAM_2));
|
||||
return bot->HasAura(static_cast<uint32>(GruulsLairSpells::SPELL_GROUND_SLAM_1)) ||
|
||||
bot->HasAura(static_cast<uint32>(GruulsLairSpells::SPELL_GROUND_SLAM_2));
|
||||
}
|
||||
|
||||
@ -1,96 +1,109 @@
|
||||
#ifndef PLAYERBOTS_RAIDGRUULSLAIRTRIGGERS_H
|
||||
#define PLAYERBOTS_RAIDGRUULSLAIRTRIGGERS_H
|
||||
#ifndef PLAYERBOTS_GRUULTRIGGERS_H
|
||||
#define PLAYERBOTS_GRUULTRIGGERS_H
|
||||
|
||||
#include "Trigger.h"
|
||||
|
||||
class HighKingMaulgarIsMainTankTrigger : public Trigger
|
||||
class HighKingMaulgarBossEngagedByMainTankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarIsMainTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar is main tank") {}
|
||||
HighKingMaulgarBossEngagedByMainTankTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar engaged by main tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarIsFirstAssistTankTrigger : public Trigger
|
||||
class HighKingMaulgarOlmEngagedByFirstAssistTankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarIsFirstAssistTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar is first assist tank") {}
|
||||
HighKingMaulgarOlmEngagedByFirstAssistTankTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar olm engaged by first assist tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarIsSecondAssistTankTrigger : public Trigger
|
||||
class HighKingMaulgarBlindeyeEngagedBySecondAssistTankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarIsSecondAssistTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar is second assist tank") {}
|
||||
HighKingMaulgarBlindeyeEngagedBySecondAssistTankTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar blindeye engaged by second assist tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarIsMageTankTrigger : public Trigger
|
||||
class HighKingMaulgarKroshEngagedByMageTankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarIsMageTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar is mage tank") {}
|
||||
HighKingMaulgarKroshEngagedByMageTankTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar krosh engaged by mage tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarIsMoonkinTankTrigger : public Trigger
|
||||
class HighKingMaulgarKigglerEngagedByMoonkinTankTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarIsMoonkinTankTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar is moonkin tank") {}
|
||||
HighKingMaulgarKigglerEngagedByMoonkinTankTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar kiggler engaged by moonkin tank") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarDeterminingKillOrderTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarDeterminingKillOrderTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar determining kill order") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarHealerInDangerTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarHealerInDangerTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar healers in danger") {}
|
||||
HighKingMaulgarDeterminingKillOrderTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar determining kill order") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarBossChannelingWhirlwindTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarBossChannelingWhirlwindTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar boss channeling whirlwind") {}
|
||||
HighKingMaulgarBossChannelingWhirlwindTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar boss channeling whirlwind") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarWildFelstalkerSpawnedTrigger : public Trigger
|
||||
class HighKingMaulgarKroshCastsBlastWaveTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarWildFelstalkerSpawnedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar wild felstalker spawned") {}
|
||||
HighKingMaulgarKroshCastsBlastWaveTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar krosh casts blast wave") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarPullingOlmAndBlindeyeTrigger : public Trigger
|
||||
class HighKingMaulgarWildFelStalkerSpawnedTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarPullingOlmAndBlindeyeTrigger(PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar pulling olm and blindeye") {}
|
||||
HighKingMaulgarWildFelStalkerSpawnedTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar wild fel stalker spawned") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class HighKingMaulgarPullingOgreCouncilTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
HighKingMaulgarPullingOgreCouncilTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "high king maulgar pulling ogre council") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerBossEngagedByTanksTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
GruulTheDragonkillerBossEngagedByTanksTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by tanks") {}
|
||||
GruulTheDragonkillerBossEngagedByTanksTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by tanks") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerBossEngagedByRangedTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
GruulTheDragonkillerBossEngagedByRangedTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by ranged") {}
|
||||
GruulTheDragonkillerBossEngagedByRangedTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller boss engaged by ranged") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class GruulTheDragonkillerIncomingShatterTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
GruulTheDragonkillerIncomingShatterTrigger(PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller incoming shatter") {}
|
||||
GruulTheDragonkillerIncomingShatterTrigger(
|
||||
PlayerbotAI* botAI) : Trigger(botAI, "gruul the dragonkiller incoming shatter") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user