diff --git a/src/Ai/Class/Mage/Action/MageActions.cpp b/src/Ai/Class/Mage/Action/MageActions.cpp index 63ba0d9d5..9c190d54c 100644 --- a/src/Ai/Class/Mage/Action/MageActions.cpp +++ b/src/Ai/Class/Mage/Action/MageActions.cpp @@ -11,6 +11,22 @@ #include "ServerFacade.h" #include "SharedDefines.h" +std::vector CastMoltenArmorAction::getAlternatives() +{ + if (!AI_VALUE2(uint32, "spell id", "molten armor")) + return NextAction::merge({ NextAction("mage armor") }, CastBuffSpellAction::getAlternatives()); + + return CastBuffSpellAction::getAlternatives(); +} + +std::vector CastMageArmorAction::getAlternatives() +{ + if (!AI_VALUE2(uint32, "spell id", "mage armor")) + return NextAction::merge({ NextAction("ice armor") }, CastBuffSpellAction::getAlternatives()); + + return CastBuffSpellAction::getAlternatives(); +} + bool UseManaSapphireAction::isUseful() { Player* bot = botAI->GetBot(); @@ -50,22 +66,23 @@ bool UseManaAgateAction::isUseful() bool CastFrostNovaAction::isUseful() { Unit* target = AI_VALUE(Unit*, "current target"); - if (!target || !target->IsInWorld()) + if (!target || !target->IsInWorld() || target->isFrozen() || + (target->ToCreature() && + target->ToCreature()->HasMechanicTemplateImmunity(1 << (MECHANIC_FREEZE - 1)))) + { return false; + } - if (target->ToCreature() && target->ToCreature()->HasMechanicTemplateImmunity(1 << (MECHANIC_FREEZE - 1))) - return false; - - if (target->isFrozen()) - return false; - - return ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f); + return ServerFacade::instance().IsDistanceLessOrEqualThan( + AI_VALUE2(float, "distance", GetTargetName()), 10.f); } bool CastConeOfColdAction::isUseful() { bool facingTarget = AI_VALUE2(bool, "facing", "current target"); - bool targetClose = ServerFacade::instance().IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f); + bool targetClose = ServerFacade::instance().IsDistanceLessOrEqualThan( + AI_VALUE2(float, "distance", GetTargetName()), 10.f); + return facingTarget && targetClose; } @@ -74,6 +91,7 @@ bool CastDragonsBreathAction::isUseful() Unit* target = AI_VALUE(Unit*, "current target"); if (!target) return false; + bool facingTarget = AI_VALUE2(bool, "facing", "current target"); bool targetClose = bot->IsWithinCombatRange(target, 10.0f); return facingTarget && targetClose; @@ -84,6 +102,7 @@ bool CastBlastWaveAction::isUseful() Unit* target = AI_VALUE(Unit*, "current target"); if (!target) return false; + bool targetClose = bot->IsWithinCombatRange(target, 10.0f); return targetClose; } @@ -100,14 +119,11 @@ Unit* CastFocusMagicOnPartyAction::GetTarget() for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) { Player* member = ref->GetSource(); - if (!member || member == bot || !member->IsAlive()) - continue; - - if (member->GetMap() != bot->GetMap() || bot->GetDistance(member) > sPlayerbotAIConfig.spellDistance) - continue; - - if (member->HasAura(54646)) + if (!member || member == bot || !member->IsAlive() || member->GetMap() != bot->GetMap() || + bot->GetDistance(member) > sPlayerbotAIConfig.spellDistance || member->HasAura(54646)) // Focus Magic + { continue; + } if (member->getClass() == CLASS_MAGE) return member; @@ -136,7 +152,7 @@ bool CastBlinkBackAction::Execute(Event event) Unit* target = AI_VALUE(Unit*, "current target"); if (!target) return false; - // can cast spell check passed in isUseful() + bot->SetOrientation(bot->GetAngle(target) + M_PI); return CastSpellAction::Execute(event); } diff --git a/src/Ai/Class/Mage/Action/MageActions.h b/src/Ai/Class/Mage/Action/MageActions.h index abd302052..4c7f76a68 100644 --- a/src/Ai/Class/Mage/Action/MageActions.h +++ b/src/Ai/Class/Mage/Action/MageActions.h @@ -18,12 +18,14 @@ class CastMoltenArmorAction : public CastBuffSpellAction { public: CastMoltenArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "molten armor") {} + std::vector getAlternatives() override; }; class CastMageArmorAction : public CastBuffSpellAction { public: CastMageArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mage armor") {} + std::vector getAlternatives() override; }; class CastIceArmorAction : public CastBuffSpellAction @@ -60,7 +62,8 @@ public: class CastSummonWaterElementalAction : public CastBuffSpellAction { public: - CastSummonWaterElementalAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "summon water elemental") {} + CastSummonWaterElementalAction(PlayerbotAI* botAI) + : CastBuffSpellAction(botAI, "summon water elemental") {} }; // Boost Actions @@ -236,7 +239,8 @@ public: class CastCounterspellOnEnemyHealerAction : public CastSpellOnEnemyHealerAction { public: - CastCounterspellOnEnemyHealerAction(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, "counterspell") {} + CastCounterspellOnEnemyHealerAction(PlayerbotAI* botAI) + : CastSpellOnEnemyHealerAction(botAI, "counterspell") {} }; class CastFrostNovaAction : public CastSpellAction @@ -275,9 +279,7 @@ class CastRemoveLesserCurseOnPartyAction : public CurePartyMemberAction { public: CastRemoveLesserCurseOnPartyAction(PlayerbotAI* botAI) - : CurePartyMemberAction(botAI, "remove lesser curse", DISPEL_CURSE) - { - } + : CurePartyMemberAction(botAI, "remove lesser curse", DISPEL_CURSE) {} }; // Damage and Debuff Actions @@ -331,7 +333,6 @@ public: CastLivingBombAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "living bomb", true) {} bool isUseful() override { - // Bypass TTL check return CastAuraSpellAction::isUseful(); } }; @@ -342,7 +343,6 @@ public: CastLivingBombOnAttackersAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "living bomb", true) {} bool isUseful() override { - // Bypass TTL check return CastAuraSpellAction::isUseful(); } }; diff --git a/src/Ai/Class/Mage/MageAiObjectContext.cpp b/src/Ai/Class/Mage/MageAiObjectContext.cpp index 477c0e075..b2b031660 100644 --- a/src/Ai/Class/Mage/MageAiObjectContext.cpp +++ b/src/Ai/Class/Mage/MageAiObjectContext.cpp @@ -89,6 +89,7 @@ public: creators["arcane intellect"] = &MageTriggerFactoryInternal::arcane_intellect; creators["arcane intellect on party"] = &MageTriggerFactoryInternal::arcane_intellect_on_party; creators["mage armor"] = &MageTriggerFactoryInternal::mage_armor; + creators["molten armor"] = &MageTriggerFactoryInternal::molten_armor; creators["remove curse"] = &MageTriggerFactoryInternal::remove_curse; creators["remove curse on party"] = &MageTriggerFactoryInternal::remove_curse_on_party; creators["counterspell"] = &MageTriggerFactoryInternal::counterspell; @@ -143,6 +144,7 @@ private: static Trigger* arcane_intellect(PlayerbotAI* botAI) { return new ArcaneIntellectTrigger(botAI); } static Trigger* arcane_intellect_on_party(PlayerbotAI* botAI) { return new ArcaneIntellectOnPartyTrigger(botAI); } static Trigger* mage_armor(PlayerbotAI* botAI) { return new MageArmorTrigger(botAI); } + static Trigger* molten_armor(PlayerbotAI* botAI) { return new MoltenArmorTrigger(botAI); } static Trigger* remove_curse(PlayerbotAI* botAI) { return new RemoveCurseTrigger(botAI); } static Trigger* remove_curse_on_party(PlayerbotAI* botAI) { return new PartyMemberRemoveCurseTrigger(botAI); } static Trigger* counterspell(PlayerbotAI* botAI) { return new CounterspellInterruptSpellTrigger(botAI); } diff --git a/src/Ai/Class/Mage/Strategy/ArcaneMageStrategy.cpp b/src/Ai/Class/Mage/Strategy/ArcaneMageStrategy.cpp index 4707231db..4ba7d42b9 100644 --- a/src/Ai/Class/Mage/Strategy/ArcaneMageStrategy.cpp +++ b/src/Ai/Class/Mage/Strategy/ArcaneMageStrategy.cpp @@ -6,35 +6,9 @@ #include "ArcaneMageStrategy.h" #include "Playerbots.h" -// ===== Action Node Factory ===== -class ArcaneMageStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - ArcaneMageStrategyActionNodeFactory() - { - creators["arcane blast"] = &arcane_blast; - creators["arcane barrage"] = &arcane_barrage; - creators["arcane missiles"] = &arcane_missiles; - creators["fire blast"] = &fire_blast; - creators["frostbolt"] = &frostbolt; - creators["arcane power"] = &arcane_power; - creators["icy veins"] = &icy_veins; - } - -private: - static ActionNode* arcane_blast(PlayerbotAI*) { return new ActionNode("arcane blast", {}, {}, {}); } - static ActionNode* arcane_barrage(PlayerbotAI*) { return new ActionNode("arcane barrage", {}, {}, {}); } - static ActionNode* arcane_missiles(PlayerbotAI*) { return new ActionNode("arcane missiles", {}, {}, {}); } - static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", {}, {}, {}); } - static ActionNode* frostbolt(PlayerbotAI*) { return new ActionNode("frostbolt", {}, {}, {}); } - static ActionNode* arcane_power(PlayerbotAI*) { return new ActionNode("arcane power", {}, {}, {}); } - static ActionNode* icy_veins(PlayerbotAI*) { return new ActionNode("icy veins", {}, {}, {}); } -}; - -// ===== Single Target Strategy ===== ArcaneMageStrategy::ArcaneMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI) { - actionNodeFactories.Add(new ArcaneMageStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } // ===== Default Actions ===== diff --git a/src/Ai/Class/Mage/Strategy/FireMageStrategy.cpp b/src/Ai/Class/Mage/Strategy/FireMageStrategy.cpp index 4914c72df..7075b1f2d 100644 --- a/src/Ai/Class/Mage/Strategy/FireMageStrategy.cpp +++ b/src/Ai/Class/Mage/Strategy/FireMageStrategy.cpp @@ -7,35 +7,9 @@ #include "Playerbots.h" #include "Strategy.h" -// ===== Action Node Factory ===== -class FireMageStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - FireMageStrategyActionNodeFactory() - { - creators["fireball"] = &fireball; - creators["frostbolt"] = &frostbolt; - creators["fire blast"] = &fire_blast; - creators["pyroblast"] = &pyroblast; - creators["scorch"] = &scorch; - creators["living bomb"] = &living_bomb; - creators["combustion"] = &combustion; - } - -private: - static ActionNode* fireball(PlayerbotAI*) { return new ActionNode("fireball", {}, {}, {}); } - static ActionNode* frostbolt(PlayerbotAI*) { return new ActionNode("frostbolt", {}, {}, {}); } - static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", {}, {}, {}); } - static ActionNode* pyroblast(PlayerbotAI*) { return new ActionNode("pyroblast", {}, {}, {}); } - static ActionNode* scorch(PlayerbotAI*) { return new ActionNode("scorch", {}, {}, {}); } - static ActionNode* living_bomb(PlayerbotAI*) { return new ActionNode("living bomb", {}, {}, {}); } - static ActionNode* combustion(PlayerbotAI*) { return new ActionNode("combustion", {}, {}, {}); } -}; - -// ===== Single Target Strategy ===== FireMageStrategy::FireMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI) { - actionNodeFactories.Add(new FireMageStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } // ===== Default Actions ===== diff --git a/src/Ai/Class/Mage/Strategy/FireMageStrategy.h b/src/Ai/Class/Mage/Strategy/FireMageStrategy.h index 03d50641b..14655de3a 100644 --- a/src/Ai/Class/Mage/Strategy/FireMageStrategy.h +++ b/src/Ai/Class/Mage/Strategy/FireMageStrategy.h @@ -28,4 +28,5 @@ public: void InitTriggers(std::vector& triggers) override; std::string const getName() override { return "firestarter"; } }; + #endif diff --git a/src/Ai/Class/Mage/Strategy/FrostFireMageStrategy.cpp b/src/Ai/Class/Mage/Strategy/FrostFireMageStrategy.cpp index 4448a4349..44baf4afc 100644 --- a/src/Ai/Class/Mage/Strategy/FrostFireMageStrategy.cpp +++ b/src/Ai/Class/Mage/Strategy/FrostFireMageStrategy.cpp @@ -6,35 +6,9 @@ #include "FrostFireMageStrategy.h" #include "Playerbots.h" -// ===== Action Node Factory ===== -class FrostFireMageStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - FrostFireMageStrategyActionNodeFactory() - { - creators["frostfire bolt"] = &frostfire_bolt; - creators["fire blast"] = &fire_blast; - creators["pyroblast"] = &pyroblast; - creators["combustion"] = &combustion; - creators["icy veins"] = &icy_veins; - creators["scorch"] = &scorch; - creators["living bomb"] = &living_bomb; - } - -private: - static ActionNode* frostfire_bolt(PlayerbotAI*) { return new ActionNode("frostfire bolt", {}, {}, {}); } - static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", {}, {}, {}); } - static ActionNode* pyroblast(PlayerbotAI*) { return new ActionNode("pyroblast", {}, {}, {}); } - static ActionNode* combustion(PlayerbotAI*) { return new ActionNode("combustion", {}, {}, {}); } - static ActionNode* icy_veins(PlayerbotAI*) { return new ActionNode("icy veins", {}, {}, {}); } - static ActionNode* scorch(PlayerbotAI*) { return new ActionNode("scorch", {}, {}, {}); } - static ActionNode* living_bomb(PlayerbotAI*) { return new ActionNode("living bomb", {}, {}, {}); } -}; - -// ===== Single Target Strategy ===== FrostFireMageStrategy::FrostFireMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI) { - actionNodeFactories.Add(new FrostFireMageStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } // ===== Default Actions ===== diff --git a/src/Ai/Class/Mage/Strategy/FrostMageStrategy.cpp b/src/Ai/Class/Mage/Strategy/FrostMageStrategy.cpp index fe703f354..4f50cee72 100644 --- a/src/Ai/Class/Mage/Strategy/FrostMageStrategy.cpp +++ b/src/Ai/Class/Mage/Strategy/FrostMageStrategy.cpp @@ -4,44 +4,11 @@ */ #include "FrostMageStrategy.h" - #include "Playerbots.h" -// ===== Action Node Factory ===== -class FrostMageStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - FrostMageStrategyActionNodeFactory() - { - creators["cold snap"] = &cold_snap; - creators["ice barrier"] = &ice_barrier; - creators["summon water elemental"] = &summon_water_elemental; - creators["deep freeze"] = &deep_freeze; - creators["icy veins"] = &icy_veins; - creators["frostbolt"] = &frostbolt; - creators["ice lance"] = &ice_lance; - creators["fire blast"] = &fire_blast; - creators["fireball"] = &fireball; - creators["frostfire bolt"] = &frostfire_bolt; - } - -private: - static ActionNode* cold_snap(PlayerbotAI*) { return new ActionNode("cold snap", {}, {}, {}); } - static ActionNode* ice_barrier(PlayerbotAI*) { return new ActionNode("ice barrier", {}, {}, {}); } - static ActionNode* summon_water_elemental(PlayerbotAI*) { return new ActionNode("summon water elemental", {}, {}, {}); } - static ActionNode* deep_freeze(PlayerbotAI*) { return new ActionNode("deep freeze", {}, {}, {}); } - static ActionNode* icy_veins(PlayerbotAI*) { return new ActionNode("icy veins", {}, {}, {}); } - static ActionNode* frostbolt(PlayerbotAI*) { return new ActionNode("frostbolt", {}, {}, {}); } - static ActionNode* ice_lance(PlayerbotAI*) { return new ActionNode("ice lance", {}, {}, {}); } - static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", {}, {}, {}); } - static ActionNode* fireball(PlayerbotAI*) { return new ActionNode("fireball", {}, {}, {}); } - static ActionNode* frostfire_bolt(PlayerbotAI*) { return new ActionNode("frostfire bolt", {}, { NextAction("fireball") }, {}); } -}; - -// ===== Single Target Strategy ===== FrostMageStrategy::FrostMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI) { - actionNodeFactories.Add(new FrostMageStrategyActionNodeFactory()); + // No custom ActionNodeFactory needed } // ===== Default Actions ===== diff --git a/src/Ai/Class/Mage/Strategy/GenericMageNonCombatStrategy.cpp b/src/Ai/Class/Mage/Strategy/GenericMageNonCombatStrategy.cpp index eab98ea5a..e93f7589e 100644 --- a/src/Ai/Class/Mage/Strategy/GenericMageNonCombatStrategy.cpp +++ b/src/Ai/Class/Mage/Strategy/GenericMageNonCombatStrategy.cpp @@ -12,28 +12,10 @@ class GenericMageNonCombatStrategyActionNodeFactory : public NamedObjectFactory< public: GenericMageNonCombatStrategyActionNodeFactory() { - creators["molten armor"] = &molten_armor; - creators["mage armor"] = &mage_armor; creators["ice armor"] = &ice_armor; } private: - static ActionNode* molten_armor([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("molten armor", - /*P*/ {}, - /*A*/ { NextAction("mage armor") }, - /*C*/ {}); - } - - static ActionNode* mage_armor([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("mage armor", - /*P*/ {}, - /*A*/ { NextAction("ice armor") }, - /*C*/ {}); - } - static ActionNode* ice_armor([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("ice armor", @@ -65,7 +47,7 @@ void MageBuffManaStrategy::InitTriggers(std::vector& triggers) void MageBuffDpsStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back(new TriggerNode("mage armor", { NextAction("molten armor", 19.0f) })); + triggers.push_back(new TriggerNode("molten armor", { NextAction("molten armor", 19.0f) })); } void MageBuffStrategy::InitTriggers(std::vector& triggers) diff --git a/src/Ai/Class/Mage/Strategy/GenericMageStrategy.cpp b/src/Ai/Class/Mage/Strategy/GenericMageStrategy.cpp index 0e26c692d..69389a8c4 100644 --- a/src/Ai/Class/Mage/Strategy/GenericMageStrategy.cpp +++ b/src/Ai/Class/Mage/Strategy/GenericMageStrategy.cpp @@ -15,16 +15,8 @@ public: { creators["frostbolt"] = &frostbolt; creators["frostfire bolt"] = &frostfire_bolt; - creators["ice lance"] = &ice_lance; - creators["fire blast"] = &fire_blast; creators["scorch"] = &scorch; - creators["frost nova"] = &frost_nova; - creators["cone of cold"] = &cone_of_cold; - creators["icy veins"] = &icy_veins; - creators["combustion"] = &combustion; creators["evocation"] = &evocation; - creators["dragon's breath"] = &dragons_breath; - creators["blast wave"] = &blast_wave; creators["remove curse"] = &remove_curse; creators["remove curse on party"] = &remove_curse_on_party; creators["fireball"] = &fireball; @@ -47,22 +39,6 @@ private: /*C*/ {}); } - static ActionNode* ice_lance([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("ice lance", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* fire_blast([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("fire blast", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - static ActionNode* scorch([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("scorch", @@ -71,38 +47,6 @@ private: /*C*/ {}); } - static ActionNode* frost_nova([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("frost nova", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* cone_of_cold([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("cone of cold", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* icy_veins([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("icy veins", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* combustion([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("combustion", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - static ActionNode* evocation([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("evocation", @@ -111,22 +55,6 @@ private: /*C*/ {}); } - static ActionNode* dragons_breath([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("dragon's breath", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - - static ActionNode* blast_wave([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("blast wave", - /*P*/ {}, - /*A*/ {}, - /*C*/ {}); - } - static ActionNode* remove_curse([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("remove curse", @@ -206,13 +134,13 @@ void MageBoostStrategy::InitTriggers(std::vector& triggers) Player* bot = botAI->GetBot(); int tab = AiFactory::GetPlayerSpecTab(bot); - if (tab == 0) // Arcane + if (tab == MAGE_TAB_ARCANE) { triggers.push_back(new TriggerNode("arcane power", { NextAction("arcane power", 29.0f) })); triggers.push_back(new TriggerNode("icy veins", { NextAction("icy veins", 28.5f) })); triggers.push_back(new TriggerNode("mirror image", { NextAction("mirror image", 28.0f) })); } - else if (tab == 1) + else if (tab == MAGE_TAB_FIRE) { if (bot->HasSpell(44614) /*Frostfire Bolt*/ && bot->HasAura(15047) /*Ice Shards*/) { // Frostfire @@ -226,7 +154,7 @@ void MageBoostStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("mirror image", { NextAction("mirror image", 17.5f) })); } } - else if (tab == 2) // Frost + else if (tab == MAGE_TAB_FROST) // Frost { triggers.push_back(new TriggerNode("cold snap", { NextAction("cold snap", 28.0f) })); triggers.push_back(new TriggerNode("icy veins", { NextAction("icy veins", 27.5f) })); @@ -254,15 +182,14 @@ void MageAoeStrategy::InitTriggers(std::vector& triggers) Player* bot = botAI->GetBot(); int tab = AiFactory::GetPlayerSpecTab(bot); - if (tab == 0) // Arcane + if (tab == MAGE_TAB_ARCANE) { triggers.push_back(new TriggerNode("flamestrike active and medium aoe", { NextAction("blizzard", 24.0f) })); triggers.push_back(new TriggerNode("medium aoe", { NextAction("flamestrike", 23.0f), NextAction("blizzard", 22.0f) })); - triggers.push_back(new TriggerNode("light aoe", { NextAction("arcane explosion", 21.0f) })); } - else if (tab == 1) // Fire and Frostfire + else if (tab == MAGE_TAB_FIRE) { triggers.push_back( new TriggerNode("medium aoe", { @@ -275,7 +202,7 @@ void MageAoeStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("firestarter", { NextAction("flamestrike", 40.0f) })); triggers.push_back(new TriggerNode("living bomb on attackers", { NextAction("living bomb on attackers", 21.0f) })); } - else if (tab == 2) // Frost + else if (tab == MAGE_TAB_FROST) { triggers.push_back(new TriggerNode("flamestrike active and medium aoe", { NextAction("blizzard", 24.0f) })); triggers.push_back(new TriggerNode("medium aoe", { diff --git a/src/Ai/Class/Mage/Trigger/MageTriggers.cpp b/src/Ai/Class/Mage/Trigger/MageTriggers.cpp index e22210798..7e7ba9ab7 100644 --- a/src/Ai/Class/Mage/Trigger/MageTriggers.cpp +++ b/src/Ai/Class/Mage/Trigger/MageTriggers.cpp @@ -4,7 +4,6 @@ */ #include "MageTriggers.h" -#include "MageActions.h" #include "Playerbots.h" #include "Player.h" #include "Spell.h" @@ -23,7 +22,7 @@ bool NoManaGemTrigger::IsActive() 5513, // Mana Jade 5514 // Mana Agate }; - Player* bot = botAI->GetBot(); + for (uint32 gemId : gemIds) { if (bot->GetItemCount(gemId, false) > 0) // false = only in bags @@ -45,17 +44,35 @@ bool ArcaneIntellectTrigger::IsActive() bool MageArmorTrigger::IsActive() { Unit* target = GetTarget(); + 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) && !botAI->HasAura("mage armor", target); + !botAI->HasAura("molten armor", target); +} + +bool MoltenArmorTrigger::IsActive() +{ + Unit* target = GetTarget(); + 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); } bool FrostNovaOnTargetTrigger::IsActive() { Unit* target = GetTarget(); if (!target || !target->IsAlive() || !target->IsInWorld()) - { return false; - } + return botAI->HasAura(spell, target); } @@ -63,15 +80,14 @@ bool FrostbiteOnTargetTrigger::IsActive() { Unit* target = GetTarget(); if (!target || !target->IsAlive() || !target->IsInWorld()) - { return false; - } + return botAI->HasAura(spell, target); } bool NoFocusMagicTrigger::IsActive() { - if (!bot->HasSpell(54646)) + if (!bot->HasSpell(54646)) // Focus Magic return false; Group* group = bot->GetGroup(); @@ -92,24 +108,19 @@ bool NoFocusMagicTrigger::IsActive() bool DeepFreezeCooldownTrigger::IsActive() { - Player* bot = botAI->GetBot(); - static const uint32 DEEP_FREEZE_SPELL_ID = 44572; - // If the bot does NOT have Deep Freeze, treat as "on cooldown" - if (!bot->HasSpell(DEEP_FREEZE_SPELL_ID)) + if (!bot->HasSpell(44572)) // Deep Freeze return true; - // Otherwise, use the default cooldown logic return SpellCooldownTrigger::IsActive(); } -const std::set FlamestrikeNearbyTrigger::FLAMESTRIKE_SPELL_IDS = {2120, 2121, 8422, 8423, 10215, - 10216, 27086, 42925, 42926}; +const std::unordered_set FlamestrikeNearbyTrigger::FLAMESTRIKE_SPELL_IDS = { + 2120, 2121, 8422, 8423, 10215, 10216, 27086, 42925, 42926 +}; bool FlamestrikeNearbyTrigger::IsActive() { - Player* bot = botAI->GetBot(); - for (uint32 spellId : FLAMESTRIKE_SPELL_IDS) { Aura* aura = bot->GetAura(spellId, bot->GetGUID()); @@ -133,7 +144,6 @@ bool ImprovedScorchTrigger::IsActive() if (!target || !target->IsAlive() || !target->IsInWorld()) return false; - // List of all spell IDs for Improved Scorch, Winter's Chill, and Shadow Mastery static const uint32 ImprovedScorchExclusiveDebuffs[] = {// Shadow Mastery 17794, 17797, 17798, 17799, 17800, // Winter's Chill @@ -147,11 +157,10 @@ bool ImprovedScorchTrigger::IsActive() return false; } - // Use default DebuffTrigger logic for the rest (only trigger if debuff is missing or expiring) return DebuffTrigger::IsActive(); } -const std::set BlizzardChannelCheckTrigger::BLIZZARD_SPELL_IDS = { +const std::unordered_set BlizzardChannelCheckTrigger::BLIZZARD_SPELL_IDS = { 10, // Blizzard Rank 1 6141, // Blizzard Rank 2 8427, // Blizzard Rank 3 @@ -165,19 +174,12 @@ const std::set BlizzardChannelCheckTrigger::BLIZZARD_SPELL_IDS = { bool BlizzardChannelCheckTrigger::IsActive() { - Player* bot = botAI->GetBot(); - - // Check if the bot is channeling a spell - if (Spell* spell = bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + if (Spell* spell = bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL); + spell && BLIZZARD_SPELL_IDS.count(spell->m_spellInfo->Id)) { - // Only trigger if the spell being channeled is Blizzard - if (BLIZZARD_SPELL_IDS.count(spell->m_spellInfo->Id)) - { - uint8 attackerCount = AI_VALUE(uint8, "attacker count"); - return attackerCount < minEnemies; - } + uint8 attackerCount = AI_VALUE(uint8, "attacker count"); + return attackerCount < minEnemies; } - // Not channeling Blizzard return false; } diff --git a/src/Ai/Class/Mage/Trigger/MageTriggers.h b/src/Ai/Class/Mage/Trigger/MageTriggers.h index e769916f4..566b6b61e 100644 --- a/src/Ai/Class/Mage/Trigger/MageTriggers.h +++ b/src/Ai/Class/Mage/Trigger/MageTriggers.h @@ -11,19 +11,15 @@ #include "SharedDefines.h" #include "Trigger.h" #include "Playerbots.h" -#include "PlayerbotAI.h" -#include #include -class PlayerbotAI; - // Buff and Out of Combat Triggers class ArcaneIntellectOnPartyTrigger : public BuffOnPartyTrigger { public: - ArcaneIntellectOnPartyTrigger(PlayerbotAI* botAI) : BuffOnPartyTrigger(botAI, "arcane intellect", 2 * 2000) {} - + ArcaneIntellectOnPartyTrigger(PlayerbotAI* botAI) + : BuffOnPartyTrigger(botAI, "arcane intellect", 2 * 2000) {} bool IsActive() override; }; @@ -41,6 +37,13 @@ public: bool IsActive() override; }; +class MoltenArmorTrigger : public BuffTrigger +{ +public: + MoltenArmorTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "molten armor", 5 * 2000) {} + bool IsActive() override; +}; + class NoFocusMagicTrigger : public Trigger { public: @@ -58,7 +61,6 @@ class NoManaGemTrigger : public Trigger { public: NoManaGemTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no mana gem") {} - bool IsActive() override; }; @@ -109,10 +111,8 @@ public: class ArcaneBlast4StacksAndMissileBarrageTrigger : public TwoTriggers { public: - ArcaneBlast4StacksAndMissileBarrageTrigger(PlayerbotAI* ai) - : TwoTriggers(ai, "arcane blast stack", "missile barrage") - { - } + ArcaneBlast4StacksAndMissileBarrageTrigger(PlayerbotAI* botAI) + : TwoTriggers(botAI, "arcane blast stack", "missile barrage") {} }; class CombustionTrigger : public BoostTrigger @@ -138,7 +138,7 @@ public: class ColdSnapTrigger : public TwoTriggers { public: - ColdSnapTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "icy veins on cd", "deep freeze on cd") {} + ColdSnapTrigger(PlayerbotAI* botAI) : TwoTriggers(botAI, "icy veins on cd", "deep freeze on cd") {} }; class MirrorImageTrigger : public BoostTrigger @@ -181,9 +181,8 @@ public: class PartyMemberRemoveCurseTrigger : public PartyMemberNeedCureTrigger { public: - PartyMemberRemoveCurseTrigger(PlayerbotAI* botAI) : PartyMemberNeedCureTrigger(botAI, "remove curse", DISPEL_CURSE) - { - } + PartyMemberRemoveCurseTrigger(PlayerbotAI* botAI) + : PartyMemberNeedCureTrigger(botAI, "remove curse", DISPEL_CURSE) {} }; class SpellstealTrigger : public TargetAuraDispelTrigger @@ -216,7 +215,7 @@ public: class LivingBombOnAttackersTrigger : public DebuffOnAttackerTrigger { public: - LivingBombOnAttackersTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "living bomb", true) {} + LivingBombOnAttackersTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "living bomb", true) {} bool IsActive() override { return BuffTrigger::IsActive(); } }; @@ -282,13 +281,13 @@ public: protected: float radius; - static const std::set FLAMESTRIKE_SPELL_IDS; + static const std::unordered_set FLAMESTRIKE_SPELL_IDS; }; class FlamestrikeBlizzardTrigger : public TwoTriggers { public: - FlamestrikeBlizzardTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "flamestrike nearby", "medium aoe") {} + FlamestrikeBlizzardTrigger(PlayerbotAI* botAI) : TwoTriggers(botAI, "flamestrike nearby", "medium aoe") {} }; class BlizzardChannelCheckTrigger : public Trigger @@ -301,7 +300,7 @@ public: protected: uint32 minEnemies; - static const std::set BLIZZARD_SPELL_IDS; + static const std::unordered_set BLIZZARD_SPELL_IDS; }; class BlastWaveOffCdTrigger : public SpellNoCooldownTrigger @@ -313,7 +312,8 @@ public: class BlastWaveOffCdTriggerAndMediumAoeTrigger : public TwoTriggers { public: - BlastWaveOffCdTriggerAndMediumAoeTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "blast wave off cd", "medium aoe") {} + BlastWaveOffCdTriggerAndMediumAoeTrigger(PlayerbotAI* botAI) + : TwoTriggers(botAI, "blast wave off cd", "medium aoe") {} }; class NoFirestarterStrategyTrigger : public Trigger diff --git a/src/Bot/Factory/AiFactory.cpp b/src/Bot/Factory/AiFactory.cpp index 6c638e807..c95180538 100644 --- a/src/Bot/Factory/AiFactory.cpp +++ b/src/Bot/Factory/AiFactory.cpp @@ -91,9 +91,6 @@ uint8 AiFactory::GetPlayerSpecTab(Player* bot) case CLASS_WARLOCK: tab = WARLOCK_TAB_DEMONOLOGY; break; - case CLASS_SHAMAN: - tab = SHAMAN_TAB_ELEMENTAL; - break; } return tab; @@ -292,24 +289,24 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa if (tab == PRIEST_TAB_SHADOW) engine->addStrategiesNoInit("dps", "shadow debuff", "shadow aoe", nullptr); else if (tab == PRIEST_TAB_DISCIPLINE) - engine->addStrategiesNoInit("heal", nullptr); - else - engine->addStrategiesNoInit("holy heal", nullptr); + engine->addStrategy("heal", false); + else // if (tab == PRIEST_TAB_HOLY) + engine->addStrategy("holy heal", false); engine->addStrategiesNoInit("dps assist", "cure", nullptr); break; case CLASS_MAGE: if (tab == MAGE_TAB_ARCANE) - engine->addStrategiesNoInit("arcane", nullptr); + engine->addStrategiesNoInit("arcane", "bdps", nullptr); else if (tab == MAGE_TAB_FIRE) { if (player->HasSpell(44614) /*Frostfire Bolt*/ && player->HasAura(15047) /*Ice Shards*/) - engine->addStrategiesNoInit("frostfire", nullptr); + engine->addStrategiesNoInit("frostfire", "bdps", nullptr); else - engine->addStrategiesNoInit("fire", nullptr); + engine->addStrategiesNoInit("fire", "bdps", nullptr); } - else - engine->addStrategiesNoInit("frost", nullptr); + else // if (tab == MAGE_TAB_FROST) + engine->addStrategiesNoInit("frost", "bmana", nullptr); engine->addStrategiesNoInit("dps", "dps assist", "cure", "cc", "aoe", nullptr); break; @@ -318,7 +315,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa engine->addStrategiesNoInit("tank", "tank assist", "pull", "pull back", "aoe", nullptr); else if (tab == WARRIOR_TAB_ARMS || !player->HasSpell(1680)) // Whirlwind engine->addStrategiesNoInit("arms", "aoe", "dps assist", nullptr); - else + else // if (tab == WARRIOR_TAB_FURY) engine->addStrategiesNoInit("fury", "aoe", "dps assist", nullptr); break; case CLASS_SHAMAN: @@ -326,7 +323,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa engine->addStrategiesNoInit("ele", "stoneskin", "wrath", "mana spring", "wrath of air", nullptr); else if (tab == SHAMAN_TAB_RESTORATION) engine->addStrategiesNoInit("resto", "stoneskin", "flametongue", "mana spring", "wrath of air", nullptr); - else + else // if (tab == SHAMAN_TAB_ENHANCEMENT) engine->addStrategiesNoInit("enh", "strength of earth", "magma", "healing stream", "windfury", nullptr); engine->addStrategiesNoInit("dps assist", "cure", "aoe", nullptr); @@ -336,18 +333,15 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa engine->addStrategiesNoInit("tank", "tank assist", "pull", "pull back", "bthreat", "barmor", "cure", nullptr); else if (tab == PALADIN_TAB_HOLY) engine->addStrategiesNoInit("heal", "dps assist", "cure", "bcast", nullptr); - else + else // if (tab == PALADIN_TAB_RETRIBUTION) engine->addStrategiesNoInit("dps", "dps assist", "cure", "baoe", nullptr); break; case CLASS_DRUID: if (tab == DRUID_TAB_BALANCE) - { - engine->addStrategiesNoInit("caster", "cure", "caster aoe", "dps assist", nullptr); - engine->addStrategy("caster debuff", false); - } + engine->addStrategiesNoInit("caster", "cure", "caster aoe", "caster debuff", "dps assist", nullptr); else if (tab == DRUID_TAB_RESTORATION) engine->addStrategiesNoInit("heal", "cure", "dps assist", nullptr); - else + else // if (tab == DRUID_TAB_FERAL) { if (player->HasSpell(768) /*cat form*/ && !player->HasAura(16931) /*thick hide*/) engine->addStrategiesNoInit("cat", "dps assist", nullptr); @@ -357,18 +351,18 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa break; case CLASS_HUNTER: if (tab == HUNTER_TAB_BEAST_MASTERY) - engine->addStrategiesNoInit("bm", nullptr); + engine->addStrategy("bm", false); else if (tab == HUNTER_TAB_MARKSMANSHIP) - engine->addStrategiesNoInit("mm", nullptr); - else - engine->addStrategiesNoInit("surv", nullptr); + engine->addStrategy("mm", false); + else // if (tab == HUNTER_TAB_SURVIVAL) + engine->addStrategy("surv", false); engine->addStrategiesNoInit("cc", "dps assist", "aoe", "bdps", nullptr); break; case CLASS_ROGUE: if (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY) engine->addStrategiesNoInit("melee", "dps assist", "aoe", nullptr); - else + else // if (tab == ROGUE_TAB_COMBAT) engine->addStrategiesNoInit("dps", "dps assist", "aoe", nullptr); break; case CLASS_WARLOCK: @@ -376,7 +370,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa engine->addStrategiesNoInit("affli", "curse of agony", nullptr); else if (tab == WARLOCK_TAB_DEMONOLOGY) engine->addStrategiesNoInit("demo", "curse of agony", "meta melee", nullptr); - else + else // if (tab == WARLOCK_TAB_DESTRUCTION) engine->addStrategiesNoInit("destro", "curse of elements", nullptr); engine->addStrategiesNoInit("cc", "dps assist", "aoe", nullptr); @@ -386,7 +380,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa engine->addStrategiesNoInit("blood", "tank assist", "pull", "pull back", nullptr); else if (tab == DEATH_KNIGHT_TAB_FROST) engine->addStrategiesNoInit("frost", "frost aoe", "dps assist", nullptr); - else + else // if (tab == DEATH_KNIGHT_TAB_UNHOLY) engine->addStrategiesNoInit("unholy", "unholy aoe", "dps assist", nullptr); break; } @@ -434,7 +428,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa case CLASS_SHAMAN: { if (tab == SHAMAN_TAB_RESTORATION) - engine->addStrategiesNoInit("caster", "caster aoe", "bmana", nullptr); + engine->addStrategiesNoInit("caster", "caster aoe", nullptr); break; } case CLASS_PALADIN: @@ -527,11 +521,6 @@ void AiFactory::AddDefaultNonCombatStrategies(Player* player, PlayerbotAI* const nonCombatEngine->addStrategiesNoInit("bdps", "dps assist", "pet", nullptr); break; case CLASS_SHAMAN: - if (tab == SHAMAN_TAB_ELEMENTAL || tab == SHAMAN_TAB_RESTORATION) - nonCombatEngine->addStrategy("bmana", false); - else - nonCombatEngine->addStrategy("bdps", false); - nonCombatEngine->addStrategiesNoInit("dps assist", "cure", nullptr); break; case CLASS_MAGE: