mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
Refactor HasSpell/HasAura and convert spellIds to constants (#2435)
<!--
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 -->
This is a PR to follow-up on a discussion with @kadeshar during the
recent mage armor PR. Main changes:
- Add new PlayerbotAI::HasSpell() overload that accepts a string for the
spell name as an argument, in order to replace repeated
bot->HasSpell(spellId) checks for places where multiple ranks of a spell
are checked, and to replace a few calls to AI_VALUE(uint32, "spell id",
...) where it existed only to check for the spell being known.
- Removed PlayerbotAI::HasAura() overload that takes a spell Id as an
argument. It is rarely used, and the few instances of its usage are
easily replaced with AC's Unit::HasAura(), which is the predominant
usage for spell Id aura checks already anyway.
- When modifying DruidPullStrategy to use the new HasSpell() method, I
went ahead and also simplified the file overall to pare down duplication
(for example, the first check in CanCastSpell is for the spell Id so we
don't need to separately check it before calling CanCastSpell()). I then
did the same for other pull strategies so they can be consistent.
- Changed many magic numbers for spell Ids to be defined as compile-time
constants. I didn't do this throughout the code, but I did in the files
where I was making changes anyway due to the HasSpell() and/or HasAura()
changes.
## 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.
- Minimum logic is described above.
- Processing cost shouldn't change much. See Impact Assessment below.
## 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.
-->
## 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?
- - [ ] No, not at all
- - [x] Minimal impact (**explain below**)
- - [ ] Moderate impact (**explain below**)
- Passing a string for the spell to check for it being known or the aura
being present is more taxing than looking up a spell Id, although the
usefulness of the string-based overload is for situations with spells
that have multiple ranks.
- 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**)
- I think these changes should simplify maintenance complexity.
## 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?
- - [ ] No
- - [x] 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.
-->
- I had AI make many of the changes and then review since they were
pretty mundane (for example, I'd tell it to just take all the magic
numbers from a file and define them in an anonymous namespace, then
replace the magic numbers with the spell constants). There isn't
anything complicated in this PR; it was mostly busywork.
<!--
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
dda9ff0d40
commit
a76f2ca268
@ -422,10 +422,9 @@ bool TameAction::RenamePet(const std::string& newName)
|
|||||||
|
|
||||||
// Remove the current pet and (re-)cast Call Pet spell if the bot is a hunter
|
// Remove the current pet and (re-)cast Call Pet spell if the bot is a hunter
|
||||||
bot->RemovePet(nullptr, PET_SAVE_AS_CURRENT, true);
|
bot->RemovePet(nullptr, PET_SAVE_AS_CURRENT, true);
|
||||||
if (bot->getClass() == CLASS_HUNTER && bot->HasSpell(883))
|
constexpr uint32 SPELL_CALL_PET = 883;
|
||||||
{
|
if (bot->getClass() == CLASS_HUNTER && bot->HasSpell(SPELL_CALL_PET))
|
||||||
bot->CastSpell(bot, 883, true);
|
bot->CastSpell(bot, SPELL_CALL_PET, true);
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,9 +67,10 @@ bool TradeStatusExtendedAction::Execute(Event event)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bot->getClass() == CLASS_ROGUE && bot->HasSpell(1804) && lockbox->IsLocked()) // Pick Lock spell
|
constexpr uint32 SPELL_PICK_LOCK = 1804;
|
||||||
|
if (bot->getClass() == CLASS_ROGUE && bot->HasSpell(SPELL_PICK_LOCK) && lockbox->IsLocked())
|
||||||
{
|
{
|
||||||
// botAI->CastSpell(1804, bot, lockbox); // Attempt to cast Pick Lock on the lockbox
|
// botAI->CastSpell(SPELL_PICK_LOCK, bot, lockbox); // Attempt to cast Pick Lock on the lockbox
|
||||||
botAI->DoSpecificAction("unlock traded item");
|
botAI->DoSpecificAction("unlock traded item");
|
||||||
botAI->SetNextCheckDelay(4000); // Delay before accepting trade
|
botAI->SetNextCheckDelay(4000); // Delay before accepting trade
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,9 +23,7 @@ bool BossFireResistanceTrigger::IsActive()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if bot have fire resistance aura
|
// Check if bot have fire resistance aura
|
||||||
if (bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_5) || bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_4) ||
|
if (botAI->HasAura("fire resistance aura", bot))
|
||||||
bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_3) || bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_2) ||
|
|
||||||
bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_1))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if bot dont have already have fire resistance strategy
|
// Check if bot dont have already have fire resistance strategy
|
||||||
@ -76,9 +74,7 @@ bool BossFrostResistanceTrigger::IsActive()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if bot have frost resistance aura
|
// Check if bot have frost resistance aura
|
||||||
if (bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_5) || bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_4) ||
|
if (botAI->HasAura("frost resistance aura", bot))
|
||||||
bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_3) || bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_2) ||
|
|
||||||
bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_1))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if bot dont have already have frost resistance strategy
|
// Check if bot dont have already have frost resistance strategy
|
||||||
@ -133,8 +129,7 @@ bool BossNatureResistanceTrigger::IsActive()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if bot have nature resistance aura
|
// Check if bot have nature resistance aura
|
||||||
if (bot->HasAura(SPELL_ASPECT_OF_THE_WILD_RANK_4) || bot->HasAura(SPELL_ASPECT_OF_THE_WILD_RANK_3) ||
|
if (botAI->HasAura("aspect of the wild", bot))
|
||||||
bot->HasAura(SPELL_ASPECT_OF_THE_WILD_RANK_2) || bot->HasAura(SPELL_ASPECT_OF_THE_WILD_RANK_1))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if bot dont have already setted nature resistance aura
|
// Check if bot dont have already setted nature resistance aura
|
||||||
@ -184,11 +179,7 @@ bool BossShadowResistanceTrigger::IsActive()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if bot have shadow resistance aura
|
// Check if bot have shadow resistance aura
|
||||||
if (bot->HasAura(SPELL_SHADOW_RESISTANCE_AURA_RANK_5) ||
|
if (botAI->HasAura("shadow resistance aura", bot))
|
||||||
bot->HasAura(SPELL_SHADOW_RESISTANCE_AURA_RANK_4) ||
|
|
||||||
bot->HasAura(SPELL_SHADOW_RESISTANCE_AURA_RANK_3) ||
|
|
||||||
bot->HasAura(SPELL_SHADOW_RESISTANCE_AURA_RANK_2) ||
|
|
||||||
bot->HasAura(SPELL_SHADOW_RESISTANCE_AURA_RANK_1))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Check if bot dont have already have shadow resistance strategy
|
// Check if bot dont have already have shadow resistance strategy
|
||||||
|
|||||||
@ -5,39 +5,27 @@
|
|||||||
|
|
||||||
#include "DeathKnightPullStrategy.h"
|
#include "DeathKnightPullStrategy.h"
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
std::string DeathKnightPullStrategy::GetPullActionName() const
|
std::string DeathKnightPullStrategy::GetPullActionName() const
|
||||||
{
|
{
|
||||||
Player* bot = botAI->GetBot();
|
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!bot || !target ||
|
if (!target ||
|
||||||
(!botAI->HasStrategy("blood", BOT_STATE_COMBAT) && !botAI->HasStrategy("blood", BOT_STATE_NON_COMBAT)))
|
(!botAI->HasStrategy("blood", BOT_STATE_COMBAT) && !botAI->HasStrategy("blood", BOT_STATE_NON_COMBAT)))
|
||||||
{
|
{
|
||||||
return PullStrategy::GetPullActionName();
|
return PullStrategy::GetPullActionName();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 const deathGripSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "death grip")->Get();
|
if (botAI->CanCastSpell("death grip", target))
|
||||||
if (deathGripSpellId && bot->HasSpell(deathGripSpellId) &&
|
|
||||||
botAI->CanCastSpell(deathGripSpellId, target))
|
|
||||||
{
|
|
||||||
return "death grip";
|
return "death grip";
|
||||||
}
|
|
||||||
|
|
||||||
uint32 const icyTouchSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "icy touch")->Get();
|
if (!botAI->CanCastSpell("icy touch", target) &&
|
||||||
if (!icyTouchSpellId || !bot->HasSpell(icyTouchSpellId) ||
|
botAI->CanCastSpell("dark command", target))
|
||||||
!botAI->CanCastSpell(icyTouchSpellId, target))
|
|
||||||
{
|
|
||||||
uint32 const darkCommandSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "dark command")->Get();
|
|
||||||
if (darkCommandSpellId && bot->HasSpell(darkCommandSpellId) &&
|
|
||||||
botAI->CanCastSpell(darkCommandSpellId, target))
|
|
||||||
{
|
{
|
||||||
return "dark command";
|
return "dark command";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return PullStrategy::GetPullActionName();
|
return PullStrategy::GetPullActionName();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -50,9 +50,10 @@ bool CastCancelDruidAction::Execute(Event /*event*/)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CastCancelDruidAction::isUseful() { return botAI->HasAura(auraId, bot); }
|
bool CastCancelDruidAction::isUseful() { return bot->HasAura(auraId); }
|
||||||
|
|
||||||
bool CastTreeFormAction::isUseful()
|
bool CastTreeFormAction::isUseful()
|
||||||
{
|
{
|
||||||
return GetTarget() && CastSpellAction::isUseful() && !botAI->HasAura(33891, bot);
|
constexpr uint32 SPELL_TREE_OF_LIFE = 33891;
|
||||||
|
return GetTarget() && CastSpellAction::isUseful() && !bot->HasAura(SPELL_TREE_OF_LIFE);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,11 @@ bool ThornsTrigger::IsActive() { return BuffTrigger::IsActive() && !botAI->HasAu
|
|||||||
|
|
||||||
bool BearFormTrigger::IsActive() { return !botAI->HasAnyAuraOf(bot, "bear form", "dire bear form", nullptr); }
|
bool BearFormTrigger::IsActive() { return !botAI->HasAnyAuraOf(bot, "bear form", "dire bear form", nullptr); }
|
||||||
|
|
||||||
bool TreeFormTrigger::IsActive() { return !botAI->HasAura(33891, bot); }
|
bool TreeFormTrigger::IsActive()
|
||||||
|
{
|
||||||
|
constexpr uint32 SPELL_TREE_OF_LIFE = 33891;
|
||||||
|
return !bot->HasAura(SPELL_TREE_OF_LIFE);
|
||||||
|
}
|
||||||
|
|
||||||
bool CatFormTrigger::IsActive() { return !botAI->HasAura("cat form", bot); }
|
bool CatFormTrigger::IsActive() { return !botAI->HasAura("cat form", bot); }
|
||||||
|
|
||||||
@ -43,8 +47,11 @@ bool ProwlTrigger::IsActive()
|
|||||||
if (botAI->HasAura("prowl", bot) || bot->IsInCombat())
|
if (botAI->HasAura("prowl", bot) || bot->IsInCombat())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint32 prowlId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "prowl")->Get();
|
if (!botAI->HasSpell("prowl"))
|
||||||
if (!prowlId || !bot->HasSpell(prowlId) || bot->HasSpellCooldown(prowlId))
|
return false;
|
||||||
|
|
||||||
|
uint32 const prowlId = AI_VALUE2(uint32, "spell id", "prowl");
|
||||||
|
if (bot->HasSpellCooldown(prowlId))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
float distance = 30.f;
|
float distance = 30.f;
|
||||||
|
|||||||
@ -393,14 +393,14 @@ public:
|
|||||||
class FerociousBiteExecuteTrigger : public Trigger
|
class FerociousBiteExecuteTrigger : public Trigger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FerociousBiteExecuteTrigger(PlayerbotAI* ai) : Trigger(ai, "ferocious bite execute") {}
|
FerociousBiteExecuteTrigger(PlayerbotAI* botAI) : Trigger(botAI, "ferocious bite execute") {}
|
||||||
bool IsActive() override
|
bool IsActive() override
|
||||||
{
|
{
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
if (!target || !target->IsAlive())
|
if (!target || !target->IsAlive())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!AI_VALUE2(uint32, "spell id", "ferocious bite"))
|
if (!botAI->HasSpell("ferocious bite"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (AI_VALUE2(uint8, "combo", "current target") < 1)
|
if (AI_VALUE2(uint8, "combo", "current target") < 1)
|
||||||
|
|||||||
@ -5,34 +5,23 @@
|
|||||||
|
|
||||||
#include "DruidPullStrategy.h"
|
#include "DruidPullStrategy.h"
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Player.h"
|
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
std::string DruidPullStrategy::GetPullActionName() const
|
std::string DruidPullStrategy::GetPullActionName() const
|
||||||
{
|
{
|
||||||
Player* bot = botAI->GetBot();
|
std::string const pullActionName = PullStrategy::GetPullActionName();
|
||||||
std::string actionName = PullStrategy::GetPullActionName();
|
std::string const actionName =
|
||||||
if (!bot)
|
botAI->HasSpell("faerie fire (feral)") &&
|
||||||
return actionName;
|
(botAI->HasStrategy("bear", BOT_STATE_COMBAT) || botAI->HasStrategy("cat", BOT_STATE_COMBAT))
|
||||||
|
? "faerie fire (feral)" : pullActionName;
|
||||||
uint32 const faerieFireFeralId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "faerie fire (feral)")->Get();
|
|
||||||
if (faerieFireFeralId && bot->HasSpell(faerieFireFeralId) &&
|
|
||||||
(botAI->HasStrategy("bear", BOT_STATE_COMBAT) || botAI->HasStrategy("cat", BOT_STATE_COMBAT)))
|
|
||||||
{
|
|
||||||
actionName = "faerie fire (feral)";
|
|
||||||
}
|
|
||||||
|
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
uint32 const faerieFireSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", actionName)->Get();
|
if (!target)
|
||||||
if (target && (!faerieFireSpellId || !bot->HasSpell(faerieFireSpellId) ||
|
return actionName;
|
||||||
!botAI->CanCastSpell(faerieFireSpellId, target)))
|
|
||||||
{
|
if (!botAI->CanCastSpell(actionName, target) && botAI->CanCastSpell("growl", target))
|
||||||
uint32 const growlSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "growl")->Get();
|
|
||||||
if (growlSpellId && bot->HasSpell(growlSpellId) && botAI->CanCastSpell(growlSpellId, target))
|
|
||||||
return "growl";
|
return "growl";
|
||||||
}
|
|
||||||
|
|
||||||
return actionName;
|
return actionName;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,23 +19,13 @@ bool CastViperStingAction::isUseful()
|
|||||||
bool CastAspectOfTheHawkAction::isUseful()
|
bool CastAspectOfTheHawkAction::isUseful()
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
return target && !botAI->HasSpell("aspect of the dragonhawk");
|
||||||
return false;
|
|
||||||
|
|
||||||
if (bot->HasSpell(61846) || bot->HasSpell(61847)) // Aspect of the Dragonhawk spell IDs
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CastArcaneShotAction::isUseful()
|
bool CastArcaneShotAction::isUseful()
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
if (!target || !botAI->HasSpell("explosive shot"))
|
||||||
return false;
|
|
||||||
|
|
||||||
if (bot->HasSpell(53301) || bot->HasSpell(60051) ||
|
|
||||||
bot->HasSpell(60052) || bot->HasSpell(60053)) // Explosive Shot spell IDs
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Armor Penetration rating check - will not cast Arcane Shot above 435 ArP
|
// Armor Penetration rating check - will not cast Arcane Shot above 435 ArP
|
||||||
@ -50,14 +40,7 @@ bool CastArcaneShotAction::isUseful()
|
|||||||
bool CastImmolationTrapAction::isUseful()
|
bool CastImmolationTrapAction::isUseful()
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
return target && !botAI->HasSpell("explosive trap");
|
||||||
return false;
|
|
||||||
|
|
||||||
if (bot->HasSpell(13813) || bot->HasSpell(14316) || bot->HasSpell(14317) || bot->HasSpell(27025) ||
|
|
||||||
bot->HasSpell(49066) || bot->HasSpell(49067)) // Explosive Trap spell IDs
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Value<Unit*>* CastFreezingTrap::GetTargetValue()
|
Value<Unit*>* CastFreezingTrap::GetTargetValue()
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
std::vector<NextAction> CastMoltenArmorAction::getAlternatives()
|
std::vector<NextAction> CastMoltenArmorAction::getAlternatives()
|
||||||
{
|
{
|
||||||
if (!AI_VALUE2(uint32, "spell id", "molten armor"))
|
if (!botAI->HasSpell("molten armor"))
|
||||||
return NextAction::merge({ NextAction("mage armor") }, CastBuffSpellAction::getAlternatives());
|
return NextAction::merge({ NextAction("mage armor") }, CastBuffSpellAction::getAlternatives());
|
||||||
|
|
||||||
return CastBuffSpellAction::getAlternatives();
|
return CastBuffSpellAction::getAlternatives();
|
||||||
@ -21,7 +21,7 @@ std::vector<NextAction> CastMoltenArmorAction::getAlternatives()
|
|||||||
|
|
||||||
std::vector<NextAction> CastMageArmorAction::getAlternatives()
|
std::vector<NextAction> CastMageArmorAction::getAlternatives()
|
||||||
{
|
{
|
||||||
if (!AI_VALUE2(uint32, "spell id", "mage armor"))
|
if (!botAI->HasSpell("mage armor"))
|
||||||
return NextAction::merge({ NextAction("ice armor") }, CastBuffSpellAction::getAlternatives());
|
return NextAction::merge({ NextAction("ice armor") }, CastBuffSpellAction::getAlternatives());
|
||||||
|
|
||||||
return CastBuffSpellAction::getAlternatives();
|
return CastBuffSpellAction::getAlternatives();
|
||||||
|
|||||||
@ -39,26 +39,16 @@ bool ArcaneIntellectTrigger::IsActive()
|
|||||||
bool MageArmorTrigger::IsActive()
|
bool MageArmorTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (botAI->HasAura("mage armor", target))
|
return botAI->HasSpell("mage armor") && !botAI->HasAura("mage armor", target) &&
|
||||||
return false;
|
!botAI->HasAura("ice armor", target) && !botAI->HasAura("frost armor", target) &&
|
||||||
|
|
||||||
if (AI_VALUE2(uint32, "spell id", "mage armor"))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return !botAI->HasAura("ice armor", target) && !botAI->HasAura("frost armor", target) &&
|
|
||||||
!botAI->HasAura("molten armor", target);
|
!botAI->HasAura("molten armor", target);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MoltenArmorTrigger::IsActive()
|
bool MoltenArmorTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (botAI->HasAura("molten armor", target))
|
return botAI->HasSpell("molten armor") && !botAI->HasAura("molten armor", target) &&
|
||||||
return false;
|
!botAI->HasAura("ice armor", target) && !botAI->HasAura("frost armor", target) &&
|
||||||
|
|
||||||
if (AI_VALUE2(uint32, "spell id", "molten armor"))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return !botAI->HasAura("ice armor", target) && !botAI->HasAura("frost armor", target) &&
|
|
||||||
!botAI->HasAura("mage armor", target);
|
!botAI->HasAura("mage armor", target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +72,8 @@ bool FrostbiteOnTargetTrigger::IsActive()
|
|||||||
|
|
||||||
bool NoFocusMagicTrigger::IsActive()
|
bool NoFocusMagicTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!bot->HasSpell(54646)) // Focus Magic
|
constexpr uint32 SPELL_FOCUS_MAGIC = 54646;
|
||||||
|
if (!bot->HasSpell(SPELL_FOCUS_MAGIC))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
@ -95,7 +86,7 @@ bool NoFocusMagicTrigger::IsActive()
|
|||||||
if (!member || member == bot || !member->IsAlive())
|
if (!member || member == bot || !member->IsAlive())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (member->HasAura(54646, bot->GetGUID()))
|
if (member->HasAura(SPELL_FOCUS_MAGIC, bot->GetGUID()))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -103,11 +94,9 @@ bool NoFocusMagicTrigger::IsActive()
|
|||||||
|
|
||||||
bool DeepFreezeCooldownTrigger::IsActive()
|
bool DeepFreezeCooldownTrigger::IsActive()
|
||||||
{
|
{
|
||||||
// If the bot does NOT have Deep Freeze, treat as "on cooldown"
|
constexpr uint32 SPELL_DEEP_FREEZE = 44572;
|
||||||
if (!bot->HasSpell(44572)) // Deep Freeze
|
return !bot->HasSpell(SPELL_DEEP_FREEZE) ||
|
||||||
return true;
|
SpellCooldownTrigger::IsActive();
|
||||||
|
|
||||||
return SpellCooldownTrigger::IsActive();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_set<uint32> FlamestrikeNearbyTrigger::FLAMESTRIKE_SPELL_IDS = {
|
const std::unordered_set<uint32> FlamestrikeNearbyTrigger::FLAMESTRIKE_SPELL_IDS = {
|
||||||
|
|||||||
@ -8,6 +8,18 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "RangedCombatStrategy.h"
|
#include "RangedCombatStrategy.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr uint32 SPELL_CONJURE_MANA_SAPPHIRE = 42985;
|
||||||
|
constexpr uint32 SPELL_CONJURE_MANA_EMERALD = 27101;
|
||||||
|
constexpr uint32 SPELL_CONJURE_MANA_RUBY = 10054;
|
||||||
|
constexpr uint32 SPELL_CONJURE_MANA_CITRINE = 10053;
|
||||||
|
constexpr uint32 SPELL_CONJURE_MANA_JADE = 3552;
|
||||||
|
constexpr uint32 SPELL_CONJURE_MANA_AGATE = 759;
|
||||||
|
constexpr uint32 SPELL_FROSTFIRE_BOLT = 44614;
|
||||||
|
constexpr uint32 SPELL_ICE_SHARDS = 15047;
|
||||||
|
}
|
||||||
|
|
||||||
class GenericMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
class GenericMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -102,17 +114,17 @@ void GenericMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
|
|
||||||
// Mana Threshold Triggers
|
// Mana Threshold Triggers
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
if (bot->HasSpell(42985)) // Mana Sapphire
|
if (bot->HasSpell(SPELL_CONJURE_MANA_SAPPHIRE))
|
||||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana sapphire", 90.0f) }));
|
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana sapphire", 90.0f) }));
|
||||||
else if (bot->HasSpell(27101)) // Mana Emerald
|
else if (bot->HasSpell(SPELL_CONJURE_MANA_EMERALD))
|
||||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana emerald", 90.0f) }));
|
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana emerald", 90.0f) }));
|
||||||
else if (bot->HasSpell(10054)) // Mana Ruby
|
else if (bot->HasSpell(SPELL_CONJURE_MANA_RUBY))
|
||||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana ruby", 90.0f) }));
|
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana ruby", 90.0f) }));
|
||||||
else if (bot->HasSpell(10053)) // Mana Citrine
|
else if (bot->HasSpell(SPELL_CONJURE_MANA_CITRINE))
|
||||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana citrine", 90.0f) }));
|
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana citrine", 90.0f) }));
|
||||||
else if (bot->HasSpell(3552)) // Mana Jade
|
else if (bot->HasSpell(SPELL_CONJURE_MANA_JADE))
|
||||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana jade", 90.0f) }));
|
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana jade", 90.0f) }));
|
||||||
else if (bot->HasSpell(759)) // Mana Agate
|
else if (bot->HasSpell(SPELL_CONJURE_MANA_AGATE))
|
||||||
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana agate", 90.0f) }));
|
triggers.push_back(new TriggerNode("high mana", { NextAction("use mana agate", 90.0f) }));
|
||||||
|
|
||||||
triggers.push_back(new TriggerNode("medium mana", { NextAction("mana potion", 90.0f) }));
|
triggers.push_back(new TriggerNode("medium mana", { NextAction("mana potion", 90.0f) }));
|
||||||
@ -142,7 +154,7 @@ void MageBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
}
|
}
|
||||||
else if (tab == MAGE_TAB_FIRE)
|
else if (tab == MAGE_TAB_FIRE)
|
||||||
{
|
{
|
||||||
if (bot->HasSpell(44614) /*Frostfire Bolt*/ && bot->HasAura(15047) /*Ice Shards*/)
|
if (bot->HasSpell(SPELL_FROSTFIRE_BOLT) && bot->HasAura(SPELL_ICE_SHARDS))
|
||||||
{ // Frostfire
|
{ // Frostfire
|
||||||
triggers.push_back(new TriggerNode("combustion", { NextAction("combustion", 18.0f) }));
|
triggers.push_back(new TriggerNode("combustion", { NextAction("combustion", 18.0f) }));
|
||||||
triggers.push_back(new TriggerNode("icy veins", { NextAction("icy veins", 17.5f) }));
|
triggers.push_back(new TriggerNode("icy veins", { NextAction("icy veins", 17.5f) }));
|
||||||
|
|||||||
@ -1145,8 +1145,7 @@ bool CastGreaterBlessingAssignmentAction::Execute(Event /*event*/)
|
|||||||
if (!FindPendingAssignment(assignment, spellName))
|
if (!FindPendingAssignment(assignment, spellName))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uint32 finalId = AI_VALUE2(uint32, "spell id", spellName);
|
if (!botAI->HasSpell(spellName))
|
||||||
if (!finalId)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return botAI->CastSpell(spellName, assignment.player);
|
return botAI->CastSpell(spellName, assignment.player);
|
||||||
|
|||||||
@ -5,34 +5,23 @@
|
|||||||
|
|
||||||
#include "PaladinPullStrategy.h"
|
#include "PaladinPullStrategy.h"
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Player.h"
|
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
std::string PaladinPullStrategy::GetPullActionName() const
|
std::string PaladinPullStrategy::GetPullActionName() const
|
||||||
{
|
{
|
||||||
Player* bot = botAI->GetBot();
|
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!bot || !target ||
|
if (!target ||
|
||||||
(!botAI->HasStrategy("tank", BOT_STATE_COMBAT) && !botAI->HasStrategy("tank", BOT_STATE_NON_COMBAT)))
|
(!botAI->HasStrategy("tank", BOT_STATE_COMBAT) && !botAI->HasStrategy("tank", BOT_STATE_NON_COMBAT)))
|
||||||
{
|
{
|
||||||
return PullStrategy::GetPullActionName();
|
return PullStrategy::GetPullActionName();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 const avengersShieldSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "avenger's shield")->Get();
|
if (botAI->CanCastSpell("avenger's shield", target))
|
||||||
if (avengersShieldSpellId && bot->HasSpell(avengersShieldSpellId) &&
|
|
||||||
botAI->CanCastSpell(avengersShieldSpellId, target))
|
|
||||||
{
|
|
||||||
return "avenger's shield";
|
return "avenger's shield";
|
||||||
}
|
|
||||||
|
|
||||||
uint32 const handOfReckoningSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "hand of reckoning")->Get();
|
if (botAI->CanCastSpell("hand of reckoning", target))
|
||||||
if (handOfReckoningSpellId && bot->HasSpell(handOfReckoningSpellId) &&
|
|
||||||
botAI->CanCastSpell(handOfReckoningSpellId, target))
|
|
||||||
{
|
|
||||||
return "hand of reckoning";
|
return "hand of reckoning";
|
||||||
}
|
|
||||||
|
|
||||||
return PullStrategy::GetPullActionName();
|
return PullStrategy::GetPullActionName();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,14 @@
|
|||||||
#include "PlayerbotAIConfig.h"
|
#include "PlayerbotAIConfig.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr uint32 SPELL_WARSONG_FLAG = 23333;
|
||||||
|
constexpr uint32 SPELL_SILVERWING_FLAG = 23335;
|
||||||
|
constexpr uint32 SPELL_NETHERSTORM_FLAG = 34976;
|
||||||
|
constexpr uint32 SPELL_MASTER_POISONER_RANK_3 = 58410;
|
||||||
|
}
|
||||||
|
|
||||||
bool CastStealthAction::isUseful()
|
bool CastStealthAction::isUseful()
|
||||||
{
|
{
|
||||||
Unit* target = AI_VALUE(Unit*, "current target");
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
@ -22,7 +30,8 @@ bool CastStealthAction::isUseful()
|
|||||||
bool CastStealthAction::isPossible()
|
bool CastStealthAction::isPossible()
|
||||||
{
|
{
|
||||||
// do not use with WSG flag or EYE flag
|
// do not use with WSG flag or EYE flag
|
||||||
return !botAI->HasAura(23333, bot) && !botAI->HasAura(23335, bot) && !botAI->HasAura(34976, bot);
|
return !bot->HasAura(SPELL_WARSONG_FLAG) && !bot->HasAura(SPELL_SILVERWING_FLAG) &&
|
||||||
|
!bot->HasAura(SPELL_NETHERSTORM_FLAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnstealthAction::Execute(Event /*event*/)
|
bool UnstealthAction::Execute(Event /*event*/)
|
||||||
@ -50,7 +59,8 @@ bool CheckStealthAction::Execute(Event /*event*/)
|
|||||||
bool CastVanishAction::isUseful()
|
bool CastVanishAction::isUseful()
|
||||||
{
|
{
|
||||||
// do not use with WSG flag or EYE flag
|
// do not use with WSG flag or EYE flag
|
||||||
return !botAI->HasAura(23333, bot) && !botAI->HasAura(23335, bot) && !botAI->HasAura(34976, bot);
|
return !bot->HasAura(SPELL_WARSONG_FLAG) && !bot->HasAura(SPELL_SILVERWING_FLAG) &&
|
||||||
|
!bot->HasAura(SPELL_NETHERSTORM_FLAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CastEnvenomAction::isUseful()
|
bool CastEnvenomAction::isUseful()
|
||||||
@ -61,7 +71,7 @@ bool CastEnvenomAction::isUseful()
|
|||||||
bool CastEnvenomAction::isPossible()
|
bool CastEnvenomAction::isPossible()
|
||||||
{
|
{
|
||||||
// alternate to eviscerate if talents unlearned
|
// alternate to eviscerate if talents unlearned
|
||||||
return botAI->HasAura(58410, bot) /* Master Poisoner Rank 3 */;
|
return bot->HasAura(SPELL_MASTER_POISONER_RANK_3);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CastTricksOfTheTradeOnMainTankAction::isUseful()
|
bool CastTricksOfTheTradeOnMainTankAction::isUseful()
|
||||||
|
|||||||
@ -9,6 +9,12 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "ServerFacade.h"
|
#include "ServerFacade.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr uint32 SPELL_STEALTH = 1784;
|
||||||
|
constexpr uint32 SPELL_SPRINT_RANK_1 = 2983;
|
||||||
|
}
|
||||||
|
|
||||||
// bool AdrenalineRushTrigger::isPossible()
|
// bool AdrenalineRushTrigger::isPossible()
|
||||||
// {
|
// {
|
||||||
// return !botAI->HasAura("stealth", bot);
|
// return !botAI->HasAura("stealth", bot);
|
||||||
@ -29,7 +35,7 @@ bool UnstealthTrigger::IsActive()
|
|||||||
|
|
||||||
bool StealthTrigger::IsActive()
|
bool StealthTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (botAI->HasAura("stealth", bot) || bot->IsInCombat() || bot->HasSpellCooldown(1784))
|
if (bot->HasAura(SPELL_STEALTH) || bot->IsInCombat() || bot->HasSpellCooldown(SPELL_STEALTH))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
float distance = 30.f;
|
float distance = 30.f;
|
||||||
@ -63,13 +69,13 @@ bool StealthTrigger::IsActive()
|
|||||||
return target && ServerFacade::instance().GetDistance2d(bot, target) < distance;
|
return target && ServerFacade::instance().GetDistance2d(bot, target) < distance;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SapTrigger::IsPossible() { return bot->GetLevel() > 10 && bot->HasSpell(6770) && !bot->IsInCombat(); }
|
bool SapTrigger::IsPossible() { return bot->GetLevel() > 10 && botAI->HasSpell("sap") && !bot->IsInCombat(); }
|
||||||
|
|
||||||
bool SprintTrigger::IsPossible() { return bot->HasSpell(2983); }
|
bool SprintTrigger::IsPossible() { return bot->HasSpell(SPELL_SPRINT_RANK_1); }
|
||||||
|
|
||||||
bool SprintTrigger::IsActive()
|
bool SprintTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (bot->HasSpellCooldown(2983))
|
if (bot->HasSpellCooldown(SPELL_SPRINT_RANK_1))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
float distance = botAI->GetMaster() ? 45.0f : 35.0f;
|
float distance = botAI->GetMaster() ? 45.0f : 35.0f;
|
||||||
@ -105,7 +111,7 @@ bool SprintTrigger::IsActive()
|
|||||||
|
|
||||||
bool ExposeArmorTrigger::IsActive()
|
bool ExposeArmorTrigger::IsActive()
|
||||||
{
|
{
|
||||||
Unit* target = AI_VALUE(Unit*, "current target"); // Get the bot's current target
|
Unit* target = AI_VALUE(Unit*, "current target");
|
||||||
return DebuffTrigger::IsActive() && !botAI->HasAura("sunder armor", target, false, false, -1, true) &&
|
return DebuffTrigger::IsActive() && !botAI->HasAura("sunder armor", target, false, false, -1, true) &&
|
||||||
AI_VALUE2(uint8, "combo", "current target") <= 3;
|
AI_VALUE2(uint8, "combo", "current target") <= 3;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,17 @@
|
|||||||
#include "TotemsShamanStrategy.h"
|
#include "TotemsShamanStrategy.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr uint32 SPELL_TOTEM_OF_WRATH = 30706;
|
||||||
|
constexpr uint32 SPELL_FLAMETONGUE_TOTEM = 8227;
|
||||||
|
constexpr uint32 SPELL_CLEANSING_TOTEM = 8170;
|
||||||
|
constexpr uint32 SPELL_MANA_SPRING_TOTEM = 5675;
|
||||||
|
constexpr uint32 SPELL_WRATH_OF_AIR_TOTEM = 3738;
|
||||||
|
constexpr uint32 SPELL_GROUNDING_TOTEM = 8177;
|
||||||
|
constexpr uint32 SPELL_WINDFURY_TOTEM = 8512;
|
||||||
|
}
|
||||||
|
|
||||||
// These combat strategies are used to set the corresponding totems on the bar, and cast the totem when it's missing.
|
// These combat strategies are used to set the corresponding totems on the bar, and cast the totem when it's missing.
|
||||||
// There are special cases for Totem of Wrath, Windfury Totem, Wrath of Air totem, and Cleansing totem - these totems
|
// There are special cases for Totem of Wrath, Windfury Totem, Wrath of Air totem, and Cleansing totem - these totems
|
||||||
// aren't learned at level 30, and have fallbacks in order to prevent the trigger from continuously firing.
|
// aren't learned at level 30, and have fallbacks in order to prevent the trigger from continuously firing.
|
||||||
@ -74,9 +85,9 @@ void TotemOfWrathStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
GenericShamanStrategy::InitTriggers(triggers);
|
GenericShamanStrategy::InitTriggers(triggers);
|
||||||
// If the bot hasn't learned Totem of Wrath yet, set Flametongue Totem instead.
|
// If the bot hasn't learned Totem of Wrath yet, set Flametongue Totem instead.
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
if (bot->HasSpell(30706))
|
if (bot->HasSpell(SPELL_TOTEM_OF_WRATH))
|
||||||
triggers.push_back(new TriggerNode("set totem of wrath", { NextAction("set totem of wrath", 60.0f) }));
|
triggers.push_back(new TriggerNode("set totem of wrath", { NextAction("set totem of wrath", 60.0f) }));
|
||||||
else if (bot->HasSpell(8227))
|
else if (bot->HasSpell(SPELL_FLAMETONGUE_TOTEM))
|
||||||
triggers.push_back(new TriggerNode("set flametongue totem", { NextAction("set flametongue totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set flametongue totem", { NextAction("set flametongue totem", 60.0f) }));
|
||||||
triggers.push_back(new TriggerNode("no fire totem", { NextAction("totem of wrath", 55.0f) }));
|
triggers.push_back(new TriggerNode("no fire totem", { NextAction("totem of wrath", 55.0f) }));
|
||||||
}
|
}
|
||||||
@ -112,9 +123,9 @@ void CleansingTotemStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
GenericShamanStrategy::InitTriggers(triggers);
|
GenericShamanStrategy::InitTriggers(triggers);
|
||||||
// If the bot hasn't learned Cleansing Totem yet, set Mana Spring Totem instead.
|
// If the bot hasn't learned Cleansing Totem yet, set Mana Spring Totem instead.
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
if (bot->HasSpell(8170))
|
if (bot->HasSpell(SPELL_CLEANSING_TOTEM))
|
||||||
triggers.push_back(new TriggerNode("set cleansing totem", { NextAction("set cleansing totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set cleansing totem", { NextAction("set cleansing totem", 60.0f) }));
|
||||||
else if (bot->HasSpell(5675))
|
else if (bot->HasSpell(SPELL_MANA_SPRING_TOTEM))
|
||||||
triggers.push_back(new TriggerNode("set mana spring totem", { NextAction("set mana spring totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set mana spring totem", { NextAction("set mana spring totem", 60.0f) }));
|
||||||
triggers.push_back(new TriggerNode("no water totem", { NextAction("cleansing totem", 55.0f) }));
|
triggers.push_back(new TriggerNode("no water totem", { NextAction("cleansing totem", 55.0f) }));
|
||||||
}
|
}
|
||||||
@ -134,9 +145,9 @@ void WrathOfAirTotemStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
GenericShamanStrategy::InitTriggers(triggers);
|
GenericShamanStrategy::InitTriggers(triggers);
|
||||||
// If the bot hasn't learned Wrath of Air Totem yet, set Grounding Totem instead.
|
// If the bot hasn't learned Wrath of Air Totem yet, set Grounding Totem instead.
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
if (bot->HasSpell(3738))
|
if (bot->HasSpell(SPELL_WRATH_OF_AIR_TOTEM))
|
||||||
triggers.push_back(new TriggerNode("set wrath of air totem", { NextAction("set wrath of air totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set wrath of air totem", { NextAction("set wrath of air totem", 60.0f) }));
|
||||||
else if (bot->HasSpell(8177))
|
else if (bot->HasSpell(SPELL_GROUNDING_TOTEM))
|
||||||
triggers.push_back(new TriggerNode("set grounding totem", { NextAction("set grounding totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set grounding totem", { NextAction("set grounding totem", 60.0f) }));
|
||||||
triggers.push_back( new TriggerNode("no air totem", { NextAction("wrath of air totem", 55.0f) }));
|
triggers.push_back( new TriggerNode("no air totem", { NextAction("wrath of air totem", 55.0f) }));
|
||||||
}
|
}
|
||||||
@ -147,9 +158,9 @@ void WindfuryTotemStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
|||||||
GenericShamanStrategy::InitTriggers(triggers);
|
GenericShamanStrategy::InitTriggers(triggers);
|
||||||
// If the bot hasn't learned Windfury Totem yet, set Grounding Totem instead.
|
// If the bot hasn't learned Windfury Totem yet, set Grounding Totem instead.
|
||||||
Player* bot = botAI->GetBot();
|
Player* bot = botAI->GetBot();
|
||||||
if (bot->HasSpell(8512))
|
if (bot->HasSpell(SPELL_WINDFURY_TOTEM))
|
||||||
triggers.push_back(new TriggerNode("set windfury totem", { NextAction("set windfury totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set windfury totem", { NextAction("set windfury totem", 60.0f) }));
|
||||||
else if (bot->HasSpell(8177))
|
else if (bot->HasSpell(SPELL_GROUNDING_TOTEM))
|
||||||
triggers.push_back(new TriggerNode("set grounding totem", { NextAction("set grounding totem", 60.0f) }));
|
triggers.push_back(new TriggerNode("set grounding totem", { NextAction("set grounding totem", 60.0f) }));
|
||||||
triggers.push_back(new TriggerNode("no air totem", { NextAction("windfury totem", 55.0f) }));
|
triggers.push_back(new TriggerNode("no air totem", { NextAction("windfury totem", 55.0f) }));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -77,11 +77,7 @@ bool CastShadowflameAction::isUseful()
|
|||||||
bool CastRainOfFireAction::isUseful()
|
bool CastRainOfFireAction::isUseful()
|
||||||
{
|
{
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!target)
|
return target && !botAI->HasSpell("seed of corruption");
|
||||||
return false;
|
|
||||||
if (bot->HasSpell(27243) || bot->HasSpell(47835) || bot->HasSpell(47836)) // Seed of Corruption spell IDs
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the enemies are close enough to use Hellfire
|
// Checks if the enemies are close enough to use Hellfire
|
||||||
|
|||||||
@ -104,10 +104,8 @@ bool LifeTapTrigger::IsActive()
|
|||||||
// Checks if the Life Tap Glyph buff is active
|
// Checks if the Life Tap Glyph buff is active
|
||||||
bool LifeTapGlyphBuffTrigger::IsActive()
|
bool LifeTapGlyphBuffTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!botAI->HasAura(63320, bot))
|
constexpr uint32 SPELL_LIFE_TAP_GLYPH = 63320;
|
||||||
return false;
|
return bot->HasAura(SPELL_LIFE_TAP_GLYPH) && BuffTrigger::IsActive();
|
||||||
|
|
||||||
return BuffTrigger::IsActive();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if the target has a conflicting debuff that is equal to Curse of the Elements
|
// Checks if the target has a conflicting debuff that is equal to Curse of the Elements
|
||||||
|
|||||||
@ -5,23 +5,16 @@
|
|||||||
|
|
||||||
#include "WarriorPullStrategy.h"
|
#include "WarriorPullStrategy.h"
|
||||||
|
|
||||||
#include "AiObjectContext.h"
|
|
||||||
#include "Player.h"
|
|
||||||
#include "PlayerbotAI.h"
|
#include "PlayerbotAI.h"
|
||||||
|
|
||||||
std::string WarriorPullStrategy::GetPullActionName() const
|
std::string WarriorPullStrategy::GetPullActionName() const
|
||||||
{
|
{
|
||||||
Player* bot = botAI->GetBot();
|
|
||||||
Unit* target = GetTarget();
|
Unit* target = GetTarget();
|
||||||
if (!bot || !target)
|
if (!target)
|
||||||
return PullStrategy::GetPullActionName();
|
return PullStrategy::GetPullActionName();
|
||||||
|
|
||||||
uint32 const heroicThrowSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "heroic throw")->Get();
|
if (botAI->CanCastSpell("heroic throw", target))
|
||||||
if (heroicThrowSpellId && bot->HasSpell(heroicThrowSpellId) &&
|
|
||||||
botAI->CanCastSpell(heroicThrowSpellId, target))
|
|
||||||
{
|
|
||||||
return "heroic throw";
|
return "heroic throw";
|
||||||
}
|
|
||||||
|
|
||||||
return PullStrategy::GetPullActionName();
|
return PullStrategy::GetPullActionName();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,15 @@
|
|||||||
#include "AiFactory.h"
|
#include "AiFactory.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr uint32 SPELL_RETALIATION = 20230;
|
||||||
|
constexpr uint32 SPELL_DIVINE_SHIELD = 642;
|
||||||
|
constexpr uint32 SPELL_ICE_BLOCK = 45438;
|
||||||
|
constexpr uint32 SPELL_BLESSING_OF_PROTECTION = 41450;
|
||||||
|
constexpr uint32 SPELL_SHATTERING_THROW = 64382;
|
||||||
|
}
|
||||||
|
|
||||||
bool CastBerserkerRageAction::isPossible()
|
bool CastBerserkerRageAction::isPossible()
|
||||||
{
|
{
|
||||||
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
|
if (botAI->IsInVehicle() && !botAI->IsInVehicle(false, false, true))
|
||||||
@ -153,14 +162,8 @@ bool CastVigilanceAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
bool CastRetaliationAction::isUseful()
|
bool CastRetaliationAction::isUseful()
|
||||||
{
|
{
|
||||||
// Spell cooldown check
|
if (!bot->HasSpell(SPELL_RETALIATION) || bot->HasSpellCooldown(SPELL_RETALIATION) ||
|
||||||
if (!bot->HasSpell(20230))
|
bot->HasAura(SPELL_RETALIATION))
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Spell cooldown check
|
|
||||||
if (bot->HasSpellCooldown(20230))
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -199,8 +202,8 @@ bool CastRetaliationAction::isUseful()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only cast Retaliation if there are at least 2 melee attackers and the buff is not active
|
// Only cast Retaliation if there are at least 2 melee attackers
|
||||||
return meleeAttackers >= 2 && !botAI->HasAura("retaliation", bot);
|
return meleeAttackers >= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Unit* CastShatteringThrowAction::GetTarget()
|
Unit* CastShatteringThrowAction::GetTarget()
|
||||||
@ -214,15 +217,15 @@ Unit* CastShatteringThrowAction::GetTarget()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (bot->IsWithinDistInMap(enemy, 25.0f) &&
|
if (bot->IsWithinDistInMap(enemy, 25.0f) &&
|
||||||
(enemy->HasAura(642) || // Divine Shield
|
(enemy->HasAura(SPELL_DIVINE_SHIELD) ||
|
||||||
enemy->HasAura(45438) || // Ice Block
|
enemy->HasAura(SPELL_ICE_BLOCK) ||
|
||||||
enemy->HasAura(41450))) // Blessing of Protection
|
enemy->HasAura(SPELL_BLESSING_OF_PROTECTION)))
|
||||||
{
|
{
|
||||||
return enemy;
|
return enemy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr; // No valid target
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CastShatteringThrowAction::Execute(Event /*event*/)
|
bool CastShatteringThrowAction::Execute(Event /*event*/)
|
||||||
@ -236,7 +239,7 @@ bool CastShatteringThrowAction::Execute(Event /*event*/)
|
|||||||
|
|
||||||
bool CastShatteringThrowAction::isUseful()
|
bool CastShatteringThrowAction::isUseful()
|
||||||
{
|
{
|
||||||
if (!bot->HasSpell(64382) || bot->HasSpellCooldown(64382))
|
if (!bot->HasSpell(SPELL_SHATTERING_THROW) || bot->HasSpellCooldown(SPELL_SHATTERING_THROW))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
GuidVector enemies = AI_VALUE(GuidVector, "possible targets");
|
GuidVector enemies = AI_VALUE(GuidVector, "possible targets");
|
||||||
@ -247,17 +250,16 @@ bool CastShatteringThrowAction::isUseful()
|
|||||||
if (!enemy || !enemy->IsAlive() || enemy->IsFriendlyTo(bot))
|
if (!enemy || !enemy->IsAlive() || enemy->IsFriendlyTo(bot))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Check if the enemy is within 25 yards and has the specific auras
|
|
||||||
if (bot->IsWithinDistInMap(enemy, 25.0f) &&
|
if (bot->IsWithinDistInMap(enemy, 25.0f) &&
|
||||||
(enemy->HasAura(642) || // Divine Shield
|
(enemy->HasAura(SPELL_DIVINE_SHIELD) ||
|
||||||
enemy->HasAura(45438) || // Ice Block
|
enemy->HasAura(SPELL_ICE_BLOCK) ||
|
||||||
enemy->HasAura(41450))) // Blessing of Protection
|
enemy->HasAura(SPELL_BLESSING_OF_PROTECTION)))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false; // No valid targets within range
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CastShatteringThrowAction::isPossible()
|
bool CastShatteringThrowAction::isPossible()
|
||||||
|
|||||||
@ -6,6 +6,16 @@
|
|||||||
#include "WarriorTriggers.h"
|
#include "WarriorTriggers.h"
|
||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr uint32 SPELL_VIGILANCE = 50720;
|
||||||
|
constexpr uint32 SPELL_SHATTERING_THROW = 64382;
|
||||||
|
constexpr uint32 SPELL_DIVINE_SHIELD = 642;
|
||||||
|
constexpr uint32 SPELL_ICE_BLOCK = 45438;
|
||||||
|
constexpr uint32 SPELL_BLESSING_OF_PROTECTION = 41450;
|
||||||
|
constexpr uint32 SPELL_COMMANDING_PRESENCE_RANKS[] = { 12318, 12857, 12858, 12860, 12861 };
|
||||||
|
}
|
||||||
|
|
||||||
bool BloodrageBuffTrigger::IsActive()
|
bool BloodrageBuffTrigger::IsActive()
|
||||||
{
|
{
|
||||||
return AI_VALUE2(uint8, "health", "self target") >= sPlayerbotAIConfig.mediumHealth &&
|
return AI_VALUE2(uint8, "health", "self target") >= sPlayerbotAIConfig.mediumHealth &&
|
||||||
@ -14,7 +24,7 @@ bool BloodrageBuffTrigger::IsActive()
|
|||||||
|
|
||||||
bool VigilanceTrigger::IsActive()
|
bool VigilanceTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!bot->HasSpell(50720))
|
if (!bot->HasSpell(SPELL_VIGILANCE))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Group* group = bot->GetGroup();
|
Group* group = bot->GetGroup();
|
||||||
@ -64,7 +74,7 @@ bool VigilanceTrigger::IsActive()
|
|||||||
|
|
||||||
bool ShatteringThrowTrigger::IsActive()
|
bool ShatteringThrowTrigger::IsActive()
|
||||||
{
|
{
|
||||||
if (!bot->HasSpell(64382) || bot->HasSpellCooldown(64382))
|
if (!bot->HasSpell(SPELL_SHATTERING_THROW) || bot->HasSpellCooldown(SPELL_SHATTERING_THROW))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
GuidVector enemies = AI_VALUE(GuidVector, "possible targets");
|
GuidVector enemies = AI_VALUE(GuidVector, "possible targets");
|
||||||
@ -76,9 +86,9 @@ bool ShatteringThrowTrigger::IsActive()
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (bot->IsWithinDistInMap(enemy, 25.0f) &&
|
if (bot->IsWithinDistInMap(enemy, 25.0f) &&
|
||||||
(enemy->HasAura(642) || // Divine Shield
|
(enemy->HasAura(SPELL_DIVINE_SHIELD) ||
|
||||||
enemy->HasAura(45438) || // Ice Block
|
enemy->HasAura(SPELL_ICE_BLOCK) ||
|
||||||
enemy->HasAura(41450))) // Blessing of Protection
|
enemy->HasAura(SPELL_BLESSING_OF_PROTECTION)))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -112,15 +122,13 @@ bool BattleShoutTrigger::IsActive()
|
|||||||
if (!bsApValue)
|
if (!bsApValue)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
static const uint32 commandingPresenceSpells[] = {
|
|
||||||
12318, 12857, 12858, 12860, 12861 };
|
|
||||||
static const float commandingPresenceBonus[] = {
|
static const float commandingPresenceBonus[] = {
|
||||||
0.05f, 0.10f, 0.15f, 0.20f, 0.25f };
|
0.05f, 0.10f, 0.15f, 0.20f, 0.25f };
|
||||||
|
|
||||||
float cpBonus = 0.0f;
|
float cpBonus = 0.0f;
|
||||||
for (int rank = 4; rank >= 0; --rank)
|
for (int rank = 4; rank >= 0; --rank)
|
||||||
{
|
{
|
||||||
if (bot->HasAura(commandingPresenceSpells[rank]))
|
if (bot->HasAura(SPELL_COMMANDING_PRESENCE_RANKS[rank]))
|
||||||
{
|
{
|
||||||
cpBonus = commandingPresenceBonus[rank];
|
cpBonus = commandingPresenceBonus[rank];
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -5,6 +5,13 @@
|
|||||||
#include "Playerbots.h"
|
#include "Playerbots.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr uint32 SPELL_UNDERSTUDY_TAUNT = 29060;
|
||||||
|
constexpr uint32 SPELL_BONE_BARRIER = 29061;
|
||||||
|
constexpr uint32 SPELL_BLOOD_STRIKE = 61696;
|
||||||
|
}
|
||||||
|
|
||||||
bool RazuviousUseObedienceCrystalAction::Execute(Event /*event*/)
|
bool RazuviousUseObedienceCrystalAction::Execute(Event /*event*/)
|
||||||
{
|
{
|
||||||
if (!helper.UpdateBossAI())
|
if (!helper.UpdateBossAI())
|
||||||
@ -42,7 +49,8 @@ bool RazuviousUseObedienceCrystalAction::Execute(Event /*event*/)
|
|||||||
bool tauntUseful = true;
|
bool tauntUseful = true;
|
||||||
if (forceObedience->GetDuration() <= (duration_time - 5000))
|
if (forceObedience->GetDuration() <= (duration_time - 5000))
|
||||||
{
|
{
|
||||||
if (target->GetVictim() && botAI->HasAura(29061, target->GetVictim()))
|
Unit* victim = target->GetVictim();
|
||||||
|
if (victim && victim->HasAura(SPELL_BONE_BARRIER))
|
||||||
tauntUseful = false;
|
tauntUseful = false;
|
||||||
|
|
||||||
if (forceObedience->GetDuration() <= 3000)
|
if (forceObedience->GetDuration() <= 3000)
|
||||||
@ -55,19 +63,19 @@ bool RazuviousUseObedienceCrystalAction::Execute(Event /*event*/)
|
|||||||
if (tauntUseful && !charm->HasSpellCooldown(29060))
|
if (tauntUseful && !charm->HasSpellCooldown(29060))
|
||||||
{
|
{
|
||||||
// shield
|
// shield
|
||||||
if (!charm->HasSpellCooldown(29061))
|
if (!charm->HasSpellCooldown(SPELL_BONE_BARRIER))
|
||||||
{
|
{
|
||||||
charm->CastSpell(charm, 29061, true);
|
charm->CastSpell(charm, SPELL_BONE_BARRIER, true);
|
||||||
charm->AddSpellCooldown(29061, 0, 30 * 1000);
|
charm->AddSpellCooldown(SPELL_BONE_BARRIER, 0, 30 * 1000);
|
||||||
}
|
}
|
||||||
charm->CastSpell(target, 29060, true);
|
charm->CastSpell(target, SPELL_UNDERSTUDY_TAUNT, true);
|
||||||
charm->AddSpellCooldown(29060, 0, 20 * 1000);
|
charm->AddSpellCooldown(SPELL_UNDERSTUDY_TAUNT, 0, 20 * 1000);
|
||||||
}
|
}
|
||||||
// strike
|
// strike
|
||||||
if (!charm->HasSpellCooldown(61696))
|
if (!charm->HasSpellCooldown(SPELL_BLOOD_STRIKE))
|
||||||
{
|
{
|
||||||
charm->CastSpell(target, 61696, true);
|
charm->CastSpell(target, SPELL_BLOOD_STRIKE, true);
|
||||||
charm->AddSpellCooldown(61696, 0, 4 * 1000);
|
charm->AddSpellCooldown(SPELL_BLOOD_STRIKE, 0, 4 * 1000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,7 +75,7 @@ bool SapphironFlightPositionAction::MoveToNearestIcebolt()
|
|||||||
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
|
||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (NaxxSpellIds::HasAnyAura(botAI, member, {NaxxSpellIds::Icebolt10, NaxxSpellIds::Icebolt25}) ||
|
if (NaxxSpellIds::HasAnyAura(member, {NaxxSpellIds::Icebolt10, NaxxSpellIds::Icebolt25}) ||
|
||||||
botAI->HasAura("icebolt", member, false, false, -1, true))
|
botAI->HasAura("icebolt", member, false, false, -1, true))
|
||||||
{
|
{
|
||||||
if (!playerWithIcebolt || minDistance > bot->GetDistance(member))
|
if (!playerWithIcebolt || minDistance > bot->GetDistance(member))
|
||||||
|
|||||||
@ -111,15 +111,13 @@ bool ThaddiusMovePolarityAction::Execute(Event /*event*/)
|
|||||||
{3504.68f, -2936.68f},
|
{3504.68f, -2936.68f},
|
||||||
};
|
};
|
||||||
uint32 idx;
|
uint32 idx;
|
||||||
if (NaxxSpellIds::HasAnyAura(
|
if (NaxxSpellIds::HasAnyAura(bot,
|
||||||
botAI, bot,
|
|
||||||
{NaxxSpellIds::NegativeCharge10, NaxxSpellIds::NegativeCharge25, NaxxSpellIds::NegativeChargeStack}) ||
|
{NaxxSpellIds::NegativeCharge10, NaxxSpellIds::NegativeCharge25, NaxxSpellIds::NegativeChargeStack}) ||
|
||||||
botAI->HasAura("negative charge", bot, false, false, -1, true))
|
botAI->HasAura("negative charge", bot, false, false, -1, true))
|
||||||
{
|
{
|
||||||
idx = 0;
|
idx = 0;
|
||||||
}
|
}
|
||||||
else if (NaxxSpellIds::HasAnyAura(
|
else if (NaxxSpellIds::HasAnyAura(bot,
|
||||||
botAI, bot,
|
|
||||||
{NaxxSpellIds::PositiveCharge10, NaxxSpellIds::PositiveCharge25, NaxxSpellIds::PositiveChargeStack}) ||
|
{NaxxSpellIds::PositiveCharge10, NaxxSpellIds::PositiveCharge25, NaxxSpellIds::PositiveChargeStack}) ||
|
||||||
botAI->HasAura("positive charge", bot, false, false, -1, true))
|
botAI->HasAura("positive charge", bot, false, false, -1, true))
|
||||||
{
|
{
|
||||||
|
|||||||
@ -192,7 +192,7 @@ public:
|
|||||||
{
|
{
|
||||||
Player* member = ref->GetSource();
|
Player* member = ref->GetSource();
|
||||||
if (member &&
|
if (member &&
|
||||||
(NaxxSpellIds::HasAnyAura(botAI, member, {NaxxSpellIds::Icebolt10, NaxxSpellIds::Icebolt25}) ||
|
(NaxxSpellIds::HasAnyAura(member, {NaxxSpellIds::Icebolt10, NaxxSpellIds::Icebolt25}) ||
|
||||||
botAI->HasAura("icebolt", member, false, false, -1, true)))
|
botAI->HasAura("icebolt", member, false, false, -1, true)))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -236,7 +236,7 @@ float AnubrekhanGenericMultiplier::GetValue(Action* action)
|
|||||||
return 1.0f;
|
return 1.0f;
|
||||||
|
|
||||||
if (NaxxSpellIds::HasAnyAura(
|
if (NaxxSpellIds::HasAnyAura(
|
||||||
botAI, boss, {NaxxSpellIds::LocustSwarm10, NaxxSpellIds::LocustSwarm10Alt, NaxxSpellIds::LocustSwarm25}) ||
|
boss, {NaxxSpellIds::LocustSwarm10, NaxxSpellIds::LocustSwarm10Alt, NaxxSpellIds::LocustSwarm25}) ||
|
||||||
botAI->HasAura("locust swarm", boss))
|
botAI->HasAura("locust swarm", boss))
|
||||||
{
|
{
|
||||||
if (dynamic_cast<FleeAction*>(action))
|
if (dynamic_cast<FleeAction*>(action))
|
||||||
|
|||||||
@ -123,14 +123,14 @@ namespace NaxxSpellIds
|
|||||||
SPELL_INEVITABLE_DOOM = 29204,
|
SPELL_INEVITABLE_DOOM = 29204,
|
||||||
SPELL_BERSERK = 26662
|
SPELL_BERSERK = 26662
|
||||||
*/
|
*/
|
||||||
inline bool HasAnyAura(PlayerbotAI* botAI, Unit* unit, std::initializer_list<uint32> spellIds)
|
inline bool HasAnyAura(Unit* unit, std::initializer_list<uint32> spellIds)
|
||||||
{
|
{
|
||||||
if (!botAI || !unit)
|
if (!unit)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (uint32 spellId : spellIds)
|
for (uint32 spellId : spellIds)
|
||||||
{
|
{
|
||||||
if (botAI->HasAura(spellId, unit))
|
if (unit->HasAura(spellId))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -1531,7 +1531,7 @@ bool VezaxShadowCrashTrigger::IsActive()
|
|||||||
if (!boss || !boss->IsAlive())
|
if (!boss || !boss->IsAlive())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return botAI->HasAura(SPELL_VEZAX_SHADOW_CRASH, bot);
|
return bot->HasAura(SPELL_VEZAX_SHADOW_CRASH);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VezaxMarkOfTheFacelessTrigger::IsActive()
|
bool VezaxMarkOfTheFacelessTrigger::IsActive()
|
||||||
@ -1542,7 +1542,7 @@ bool VezaxMarkOfTheFacelessTrigger::IsActive()
|
|||||||
if (!boss || !boss->IsAlive())
|
if (!boss || !boss->IsAlive())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!botAI->HasAura(SPELL_MARK_OF_THE_FACELESS, bot))
|
if (!bot->HasAura(SPELL_MARK_OF_THE_FACELESS))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
float distance = bot->GetDistance2d(ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionX(),
|
float distance = bot->GetDistance2d(ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionX(),
|
||||||
|
|||||||
@ -26,6 +26,15 @@
|
|||||||
#include "WarlockAiObjectContext.h"
|
#include "WarlockAiObjectContext.h"
|
||||||
#include "WarriorAiObjectContext.h"
|
#include "WarriorAiObjectContext.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr uint32 SPELL_FROSTFIRE_BOLT = 44614;
|
||||||
|
constexpr uint32 SPELL_ICE_SHARDS = 15047;
|
||||||
|
constexpr uint32 SPELL_WHIRLWIND = 1680;
|
||||||
|
constexpr uint32 SPELL_CAT_FORM = 768;
|
||||||
|
constexpr uint32 SPELL_DRUID_THICK_HIDE = 16931;
|
||||||
|
}
|
||||||
|
|
||||||
AiObjectContext* AiFactory::createAiObjectContext(Player* player, PlayerbotAI* botAI)
|
AiObjectContext* AiFactory::createAiObjectContext(Player* player, PlayerbotAI* botAI)
|
||||||
{
|
{
|
||||||
switch (player->getClass())
|
switch (player->getClass())
|
||||||
@ -300,7 +309,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
engine->addStrategiesNoInit("arcane", "bdps", nullptr);
|
engine->addStrategiesNoInit("arcane", "bdps", nullptr);
|
||||||
else if (tab == MAGE_TAB_FIRE)
|
else if (tab == MAGE_TAB_FIRE)
|
||||||
{
|
{
|
||||||
if (player->HasSpell(44614) /*Frostfire Bolt*/ && player->HasAura(15047) /*Ice Shards*/)
|
if (player->HasSpell(SPELL_FROSTFIRE_BOLT) && player->HasAura(SPELL_ICE_SHARDS))
|
||||||
engine->addStrategiesNoInit("frostfire", "bdps", nullptr);
|
engine->addStrategiesNoInit("frostfire", "bdps", nullptr);
|
||||||
else
|
else
|
||||||
engine->addStrategiesNoInit("fire", "bdps", nullptr);
|
engine->addStrategiesNoInit("fire", "bdps", nullptr);
|
||||||
@ -313,7 +322,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
case CLASS_WARRIOR:
|
case CLASS_WARRIOR:
|
||||||
if (tab == WARRIOR_TAB_PROTECTION)
|
if (tab == WARRIOR_TAB_PROTECTION)
|
||||||
engine->addStrategiesNoInit("tank", "tank assist", "pull", "pull back", "aoe", nullptr);
|
engine->addStrategiesNoInit("tank", "tank assist", "pull", "pull back", "aoe", nullptr);
|
||||||
else if (tab == WARRIOR_TAB_ARMS || !player->HasSpell(1680)) // Whirlwind
|
else if (tab == WARRIOR_TAB_ARMS || !player->HasSpell(SPELL_WHIRLWIND))
|
||||||
engine->addStrategiesNoInit("arms", "aoe", "dps assist", nullptr);
|
engine->addStrategiesNoInit("arms", "aoe", "dps assist", nullptr);
|
||||||
else // if (tab == WARRIOR_TAB_FURY)
|
else // if (tab == WARRIOR_TAB_FURY)
|
||||||
engine->addStrategiesNoInit("fury", "aoe", "dps assist", nullptr);
|
engine->addStrategiesNoInit("fury", "aoe", "dps assist", nullptr);
|
||||||
@ -345,7 +354,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
|||||||
engine->addStrategiesNoInit("resto", "cure", "dps assist", "blanketing", "tranquility", nullptr);
|
engine->addStrategiesNoInit("resto", "cure", "dps assist", "blanketing", "tranquility", nullptr);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (player->HasSpell(768) /*cat form*/ && !player->HasAura(16931) /*thick hide*/)
|
if (player->HasSpell(SPELL_CAT_FORM) && !player->HasAura(SPELL_DRUID_THICK_HIDE))
|
||||||
engine->addStrategiesNoInit("cat", "aoe", "cc", "dps assist", "feral charge", nullptr);
|
engine->addStrategiesNoInit("cat", "aoe", "cc", "dps assist", "feral charge", nullptr);
|
||||||
else
|
else
|
||||||
engine->addStrategiesNoInit("bear", "tank assist", "pull", "pull back", "feral charge", nullptr);
|
engine->addStrategiesNoInit("bear", "tank assist", "pull", "pull back", "feral charge", nullptr);
|
||||||
@ -535,7 +544,7 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const
|
|||||||
case CLASS_DRUID:
|
case CLASS_DRUID:
|
||||||
if (tab == DRUID_TAB_FERAL)
|
if (tab == DRUID_TAB_FERAL)
|
||||||
{
|
{
|
||||||
if (player->GetLevel() >= 20 && !player->HasAura(16931) /*thick hide*/)
|
if (player->GetLevel() >= 20 && !player->HasAura(SPELL_DRUID_THICK_HIDE))
|
||||||
nonCombatEngine->addStrategy("dps assist", false);
|
nonCombatEngine->addStrategy("dps assist", false);
|
||||||
else
|
else
|
||||||
nonCombatEngine->addStrategiesNoInit("tank assist", "pull", nullptr);
|
nonCombatEngine->addStrategiesNoInit("tank assist", "pull", nullptr);
|
||||||
|
|||||||
@ -61,6 +61,56 @@ std::vector<uint32> PlayerbotFactory::enchantGemIdCache;
|
|||||||
std::unordered_map<uint32, std::vector<uint32>> PlayerbotFactory::trainerIdCache;
|
std::unordered_map<uint32, std::vector<uint32>> PlayerbotFactory::trainerIdCache;
|
||||||
std::vector<uint32> PlayerbotFactory::ccBreakTrinketCache;
|
std::vector<uint32> PlayerbotFactory::ccBreakTrinketCache;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr uint32 SPELL_DRUID_THICK_HIDE = 16931;
|
||||||
|
constexpr uint32 SPELL_OWLKIN_FRENZY = 48393;
|
||||||
|
constexpr uint32 SPELL_PRIMAL_TENACITY = 33957;
|
||||||
|
constexpr uint32 SPELL_IMPROVED_BARKSKIN = 63411;
|
||||||
|
|
||||||
|
constexpr uint32 SPELL_SECOND_WIND = 29838;
|
||||||
|
constexpr uint32 SPELL_BLOOD_CRAZE = 16492;
|
||||||
|
constexpr uint32 SPELL_GAG_ORDER = 12958;
|
||||||
|
|
||||||
|
constexpr uint32 SPELL_SACRED_CLEANSING = 53553;
|
||||||
|
constexpr uint32 SPELL_RECKONING = 20179;
|
||||||
|
constexpr uint32 SPELL_DIVINE_PURPOSE = 31872;
|
||||||
|
|
||||||
|
constexpr uint32 SPELL_HUNTER_THICK_HIDE = 19612;
|
||||||
|
constexpr uint32 SPELL_CONCUSSIVE_BARRAGE = 35102;
|
||||||
|
constexpr uint32 SPELL_ENTRAPMENT = 19388;
|
||||||
|
|
||||||
|
constexpr uint32 SPELL_DEADLY_BREW = 51626;
|
||||||
|
constexpr uint32 SPELL_THROWING_SPECIALIZATION = 51679;
|
||||||
|
constexpr uint32 SPELL_WAYLAY = 51696;
|
||||||
|
|
||||||
|
constexpr uint32 SPELL_IMPROVED_MANA_BURN = 14772;
|
||||||
|
constexpr uint32 SPELL_BODY_AND_SOUL = 64129;
|
||||||
|
constexpr uint32 SPELL_IMPROVED_VAMPIRIC_EMBRACE = 27840;
|
||||||
|
|
||||||
|
constexpr uint32 SPELL_ABOMINATIONS_MIGHT = 53138;
|
||||||
|
constexpr uint32 SPELL_IMPROVED_ICY_TALONS = 55610;
|
||||||
|
constexpr uint32 SPELL_SUDDEN_DOOM = 49529;
|
||||||
|
constexpr uint32 SPELL_ACCLIMATION = 50152;
|
||||||
|
constexpr uint32 SPELL_MAGIC_SUPPRESSION = 49611;
|
||||||
|
|
||||||
|
constexpr uint32 SPELL_SHAMAN_DUAL_WIELD = 30798;
|
||||||
|
constexpr uint32 SPELL_ASTRAL_SHIFT = 51479;
|
||||||
|
constexpr uint32 SPELL_EARTHEN_POWER = 51524;
|
||||||
|
constexpr uint32 SPELL_FOCUSED_MIND = 30866;
|
||||||
|
|
||||||
|
constexpr uint32 SPELL_BURNOUT = 44472;
|
||||||
|
constexpr uint32 SPELL_ICE_SHARDS = 15047;
|
||||||
|
constexpr uint32 SPELL_IMPROVED_BLINK = 31570;
|
||||||
|
constexpr uint32 SPELL_FIERY_PAYBACK = 64357;
|
||||||
|
constexpr uint32 SPELL_SHATTERED_BARRIER = 54787;
|
||||||
|
|
||||||
|
constexpr uint32 SPELL_IMPROVED_HOWL_OF_TERROR = 30057;
|
||||||
|
constexpr uint32 SPELL_NEMESIS = 63123;
|
||||||
|
constexpr uint32 SPELL_INTENSITY = 18136;
|
||||||
|
constexpr uint32 SPELL_NETHER_PROTECTION = 30302;
|
||||||
|
}
|
||||||
|
|
||||||
bool PlayerbotFactory::IsPrimaryTradeSkill(uint16 skillId)
|
bool PlayerbotFactory::IsPrimaryTradeSkill(uint16 skillId)
|
||||||
{
|
{
|
||||||
SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skillId);
|
SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skillId);
|
||||||
@ -1440,7 +1490,7 @@ uint32 PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_temp
|
|||||||
/// @todo: fix cat druid hardcode
|
/// @todo: fix cat druid hardcode
|
||||||
if (bot->getClass() == CLASS_DRUID && specTab == DRUID_TAB_FERAL && bot->GetLevel() >= 20)
|
if (bot->getClass() == CLASS_DRUID && specTab == DRUID_TAB_FERAL && bot->GetLevel() >= 20)
|
||||||
{
|
{
|
||||||
bool isCat = !bot->HasAura(16931);
|
bool isCat = !bot->HasAura(SPELL_DRUID_THICK_HIDE);
|
||||||
if (!isCat && bot->GetLevel() == 20)
|
if (!isCat && bot->GetLevel() == 20)
|
||||||
{
|
{
|
||||||
uint32 bearP = sPlayerbotAIConfig.randomClassSpecProb[cls][1];
|
uint32 bearP = sPlayerbotAIConfig.randomClassSpecProb[cls][1];
|
||||||
@ -1495,7 +1545,7 @@ uint32 PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_temp
|
|||||||
if (bot->GetFreeTalentPoints())
|
if (bot->GetFreeTalentPoints())
|
||||||
InitTalents((specTab + 2) % 3);
|
InitTalents((specTab + 2) % 3);
|
||||||
|
|
||||||
if (bot->getClass() == CLASS_SHAMAN && bot->HasSpell(30798))
|
if (bot->getClass() == CLASS_SHAMAN && bot->HasSpell(SPELL_SHAMAN_DUAL_WIELD))
|
||||||
{
|
{
|
||||||
bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1);
|
bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1);
|
||||||
bot->SetCanDualWield(true);
|
bot->SetCanDualWield(true);
|
||||||
@ -1581,7 +1631,7 @@ void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bot->getClass() == CLASS_SHAMAN && bot->HasSpell(30798))
|
if (bot->getClass() == CLASS_SHAMAN && bot->HasSpell(SPELL_SHAMAN_DUAL_WIELD))
|
||||||
{
|
{
|
||||||
bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1);
|
bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1);
|
||||||
bot->SetCanDualWield(true);
|
bot->SetCanDualWield(true);
|
||||||
@ -4170,13 +4220,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
|||||||
if (bot->getClass() == CLASS_WARRIOR)
|
if (bot->getClass() == CLASS_WARRIOR)
|
||||||
{
|
{
|
||||||
// Arms PvP (spec index 3): If the bot has the Second Wind talent
|
// Arms PvP (spec index 3): If the bot has the Second Wind talent
|
||||||
if (bot->HasAura(29838))
|
if (bot->HasAura(SPELL_SECOND_WIND))
|
||||||
tab = 3;
|
tab = 3;
|
||||||
// Fury PvP (spec index 4): If the bot has the Blood Craze talent
|
// Fury PvP (spec index 4): If the bot has the Blood Craze talent
|
||||||
else if (bot->HasAura(16492))
|
else if (bot->HasAura(SPELL_BLOOD_CRAZE))
|
||||||
tab = 4;
|
tab = 4;
|
||||||
// Protection PvP (spec index 5): If the bot has the Gag Order talent
|
// Protection PvP (spec index 5): If the bot has the Gag Order talent
|
||||||
else if (bot->HasAura(12958))
|
else if (bot->HasAura(SPELL_GAG_ORDER))
|
||||||
tab = 5;
|
tab = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4184,13 +4234,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
|||||||
if (bot->getClass() == CLASS_PALADIN)
|
if (bot->getClass() == CLASS_PALADIN)
|
||||||
{
|
{
|
||||||
// Holy PvP (spec index 3): If the bot has the Sacred Cleansing talent
|
// Holy PvP (spec index 3): If the bot has the Sacred Cleansing talent
|
||||||
if (bot->HasAura(53553))
|
if (bot->HasAura(SPELL_SACRED_CLEANSING))
|
||||||
tab = 3;
|
tab = 3;
|
||||||
// Protection PvP (spec index 4): If the bot has the Reckoning talent
|
// Protection PvP (spec index 4): If the bot has the Reckoning talent
|
||||||
else if (bot->HasAura(20179))
|
else if (bot->HasAura(SPELL_RECKONING))
|
||||||
tab = 4;
|
tab = 4;
|
||||||
// Retribution PvP (spec index 5): If the bot has the Divine Purpose talent
|
// Retribution PvP (spec index 5): If the bot has the Divine Purpose talent
|
||||||
else if (bot->HasAura(31872))
|
else if (bot->HasAura(SPELL_DIVINE_PURPOSE))
|
||||||
tab = 5;
|
tab = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4198,13 +4248,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
|||||||
if (bot->getClass() == CLASS_HUNTER)
|
if (bot->getClass() == CLASS_HUNTER)
|
||||||
{
|
{
|
||||||
// Beast Mastery PvP (spec index 3): If the bot has the Thick Hide talent
|
// Beast Mastery PvP (spec index 3): If the bot has the Thick Hide talent
|
||||||
if (bot->HasAura(19612))
|
if (bot->HasAura(SPELL_HUNTER_THICK_HIDE))
|
||||||
tab = 3;
|
tab = 3;
|
||||||
// Marksmanship PvP (spec index 4): If the bot has the Concussive Barrage talent
|
// Marksmanship PvP (spec index 4): If the bot has the Concussive Barrage talent
|
||||||
else if (bot->HasAura(35102))
|
else if (bot->HasAura(SPELL_CONCUSSIVE_BARRAGE))
|
||||||
tab = 4;
|
tab = 4;
|
||||||
// Survival PvP (spec index 5): If the bot has the Entrapment talent and does NOT have the Concussive Barrage talent
|
// Survival PvP (spec index 5): If the bot has the Entrapment talent and does NOT have the Concussive Barrage talent
|
||||||
else if (bot->HasAura(19388) && !bot->HasAura(35102))
|
else if (bot->HasAura(SPELL_ENTRAPMENT) && !bot->HasAura(SPELL_CONCUSSIVE_BARRAGE))
|
||||||
tab = 5;
|
tab = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4212,13 +4262,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
|||||||
if (bot->getClass() == CLASS_ROGUE)
|
if (bot->getClass() == CLASS_ROGUE)
|
||||||
{
|
{
|
||||||
// Assassination PvP (spec index 3): If the bot has the Deadly Brew talent
|
// Assassination PvP (spec index 3): If the bot has the Deadly Brew talent
|
||||||
if (bot->HasAura(51626))
|
if (bot->HasAura(SPELL_DEADLY_BREW))
|
||||||
tab = 3;
|
tab = 3;
|
||||||
// Combat PvP (spec index 4): If the bot has the Throwing Specialization talent
|
// Combat PvP (spec index 4): If the bot has the Throwing Specialization talent
|
||||||
else if (bot->HasAura(51679))
|
else if (bot->HasAura(SPELL_THROWING_SPECIALIZATION))
|
||||||
tab = 4;
|
tab = 4;
|
||||||
// Subtlety PvP (spec index 5): If the bot has the Waylay talent
|
// Subtlety PvP (spec index 5): If the bot has the Waylay talent
|
||||||
else if (bot->HasAura(51696))
|
else if (bot->HasAura(SPELL_WAYLAY))
|
||||||
tab = 5;
|
tab = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4226,13 +4276,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
|||||||
if (bot->getClass() == CLASS_PRIEST)
|
if (bot->getClass() == CLASS_PRIEST)
|
||||||
{
|
{
|
||||||
// Discipline PvP (spec index 3): If the bot has the Improved Mana Burn talent
|
// Discipline PvP (spec index 3): If the bot has the Improved Mana Burn talent
|
||||||
if (bot->HasAura(14772))
|
if (bot->HasAura(SPELL_IMPROVED_MANA_BURN))
|
||||||
tab = 3;
|
tab = 3;
|
||||||
// Holy PvP (spec index 4): If the bot has the Body and Soul talent
|
// Holy PvP (spec index 4): If the bot has the Body and Soul talent
|
||||||
else if (bot->HasAura(64129))
|
else if (bot->HasAura(SPELL_BODY_AND_SOUL))
|
||||||
tab = 4;
|
tab = 4;
|
||||||
// Shadow PvP (spec index 5): If the bot has the Improved Vampiric Embrace talent
|
// Shadow PvP (spec index 5): If the bot has the Improved Vampiric Embrace talent
|
||||||
else if (bot->HasAura(27840))
|
else if (bot->HasAura(SPELL_IMPROVED_VAMPIRIC_EMBRACE))
|
||||||
tab = 5;
|
tab = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4241,16 +4291,16 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
|||||||
{
|
{
|
||||||
// Double Aura Blood PvE (spec index 3): If the bot has both the Abomination's Might and Improved Icy Talons
|
// Double Aura Blood PvE (spec index 3): If the bot has both the Abomination's Might and Improved Icy Talons
|
||||||
// talents
|
// talents
|
||||||
if (bot->HasAura(53138) && bot->HasAura(55610))
|
if (bot->HasAura(SPELL_ABOMINATIONS_MIGHT) && bot->HasAura(SPELL_IMPROVED_ICY_TALONS))
|
||||||
tab = 3;
|
tab = 3;
|
||||||
// Blood PvP (spec index 4): If the bot has the Sudden Doom talent
|
// Blood PvP (spec index 4): If the bot has the Sudden Doom talent
|
||||||
else if (bot->HasAura(49529))
|
else if (bot->HasAura(SPELL_SUDDEN_DOOM))
|
||||||
tab = 4;
|
tab = 4;
|
||||||
// Frost PvP (spec index 5): If the bot has the Acclimation talent
|
// Frost PvP (spec index 5): If the bot has the Acclimation talent
|
||||||
else if (bot->HasAura(50152))
|
else if (bot->HasAura(SPELL_ACCLIMATION))
|
||||||
tab = 5;
|
tab = 5;
|
||||||
// Unholy PvP (spec index 6): If the bot has the Magic Suppression talent
|
// Unholy PvP (spec index 6): If the bot has the Magic Suppression talent
|
||||||
else if (bot->HasAura(49611))
|
else if (bot->HasAura(SPELL_MAGIC_SUPPRESSION))
|
||||||
tab = 6;
|
tab = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4258,13 +4308,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
|||||||
if (bot->getClass() == CLASS_SHAMAN)
|
if (bot->getClass() == CLASS_SHAMAN)
|
||||||
{
|
{
|
||||||
// Elemental PvP (spec index 3): If the bot has the Astral Shift talent
|
// Elemental PvP (spec index 3): If the bot has the Astral Shift talent
|
||||||
if (bot->HasAura(51479))
|
if (bot->HasAura(SPELL_ASTRAL_SHIFT))
|
||||||
tab = 3;
|
tab = 3;
|
||||||
// Enhancement PvP (spec index 4): If the bot has the Earthen Power talent
|
// Enhancement PvP (spec index 4): If the bot has the Earthen Power talent
|
||||||
else if (bot->HasAura(51524))
|
else if (bot->HasAura(SPELL_EARTHEN_POWER))
|
||||||
tab = 4;
|
tab = 4;
|
||||||
// Restoration PvP (spec index 5): If the bot has the Focused Mind talent
|
// Restoration PvP (spec index 5): If the bot has the Focused Mind talent
|
||||||
else if (bot->HasAura(30866))
|
else if (bot->HasAura(SPELL_FOCUSED_MIND))
|
||||||
tab = 5;
|
tab = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4272,16 +4322,16 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
|||||||
if (bot->getClass() == CLASS_MAGE)
|
if (bot->getClass() == CLASS_MAGE)
|
||||||
{
|
{
|
||||||
// Frostfire PvE (spec index 3): If the bot has both the Burnout talent and the Ice Shards talent
|
// Frostfire PvE (spec index 3): If the bot has both the Burnout talent and the Ice Shards talent
|
||||||
if (bot->HasAura(44472) && bot->HasAura(15047))
|
if (bot->HasAura(SPELL_BURNOUT) && bot->HasAura(SPELL_ICE_SHARDS))
|
||||||
tab = 3;
|
tab = 3;
|
||||||
// Arcane PvP (spec index 4): If the bot has the Improved Blink talent
|
// Arcane PvP (spec index 4): If the bot has the Improved Blink talent
|
||||||
else if (bot->HasAura(31570))
|
else if (bot->HasAura(SPELL_IMPROVED_BLINK))
|
||||||
tab = 4;
|
tab = 4;
|
||||||
// Fire PvP (spec index 5): If the bot has the Fiery Payback talent
|
// Fire PvP (spec index 5): If the bot has the Fiery Payback talent
|
||||||
else if (bot->HasAura(64357))
|
else if (bot->HasAura(SPELL_FIERY_PAYBACK))
|
||||||
tab = 5;
|
tab = 5;
|
||||||
// Frost PvP (spec index 6): If the bot has the Shattered Barrier talent
|
// Frost PvP (spec index 6): If the bot has the Shattered Barrier talent
|
||||||
else if (bot->HasAura(54787))
|
else if (bot->HasAura(SPELL_SHATTERED_BARRIER))
|
||||||
tab = 6;
|
tab = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4289,13 +4339,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
|||||||
if (bot->getClass() == CLASS_WARLOCK)
|
if (bot->getClass() == CLASS_WARLOCK)
|
||||||
{
|
{
|
||||||
// Affliction PvP (spec index 3): If the bot has the Improved Howl of Terror talent
|
// Affliction PvP (spec index 3): If the bot has the Improved Howl of Terror talent
|
||||||
if (bot->HasAura(30057))
|
if (bot->HasAura(SPELL_IMPROVED_HOWL_OF_TERROR))
|
||||||
tab = 3;
|
tab = 3;
|
||||||
// Demonology PvP (spec index 4): If the bot has both the Nemesis talent and the Intensity talent
|
// Demonology PvP (spec index 4): If the bot has both the Nemesis talent and the Intensity talent
|
||||||
else if (bot->HasAura(63123) && bot->HasAura(18136))
|
else if (bot->HasAura(SPELL_NEMESIS) && bot->HasAura(SPELL_INTENSITY))
|
||||||
tab = 4;
|
tab = 4;
|
||||||
// Destruction PvP (spec index 5): If the bot has the Nether Protection talent
|
// Destruction PvP (spec index 5): If the bot has the Nether Protection talent
|
||||||
else if (bot->HasAura(30302))
|
else if (bot->HasAura(SPELL_NETHER_PROTECTION))
|
||||||
tab = 5;
|
tab = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4303,16 +4353,16 @@ void PlayerbotFactory::InitGlyphs(bool increment)
|
|||||||
if (bot->getClass() == CLASS_DRUID)
|
if (bot->getClass() == CLASS_DRUID)
|
||||||
{
|
{
|
||||||
// Cat PvE (spec index 3): If the bot is Feral spec, level 20 or higher, and does NOT have the Thick Hide talent
|
// Cat PvE (spec index 3): If the bot is Feral spec, level 20 or higher, and does NOT have the Thick Hide talent
|
||||||
if (tab == DRUID_TAB_FERAL && bot->GetLevel() >= 20 && !bot->HasAura(16931))
|
if (tab == DRUID_TAB_FERAL && bot->GetLevel() >= 20 && !bot->HasAura(SPELL_DRUID_THICK_HIDE))
|
||||||
tab = 3;
|
tab = 3;
|
||||||
// Balance PvP (spec index 4): If the bot has the Owlkin Frenzy talent
|
// Balance PvP (spec index 4): If the bot has the Owlkin Frenzy talent
|
||||||
else if (bot->HasAura(48393))
|
else if (bot->HasAura(SPELL_OWLKIN_FRENZY))
|
||||||
tab = 4;
|
tab = 4;
|
||||||
// Feral PvP (spec index 5): If the bot has the Primal Tenacity talent
|
// Feral PvP (spec index 5): If the bot has the Primal Tenacity talent
|
||||||
else if (bot->HasAura(33957))
|
else if (bot->HasAura(SPELL_PRIMAL_TENACITY))
|
||||||
tab = 5;
|
tab = 5;
|
||||||
// Resto PvP (spec index 6): If the bot has the Improved Barkskin talent
|
// Resto PvP (spec index 6): If the bot has the Improved Barkskin talent
|
||||||
else if (bot->HasAura(63411))
|
else if (bot->HasAura(SPELL_IMPROVED_BARKSKIN))
|
||||||
tab = 6;
|
tab = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3152,20 +3152,10 @@ bool PlayerbotAI::HasAura(std::string const name, Unit* unit, bool maxStack, boo
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlayerbotAI::HasAura(uint32 spellId, Unit const* unit)
|
bool PlayerbotAI::HasSpell(std::string const spellName) const
|
||||||
{
|
{
|
||||||
if (!spellId || !unit)
|
uint32 const spellId = aiObjectContext->GetValue<uint32>("spell id", spellName)->Get();
|
||||||
return false;
|
return spellId && bot->HasSpell(spellId);
|
||||||
|
|
||||||
return unit->HasAura(spellId);
|
|
||||||
// for (uint8 effect = EFFECT_0; effect <= EFFECT_2; effect++)
|
|
||||||
// {
|
|
||||||
// AuraEffect const* aurEff = unit->GetAuraEffect(spellId, effect);
|
|
||||||
// if (IsRealAura(bot, aurEff, unit))
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Aura* PlayerbotAI::GetAura(std::string const name, Unit* unit, bool checkIsOwner, bool checkDuration, int checkStack)
|
Aura* PlayerbotAI::GetAura(std::string const name, Unit* unit, bool checkIsOwner, bool checkDuration, int checkStack)
|
||||||
@ -4269,7 +4259,7 @@ void PlayerbotAI::InterruptSpell()
|
|||||||
void PlayerbotAI::RemoveAura(std::string const name)
|
void PlayerbotAI::RemoveAura(std::string const name)
|
||||||
{
|
{
|
||||||
uint32 spellid = aiObjectContext->GetValue<uint32>("spell id", name)->Get();
|
uint32 spellid = aiObjectContext->GetValue<uint32>("spell id", name)->Get();
|
||||||
if (spellid && HasAura(spellid, bot))
|
if (spellid && bot->HasAura(spellid))
|
||||||
bot->RemoveAurasDueToSpell(spellid);
|
bot->RemoveAurasDueToSpell(spellid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -497,6 +497,7 @@ public:
|
|||||||
|
|
||||||
virtual bool CanCastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr);
|
virtual bool CanCastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr);
|
||||||
virtual bool CastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr);
|
virtual bool CastSpell(std::string const name, Unit* target, Item* itemTarget = nullptr);
|
||||||
|
virtual bool HasSpell(std::string const spellName) const;
|
||||||
virtual bool HasAura(std::string const spellName, Unit* player, bool maxStack = false, bool checkIsOwner = false,
|
virtual bool HasAura(std::string const spellName, Unit* player, bool maxStack = false, bool checkIsOwner = false,
|
||||||
int maxAmount = -1, bool checkDuration = false);
|
int maxAmount = -1, bool checkDuration = false);
|
||||||
virtual bool HasAnyAuraOf(Unit* player, ...);
|
virtual bool HasAnyAuraOf(Unit* player, ...);
|
||||||
@ -509,7 +510,6 @@ public:
|
|||||||
bool CanCastSpell(uint32 spellid, float x, float y, float z, bool checkHasSpell = true,
|
bool CanCastSpell(uint32 spellid, float x, float y, float z, bool checkHasSpell = true,
|
||||||
Item* itemTarget = nullptr);
|
Item* itemTarget = nullptr);
|
||||||
|
|
||||||
bool HasAura(uint32 spellId, Unit const* player);
|
|
||||||
Aura* GetAura(std::string const spellName, Unit* unit, bool checkIsOwner = false, bool checkDuration = false,
|
Aura* GetAura(std::string const spellName, Unit* unit, bool checkIsOwner = false, bool checkDuration = false,
|
||||||
int checkStack = -1);
|
int checkStack = -1);
|
||||||
bool CastSpell(uint32 spellId, Unit* target, Item* itemTarget = nullptr);
|
bool CastSpell(uint32 spellId, Unit* target, Item* itemTarget = nullptr);
|
||||||
|
|||||||
@ -23,13 +23,29 @@
|
|||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_1 = 30482;
|
constexpr uint32 SPELL_MOLTEN_ARMOR_RANKS[] = { 30482, 43045, 43046 };
|
||||||
constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_2 = 43045;
|
constexpr uint32 SPELL_FEL_ARMOR_RANKS[] = { 28176, 28189, 47892, 47893 };
|
||||||
constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_3 = 43046;
|
constexpr uint32 SPELL_CAREFUL_AIM = 34484;
|
||||||
constexpr uint32 SPELL_FEL_ARMOR_RANK_1 = 28176;
|
constexpr uint32 SPELL_HUNTER_VS_WILD = 56341;
|
||||||
constexpr uint32 SPELL_FEL_ARMOR_RANK_2 = 28189;
|
constexpr uint32 SPELL_ARMORED_TO_THE_TEETH = 61222;
|
||||||
constexpr uint32 SPELL_FEL_ARMOR_RANK_3 = 47892;
|
constexpr uint32 SPELL_MENTAL_DEXTERITY = 51885;
|
||||||
constexpr uint32 SPELL_FEL_ARMOR_RANK_4 = 47893;
|
constexpr uint32 SPELL_ROGUE_SWORD_SPECIALIZATION = 13964;
|
||||||
|
constexpr uint32 SPELL_POLEAXE_SPECIALIZATION = 12785;
|
||||||
|
constexpr uint32 SPELL_NERVES_OF_COLD_STEEL = 50138;
|
||||||
|
constexpr uint32 SPELL_SHADOW_FOCUS = 15835;
|
||||||
|
constexpr uint32 SPELL_ARCANE_FOCUS = 12840;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t Size>
|
||||||
|
bool HasAnySpell(Player* player, uint32 const (&spellIds)[Size])
|
||||||
|
{
|
||||||
|
for (uint32 const spellId : spellIds)
|
||||||
|
{
|
||||||
|
if (player->HasSpell(spellId))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
StatsWeightCalculator::StatsWeightCalculator(Player* player) : player_(player)
|
StatsWeightCalculator::StatsWeightCalculator(Player* player) : player_(player)
|
||||||
@ -512,26 +528,24 @@ void StatsWeightCalculator::GenerateAdditionalWeights(Player* player)
|
|||||||
// int tab = AiFactory::GetPlayerSpecTab(player);
|
// int tab = AiFactory::GetPlayerSpecTab(player);
|
||||||
if (cls == CLASS_HUNTER)
|
if (cls == CLASS_HUNTER)
|
||||||
{
|
{
|
||||||
if (player->HasAura(34484))
|
if (player->HasAura(SPELL_CAREFUL_AIM))
|
||||||
stats_weights_[STATS_TYPE_INTELLECT] += 1.1f;
|
stats_weights_[STATS_TYPE_INTELLECT] += 1.1f;
|
||||||
if (player->HasAura(56341))
|
if (player->HasAura(SPELL_HUNTER_VS_WILD))
|
||||||
stats_weights_[STATS_TYPE_STAMINA] += 0.3f;
|
stats_weights_[STATS_TYPE_STAMINA] += 0.3f;
|
||||||
}
|
}
|
||||||
else if (cls == CLASS_WARRIOR)
|
else if (cls == CLASS_WARRIOR)
|
||||||
{
|
{
|
||||||
if (player->HasAura(61222))
|
if (player->HasAura(SPELL_ARMORED_TO_THE_TEETH))
|
||||||
stats_weights_[STATS_TYPE_ARMOR] += 0.03f;
|
stats_weights_[STATS_TYPE_ARMOR] += 0.03f;
|
||||||
}
|
}
|
||||||
else if (cls == CLASS_SHAMAN)
|
else if (cls == CLASS_SHAMAN)
|
||||||
{
|
{
|
||||||
if (player->HasAura(51885))
|
if (player->HasAura(SPELL_MENTAL_DEXTERITY))
|
||||||
stats_weights_[STATS_TYPE_INTELLECT] += 1.1f;
|
stats_weights_[STATS_TYPE_INTELLECT] += 1.1f;
|
||||||
}
|
}
|
||||||
else if (cls == CLASS_MAGE)
|
else if (cls == CLASS_MAGE)
|
||||||
{
|
{
|
||||||
if (!player->HasSpell(SPELL_MOLTEN_ARMOR_RANK_1)
|
if (!HasAnySpell(player, SPELL_MOLTEN_ARMOR_RANKS))
|
||||||
&& !player->HasSpell(SPELL_MOLTEN_ARMOR_RANK_2)
|
|
||||||
&& !player->HasSpell(SPELL_MOLTEN_ARMOR_RANK_3))
|
|
||||||
{
|
{
|
||||||
if (tab != MAGE_TAB_FIRE)
|
if (tab != MAGE_TAB_FIRE)
|
||||||
stats_weights_[STATS_TYPE_SPIRIT] -= 0.6f;
|
stats_weights_[STATS_TYPE_SPIRIT] -= 0.6f;
|
||||||
@ -541,8 +555,7 @@ void StatsWeightCalculator::GenerateAdditionalWeights(Player* player)
|
|||||||
}
|
}
|
||||||
else if (cls == CLASS_WARLOCK)
|
else if (cls == CLASS_WARLOCK)
|
||||||
{
|
{
|
||||||
if (!player->HasSpell(SPELL_FEL_ARMOR_RANK_1) && !player->HasSpell(SPELL_FEL_ARMOR_RANK_2) &&
|
if (!HasAnySpell(player, SPELL_FEL_ARMOR_RANKS))
|
||||||
!player->HasSpell(SPELL_FEL_ARMOR_RANK_3) && !player->HasSpell(SPELL_FEL_ARMOR_RANK_4))
|
|
||||||
stats_weights_[STATS_TYPE_SPIRIT] -= 0.4f;
|
stats_weights_[STATS_TYPE_SPIRIT] -= 0.4f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,17 +703,17 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
|
|||||||
weight_ *= 1.5;
|
weight_ *= 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cls == CLASS_ROGUE && player_->HasAura(13964) &&
|
if (cls == CLASS_ROGUE && player_->HasAura(SPELL_ROGUE_SWORD_SPECIALIZATION) &&
|
||||||
(proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE))
|
(proto->SubClass == ITEM_SUBCLASS_WEAPON_SWORD || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE))
|
||||||
{
|
{
|
||||||
weight_ *= 1.1;
|
weight_ *= 1.1;
|
||||||
}
|
}
|
||||||
if (cls == CLASS_WARRIOR && player_->HasAura(12785) &&
|
if (cls == CLASS_WARRIOR && player_->HasAura(SPELL_POLEAXE_SPECIALIZATION) &&
|
||||||
(proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2))
|
(proto->SubClass == ITEM_SUBCLASS_WEAPON_POLEARM || proto->SubClass == ITEM_SUBCLASS_WEAPON_AXE2))
|
||||||
{
|
{
|
||||||
weight_ *= 1.1;
|
weight_ *= 1.1;
|
||||||
}
|
}
|
||||||
if (cls == CLASS_DEATH_KNIGHT && player_->HasAura(50138) && !isDoubleHand)
|
if (cls == CLASS_DEATH_KNIGHT && player_->HasAura(SPELL_NERVES_OF_COLD_STEEL) && !isDoubleHand)
|
||||||
{
|
{
|
||||||
weight_ *= 1.3;
|
weight_ *= 1.3;
|
||||||
}
|
}
|
||||||
@ -739,9 +752,9 @@ void StatsWeightCalculator::ApplyOverflowPenalty(Player* player)
|
|||||||
player->GetTotalAuraModifier(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT); // suppression (18176)
|
player->GetTotalAuraModifier(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT); // suppression (18176)
|
||||||
hit_current += player->GetRatingBonusValue(CR_HIT_SPELL);
|
hit_current += player->GetRatingBonusValue(CR_HIT_SPELL);
|
||||||
|
|
||||||
if (cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW && player->HasAura(15835)) // Shadow Focus
|
if (cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW && player->HasAura(SPELL_SHADOW_FOCUS))
|
||||||
hit_current += 3;
|
hit_current += 3;
|
||||||
if (cls == CLASS_MAGE && tab == MAGE_TAB_ARCANE && player->HasAura(12840)) // Arcane Focus
|
if (cls == CLASS_MAGE && tab == MAGE_TAB_ARCANE && player->HasAura(SPELL_ARCANE_FOCUS))
|
||||||
hit_current += 3;
|
hit_current += 3;
|
||||||
|
|
||||||
hit_overflow = SPELL_HIT_OVERFLOW;
|
hit_overflow = SPELL_HIT_OVERFLOW;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user