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"
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
std::unordered_map<uint32, PreferredMountCache> CheckMountStateAction::mountCache;
@ -62,21 +61,6 @@ MountData CollectMountData(const Player* bot)
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
bool noAttackers = !AI_VALUE2(bool, "combat", "self target") || !AI_VALUE(uint8, "attacker count");
bool enemy = AI_VALUE(Unit*, "enemy player target");
@ -220,7 +204,7 @@ bool CheckMountStateAction::Mount()
// Get bot mount data
MountData mountData = CollectMountData(bot);
int32 masterMountType = GetMountType(master);
int32 masterSpeed = CalculateMasterMountSpeed(master);
int32 masterSpeed = CalculateMasterMountSpeed(master, mountData);
// Try shapeshift
if (TryForms(master, masterMountType, masterSpeed))
@ -250,17 +234,14 @@ void CheckMountStateAction::Dismount()
WorldPacket emptyPacket;
bot->GetSession()->HandleCancelMountAuraOpcode(emptyPacket);
ClearStaleFlightFlags();
}
void CheckMountStateAction::ClearStaleFlightFlags()
{
if (bot->HasIncreaseMountedFlightSpeedAura() || bot->HasFlyAura())
return;
if (bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_DISABLE_GRAVITY))
bool const wantsFly = bot->HasIncreaseMountedFlightSpeedAura() || bot->HasFlyAura();
bool const isWaterWalking = bot->HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING);
bool const isFlying = bot->HasUnitMovementFlag(MOVEMENTFLAG_FLYING);
bool const hasGravityDisabled = bot->HasUnitMovementFlag(MOVEMENTFLAG_DISABLE_GRAVITY);
if (!wantsFly && !isWaterWalking && (isFlying || hasGravityDisabled))
{
bot->RemoveUnitMovementFlag(MOVEMENTFLAG_FLYING | MOVEMENTFLAG_DISABLE_GRAVITY | MOVEMENTFLAG_CAN_FLY);
bot->RemoveUnitMovementFlag(
MOVEMENTFLAG_FLYING | MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY);
if (!bot->IsRooted())
bot->SendMovementFlagUpdate();
}
@ -509,7 +490,7 @@ static bool BotCanUseFlyingMount(Player const* bot)
return true;
}
int32 CheckMountStateAction::CalculateMasterMountSpeed(Player* master) const
int32 CheckMountStateAction::CalculateMasterMountSpeed(Player* master, const MountData& mountData) const
{
// Check riding skill and level requirements
int32 ridingSkill = bot->GetPureSkillValue(SKILL_RIDING);

View File

@ -53,10 +53,9 @@ private:
float CalculateDismountDistance() const;
float CalculateMountDistance() const;
void Dismount();
void ClearStaleFlightFlags();
bool ShouldFollowMasterMountState(Player* master, bool noAttackers, bool shouldMount) const;
bool ShouldDismountForMaster(Player* master) const;
int32 CalculateMasterMountSpeed(Player* master) const;
int32 CalculateMasterMountSpeed(Player* master, const MountData& mountData) const;
bool CheckForSwiftMount() const;
std::map<uint32, std::map<int32, std::vector<uint32>>> GetAllMountSpells() 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
bot->RemovePet(nullptr, PET_SAVE_AS_CURRENT, true);
constexpr uint32 SPELL_CALL_PET = 883;
if (bot->getClass() == CLASS_HUNTER && bot->HasSpell(SPELL_CALL_PET))
bot->CastSpell(bot, SPELL_CALL_PET, true);
if (bot->getClass() == CLASS_HUNTER && bot->HasSpell(883))
{
bot->CastSpell(bot, 883, true);
}
return true;
}

View File

@ -67,10 +67,9 @@ bool TradeStatusExtendedAction::Execute(Event event)
return false;
}
constexpr uint32 SPELL_PICK_LOCK = 1804;
if (bot->getClass() == CLASS_ROGUE && bot->HasSpell(SPELL_PICK_LOCK) && lockbox->IsLocked())
if (bot->getClass() == CLASS_ROGUE && bot->HasSpell(1804) && lockbox->IsLocked()) // Pick Lock spell
{
// 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->SetNextCheckDelay(4000); // Delay before accepting trade
}

View File

@ -23,7 +23,9 @@ bool BossFireResistanceTrigger::IsActive()
return false;
// 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;
// Check if bot dont have already have fire resistance strategy
@ -74,7 +76,9 @@ bool BossFrostResistanceTrigger::IsActive()
return false;
// 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;
// Check if bot dont have already have frost resistance strategy
@ -129,7 +133,8 @@ bool BossNatureResistanceTrigger::IsActive()
return false;
// 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;
// Check if bot dont have already setted nature resistance aura
@ -179,7 +184,11 @@ bool BossShadowResistanceTrigger::IsActive()
return false;
// 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;
// Check if bot dont have already have shadow resistance strategy

View File

@ -5,27 +5,39 @@
#include "DeathKnightPullStrategy.h"
#include "AiObjectContext.h"
#include "Player.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
std::string DeathKnightPullStrategy::GetPullActionName() const
{
Player* bot = botAI->GetBot();
Unit* target = GetTarget();
if (!target ||
if (!bot || !target ||
(!botAI->HasStrategy("blood", BOT_STATE_COMBAT) && !botAI->HasStrategy("blood", BOT_STATE_NON_COMBAT)))
{
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";
}
if (!botAI->CanCastSpell("icy touch", target) &&
botAI->CanCastSpell("dark command", target))
uint32 const icyTouchSpellId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "icy touch")->Get();
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 PullStrategy::GetPullActionName();
}

View File

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

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 TreeFormTrigger::IsActive()
{
constexpr uint32 SPELL_TREE_OF_LIFE = 33891;
return !bot->HasAura(SPELL_TREE_OF_LIFE);
}
bool TreeFormTrigger::IsActive() { return !botAI->HasAura(33891, bot); }
bool CatFormTrigger::IsActive() { return !botAI->HasAura("cat form", bot); }
@ -47,11 +43,8 @@ bool ProwlTrigger::IsActive()
if (botAI->HasAura("prowl", bot) || bot->IsInCombat())
return false;
if (!botAI->HasSpell("prowl"))
return false;
uint32 const prowlId = AI_VALUE2(uint32, "spell id", "prowl");
if (bot->HasSpellCooldown(prowlId))
uint32 prowlId = botAI->GetAiObjectContext()->GetValue<uint32>("spell id", "prowl")->Get();
if (!prowlId || !bot->HasSpell(prowlId) || bot->HasSpellCooldown(prowlId))
return false;
float distance = 30.f;

View File

@ -393,14 +393,14 @@ public:
class FerociousBiteExecuteTrigger : public Trigger
{
public:
FerociousBiteExecuteTrigger(PlayerbotAI* botAI) : Trigger(botAI, "ferocious bite execute") {}
FerociousBiteExecuteTrigger(PlayerbotAI* ai) : Trigger(ai, "ferocious bite execute") {}
bool IsActive() override
{
Unit* target = AI_VALUE(Unit*, "current target");
if (!target || !target->IsAlive())
return false;
if (!botAI->HasSpell("ferocious bite"))
if (!AI_VALUE2(uint32, "spell id", "ferocious bite"))
return false;
if (AI_VALUE2(uint8, "combo", "current target") < 1)

View File

@ -5,23 +5,34 @@
#include "DruidPullStrategy.h"
#include "AiObjectContext.h"
#include "Player.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
std::string DruidPullStrategy::GetPullActionName() const
{
std::string const pullActionName = PullStrategy::GetPullActionName();
std::string const actionName =
botAI->HasSpell("faerie fire (feral)") &&
(botAI->HasStrategy("bear", BOT_STATE_COMBAT) || botAI->HasStrategy("cat", BOT_STATE_COMBAT))
? "faerie fire (feral)" : pullActionName;
Unit* target = GetTarget();
if (!target)
Player* bot = botAI->GetBot();
std::string actionName = PullStrategy::GetPullActionName();
if (!bot)
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 actionName;
}

View File

@ -19,13 +19,23 @@ bool CastViperStingAction::isUseful()
bool CastAspectOfTheHawkAction::isUseful()
{
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()
{
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;
// Armor Penetration rating check - will not cast Arcane Shot above 435 ArP
@ -40,7 +50,14 @@ bool CastArcaneShotAction::isUseful()
bool CastImmolationTrapAction::isUseful()
{
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()

View File

@ -13,7 +13,7 @@
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 CastBuffSpellAction::getAlternatives();
@ -21,7 +21,7 @@ std::vector<NextAction> CastMoltenArmorAction::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 CastBuffSpellAction::getAlternatives();

View File

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

View File

@ -8,18 +8,6 @@
#include "Playerbots.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>
{
public:
@ -114,17 +102,17 @@ void GenericMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
// Mana Threshold Triggers
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) }));
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) }));
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) }));
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) }));
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) }));
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("medium mana", { NextAction("mana potion", 90.0f) }));
@ -154,7 +142,7 @@ void MageBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
}
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
triggers.push_back(new TriggerNode("combustion", { NextAction("combustion", 18.0f) }));
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))
return false;
if (!botAI->HasSpell(spellName))
uint32 finalId = AI_VALUE2(uint32, "spell id", spellName);
if (!finalId)
return false;
return botAI->CastSpell(spellName, assignment.player);

View File

@ -5,23 +5,34 @@
#include "PaladinPullStrategy.h"
#include "AiObjectContext.h"
#include "Player.h"
#include "PlayerbotAI.h"
#include "Playerbots.h"
std::string PaladinPullStrategy::GetPullActionName() const
{
Player* bot = botAI->GetBot();
Unit* target = GetTarget();
if (!target ||
if (!bot || !target ||
(!botAI->HasStrategy("tank", BOT_STATE_COMBAT) && !botAI->HasStrategy("tank", BOT_STATE_NON_COMBAT)))
{
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";
}
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 PullStrategy::GetPullActionName();
}

View File

@ -11,14 +11,6 @@
#include "PlayerbotAIConfig.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()
{
Unit* target = AI_VALUE(Unit*, "current target");
@ -30,8 +22,7 @@ bool CastStealthAction::isUseful()
bool CastStealthAction::isPossible()
{
// do not use with WSG flag or EYE flag
return !bot->HasAura(SPELL_WARSONG_FLAG) && !bot->HasAura(SPELL_SILVERWING_FLAG) &&
!bot->HasAura(SPELL_NETHERSTORM_FLAG);
return !botAI->HasAura(23333, bot) && !botAI->HasAura(23335, bot) && !botAI->HasAura(34976, bot);
}
bool UnstealthAction::Execute(Event /*event*/)
@ -59,8 +50,7 @@ bool CheckStealthAction::Execute(Event /*event*/)
bool CastVanishAction::isUseful()
{
// do not use with WSG flag or EYE flag
return !bot->HasAura(SPELL_WARSONG_FLAG) && !bot->HasAura(SPELL_SILVERWING_FLAG) &&
!bot->HasAura(SPELL_NETHERSTORM_FLAG);
return !botAI->HasAura(23333, bot) && !botAI->HasAura(23335, bot) && !botAI->HasAura(34976, bot);
}
bool CastEnvenomAction::isUseful()
@ -71,7 +61,7 @@ bool CastEnvenomAction::isUseful()
bool CastEnvenomAction::isPossible()
{
// 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()

View File

@ -9,12 +9,6 @@
#include "Playerbots.h"
#include "ServerFacade.h"
namespace
{
constexpr uint32 SPELL_STEALTH = 1784;
constexpr uint32 SPELL_SPRINT_RANK_1 = 2983;
}
// bool AdrenalineRushTrigger::isPossible()
// {
// return !botAI->HasAura("stealth", bot);
@ -35,7 +29,7 @@ bool UnstealthTrigger::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;
float distance = 30.f;
@ -69,13 +63,13 @@ bool StealthTrigger::IsActive()
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()
{
if (bot->HasSpellCooldown(SPELL_SPRINT_RANK_1))
if (bot->HasSpellCooldown(2983))
return false;
float distance = botAI->GetMaster() ? 45.0f : 35.0f;
@ -111,7 +105,7 @@ bool SprintTrigger::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) &&
AI_VALUE2(uint8, "combo", "current target") <= 3;
}

View File

@ -6,17 +6,6 @@
#include "TotemsShamanStrategy.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.
// 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.
@ -85,9 +74,9 @@ void TotemOfWrathStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
GenericShamanStrategy::InitTriggers(triggers);
// If the bot hasn't learned Totem of Wrath yet, set Flametongue Totem instead.
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) }));
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("no fire totem", { NextAction("totem of wrath", 55.0f) }));
}
@ -123,9 +112,9 @@ void CleansingTotemStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
GenericShamanStrategy::InitTriggers(triggers);
// If the bot hasn't learned Cleansing Totem yet, set Mana Spring Totem instead.
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) }));
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("no water totem", { NextAction("cleansing totem", 55.0f) }));
}
@ -145,9 +134,9 @@ void WrathOfAirTotemStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
GenericShamanStrategy::InitTriggers(triggers);
// If the bot hasn't learned Wrath of Air Totem yet, set Grounding Totem instead.
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) }));
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("no air totem", { NextAction("wrath of air totem", 55.0f) }));
}
@ -158,9 +147,9 @@ void WindfuryTotemStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
GenericShamanStrategy::InitTriggers(triggers);
// If the bot hasn't learned Windfury Totem yet, set Grounding Totem instead.
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) }));
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("no air totem", { NextAction("windfury totem", 55.0f) }));
}

View File

@ -77,7 +77,11 @@ bool CastShadowflameAction::isUseful()
bool CastRainOfFireAction::isUseful()
{
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

View File

@ -104,8 +104,10 @@ bool LifeTapTrigger::IsActive()
// Checks if the Life Tap Glyph buff is active
bool LifeTapGlyphBuffTrigger::IsActive()
{
constexpr uint32 SPELL_LIFE_TAP_GLYPH = 63320;
return bot->HasAura(SPELL_LIFE_TAP_GLYPH) && BuffTrigger::IsActive();
if (!botAI->HasAura(63320, bot))
return false;
return BuffTrigger::IsActive();
}
// 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 "AiObjectContext.h"
#include "Player.h"
#include "PlayerbotAI.h"
std::string WarriorPullStrategy::GetPullActionName() const
{
Player* bot = botAI->GetBot();
Unit* target = GetTarget();
if (!target)
if (!bot || !target)
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 PullStrategy::GetPullActionName();
}

View File

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

View File

@ -6,16 +6,6 @@
#include "WarriorTriggers.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()
{
return AI_VALUE2(uint8, "health", "self target") >= sPlayerbotAIConfig.mediumHealth &&
@ -24,7 +14,7 @@ bool BloodrageBuffTrigger::IsActive()
bool VigilanceTrigger::IsActive()
{
if (!bot->HasSpell(SPELL_VIGILANCE))
if (!bot->HasSpell(50720))
return false;
Group* group = bot->GetGroup();
@ -74,7 +64,7 @@ bool VigilanceTrigger::IsActive()
bool ShatteringThrowTrigger::IsActive()
{
if (!bot->HasSpell(SPELL_SHATTERING_THROW) || bot->HasSpellCooldown(SPELL_SHATTERING_THROW))
if (!bot->HasSpell(64382) || bot->HasSpellCooldown(64382))
return false;
GuidVector enemies = AI_VALUE(GuidVector, "possible targets");
@ -86,9 +76,9 @@ bool ShatteringThrowTrigger::IsActive()
continue;
if (bot->IsWithinDistInMap(enemy, 25.0f) &&
(enemy->HasAura(SPELL_DIVINE_SHIELD) ||
enemy->HasAura(SPELL_ICE_BLOCK) ||
enemy->HasAura(SPELL_BLESSING_OF_PROTECTION)))
(enemy->HasAura(642) || // Divine Shield
enemy->HasAura(45438) || // Ice Block
enemy->HasAura(41450))) // Blessing of Protection
{
return true;
}
@ -122,13 +112,15 @@ bool BattleShoutTrigger::IsActive()
if (!bsApValue)
return false;
static const uint32 commandingPresenceSpells[] = {
12318, 12857, 12858, 12860, 12861 };
static const float commandingPresenceBonus[] = {
0.05f, 0.10f, 0.15f, 0.20f, 0.25f };
float cpBonus = 0.0f;
for (int rank = 4; rank >= 0; --rank)
{
if (bot->HasAura(SPELL_COMMANDING_PRESENCE_RANKS[rank]))
if (bot->HasAura(commandingPresenceSpells[rank]))
{
cpBonus = commandingPresenceBonus[rank];
break;

View File

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

View File

@ -75,7 +75,7 @@ bool SapphironFlightPositionAction::MoveToNearestIcebolt()
for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next())
{
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))
{
if (!playerWithIcebolt || minDistance > bot->GetDistance(member))

View File

@ -111,13 +111,15 @@ bool ThaddiusMovePolarityAction::Execute(Event /*event*/)
{3504.68f, -2936.68f},
};
uint32 idx;
if (NaxxSpellIds::HasAnyAura(bot,
if (NaxxSpellIds::HasAnyAura(
botAI, bot,
{NaxxSpellIds::NegativeCharge10, NaxxSpellIds::NegativeCharge25, NaxxSpellIds::NegativeChargeStack}) ||
botAI->HasAura("negative charge", bot, false, false, -1, true))
{
idx = 0;
}
else if (NaxxSpellIds::HasAnyAura(bot,
else if (NaxxSpellIds::HasAnyAura(
botAI, bot,
{NaxxSpellIds::PositiveCharge10, NaxxSpellIds::PositiveCharge25, NaxxSpellIds::PositiveChargeStack}) ||
botAI->HasAura("positive charge", bot, false, false, -1, true))
{

View File

@ -192,7 +192,7 @@ public:
{
Player* member = ref->GetSource();
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)))
{
return true;

View File

@ -236,7 +236,7 @@ float AnubrekhanGenericMultiplier::GetValue(Action* action)
return 1.0f;
if (NaxxSpellIds::HasAnyAura(
boss, {NaxxSpellIds::LocustSwarm10, NaxxSpellIds::LocustSwarm10Alt, NaxxSpellIds::LocustSwarm25}) ||
botAI, boss, {NaxxSpellIds::LocustSwarm10, NaxxSpellIds::LocustSwarm10Alt, NaxxSpellIds::LocustSwarm25}) ||
botAI->HasAura("locust swarm", boss))
{
if (dynamic_cast<FleeAction*>(action))

View File

@ -123,14 +123,14 @@ namespace NaxxSpellIds
SPELL_INEVITABLE_DOOM = 29204,
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;
for (uint32 spellId : spellIds)
{
if (unit->HasAura(spellId))
if (botAI->HasAura(spellId, unit))
return true;
}
return false;

View File

@ -1531,7 +1531,7 @@ bool VezaxShadowCrashTrigger::IsActive()
if (!boss || !boss->IsAlive())
return false;
return bot->HasAura(SPELL_VEZAX_SHADOW_CRASH);
return botAI->HasAura(SPELL_VEZAX_SHADOW_CRASH, bot);
}
bool VezaxMarkOfTheFacelessTrigger::IsActive()
@ -1542,7 +1542,7 @@ bool VezaxMarkOfTheFacelessTrigger::IsActive()
if (!boss || !boss->IsAlive())
return false;
if (!bot->HasAura(SPELL_MARK_OF_THE_FACELESS))
if (!botAI->HasAura(SPELL_MARK_OF_THE_FACELESS, bot))
return false;
float distance = bot->GetDistance2d(ULDUAR_VEZAX_MARK_OF_THE_FACELESS_SPOT.GetPositionX(),

View File

@ -26,15 +26,6 @@
#include "WarlockAiObjectContext.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)
{
switch (player->getClass())
@ -309,7 +300,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
engine->addStrategiesNoInit("arcane", "bdps", nullptr);
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);
else
engine->addStrategiesNoInit("fire", "bdps", nullptr);
@ -322,7 +313,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
case CLASS_WARRIOR:
if (tab == WARRIOR_TAB_PROTECTION)
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);
else // if (tab == WARRIOR_TAB_FURY)
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);
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);
else
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:
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);
else
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::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)
{
SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(skillId);
@ -1490,7 +1440,7 @@ uint32 PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_temp
/// @todo: fix cat druid hardcode
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)
{
uint32 bearP = sPlayerbotAIConfig.randomClassSpecProb[cls][1];
@ -1545,7 +1495,7 @@ uint32 PlayerbotFactory::InitTalentsTree(bool increment /*false*/, bool use_temp
if (bot->GetFreeTalentPoints())
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->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->SetCanDualWield(true);
@ -4220,13 +4170,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
if (bot->getClass() == CLASS_WARRIOR)
{
// 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;
// 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;
// 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;
}
@ -4234,13 +4184,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
if (bot->getClass() == CLASS_PALADIN)
{
// 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;
// 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;
// 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;
}
@ -4248,13 +4198,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
if (bot->getClass() == CLASS_HUNTER)
{
// 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;
// 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;
// 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;
}
@ -4262,13 +4212,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
if (bot->getClass() == CLASS_ROGUE)
{
// 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;
// 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;
// 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;
}
@ -4276,13 +4226,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
if (bot->getClass() == CLASS_PRIEST)
{
// 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;
// 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;
// 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;
}
@ -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
// talents
if (bot->HasAura(SPELL_ABOMINATIONS_MIGHT) && bot->HasAura(SPELL_IMPROVED_ICY_TALONS))
if (bot->HasAura(53138) && bot->HasAura(55610))
tab = 3;
// 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;
// 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;
// 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;
}
@ -4308,13 +4258,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
if (bot->getClass() == CLASS_SHAMAN)
{
// 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;
// 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;
// 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;
}
@ -4322,16 +4272,16 @@ void PlayerbotFactory::InitGlyphs(bool increment)
if (bot->getClass() == CLASS_MAGE)
{
// 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;
// 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;
// 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;
// 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;
}
@ -4339,13 +4289,13 @@ void PlayerbotFactory::InitGlyphs(bool increment)
if (bot->getClass() == CLASS_WARLOCK)
{
// 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;
// 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;
// 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;
}
@ -4353,16 +4303,16 @@ void PlayerbotFactory::InitGlyphs(bool increment)
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
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;
// 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;
// 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;
// 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;
}

View File

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

View File

@ -497,7 +497,6 @@ public:
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 HasSpell(std::string const spellName) const;
virtual bool HasAura(std::string const spellName, Unit* player, bool maxStack = false, bool checkIsOwner = false,
int maxAmount = -1, bool checkDuration = false);
virtual bool HasAnyAuraOf(Unit* player, ...);
@ -510,6 +509,7 @@ public:
bool CanCastSpell(uint32 spellid, float x, float y, float z, bool checkHasSpell = true,
Item* itemTarget = nullptr);
bool HasAura(uint32 spellId, Unit const* player);
Aura* GetAura(std::string const spellName, Unit* unit, bool checkIsOwner = false, bool checkDuration = false,
int checkStack = -1);
bool CastSpell(uint32 spellId, Unit* target, Item* itemTarget = nullptr);

View File

@ -23,29 +23,13 @@
namespace
{
constexpr uint32 SPELL_MOLTEN_ARMOR_RANKS[] = { 30482, 43045, 43046 };
constexpr uint32 SPELL_FEL_ARMOR_RANKS[] = { 28176, 28189, 47892, 47893 };
constexpr uint32 SPELL_CAREFUL_AIM = 34484;
constexpr uint32 SPELL_HUNTER_VS_WILD = 56341;
constexpr uint32 SPELL_ARMORED_TO_THE_TEETH = 61222;
constexpr uint32 SPELL_MENTAL_DEXTERITY = 51885;
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;
constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_1 = 30482;
constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_2 = 43045;
constexpr uint32 SPELL_MOLTEN_ARMOR_RANK_3 = 43046;
constexpr uint32 SPELL_FEL_ARMOR_RANK_1 = 28176;
constexpr uint32 SPELL_FEL_ARMOR_RANK_2 = 28189;
constexpr uint32 SPELL_FEL_ARMOR_RANK_3 = 47892;
constexpr uint32 SPELL_FEL_ARMOR_RANK_4 = 47893;
}
StatsWeightCalculator::StatsWeightCalculator(Player* player) : player_(player)
@ -528,24 +512,26 @@ void StatsWeightCalculator::GenerateAdditionalWeights(Player* player)
// int tab = AiFactory::GetPlayerSpecTab(player);
if (cls == CLASS_HUNTER)
{
if (player->HasAura(SPELL_CAREFUL_AIM))
if (player->HasAura(34484))
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;
}
else if (cls == CLASS_WARRIOR)
{
if (player->HasAura(SPELL_ARMORED_TO_THE_TEETH))
if (player->HasAura(61222))
stats_weights_[STATS_TYPE_ARMOR] += 0.03f;
}
else if (cls == CLASS_SHAMAN)
{
if (player->HasAura(SPELL_MENTAL_DEXTERITY))
if (player->HasAura(51885))
stats_weights_[STATS_TYPE_INTELLECT] += 1.1f;
}
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)
stats_weights_[STATS_TYPE_SPIRIT] -= 0.6f;
@ -555,7 +541,8 @@ void StatsWeightCalculator::GenerateAdditionalWeights(Player* player)
}
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;
}
@ -703,17 +690,17 @@ void StatsWeightCalculator::CalculateItemTypePenalty(ItemTemplate const* proto)
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))
{
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))
{
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;
}
@ -752,9 +739,9 @@ void StatsWeightCalculator::ApplyOverflowPenalty(Player* player)
player->GetTotalAuraModifier(SPELL_AURA_MOD_INCREASES_SPELL_PCT_TO_HIT); // suppression (18176)
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;
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_overflow = SPELL_HIT_OVERFLOW;