Compare commits

..

No commits in common. "085e127e38bcc9952338e40e45a8a22472585502" and "f989976c9392fe750a4e823341dd6bf7d0db1ae5" have entirely different histories.

36 changed files with 301 additions and 363 deletions

View File

@ -17,7 +17,6 @@
#include "SpellAuraEffects.h" #include "SpellAuraEffects.h"
static constexpr uint32 SPELL_COLD_WEATHER_FLYING = 54197; static constexpr uint32 SPELL_COLD_WEATHER_FLYING = 54197;
static constexpr float PARACHUTE_LAND_THRESHOLD = 15.0f;
// Define the static map / init bool for caching bot preferred mount data globally // Define the static map / init bool for caching bot preferred mount data globally
std::unordered_map<uint32, PreferredMountCache> CheckMountStateAction::mountCache; std::unordered_map<uint32, PreferredMountCache> CheckMountStateAction::mountCache;
@ -62,21 +61,6 @@ MountData CollectMountData(const Player* bot)
bool CheckMountStateAction::Execute(Event /*event*/) bool CheckMountStateAction::Execute(Event /*event*/)
{ {
// Forced flight dismount:
// Bots get stale flight movement flags after a forced dismount (e.g: Dalaran) because the post landing dismount cleanup
// needs MSG_MOVE_FALL_LAND (a client opcode) and client movement packets. The stale flags cause the bot to be stuck with
// the parachute, or even keep the bot hovering indefinitely and block MMAP routing.
// Note: Without MSG_MOVE_FALL_LAND, HandleFall doesn't trigger, meaning bots don't get fall damage in forced dismounts anyway,
// so the parachute usage here is more of an immersion feature.
if (bot->HasFeatherFallAura())
{
float floorZ = bot->GetMapHeight(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
if (floorZ != INVALID_HEIGHT && floorZ != VMAP_INVALID_HEIGHT_VALUE &&
bot->GetPositionZ() - floorZ <= PARACHUTE_LAND_THRESHOLD)
bot->RemoveAurasByType(SPELL_AURA_FEATHER_FALL);
}
ClearStaleFlightFlags();
// Determine if there are no attackers // Determine if there are no attackers
bool noAttackers = !AI_VALUE2(bool, "combat", "self target") || !AI_VALUE(uint8, "attacker count"); bool noAttackers = !AI_VALUE2(bool, "combat", "self target") || !AI_VALUE(uint8, "attacker count");
bool enemy = AI_VALUE(Unit*, "enemy player target"); bool enemy = AI_VALUE(Unit*, "enemy player target");
@ -220,7 +204,7 @@ bool CheckMountStateAction::Mount()
// Get bot mount data // Get bot mount data
MountData mountData = CollectMountData(bot); MountData mountData = CollectMountData(bot);
int32 masterMountType = GetMountType(master); int32 masterMountType = GetMountType(master);
int32 masterSpeed = CalculateMasterMountSpeed(master); int32 masterSpeed = CalculateMasterMountSpeed(master, mountData);
// Try shapeshift // Try shapeshift
if (TryForms(master, masterMountType, masterSpeed)) if (TryForms(master, masterMountType, masterSpeed))
@ -250,17 +234,14 @@ void CheckMountStateAction::Dismount()
WorldPacket emptyPacket; WorldPacket emptyPacket;
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket); bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
ClearStaleFlightFlags(); bool const wantsFly = bot->HasIncreaseMountedFlightSpeedAura() || bot->HasFlyAura();
} bool const isWaterWalking = bot->HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
bool const isFlying = bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING);
void CheckMountStateAction::ClearStaleFlightFlags() bool const hasGravityDisabled = bot->HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
{ if (!wantsFly && !isWaterWalking && (isFlying || hasGravityDisabled))
if (bot->HasIncreaseMountedFlightSpeedAura() || bot->HasFlyAura())
return;
if (bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_DISABLE_GRAVITY))
{ {
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_DISABLE_GRAVITY | MOVEMENTFLAG_CAN_FLY); bot->RemoveUnitMovementFlag(
MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY);
if (!bot->IsRooted()) if (!bot->IsRooted())
bot->SendMovementFlagUpdate(); bot->SendMovementFlagUpdate();
} }
@ -509,7 +490,7 @@ static bool BotCanUseFlyingMount(Player const* bot)
return true; return true;
} }
int32 CheckMountStateAction::CalculateMasterMountSpeed(Player* master) const int32 CheckMountStateAction::CalculateMasterMountSpeed(Player* master, const MountData& mountData) const
{ {
// Check riding skill and level requirements // Check riding skill and level requirements
int32 ridingSkill = bot->GetPureSkillValue(SKILL_RIDING); int32 ridingSkill = bot->GetPureSkillValue(SKILL_RIDING);

View File

@ -53,10 +53,9 @@ private:
float CalculateDismountDistance() const; float CalculateDismountDistance() const;
float CalculateMountDistance() const; float CalculateMountDistance() const;
void Dismount(); void Dismount();
void ClearStaleFlightFlags();
bool ShouldFollowMasterMountState(Player* master, bool noAttackers, bool shouldMount) const; bool ShouldFollowMasterMountState(Player* master, bool noAttackers, bool shouldMount) const;
bool ShouldDismountForMaster(Player* master) const; bool ShouldDismountForMaster(Player* master) const;
int32 CalculateMasterMountSpeed(Player* master) const; int32 CalculateMasterMountSpeed(Player* master, const MountData& mountData) const;
bool CheckForSwiftMount() const; bool CheckForSwiftMount() const;
std::map<uint32, std::map<int32, std::vector<uint32>>> GetAllMountSpells() const; std::map<uint32, std::map<int32, std::vector<uint32>>> GetAllMountSpells() const;
bool TryForms(Player* master, int32 masterMountType, int32 masterSpeed) const; bool TryForms(Player* master, int32 masterMountType, int32 masterSpeed) const;

View File

@ -422,9 +422,10 @@ 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);
constexpr uint32 SPELL_CALL_PET = 883; if (bot->getClass() == CLASS_HUNTER && bot->HasSpell(883))
if (bot->getClass() == CLASS_HUNTER && bot->HasSpell(SPELL_CALL_PET)) {
bot->CastSpell(bot, SPELL_CALL_PET, true); bot->CastSpell(bot, 883, true);
}
return true; return true;
} }

View File

@ -67,10 +67,9 @@ bool TradeStatusExtendedAction::Execute(Event event)
return false; return false;
} }
constexpr uint32 SPELL_PICK_LOCK = 1804; if (bot->getClass() == CLASS_ROGUE && bot->HasSpell(1804) && lockbox->IsLocked()) // Pick Lock spell
if (bot->getClass() == CLASS_ROGUE && bot->HasSpell(SPELL_PICK_LOCK) && lockbox->IsLocked())
{ {
// botAI->CastSpell(SPELL_PICK_LOCK, bot, lockbox); // Attempt to cast Pick Lock on the lockbox // botAI->CastSpell(1804, 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
} }

View File

@ -23,7 +23,9 @@ bool BossFireResistanceTrigger::IsActive()
return false; return false;
// Check if bot have fire resistance aura // Check if bot have fire resistance aura
if (botAI->HasAura("fire resistance aura", bot)) if (bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_5) || bot->HasAura(SPELL_FIRE_RESISTANCE_AURA_RANK_4) ||
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
@ -74,7 +76,9 @@ bool BossFrostResistanceTrigger::IsActive()
return false; return false;
// Check if bot have frost resistance aura // Check if bot have frost resistance aura
if (botAI->HasAura("frost resistance aura", bot)) if (bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_5) || bot->HasAura(SPELL_FROST_RESISTANCE_AURA_RANK_4) ||
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
@ -129,7 +133,8 @@ bool BossNatureResistanceTrigger::IsActive()
return false; return false;
// Check if bot have nature resistance aura // Check if bot have nature resistance aura
if (botAI->HasAura("aspect of the wild", bot)) if (bot->HasAura(SPELL_ASPECT_OF_THE_WILD_RANK_4) || bot->HasAura(SPELL_ASPECT_OF_THE_WILD_RANK_3) ||
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
@ -179,7 +184,11 @@ bool BossShadowResistanceTrigger::IsActive()
return false; return false;
// Check if bot have shadow resistance aura // Check if bot have shadow resistance aura
if (botAI->HasAura("shadow resistance aura", bot)) if (bot->HasAura(SPELL_SHADOW_RESISTANCE_AURA_RANK_5) ||
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

View File

@ -5,27 +5,39 @@
#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 (!target || if (!bot || !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();
} }
if (botAI->CanCastSpell("death grip", target)) uint32 const deathGripSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "death grip")->Get();
if (deathGripSpellId && bot->HasSpell(deathGripSpellId) &&
botAI->CanCastSpell(deathGripSpellId, target))
{
return "death grip"; return "death grip";
}
if (!botAI->CanCastSpell("icy touch", target) && uint32 const icyTouchSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "icy touch")->Get();
botAI->CanCastSpell("dark command", target)) if (!icyTouchSpellId || !bot->HasSpell(icyTouchSpellId) ||
!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();
} }

View File

@ -50,10 +50,9 @@ bool CastCancelDruidAction::Execute(Event /*event*/)
return true; return true;
} }
bool CastCancelDruidAction::isUseful() { return bot->HasAura(auraId); } bool CastCancelDruidAction::isUseful() { return botAI->HasAura(auraId, bot); }
bool CastTreeFormAction::isUseful() bool CastTreeFormAction::isUseful()
{ {
constexpr uint32 SPELL_TREE_OF_LIFE = 33891; return GetTarget() && CastSpellAction::isUseful() && !botAI->HasAura(33891, bot);
return GetTarget() && CastSpellAction::isUseful() && !bot->HasAura(SPELL_TREE_OF_LIFE);
} }

View File

@ -28,11 +28,7 @@ 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() bool TreeFormTrigger::IsActive() { return !botAI->HasAura(33891, bot); }
{
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); }
@ -47,11 +43,8 @@ bool ProwlTrigger::IsActive()
if (botAI->HasAura("prowl", bot) || bot->IsInCombat()) if (botAI->HasAura("prowl", bot) || bot->IsInCombat())
return false; return false;
if (!botAI->HasSpell("prowl")) uint32 prowlId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "prowl")->Get();
return false; if (!prowlId || !bot->HasSpell(prowlId) || bot->HasSpellCooldown(prowlId))
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;

View File

@ -393,14 +393,14 @@ public:
class FerociousBiteExecuteTrigger : public Trigger class FerociousBiteExecuteTrigger : public Trigger
{ {
public: public:
FerociousBiteExecuteTrigger(PlayerbotAI* botAI) : Trigger(botAI, "ferocious bite execute") {} FerociousBiteExecuteTrigger(PlayerbotAI* ai) : Trigger(ai, "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 (!botAI->HasSpell("ferocious bite")) if (!AI_VALUE2(uint32, "spell id", "ferocious bite"))
return false; return false;
if (AI_VALUE2(uint8, "combo", "current target") < 1) if (AI_VALUE2(uint8, "combo", "current target") < 1)

View File

@ -5,23 +5,34 @@
#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
{ {
std::string const pullActionName = PullStrategy::GetPullActionName(); Player* bot = botAI->GetBot();
std::string const actionName = std::string actionName = PullStrategy::GetPullActionName();
botAI->HasSpell("faerie fire (feral)") && if (!bot)
(botAI->HasStrategy("bear", BOT_STATE_COMBAT) || botAI->HasStrategy("cat", BOT_STATE_COMBAT))
? "faerie fire (feral)" : pullActionName;
Unit* target = GetTarget();
if (!target)
return actionName; return actionName;
if (!botAI->CanCastSpell(actionName, target) && botAI->CanCastSpell("growl", target)) 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();
uint32 const faerieFireSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", actionName)->Get();
if (target && (!faerieFireSpellId || !bot->HasSpell(faerieFireSpellId) ||
!botAI->CanCastSpell(faerieFireSpellId, 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;
} }

View File

@ -19,13 +19,23 @@ bool CastViperStingAction::isUseful()
bool CastAspectOfTheHawkAction::isUseful() bool CastAspectOfTheHawkAction::isUseful()
{ {
Unit* target = GetTarget(); Unit* target = GetTarget();
return target && !botAI->HasSpell("aspect of the dragonhawk"); if (!target)
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 || !botAI->HasSpell("explosive shot")) if (!target)
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
@ -40,7 +50,14 @@ bool CastArcaneShotAction::isUseful()
bool CastImmolationTrapAction::isUseful() bool CastImmolationTrapAction::isUseful()
{ {
Unit* target = GetTarget(); Unit* target = GetTarget();
return target && !botAI->HasSpell("explosive trap"); if (!target)
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()

View File

@ -13,7 +13,7 @@
std::vector<NextAction> CastMoltenArmorAction::getAlternatives() std::vector<NextAction> CastMoltenArmorAction::getAlternatives()
{ {
if (!botAI->HasSpell("molten armor")) if (!AI_VALUE2(uint32, "spell id", "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 (!botAI->HasSpell("mage armor")) if (!AI_VALUE2(uint32, "spell id", "mage armor"))
return NextAction::merge({ NextAction("ice armor") }, CastBuffSpellAction::getAlternatives()); return NextAction::merge({ NextAction("ice armor") }, CastBuffSpellAction::getAlternatives());
return CastBuffSpellAction::getAlternatives(); return CastBuffSpellAction::getAlternatives();

View File

@ -39,16 +39,26 @@ bool ArcaneIntellectTrigger::IsActive()
bool MageArmorTrigger::IsActive() bool MageArmorTrigger::IsActive()
{ {
Unit* target = GetTarget(); Unit* target = GetTarget();
return botAI->HasSpell("mage armor") && !botAI->HasAura("mage armor", target) && if (botAI->HasAura("mage armor", target))
!botAI->HasAura("ice armor", target) && !botAI->HasAura("frost armor", target) && return false;
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();
return botAI->HasSpell("molten armor") && !botAI->HasAura("molten armor", target) && if (botAI->HasAura("molten armor", target))
!botAI->HasAura("ice armor", target) && !botAI->HasAura("frost armor", target) && return false;
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);
} }
@ -72,8 +82,7 @@ bool FrostbiteOnTargetTrigger::IsActive()
bool NoFocusMagicTrigger::IsActive() bool NoFocusMagicTrigger::IsActive()
{ {
constexpr uint32 SPELL_FOCUS_MAGIC = 54646; if (!bot->HasSpell(54646)) // Focus Magic
if (!bot->HasSpell(SPELL_FOCUS_MAGIC))
return false; return false;
Group* group = bot->GetGroup(); Group* group = bot->GetGroup();
@ -86,7 +95,7 @@ bool NoFocusMagicTrigger::IsActive()
if (!member || member == bot || !member->IsAlive()) if (!member || member == bot || !member->IsAlive())
continue; continue;
if (member->HasAura(SPELL_FOCUS_MAGIC, bot->GetGUID())) if (member->HasAura(54646, bot->GetGUID()))
return false; return false;
} }
return true; return true;
@ -94,9 +103,11 @@ bool NoFocusMagicTrigger::IsActive()
bool DeepFreezeCooldownTrigger::IsActive() bool DeepFreezeCooldownTrigger::IsActive()
{ {
constexpr uint32 SPELL_DEEP_FREEZE = 44572; // If the bot does NOT have Deep Freeze, treat as "on cooldown"
return !bot->HasSpell(SPELL_DEEP_FREEZE) || if (!bot->HasSpell(44572)) // Deep Freeze
SpellCooldownTrigger::IsActive(); return true;
return SpellCooldownTrigger::IsActive();
} }
const std::unordered_set<uint32> FlamestrikeNearbyTrigger::FLAMESTRIKE_SPELL_IDS = { const std::unordered_set<uint32> FlamestrikeNearbyTrigger::FLAMESTRIKE_SPELL_IDS = {

View File

@ -8,18 +8,6 @@
#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:
@ -114,17 +102,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(SPELL_CONJURE_MANA_SAPPHIRE)) if (bot->HasSpell(42985)) // 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(SPELL_CONJURE_MANA_EMERALD)) else if (bot->HasSpell(27101)) // 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(SPELL_CONJURE_MANA_RUBY)) else if (bot->HasSpell(10054)) // 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(SPELL_CONJURE_MANA_CITRINE)) else if (bot->HasSpell(10053)) // 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(SPELL_CONJURE_MANA_JADE)) else if (bot->HasSpell(3552)) // 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(SPELL_CONJURE_MANA_AGATE)) else if (bot->HasSpell(759)) // 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) }));
@ -154,7 +142,7 @@ void MageBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
} }
else if (tab == MAGE_TAB_FIRE) else if (tab == MAGE_TAB_FIRE)
{ {
if (bot->HasSpell(SPELL_FROSTFIRE_BOLT) && bot->HasAura(SPELL_ICE_SHARDS)) if (bot->HasSpell(44614) /*Frostfire Bolt*/ && bot->HasAura(15047) /*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) }));

View File

@ -1145,7 +1145,8 @@ bool CastGreaterBlessingAssignmentAction::Execute(Event /*event*/)
if (!FindPendingAssignment(assignment, spellName)) if (!FindPendingAssignment(assignment, spellName))
return false; return false;
if (!botAI->HasSpell(spellName)) uint32 finalId = AI_VALUE2(uint32, "spell id", spellName);
if (!finalId)
return false; return false;
return botAI->CastSpell(spellName, assignment.player); return botAI->CastSpell(spellName, assignment.player);

View File

@ -5,23 +5,34 @@
#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 (!target || if (!bot || !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();
} }
if (botAI->CanCastSpell("avenger's shield", target)) uint32 const avengersShieldSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "avenger's shield")->Get();
if (avengersShieldSpellId && bot->HasSpell(avengersShieldSpellId) &&
botAI->CanCastSpell(avengersShieldSpellId, target))
{
return "avenger's shield"; return "avenger's shield";
}
if (botAI->CanCastSpell("hand of reckoning", target)) uint32 const handOfReckoningSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "hand of reckoning")->Get();
if (handOfReckoningSpellId && bot->HasSpell(handOfReckoningSpellId) &&
botAI->CanCastSpell(handOfReckoningSpellId, target))
{
return "hand of reckoning"; return "hand of reckoning";
}
return PullStrategy::GetPullActionName(); return PullStrategy::GetPullActionName();
} }

View File

@ -11,14 +11,6 @@
#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");
@ -30,8 +22,7 @@ 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 !bot->HasAura(SPELL_WARSONG_FLAG) && !bot->HasAura(SPELL_SILVERWING_FLAG) && return !botAI->HasAura(23333, bot) && !botAI->HasAura(23335, bot) && !botAI->HasAura(34976, bot);
!bot->HasAura(SPELL_NETHERSTORM_FLAG);
} }
bool UnstealthAction::Execute(Event /*event*/) bool UnstealthAction::Execute(Event /*event*/)
@ -59,8 +50,7 @@ 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 !bot->HasAura(SPELL_WARSONG_FLAG) && !bot->HasAura(SPELL_SILVERWING_FLAG) && return !botAI->HasAura(23333, bot) && !botAI->HasAura(23335, bot) && !botAI->HasAura(34976, bot);
!bot->HasAura(SPELL_NETHERSTORM_FLAG);
} }
bool CastEnvenomAction::isUseful() bool CastEnvenomAction::isUseful()
@ -71,7 +61,7 @@ bool CastEnvenomAction::isUseful()
bool CastEnvenomAction::isPossible() bool CastEnvenomAction::isPossible()
{ {
// alternate to eviscerate if talents unlearned // alternate to eviscerate if talents unlearned
return bot->HasAura(SPELL_MASTER_POISONER_RANK_3); return botAI->HasAura(58410, bot) /* Master Poisoner Rank 3 */;
} }
bool CastTricksOfTheTradeOnMainTankAction::isUseful() bool CastTricksOfTheTradeOnMainTankAction::isUseful()

View File

@ -9,12 +9,6 @@
#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);
@ -35,7 +29,7 @@ bool UnstealthTrigger::IsActive()
bool StealthTrigger::IsActive() bool StealthTrigger::IsActive()
{ {
if (bot->HasAura(SPELL_STEALTH) || bot->IsInCombat() || bot->HasSpellCooldown(SPELL_STEALTH)) if (botAI->HasAura("stealth", bot) || bot->IsInCombat() || bot->HasSpellCooldown(1784))
return false; return false;
float distance = 30.f; float distance = 30.f;
@ -69,13 +63,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 && botAI->HasSpell("sap") && !bot->IsInCombat(); } bool SapTrigger::IsPossible() { return bot->GetLevel() > 10 && bot->HasSpell(6770) && !bot->IsInCombat(); }
bool SprintTrigger::IsPossible() { return bot->HasSpell(SPELL_SPRINT_RANK_1); } bool SprintTrigger::IsPossible() { return bot->HasSpell(2983); }
bool SprintTrigger::IsActive() bool SprintTrigger::IsActive()
{ {
if (bot->HasSpellCooldown(SPELL_SPRINT_RANK_1)) if (bot->HasSpellCooldown(2983))
return false; return false;
float distance = botAI->GetMaster() ? 45.0f : 35.0f; float distance = botAI->GetMaster() ? 45.0f : 35.0f;
@ -111,7 +105,7 @@ bool SprintTrigger::IsActive()
bool ExposeArmorTrigger::IsActive() bool ExposeArmorTrigger::IsActive()
{ {
Unit* target = AI_VALUE(Unit*, "current target"); Unit* target = AI_VALUE(Unit*, "current target"); // Get the bot's 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;
} }

View File

@ -6,17 +6,6 @@
#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.
@ -85,9 +74,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(SPELL_TOTEM_OF_WRATH)) if (bot->HasSpell(30706))
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(SPELL_FLAMETONGUE_TOTEM)) else if (bot->HasSpell(8227))
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) }));
} }
@ -123,9 +112,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(SPELL_CLEANSING_TOTEM)) if (bot->HasSpell(8170))
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(SPELL_MANA_SPRING_TOTEM)) else if (bot->HasSpell(5675))
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) }));
} }
@ -145,9 +134,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(SPELL_WRATH_OF_AIR_TOTEM)) if (bot->HasSpell(3738))
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(SPELL_GROUNDING_TOTEM)) else if (bot->HasSpell(8177))
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) }));
} }
@ -158,9 +147,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(SPELL_WINDFURY_TOTEM)) if (bot->HasSpell(8512))
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(SPELL_GROUNDING_TOTEM)) else if (bot->HasSpell(8177))
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) }));
} }

View File

@ -77,7 +77,11 @@ bool CastShadowflameAction::isUseful()
bool CastRainOfFireAction::isUseful() bool CastRainOfFireAction::isUseful()
{ {
Unit* target = GetTarget(); Unit* target = GetTarget();
return target && !botAI->HasSpell("seed of corruption"); if (!target)
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

View File

@ -104,8 +104,10 @@ 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()
{ {
constexpr uint32 SPELL_LIFE_TAP_GLYPH = 63320; if (!botAI->HasAura(63320, bot))
return bot->HasAura(SPELL_LIFE_TAP_GLYPH) && BuffTrigger::IsActive(); return false;
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

View File

@ -5,16 +5,23 @@
#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 (!target) if (!bot || !target)
return PullStrategy::GetPullActionName(); return PullStrategy::GetPullActionName();
if (botAI->CanCastSpell("heroic throw", target)) uint32 const heroicThrowSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "heroic throw")->Get();
if (heroicThrowSpellId && bot->HasSpell(heroicThrowSpellId) &&
botAI->CanCastSpell(heroicThrowSpellId, target))
{
return "heroic throw"; return "heroic throw";
}
return PullStrategy::GetPullActionName(); return PullStrategy::GetPullActionName();
} }

View File

@ -8,15 +8,6 @@
#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))
@ -162,8 +153,14 @@ bool CastVigilanceAction::Execute(Event /*event*/)
bool CastRetaliationAction::isUseful() bool CastRetaliationAction::isUseful()
{ {
if (!bot->HasSpell(SPELL_RETALIATION) || bot->HasSpellCooldown(SPELL_RETALIATION) || // Spell cooldown check
bot->HasAura(SPELL_RETALIATION)) if (!bot->HasSpell(20230))
{
return false;
}
// Spell cooldown check
if (bot->HasSpellCooldown(20230))
{ {
return false; return false;
} }
@ -202,8 +199,8 @@ bool CastRetaliationAction::isUseful()
break; break;
} }
// Only cast Retaliation if there are at least 2 melee attackers // Only cast Retaliation if there are at least 2 melee attackers and the buff is not active
return meleeAttackers >= 2; return meleeAttackers >= 2 && !botAI->HasAura("retaliation", bot);
} }
Unit* CastShatteringThrowAction::GetTarget() Unit* CastShatteringThrowAction::GetTarget()
@ -217,15 +214,15 @@ Unit* CastShatteringThrowAction::GetTarget()
continue; continue;
if (bot->IsWithinDistInMap(enemy, 25.0f) && if (bot->IsWithinDistInMap(enemy, 25.0f) &&
(enemy->HasAura(SPELL_DIVINE_SHIELD) || (enemy->HasAura(642) || // Divine Shield
enemy->HasAura(SPELL_ICE_BLOCK) || enemy->HasAura(45438) || // Ice Block
enemy->HasAura(SPELL_BLESSING_OF_PROTECTION))) enemy->HasAura(41450))) // Blessing of Protection
{ {
return enemy; return enemy;
} }
} }
return nullptr; return nullptr; // No valid target
} }
bool CastShatteringThrowAction::Execute(Event /*event*/) bool CastShatteringThrowAction::Execute(Event /*event*/)
@ -239,7 +236,7 @@ bool CastShatteringThrowAction::Execute(Event /*event*/)
bool CastShatteringThrowAction::isUseful() bool CastShatteringThrowAction::isUseful()
{ {
if (!bot->HasSpell(SPELL_SHATTERING_THROW) || bot->HasSpellCooldown(SPELL_SHATTERING_THROW)) if (!bot->HasSpell(64382) || bot->HasSpellCooldown(64382))
return false; return false;
GuidVector enemies = AI_VALUE(GuidVector, "possible targets"); GuidVector enemies = AI_VALUE(GuidVector, "possible targets");
@ -250,16 +247,17 @@ 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(SPELL_DIVINE_SHIELD) || (enemy->HasAura(642) || // Divine Shield
enemy->HasAura(SPELL_ICE_BLOCK) || enemy->HasAura(45438) || // Ice Block
enemy->HasAura(SPELL_BLESSING_OF_PROTECTION))) enemy->HasAura(41450))) // Blessing of Protection
{ {
return true; return true;
} }
} }
return false; return false; // No valid targets within range
} }
bool CastShatteringThrowAction::isPossible() bool CastShatteringThrowAction::isPossible()

View File

@ -6,16 +6,6 @@
#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 &&
@ -24,7 +14,7 @@ bool BloodrageBuffTrigger::IsActive()
bool VigilanceTrigger::IsActive() bool VigilanceTrigger::IsActive()
{ {
if (!bot->HasSpell(SPELL_VIGILANCE)) if (!bot->HasSpell(50720))
return false; return false;
Group* group = bot->GetGroup(); Group* group = bot->GetGroup();
@ -74,7 +64,7 @@ bool VigilanceTrigger::IsActive()
bool ShatteringThrowTrigger::IsActive() bool ShatteringThrowTrigger::IsActive()
{ {
if (!bot->HasSpell(SPELL_SHATTERING_THROW) || bot->HasSpellCooldown(SPELL_SHATTERING_THROW)) if (!bot->HasSpell(64382) || bot->HasSpellCooldown(64382))
return false; return false;
GuidVector enemies = AI_VALUE(GuidVector, "possible targets"); GuidVector enemies = AI_VALUE(GuidVector, "possible targets");
@ -86,9 +76,9 @@ bool ShatteringThrowTrigger::IsActive()
continue; continue;
if (bot->IsWithinDistInMap(enemy, 25.0f) && if (bot->IsWithinDistInMap(enemy, 25.0f) &&
(enemy->HasAura(SPELL_DIVINE_SHIELD) || (enemy->HasAura(642) || // Divine Shield
enemy->HasAura(SPELL_ICE_BLOCK) || enemy->HasAura(45438) || // Ice Block
enemy->HasAura(SPELL_BLESSING_OF_PROTECTION))) enemy->HasAura(41450))) // Blessing of Protection
{ {
return true; return true;
} }
@ -122,13 +112,15 @@ 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(SPELL_COMMANDING_PRESENCE_RANKS[rank])) if (bot->HasAura(commandingPresenceSpells[rank]))
{ {
cpBonus = commandingPresenceBonus[rank]; cpBonus = commandingPresenceBonus[rank];
break; break;

View File

@ -5,13 +5,6 @@
#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())
@ -49,8 +42,7 @@ bool RazuviousUseObedienceCrystalAction::Execute(Event /*event*/)
bool tauntUseful = true; bool tauntUseful = true;
if (forceObedience->GetDuration() <= (duration_time - 5000)) if (forceObedience->GetDuration() <= (duration_time - 5000))
{ {
Unit* victim = target->GetVictim(); if (target->GetVictim() && botAI->HasAura(29061, target->GetVictim()))
if (victim && victim->HasAura(SPELL_BONE_BARRIER))
tauntUseful = false; tauntUseful = false;
if (forceObedience->GetDuration() <= 3000) if (forceObedience->GetDuration() <= 3000)
@ -63,19 +55,19 @@ bool RazuviousUseObedienceCrystalAction::Execute(Event /*event*/)
if (tauntUseful && !charm->HasSpellCooldown(29060)) if (tauntUseful && !charm->HasSpellCooldown(29060))
{ {
// shield // shield
if (!charm->HasSpellCooldown(SPELL_BONE_BARRIER)) if (!charm->HasSpellCooldown(29061))
{ {
charm->CastSpell(charm, SPELL_BONE_BARRIER, true); charm->CastSpell(charm, 29061, true);
charm->AddSpellCooldown(SPELL_BONE_BARRIER, 0, 30 * 1000); charm->AddSpellCooldown(29061, 0, 30 * 1000);
} }
charm->CastSpell(target, SPELL_UNDERSTUDY_TAUNT, true); charm->CastSpell(target, 29060, true);
charm->AddSpellCooldown(SPELL_UNDERSTUDY_TAUNT, 0, 20 * 1000); charm->AddSpellCooldown(29060, 0, 20 * 1000);
} }
// strike // strike
if (!charm->HasSpellCooldown(SPELL_BLOOD_STRIKE)) if (!charm->HasSpellCooldown(61696))
{ {
charm->CastSpell(target, SPELL_BLOOD_STRIKE, true); charm->CastSpell(target, 61696, true);
charm->AddSpellCooldown(SPELL_BLOOD_STRIKE, 0, 4 * 1000); charm->AddSpellCooldown(61696, 0, 4 * 1000);
} }
} }
} }

View File

@ -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(member, {NaxxSpellIds::Icebolt10, NaxxSpellIds::Icebolt25}) || if (NaxxSpellIds::HasAnyAura(botAI, 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))

View File

@ -111,13 +111,15 @@ bool ThaddiusMovePolarityAction::Execute(Event /*event*/)
{3504.68f, -2936.68f}, {3504.68f, -2936.68f},
}; };
uint32 idx; uint32 idx;
if (NaxxSpellIds::HasAnyAura(bot, if (NaxxSpellIds::HasAnyAura(
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(bot, else if (NaxxSpellIds::HasAnyAura(
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))
{ {

View File

@ -192,7 +192,7 @@ public:
{ {
Player* member = ref->GetSource(); Player* member = ref->GetSource();
if (member && if (member &&
(NaxxSpellIds::HasAnyAura(member, {NaxxSpellIds::Icebolt10, NaxxSpellIds::Icebolt25}) || (NaxxSpellIds::HasAnyAura(botAI, 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;

View File

@ -236,7 +236,7 @@ float AnubrekhanGenericMultiplier::GetValue(Action* action)
return 1.0f; return 1.0f;
if (NaxxSpellIds::HasAnyAura( if (NaxxSpellIds::HasAnyAura(
boss, {NaxxSpellIds::LocustSwarm10, NaxxSpellIds::LocustSwarm10Alt, NaxxSpellIds::LocustSwarm25}) || botAI, 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))

View File

@ -123,14 +123,14 @@ namespace NaxxSpellIds
SPELL_INEVITABLE_DOOM = 29204, SPELL_INEVITABLE_DOOM = 29204,
SPELL_BERSERK = 26662 SPELL_BERSERK = 26662
*/ */
inline bool HasAnyAura(Unit* unit, std::initializer_list<uint32> spellIds) inline bool HasAnyAura(PlayerbotAI* botAI, Unit* unit, std::initializer_list<uint32> spellIds)
{ {
if (!unit) if (!botAI || !unit)
return false; return false;
for (uint32 spellId : spellIds) for (uint32 spellId : spellIds)
{ {
if (unit->HasAura(spellId)) if (botAI->HasAura(spellId, unit))
return true; return true;
} }
return false; return false;

View File

@ -1531,7 +1531,7 @@ bool VezaxShadowCrashTrigger::IsActive()
if (!boss || !boss->IsAlive()) if (!boss || !boss->IsAlive())
return false; return false;
return bot->HasAura(SPELL_VEZAX_SHADOW_CRASH); return botAI->HasAura(SPELL_VEZAX_SHADOW_CRASH, bot);
} }
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 (!bot->HasAura(SPELL_MARK_OF_THE_FACELESS)) if (!botAI->HasAura(SPELL_MARK_OF_THE_FACELESS, bot))
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(),

View File

@ -26,15 +26,6 @@
#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())
@ -309,7 +300,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(SPELL_FROSTFIRE_BOLT) && player->HasAura(SPELL_ICE_SHARDS)) if (player->HasSpell(44614) /*Frostfire Bolt*/ && player->HasAura(15047) /*Ice Shards*/)
engine->addStrategiesNoInit("frostfire", "bdps", nullptr); engine->addStrategiesNoInit("frostfire", "bdps", nullptr);
else else
engine->addStrategiesNoInit("fire", "bdps", nullptr); engine->addStrategiesNoInit("fire", "bdps", nullptr);
@ -322,7 +313,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(SPELL_WHIRLWIND)) else if (tab == WARRIOR_TAB_ARMS || !player->HasSpell(1680)) // 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);
@ -354,7 +345,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(SPELL_CAT_FORM) && !player->HasAura(SPELL_DRUID_THICK_HIDE)) if (player->HasSpell(768) /*cat form*/ && !player->HasAura(16931) /*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);
@ -544,7 +535,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(SPELL_DRUID_THICK_HIDE)) if (player->GetLevel() >= 20 && !player->HasAura(16931) /*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);

View File

@ -61,56 +61,6 @@ 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);
@ -1490,7 +1440,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(SPELL_DRUID_THICK_HIDE); bool isCat = !bot->HasAura(16931);
if (!isCat && bot->GetLevel() == 20) if (!isCat && bot->GetLevel() == 20)
{ {
uint32 bearP = sPlayerbotAIConfig.randomClassSpecProb[cls][1]; uint32 bearP = sPlayerbotAIConfig.randomClassSpecProb[cls][1];
@ -1545,7 +1495,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(SPELL_SHAMAN_DUAL_WIELD)) if (bot->getClass() == CLASS_SHAMAN && bot->HasSpell(30798))
{ {
bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1); bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1);
bot->SetCanDualWield(true); bot->SetCanDualWield(true);
@ -1631,7 +1581,7 @@ void PlayerbotFactory::InitTalentsBySpecNo(Player* bot, int specNo, bool reset)
} }
} }
if (bot->getClass() == CLASS_SHAMAN && bot->HasSpell(SPELL_SHAMAN_DUAL_WIELD)) if (bot->getClass() == CLASS_SHAMAN && bot->HasSpell(30798))
{ {
bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1); bot->SetSkill(SKILL_DUAL_WIELD, 0, 1, 1);
bot->SetCanDualWield(true); bot->SetCanDualWield(true);
@ -4220,13 +4170,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(SPELL_SECOND_WIND)) if (bot->HasAura(29838))
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(SPELL_BLOOD_CRAZE)) else if (bot->HasAura(16492))
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(SPELL_GAG_ORDER)) else if (bot->HasAura(12958))
tab = 5; tab = 5;
} }
@ -4234,13 +4184,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(SPELL_SACRED_CLEANSING)) if (bot->HasAura(53553))
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(SPELL_RECKONING)) else if (bot->HasAura(20179))
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(SPELL_DIVINE_PURPOSE)) else if (bot->HasAura(31872))
tab = 5; tab = 5;
} }
@ -4248,13 +4198,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(SPELL_HUNTER_THICK_HIDE)) if (bot->HasAura(19612))
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(SPELL_CONCUSSIVE_BARRAGE)) else if (bot->HasAura(35102))
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(SPELL_ENTRAPMENT) && !bot->HasAura(SPELL_CONCUSSIVE_BARRAGE)) else if (bot->HasAura(19388) && !bot->HasAura(35102))
tab = 5; tab = 5;
} }
@ -4262,13 +4212,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(SPELL_DEADLY_BREW)) if (bot->HasAura(51626))
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(SPELL_THROWING_SPECIALIZATION)) else if (bot->HasAura(51679))
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(SPELL_WAYLAY)) else if (bot->HasAura(51696))
tab = 5; tab = 5;
} }
@ -4276,13 +4226,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(SPELL_IMPROVED_MANA_BURN)) if (bot->HasAura(14772))
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(SPELL_BODY_AND_SOUL)) else if (bot->HasAura(64129))
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(SPELL_IMPROVED_VAMPIRIC_EMBRACE)) else if (bot->HasAura(27840))
tab = 5; tab = 5;
} }
@ -4291,16 +4241,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(SPELL_ABOMINATIONS_MIGHT) && bot->HasAura(SPELL_IMPROVED_ICY_TALONS)) if (bot->HasAura(53138) && bot->HasAura(55610))
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(SPELL_SUDDEN_DOOM)) else if (bot->HasAura(49529))
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(SPELL_ACCLIMATION)) else if (bot->HasAura(50152))
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(SPELL_MAGIC_SUPPRESSION)) else if (bot->HasAura(49611))
tab = 6; tab = 6;
} }
@ -4308,13 +4258,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(SPELL_ASTRAL_SHIFT)) if (bot->HasAura(51479))
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(SPELL_EARTHEN_POWER)) else if (bot->HasAura(51524))
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(SPELL_FOCUSED_MIND)) else if (bot->HasAura(30866))
tab = 5; tab = 5;
} }
@ -4322,16 +4272,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(SPELL_BURNOUT) && bot->HasAura(SPELL_ICE_SHARDS)) if (bot->HasAura(44472) && bot->HasAura(15047))
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(SPELL_IMPROVED_BLINK)) else if (bot->HasAura(31570))
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(SPELL_FIERY_PAYBACK)) else if (bot->HasAura(64357))
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(SPELL_SHATTERED_BARRIER)) else if (bot->HasAura(54787))
tab = 6; tab = 6;
} }
@ -4339,13 +4289,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(SPELL_IMPROVED_HOWL_OF_TERROR)) if (bot->HasAura(30057))
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(SPELL_NEMESIS) && bot->HasAura(SPELL_INTENSITY)) else if (bot->HasAura(63123) && bot->HasAura(18136))
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(SPELL_NETHER_PROTECTION)) else if (bot->HasAura(30302))
tab = 5; tab = 5;
} }
@ -4353,16 +4303,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(SPELL_DRUID_THICK_HIDE)) if (tab == DRUID_TAB_FERAL && bot->GetLevel() >= 20 && !bot->HasAura(16931))
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(SPELL_OWLKIN_FRENZY)) else if (bot->HasAura(48393))
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(SPELL_PRIMAL_TENACITY)) else if (bot->HasAura(33957))
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(SPELL_IMPROVED_BARKSKIN)) else if (bot->HasAura(63411))
tab = 6; tab = 6;
} }

View File

@ -3027,8 +3027,6 @@ bool PlayerbotAI::TellMaster(std::string const text, PlayerbotSecurityLevel secu
{ {
if (sPlayerbotAIConfig.randomBotSayWithoutMaster) if (sPlayerbotAIConfig.randomBotSayWithoutMaster)
return TellMasterNoFacing(text, securityLevel); return TellMasterNoFacing(text, securityLevel);
return false;
} }
if (!TellMasterNoFacing(text, securityLevel)) if (!TellMasterNoFacing(text, securityLevel))
return false; return false;
@ -3152,10 +3150,20 @@ bool PlayerbotAI::HasAura(std::string const name, Unit* unit, bool maxStack, boo
return false; return false;
} }
bool PlayerbotAI::HasSpell(std::string const spellName) const bool PlayerbotAI::HasAura(uint32 spellId, Unit const* unit)
{ {
uint32 const spellId = aiObjectContext->GetValue<uint32>("spell id", spellName)->Get(); if (!spellId || !unit)
return spellId && bot->HasSpell(spellId); return false;
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)
@ -4259,7 +4267,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 && bot->HasAura(spellid)) if (spellid && HasAura(spellid, bot))
bot->RemoveAurasDueToSpell(spellid); bot->RemoveAurasDueToSpell(spellid);
} }

View File

@ -497,7 +497,6 @@ 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, ...);
@ -510,6 +509,7 @@ 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);

View File

@ -23,29 +23,13 @@
namespace namespace
{ {
constexpr uint32 SPELL_MOLTEN_ARMOR_RANKS[] = { 30482, 43045, 43046 }; constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_1 = 30482;
constexpr uint32 SPELL_FEL_ARMOR_RANKS[] = { 28176, 28189, 47892, 47893 }; constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_2 = 43045;
constexpr uint32 SPELL_CAREFUL_AIM = 34484; constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_3 = 43046;
constexpr uint32 SPELL_HUNTER_VS_WILD = 56341; constexpr uint32 SPELL_FEL_ARMOR_RANK_1 = 28176;
constexpr uint32 SPELL_ARMORED_TO_THE_TEETH = 61222; constexpr uint32 SPELL_FEL_ARMOR_RANK_2 = 28189;
constexpr uint32 SPELL_MENTAL_DEXTERITY = 51885; constexpr uint32 SPELL_FEL_ARMOR_RANK_3 = 47892;
constexpr uint32 SPELL_ROGUE_SWORD_SPECIALIZATION = 13964; constexpr uint32 SPELL_FEL_ARMOR_RANK_4 = 47893;
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)
@ -528,24 +512,26 @@ 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(SPELL_CAREFUL_AIM)) if (player->HasAura(34484))
stats_weights_[STATS_TYPE_INTELLECT] += 1.1f; stats_weights_[STATS_TYPE_INTELLECT] += 1.1f;
if (player->HasAura(SPELL_HUNTER_VS_WILD)) if (player->HasAura(56341))
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(SPELL_ARMORED_TO_THE_TEETH)) if (player->HasAura(61222))
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(SPELL_MENTAL_DEXTERITY)) if (player->HasAura(51885))
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 (!HasAnySpell(player, SPELL_MOLTEN_ARMOR_RANKS)) if (!player->HasSpell(SPELL_MOLTEN_ARMOR_RANK_1)
&& !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;
@ -555,7 +541,8 @@ void StatsWeightCalculator::GenerateAdditionalWeights(Player* player)
} }
else if (cls == CLASS_WARLOCK) else if (cls == CLASS_WARLOCK)
{ {
if (!HasAnySpell(player, SPELL_FEL_ARMOR_RANKS)) if (!player->HasSpell(SPELL_FEL_ARMOR_RANK_1) && !player->HasSpell(SPELL_FEL_ARMOR_RANK_2) &&
!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;
} }
@ -703,17 +690,17 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
weight_ *= 1.5; weight_ *= 1.5;
} }
if (cls == CLASS_ROGUE && player_->HasAura(SPELL_ROGUE_SWORD_SPECIALIZATION) && if (cls == CLASS_ROGUE && player_->HasAura(13964) &&
(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(SPELL_POLEAXE_SPECIALIZATION) && if (cls == CLASS_WARRIOR && player_->HasAura(12785) &&
(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(SPELL_NERVES_OF_COLD_STEEL) && !isDoubleHand) if (cls == CLASS_DEATH_KNIGHT && player_->HasAura(50138) && !isDoubleHand)
{ {
weight_ *= 1.3; weight_ *= 1.3;
} }
@ -752,9 +739,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(SPELL_SHADOW_FOCUS)) if (cls == CLASS_PRIEST && tab == PRIEST_TAB_SHADOW && player->HasAura(15835)) // Shadow Focus
hit_current += 3; hit_current += 3;
if (cls == CLASS_MAGE && tab == MAGE_TAB_ARCANE && player->HasAura(SPELL_ARCANE_FOCUS)) if (cls == CLASS_MAGE && tab == MAGE_TAB_ARCANE && player->HasAura(12840)) // Arcane Focus
hit_current += 3; hit_current += 3;
hit_overflow = SPELL_HIT_OVERFLOW; hit_overflow = SPELL_HIT_OVERFLOW;