mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Merge pull request #1468 from ThePenguinMan96/Mage-Overhaul
Mage Overhaul
This commit is contained in:
@@ -1428,8 +1428,8 @@ AiPlayerbot.PremadeSpecLink.7.5.80 = -023222301004-05032331331013501120331251
|
||||
|
||||
AiPlayerbot.PremadeSpecName.8.0 = arcane pve
|
||||
AiPlayerbot.PremadeSpecGlyph.8.0 = 42735,43339,44955,43364,43361,42751
|
||||
AiPlayerbot.PremadeSpecLink.8.0.60 = 23000503110033014032310150532
|
||||
AiPlayerbot.PremadeSpecLink.8.0.80 = 23000523310033015032310250532-03-203203001
|
||||
AiPlayerbot.PremadeSpecLink.8.0.60 = 230005231100330150323102500321
|
||||
AiPlayerbot.PremadeSpecLink.8.0.80 = 230005231100330150323102505321-03-203303001
|
||||
AiPlayerbot.PremadeSpecName.8.1 = fire pve
|
||||
AiPlayerbot.PremadeSpecGlyph.8.1 = 42739,43339,45737,43364,44920,42751
|
||||
AiPlayerbot.PremadeSpecLink.8.1.60 = -0055030011302231053120321341
|
||||
@@ -1441,7 +1441,7 @@ AiPlayerbot.PremadeSpecLink.8.2.80 = 23002303110003--053303031320310003015223135
|
||||
AiPlayerbot.PremadeSpecName.8.3 = frostfire pve
|
||||
AiPlayerbot.PremadeSpecGlyph.8.3 = 44684,44920,42751,43339,43364,45737
|
||||
AiPlayerbot.PremadeSpecLink.8.3.60 = -2305032012303331053120300051
|
||||
AiPlayerbot.PremadeSpecLink.8.3.80 = -2305032012303331053120311351-023303031
|
||||
AiPlayerbot.PremadeSpecLink.8.3.80 = -2305032012303331053120321351-023302031
|
||||
AiPlayerbot.PremadeSpecName.8.4 = arcane pvp
|
||||
AiPlayerbot.PremadeSpecGlyph.8.4 = 42735,43364,42738,43360,43357,42752
|
||||
AiPlayerbot.PremadeSpecLink.8.4.60 = 205323200122032103303102015221
|
||||
|
||||
@@ -305,22 +305,22 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa
|
||||
break;
|
||||
case CLASS_MAGE:
|
||||
if (tab == 0)
|
||||
engine->addStrategiesNoInit("arcane", "arcane aoe", nullptr);
|
||||
engine->addStrategiesNoInit("arcane", nullptr);
|
||||
else if (tab == 1)
|
||||
{
|
||||
if (player->HasSpell(44614) /*Frostfire Bolt*/ && player->HasAura(15047) /*Ice Shards*/)
|
||||
{
|
||||
engine->addStrategiesNoInit("frostfire", "frostfire aoe", nullptr);
|
||||
engine->addStrategiesNoInit("frostfire", nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
engine->addStrategiesNoInit("fire", "fire aoe", nullptr);
|
||||
engine->addStrategiesNoInit("fire", nullptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
engine->addStrategiesNoInit("frost", "frost aoe", nullptr);
|
||||
engine->addStrategiesNoInit("frost", nullptr);
|
||||
|
||||
engine->addStrategiesNoInit("dps", "dps assist", "cure", nullptr);
|
||||
engine->addStrategiesNoInit("dps", "dps assist", "cure", "aoe", nullptr);
|
||||
break;
|
||||
case CLASS_WARRIOR:
|
||||
if (tab == 2)
|
||||
|
||||
@@ -2949,14 +2949,19 @@ bool PlayerbotAI::CanCastSpell(uint32 spellid, Unit* target, bool checkHasSpell,
|
||||
|
||||
if (!itemTarget)
|
||||
{
|
||||
// Exception for Deep Freeze (44572) - allow cast for damage on immune targets (e.g., bosses)
|
||||
if (target->IsImmunedToSpell(spellInfo))
|
||||
{
|
||||
if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster()))
|
||||
if (spellid != 44572) // Deep Freeze
|
||||
{
|
||||
LOG_DEBUG("playerbots", "target is immuned to spell - target name: {}, spellid: {}, bot name: {}",
|
||||
target->GetName(), spellid, bot->GetName());
|
||||
if (!sPlayerbotAIConfig->logInGroupOnly || (bot->GetGroup() && HasRealPlayerMaster()))
|
||||
{
|
||||
LOG_DEBUG("playerbots", "target is immuned to spell - target name: {}, spellid: {}, bot name: {}",
|
||||
target->GetName(), spellid, bot->GetName());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
// Otherwise, allow Deep Freeze even if immune
|
||||
}
|
||||
|
||||
if (bot != target && sServerFacade->GetDistance2d(bot, target) > sPlayerbotAIConfig->sightDistance)
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
*/
|
||||
|
||||
#include "ArcaneMageStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
// ===== Action Node Factory =====
|
||||
class ArcaneMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
@@ -15,69 +15,44 @@ public:
|
||||
creators["arcane blast"] = &arcane_blast;
|
||||
creators["arcane barrage"] = &arcane_barrage;
|
||||
creators["arcane missiles"] = &arcane_missiles;
|
||||
// creators["firebolt"] = &firebolt;
|
||||
creators["fire blast"] = &fire_blast;
|
||||
creators["frostbolt"] = &frostbolt;
|
||||
creators["arcane power"] = &arcane_power;
|
||||
creators["icy veins"] = &icy_veins;
|
||||
}
|
||||
|
||||
private:
|
||||
static ActionNode* arcane_blast([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("arcane blast",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ NextAction::array(0, new NextAction("arcane missiles"), nullptr),
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
static ActionNode* arcane_barrage([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("arcane barrage",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
static ActionNode* arcane_missiles([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("arcane missiles",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ NextAction::array(0, new NextAction("fireball"), nullptr),
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
// static ActionNode* firebolt([[maybe_unused]] PlayerbotAI* botAI)
|
||||
// {
|
||||
// return new ActionNode ("firebolt",
|
||||
// /*P*/ nullptr,
|
||||
// /*A*/ NextAction::array(0, new NextAction("shoot"), nullptr),
|
||||
// /*C*/ nullptr);
|
||||
// }
|
||||
static ActionNode* arcane_blast(PlayerbotAI*) { return new ActionNode("arcane blast", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* arcane_barrage(PlayerbotAI*) { return new ActionNode("arcane barrage", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* arcane_missiles(PlayerbotAI*) { return new ActionNode("arcane missiles", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* frostbolt(PlayerbotAI*) { return new ActionNode("frostbolt", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* arcane_power(PlayerbotAI*) { return new ActionNode("arcane power", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* icy_veins(PlayerbotAI*) { return new ActionNode("icy veins", nullptr, nullptr, nullptr); }
|
||||
};
|
||||
|
||||
// ===== Single Target Strategy =====
|
||||
ArcaneMageStrategy::ArcaneMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new ArcaneMageStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
// ===== Default Actions =====
|
||||
NextAction** ArcaneMageStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("arcane blast", ACTION_DEFAULT + 0.3f),
|
||||
new NextAction("frostbolt", ACTION_DEFAULT + 0.2f), // arcane immune target
|
||||
new NextAction("fire blast", ACTION_DEFAULT + 0.1f), // cast during movement
|
||||
new NextAction("shoot", ACTION_DEFAULT), nullptr);
|
||||
return NextAction::array(0, new NextAction("arcane blast", 5.6f),
|
||||
new NextAction("arcane missiles", 5.5f),
|
||||
new NextAction("arcane barrage", 5.4f), // cast while moving
|
||||
new NextAction("fire blast", 5.3f), // cast while moving if arcane barrage isn't available/learned
|
||||
new NextAction("frostbolt", 5.2f), // for arcane immune targets
|
||||
new NextAction("shoot", 5.1f), nullptr);
|
||||
}
|
||||
|
||||
// ===== Trigger Initialization ===
|
||||
void ArcaneMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericMageStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("arcane blast stack", NextAction::array(0, new NextAction("arcane missiles", 15.0f), NULL)));
|
||||
// Proc Trigger
|
||||
triggers.push_back(new TriggerNode("arcane blast 4 stacks and missile barrage", NextAction::array(0, new NextAction("arcane missiles", 15.0f), nullptr)));
|
||||
}
|
||||
|
||||
void ArcaneMageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
// triggers.push_back(new TriggerNode(
|
||||
// "high aoe",
|
||||
// NextAction::array(0, new NextAction("arcane explosion", 39.0f), NULL)));
|
||||
|
||||
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("blizzard", 40.0f), NULL)));
|
||||
}
|
||||
@@ -20,13 +20,4 @@ public:
|
||||
NextAction** getDefaultActions() override;
|
||||
};
|
||||
|
||||
class ArcaneMageAoeStrategy : public CombatStrategy
|
||||
{
|
||||
public:
|
||||
ArcaneMageAoeStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {}
|
||||
|
||||
public:
|
||||
virtual void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "arcane aoe"; }
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -4,42 +4,71 @@
|
||||
*/
|
||||
|
||||
#include "FireMageStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
#include "Strategy.h"
|
||||
|
||||
NextAction** FireMageStrategy::getDefaultActions()
|
||||
// ===== Action Node Factory =====
|
||||
class FireMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
return NextAction::array(0, new NextAction("fireball", ACTION_DEFAULT + 0.3f),
|
||||
new NextAction("frostbolt", ACTION_DEFAULT + 0.2f), // fire immune target
|
||||
new NextAction("fire blast", ACTION_DEFAULT + 0.1f), // cast during movement
|
||||
new NextAction("shoot", ACTION_DEFAULT), NULL);
|
||||
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", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* frostbolt(PlayerbotAI*) { return new ActionNode("frostbolt", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* pyroblast(PlayerbotAI*) { return new ActionNode("pyroblast", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* scorch(PlayerbotAI*) { return new ActionNode("scorch", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* living_bomb(PlayerbotAI*) { return new ActionNode("living bomb", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* combustion(PlayerbotAI*) { return new ActionNode("combustion", nullptr, nullptr, nullptr); }
|
||||
};
|
||||
|
||||
// ===== Single Target Strategy =====
|
||||
FireMageStrategy::FireMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new FireMageStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
// ===== Default Actions =====
|
||||
NextAction** FireMageStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("fireball", 5.3f),
|
||||
new NextAction("frostbolt", 5.2f), // fire immune target
|
||||
new NextAction("fire blast", 5.1f), // cast during movement
|
||||
new NextAction("shoot", 5.0f), nullptr);
|
||||
}
|
||||
|
||||
// ===== Trigger Initialization =====
|
||||
void FireMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericMageStrategy::InitTriggers(triggers);
|
||||
|
||||
// triggers.push_back(new TriggerNode("pyroblast", NextAction::array(0, new NextAction("pyroblast", 10.0f),
|
||||
// nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("hot streak", NextAction::array(0, new NextAction("pyroblast", 25.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("combustion", NextAction::array(0, new NextAction("combustion", 50.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("living bomb", NextAction::array(0, new NextAction("living bomb", 19.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("dragon's
|
||||
// breath", 70.0f), nullptr)));
|
||||
// Debuff Triggers
|
||||
triggers.push_back(new TriggerNode("improved scorch", NextAction::array(0, new NextAction("scorch", 19.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("living bomb", NextAction::array(0, new NextAction("living bomb", 18.5f), nullptr)));
|
||||
|
||||
// Proc Trigger
|
||||
triggers.push_back(new TriggerNode("hot streak", NextAction::array(0, new NextAction("pyroblast", 25.0f), nullptr)));
|
||||
}
|
||||
|
||||
void FireMageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
// Combat strategy to run to melee for Dragon's Breath and Blast Wave
|
||||
// Disabled by default for the Fire/Frostfire spec
|
||||
// To enable, type "co +firestarter"
|
||||
// To disable, type "co -firestarter"
|
||||
FirestarterStrategy::FirestarterStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
|
||||
|
||||
void FirestarterStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
// higher priority to cast before move away
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium aoe", NextAction::array(0,
|
||||
new NextAction("dragon's breath", ACTION_MOVE + 9),
|
||||
new NextAction("flamestrike", ACTION_MOVE + 8),
|
||||
new NextAction("blast wave", ACTION_MOVE + 7),
|
||||
new NextAction("living bomb on attackers", 21.0f),
|
||||
new NextAction("blizzard", 20.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"blast wave off cd and medium aoe",
|
||||
NextAction::array(0, new NextAction("reach melee", 25.5f), nullptr)));
|
||||
}
|
||||
|
||||
@@ -13,20 +13,19 @@ class PlayerbotAI;
|
||||
class FireMageStrategy : public GenericMageStrategy
|
||||
{
|
||||
public:
|
||||
FireMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI) {}
|
||||
FireMageStrategy(PlayerbotAI* botAI);
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "fire"; }
|
||||
NextAction** getDefaultActions() override;
|
||||
};
|
||||
|
||||
class FireMageAoeStrategy : public CombatStrategy
|
||||
class FirestarterStrategy : public CombatStrategy
|
||||
{
|
||||
public:
|
||||
FireMageAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
|
||||
FirestarterStrategy(PlayerbotAI* botAI);
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "fire aoe"; }
|
||||
std::string const getName() override { return "firestarter"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,31 +4,56 @@
|
||||
*/
|
||||
|
||||
#include "FrostFireMageStrategy.h"
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
NextAction** FrostFireMageStrategy::getDefaultActions()
|
||||
// ===== Action Node Factory =====
|
||||
class FrostFireMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
return NextAction::array(0, new NextAction("frostfire bolt", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("shoot", ACTION_DEFAULT), NULL);
|
||||
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", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* pyroblast(PlayerbotAI*) { return new ActionNode("pyroblast", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* combustion(PlayerbotAI*) { return new ActionNode("combustion", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* icy_veins(PlayerbotAI*) { return new ActionNode("icy veins", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* scorch(PlayerbotAI*) { return new ActionNode("scorch", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* living_bomb(PlayerbotAI*) { return new ActionNode("living bomb", nullptr, nullptr, nullptr); }
|
||||
};
|
||||
|
||||
// ===== Single Target Strategy =====
|
||||
FrostFireMageStrategy::FrostFireMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new FrostFireMageStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
// ===== Default Actions =====
|
||||
NextAction** FrostFireMageStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("frostfire bolt", 5.2f),
|
||||
new NextAction("fire blast", 5.1f), // cast during movement
|
||||
new NextAction("shoot", 5.0f), nullptr);
|
||||
}
|
||||
|
||||
// ===== Trigger Initialization =====
|
||||
void FrostFireMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericMageStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("hot streak", NextAction::array(0, new NextAction("pyroblast", 25.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("combustion", NextAction::array(0, new NextAction("combustion", 50.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("icy veins", NextAction::array(0, new NextAction("icy veins", 60.0f), nullptr)));
|
||||
}
|
||||
// Debuff Triggers
|
||||
triggers.push_back(new TriggerNode("improved scorch", NextAction::array(0, new NextAction("scorch", 19.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("living bomb", NextAction::array(0, new NextAction("living bomb", 18.5f), nullptr)));
|
||||
|
||||
void FrostFireMageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("flamestrike", 20.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("living bomb", NextAction::array(0, new NextAction("living bomb", 25.0f), nullptr)));
|
||||
// Proc Trigger
|
||||
triggers.push_back(new TriggerNode("hot streak", NextAction::array(0, new NextAction("pyroblast", 25.0f), nullptr)));
|
||||
}
|
||||
|
||||
@@ -13,20 +13,11 @@ class PlayerbotAI;
|
||||
class FrostFireMageStrategy : public GenericMageStrategy
|
||||
{
|
||||
public:
|
||||
FrostFireMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI) {}
|
||||
FrostFireMageStrategy(PlayerbotAI* botAI);
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "frostfire"; }
|
||||
NextAction** getDefaultActions() override;
|
||||
};
|
||||
|
||||
class FrostFireMageAoeStrategy : public CombatStrategy
|
||||
{
|
||||
public:
|
||||
FrostFireMageAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "frostfire aoe"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "Playerbots.h"
|
||||
|
||||
// ===== Action Node Factory =====
|
||||
class FrostMageStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
{
|
||||
public:
|
||||
@@ -16,96 +17,66 @@ public:
|
||||
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([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("cold snap",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
static ActionNode* ice_barrier([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("ice barrier",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
static ActionNode* summon_water_elemental([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("summon water elemental",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ nullptr,
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
|
||||
static ActionNode* deep_freeze([[maybe_unused]] PlayerbotAI* botAI)
|
||||
{
|
||||
return new ActionNode("deep freeze",
|
||||
/*P*/ nullptr,
|
||||
/*A*/ NextAction::array(0, new NextAction("ice lance"), nullptr),
|
||||
/*C*/ nullptr);
|
||||
}
|
||||
static ActionNode* cold_snap(PlayerbotAI*) { return new ActionNode("cold snap", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* ice_barrier(PlayerbotAI*) { return new ActionNode("ice barrier", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* summon_water_elemental(PlayerbotAI*) { return new ActionNode("summon water elemental", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* deep_freeze(PlayerbotAI*) { return new ActionNode("deep freeze", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* icy_veins(PlayerbotAI*) { return new ActionNode("icy veins", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* frostbolt(PlayerbotAI*) { return new ActionNode("frostbolt", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* ice_lance(PlayerbotAI*) { return new ActionNode("ice lance", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* fire_blast(PlayerbotAI*) { return new ActionNode("fire blast", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* fireball(PlayerbotAI*) { return new ActionNode("fireball", nullptr, nullptr, nullptr); }
|
||||
static ActionNode* frostfire_bolt(PlayerbotAI*) { return new ActionNode("frostfire bolt", nullptr, nullptr, nullptr); }
|
||||
};
|
||||
|
||||
// ===== Single Target Strategy =====
|
||||
FrostMageStrategy::FrostMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI)
|
||||
{
|
||||
actionNodeFactories.Add(new FrostMageStrategyActionNodeFactory());
|
||||
}
|
||||
|
||||
// ===== Default Actions =====
|
||||
NextAction** FrostMageStrategy::getDefaultActions()
|
||||
{
|
||||
return NextAction::array(0, new NextAction("frostbolt", ACTION_DEFAULT + 0.3f),
|
||||
new NextAction("fire blast", ACTION_DEFAULT + 0.2f), // cast during movement
|
||||
new NextAction("shoot", ACTION_DEFAULT + 0.1f),
|
||||
new NextAction("fireball", ACTION_DEFAULT), nullptr);
|
||||
return NextAction::array(0, new NextAction("frostbolt", 5.4f),
|
||||
new NextAction("ice lance", 5.3f), // cast during movement
|
||||
new NextAction("fire blast", 5.2f), // cast during movement if ice lance is not learned
|
||||
new NextAction("shoot", 5.1f),
|
||||
new NextAction("fireball", 5.0f), nullptr);
|
||||
}
|
||||
|
||||
// ===== Trigger Initialization ===
|
||||
void FrostMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
GenericMageStrategy::InitTriggers(triggers);
|
||||
triggers.push_back(new TriggerNode("icy veins", NextAction::array(0, new NextAction("icy veins", 50.0f), nullptr)));
|
||||
// No logic currently for cold snap usage.. possibly use right after icy veins drops off?
|
||||
// triggers.push_back(new TriggerNode("cold snap", NextAction::array(0, new NextAction("cold snap", 50.0f),
|
||||
// nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode(
|
||||
"no pet", NextAction::array(0, new NextAction("summon water elemental", ACTION_HIGH), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", ACTION_HIGH + 1), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium health", NextAction::array(0, new NextAction("ice barrier", ACTION_NORMAL), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("being attacked", NextAction::array(0, new NextAction("ice barrier", ACTION_HIGH + 1), nullptr)));
|
||||
triggers.push_back(new TriggerNode(
|
||||
"brain freeze", NextAction::array(0, new NextAction("frostfire bolt", ACTION_NORMAL + 3), nullptr)));
|
||||
// Combo cast the last charge of fingers of frost for double crits.
|
||||
// Should only do this on the final charge of FoF.
|
||||
triggers.push_back(new TriggerNode("fingers of frost single",
|
||||
NextAction::array(0, new NextAction("frostbolt", ACTION_NORMAL + 2),
|
||||
new NextAction("deep freeze", ACTION_NORMAL + 1), nullptr)));
|
||||
// May not need this, frostbolt is the default action so probably don't need to specify.
|
||||
// Maybe uncomment if you find the mage is prioritising auxillary spells while this buff is up, and wasting the
|
||||
// proc. triggers.push_back(new TriggerNode("fingers of frost double", NextAction::array(0, new
|
||||
// NextAction("frostbolt", ACTION_NORMAL), nullptr)));
|
||||
// Pet/Defensive triggers
|
||||
triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon water elemental", 30.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", 29.5f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("medium health", NextAction::array(0, new NextAction("ice barrier", 29.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("being attacked", NextAction::array(0, new NextAction("ice barrier", 29.0f), nullptr)));
|
||||
|
||||
// Same 2-spell combo for various freeze procs
|
||||
triggers.push_back(new TriggerNode("frost nova on target",
|
||||
NextAction::array(0, new NextAction("frostbolt", ACTION_NORMAL + 2),
|
||||
new NextAction("deep freeze", ACTION_NORMAL + 1), nullptr)));
|
||||
triggers.push_back(new TriggerNode("frostbite on target",
|
||||
NextAction::array(0, new NextAction("frostbolt", ACTION_NORMAL + 2),
|
||||
new NextAction("deep freeze", ACTION_NORMAL + 1), nullptr)));
|
||||
}
|
||||
|
||||
void FrostMageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium aoe", NextAction::array(0, new NextAction("blizzard", ACTION_HIGH), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("light aoe", NextAction::array(0, new NextAction("cone of cold", ACTION_HIGH + 1), nullptr)));
|
||||
// Proc/Freeze triggers
|
||||
triggers.push_back(new TriggerNode("brain freeze", NextAction::array(0, new NextAction("frostfire bolt", 19.5f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("fingers of frost", NextAction::array(0,
|
||||
new NextAction("deep freeze", 19.0f),
|
||||
new NextAction("frostbolt", 18.0f), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("frostbite on target", NextAction::array(0,
|
||||
new NextAction("deep freeze", 19.0f),
|
||||
new NextAction("frostbolt", 18.0f), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("frost nova on target", NextAction::array(0,
|
||||
new NextAction("deep freeze", 19.0f),
|
||||
new NextAction("frostbolt", 18.0f), nullptr)));
|
||||
|
||||
}
|
||||
|
||||
@@ -20,13 +20,4 @@ public:
|
||||
NextAction** getDefaultActions() override;
|
||||
};
|
||||
|
||||
class FrostMageAoeStrategy : public CombatStrategy
|
||||
{
|
||||
public:
|
||||
FrostMageAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "frost aoe"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
#include "GenericMageNonCombatStrategy.h"
|
||||
|
||||
#include "AiFactory.h"
|
||||
#include "Playerbots.h"
|
||||
|
||||
class GenericMageNonCombatStrategyActionNodeFactory : public NamedObjectFactory<ActionNode>
|
||||
@@ -52,35 +52,23 @@ void GenericMageNonCombatStrategy::InitTriggers(std::vector<TriggerNode*>& trigg
|
||||
{
|
||||
NonCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("arcane intellect", NextAction::array(0, new NextAction("arcane intellect", 21.0f), nullptr)));
|
||||
|
||||
triggers.push_back(
|
||||
new TriggerNode("no focus magic", NextAction::array(0, new NextAction("focus magic on party", 19.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("no drink", NextAction::array(0, new NextAction("conjure water", 16.0f),
|
||||
// nullptr))); triggers.push_back(new TriggerNode("no food", NextAction::array(0, new NextAction("conjure
|
||||
// food", 15.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("arcane intellect", NextAction::array(0, new NextAction("arcane intellect", 21.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("no focus magic", NextAction::array(0, new NextAction("focus magic on party", 19.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("often", NextAction::array(0, new NextAction("apply oil", 1.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("no mana gem", NextAction::array(0, new NextAction("conjure mana gem", 20.0f), nullptr)));
|
||||
}
|
||||
|
||||
void MageBuffManaStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("mage armor", NextAction::array(0, new NextAction("mage armor", 19.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("mage armor", NextAction::array(0, new NextAction("mage armor", 19.0f), nullptr)));
|
||||
}
|
||||
|
||||
void MageBuffDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("mage armor", NextAction::array(0, new NextAction("molten armor", 19.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("mage armor", NextAction::array(0, new NextAction("molten armor", 19.0f), nullptr)));
|
||||
}
|
||||
|
||||
void MageBuffStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("arcane intellect on party",
|
||||
NextAction::array(0, new NextAction("arcane intellect on party", 20.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("give water", NextAction::array(0, new NextAction("give water", 14.0f),
|
||||
// nullptr))); triggers.push_back(new TriggerNode("give food", NextAction::array(0, new NextAction("give
|
||||
// food", 13.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("arcane intellect on party", NextAction::array(0, new NextAction("arcane intellect on party", 20.0f), nullptr)));
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
#include "GenericMageStrategy.h"
|
||||
|
||||
#include "AiFactory.h"
|
||||
#include "Playerbots.h"
|
||||
#include "RangedCombatStrategy.h"
|
||||
|
||||
@@ -160,49 +160,119 @@ void GenericMageStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
RangedCombatStrategy::InitTriggers(triggers);
|
||||
|
||||
// triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell",
|
||||
// ACTION_MOVE + 9), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("enemy is close", NextAction::array(0, new NextAction("frost nova", 50.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("counterspell on enemy healer",
|
||||
NextAction::array(0, new NextAction("counterspell on enemy healer", 40.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("critical health", NextAction::array(0, new NextAction("ice block", 80.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("spellsteal", NextAction::array(0, new NextAction("spellsteal", 40.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium threat", NextAction::array(0, new NextAction("invisibility", 60.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("low mana", NextAction::array(0, new NextAction("evocation", ACTION_EMERGENCY + 5), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("fire ward", NextAction::array(0, new NextAction("fire ward", ACTION_EMERGENCY), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("frost ward", NextAction::array(0, new NextAction("frost ward", ACTION_EMERGENCY), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("enemy too close for spell",
|
||||
NextAction::array(0, new NextAction("blink back", ACTION_MOVE + 5), nullptr)));
|
||||
// Threat Triggers
|
||||
triggers.push_back(new TriggerNode("high threat", NextAction::array(0, new NextAction("mirror image", 60.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("medium threat", NextAction::array(0, new NextAction("invisibility", 30.0f), nullptr)));
|
||||
|
||||
// Defensive Triggers
|
||||
triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("ice block", 90.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("mana shield", 85.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("fire ward", NextAction::array(0, new NextAction("fire ward", 90.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("frost ward", NextAction::array(0, new NextAction("frost ward", 90.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("enemy is close and no firestarter strategy", NextAction::array(0, new NextAction("frost nova", 50.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("enemy too close for spell and no firestarter strategy", NextAction::array(0, new NextAction("blink back", 35.0f), nullptr)));
|
||||
|
||||
// Mana Threshold Triggers
|
||||
Player* bot = botAI->GetBot();
|
||||
if (bot->HasSpell(42985)) // Mana Sapphire
|
||||
triggers.push_back(new TriggerNode("high mana", NextAction::array(0, new NextAction("use mana sapphire", 90.0f), nullptr)));
|
||||
else if (bot->HasSpell(27101)) // Mana Emerald
|
||||
triggers.push_back(new TriggerNode("high mana", NextAction::array(0, new NextAction("use mana emerald", 90.0f), nullptr)));
|
||||
else if (bot->HasSpell(10054)) // Mana Ruby
|
||||
triggers.push_back(new TriggerNode("high mana", NextAction::array(0, new NextAction("use mana ruby", 90.0f), nullptr)));
|
||||
else if (bot->HasSpell(10053)) // Mana Citrine
|
||||
triggers.push_back(new TriggerNode("high mana", NextAction::array(0, new NextAction("use mana citrine", 90.0f), nullptr)));
|
||||
else if (bot->HasSpell(3552)) // Mana Jade
|
||||
triggers.push_back(new TriggerNode("high mana", NextAction::array(0, new NextAction("use mana jade", 90.0f), nullptr)));
|
||||
else if (bot->HasSpell(759)) // Mana Agate
|
||||
triggers.push_back(new TriggerNode("high mana", NextAction::array(0, new NextAction("use mana agate", 90.0f), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("medium mana", NextAction::array(0, new NextAction("mana potion", 90.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("evocation", 90.0f), nullptr)));
|
||||
|
||||
// Counterspell / Spellsteal Triggers
|
||||
triggers.push_back(new TriggerNode("spellsteal", NextAction::array(0, new NextAction("spellsteal", 40.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("counterspell on enemy healer", NextAction::array(0, new NextAction("counterspell on enemy healer", 40.0f), nullptr)));
|
||||
}
|
||||
|
||||
void MageCureStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("remove curse", NextAction::array(0, new NextAction("remove curse", 41.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("remove curse on party",
|
||||
NextAction::array(0, new NextAction("remove curse on party", 40.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("remove curse", NextAction::array(0, new NextAction("remove curse", 41.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("remove curse on party", NextAction::array(0, new NextAction("remove curse on party", 40.0f), nullptr)));
|
||||
}
|
||||
|
||||
void MageBoostStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("icy veins", NextAction::array(0, new NextAction("icy veins", 50.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("presence of mind", NextAction::array(0, new NextAction("presence of mind", 42.0f), nullptr)));
|
||||
// triggers.push_back(new TriggerNode("arcane power", NextAction::array(0, new NextAction("arcane power", 41.0f), nullptr)));
|
||||
triggers.push_back(
|
||||
new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 41.0f), nullptr)));
|
||||
Player* bot = botAI->GetBot();
|
||||
int tab = AiFactory::GetPlayerSpecTab(bot);
|
||||
|
||||
if (tab == 0) // Arcane
|
||||
{
|
||||
triggers.push_back(new TriggerNode("arcane power", NextAction::array(0, new NextAction("arcane power", 29.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("icy veins", NextAction::array(0, new NextAction("icy veins", 28.5f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 28.0f), nullptr)));
|
||||
}
|
||||
else if (tab == 1)
|
||||
{
|
||||
if (bot->HasSpell(44614) /*Frostfire Bolt*/ && bot->HasAura(15047) /*Ice Shards*/)
|
||||
{ // Frostfire
|
||||
triggers.push_back(new TriggerNode("combustion", NextAction::array(0, new NextAction("combustion", 18.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("icy veins", NextAction::array(0, new NextAction("icy veins", 17.5f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 17.0f), nullptr)));
|
||||
}
|
||||
else
|
||||
{ // Fire
|
||||
triggers.push_back(new TriggerNode("combustion", NextAction::array(0, new NextAction("combustion", 18.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 17.5f), nullptr)));
|
||||
}
|
||||
}
|
||||
else if (tab == 2) // Frost
|
||||
{
|
||||
triggers.push_back(new TriggerNode("cold snap", NextAction::array(0, new NextAction("cold snap", 28.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("icy veins", NextAction::array(0, new NextAction("icy veins", 27.5f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("mirror image", NextAction::array(0, new NextAction("mirror image", 26.0f), nullptr)));
|
||||
}
|
||||
}
|
||||
|
||||
void MageCcStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("polymorph", NextAction::array(0, new NextAction("polymorph", 30.0f), nullptr)));
|
||||
}
|
||||
|
||||
void MageAoeStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
|
||||
{
|
||||
triggers.push_back(new TriggerNode("blizzard channel check", NextAction::array(0, new NextAction("cancel channel", 26.0f), nullptr)));
|
||||
|
||||
Player* bot = botAI->GetBot();
|
||||
int tab = AiFactory::GetPlayerSpecTab(bot);
|
||||
|
||||
if (tab == 0) // Arcane
|
||||
{
|
||||
triggers.push_back(new TriggerNode("flamestrike active and medium aoe", NextAction::array(0, new NextAction("blizzard", 24.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0,
|
||||
new NextAction("flamestrike", 23.0f),
|
||||
new NextAction("blizzard", 22.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("arcane explosion", 21.0f), nullptr)));
|
||||
}
|
||||
else if (tab == 1) // Fire and Frostfire
|
||||
{
|
||||
triggers.push_back(
|
||||
new TriggerNode("medium aoe", NextAction::array(0,
|
||||
new NextAction("dragon's breath", 39.0f),
|
||||
new NextAction("blast wave", 38.0f),
|
||||
new NextAction("flamestrike", 23.0f),
|
||||
new NextAction("blizzard", 22.0f), nullptr)));
|
||||
|
||||
triggers.push_back(new TriggerNode("flamestrike active and medium aoe", NextAction::array(0, new NextAction("blizzard", 24.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("firestarter", NextAction::array(0, new NextAction("flamestrike", 40.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("living bomb on attackers", NextAction::array(0, new NextAction("living bomb on attackers", 21.0f), nullptr)));
|
||||
}
|
||||
else if (tab == 2) // Frost
|
||||
{
|
||||
triggers.push_back(new TriggerNode("flamestrike active and medium aoe", NextAction::array(0, new NextAction("blizzard", 24.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0,
|
||||
new NextAction("flamestrike", 23.0f),
|
||||
new NextAction("blizzard", 22.0f), nullptr)));
|
||||
triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("cone of cold", 21.0f), nullptr)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,4 +51,13 @@ public:
|
||||
std::string const getName() override { return "cc"; }
|
||||
};
|
||||
|
||||
class MageAoeStrategy : public CombatStrategy
|
||||
{
|
||||
public:
|
||||
MageAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {}
|
||||
|
||||
void InitTriggers(std::vector<TriggerNode*>& triggers) override;
|
||||
std::string const getName() override { return "aoe"; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "MageActions.h"
|
||||
#include <cmath>
|
||||
|
||||
#include "UseItemAction.h"
|
||||
#include "PlayerbotAIConfig.h"
|
||||
#include "Playerbots.h"
|
||||
#include "ServerFacade.h"
|
||||
@@ -13,6 +13,42 @@
|
||||
|
||||
Value<Unit*>* CastPolymorphAction::GetTargetValue() { return context->GetValue<Unit*>("cc target", getName()); }
|
||||
|
||||
bool UseManaSapphireAction::isUseful()
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
return AI_VALUE2(bool, "combat", "self target") && bot->GetItemCount(33312, false) > 0; // Mana Sapphire
|
||||
}
|
||||
|
||||
bool UseManaEmeraldAction::isUseful()
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
return AI_VALUE2(bool, "combat", "self target") && bot->GetItemCount(22044, false) > 0; // Mana Emerald
|
||||
}
|
||||
|
||||
bool UseManaRubyAction::isUseful()
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
return AI_VALUE2(bool, "combat", "self target") && bot->GetItemCount(8008, false) > 0; // Mana Ruby
|
||||
}
|
||||
|
||||
bool UseManaCitrineAction::isUseful()
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
return AI_VALUE2(bool, "combat", "self target") && bot->GetItemCount(8007, false) > 0; // Mana Citrine
|
||||
}
|
||||
|
||||
bool UseManaJadeAction::isUseful()
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
return AI_VALUE2(bool, "combat", "self target") && bot->GetItemCount(5513, false) > 0; // Mana Jade
|
||||
}
|
||||
|
||||
bool UseManaAgateAction::isUseful()
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
return AI_VALUE2(bool, "combat", "self target") && bot->GetItemCount(5514, false) > 0; // Mana Agate
|
||||
}
|
||||
|
||||
bool CastFrostNovaAction::isUseful()
|
||||
{
|
||||
Unit* target = AI_VALUE(Unit*, "current target");
|
||||
@@ -105,4 +141,14 @@ bool CastBlinkBackAction::Execute(Event event)
|
||||
// can cast spell check passed in isUseful()
|
||||
bot->SetOrientation(bot->GetAngle(target) + M_PI);
|
||||
return CastSpellAction::Execute(event);
|
||||
}
|
||||
}
|
||||
|
||||
bool CancelChannelAction::Execute(Event event)
|
||||
{
|
||||
if (bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
|
||||
{
|
||||
bot->InterruptSpell(CURRENT_CHANNELED_SPELL);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,11 +8,280 @@
|
||||
|
||||
#include "GenericSpellActions.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "UseItemAction.h"
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
BUFF_ACTION(CastFireWardAction, "fire ward");
|
||||
BUFF_ACTION(CastFrostWardAction, "frost ward");
|
||||
// Buff and Out of Combat Actions
|
||||
|
||||
class CastMoltenArmorAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastMoltenArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "molten armor") {}
|
||||
};
|
||||
|
||||
class CastMageArmorAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastMageArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mage armor") {}
|
||||
};
|
||||
|
||||
class CastIceArmorAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastIceArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "ice armor") {}
|
||||
};
|
||||
|
||||
class CastFrostArmorAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastFrostArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "frost armor") {}
|
||||
};
|
||||
|
||||
class CastArcaneIntellectAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastArcaneIntellectAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "arcane intellect") {}
|
||||
};
|
||||
|
||||
class CastArcaneIntellectOnPartyAction : public BuffOnPartyAction
|
||||
{
|
||||
public:
|
||||
CastArcaneIntellectOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "arcane intellect") {}
|
||||
};
|
||||
|
||||
class CastFocusMagicOnPartyAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastFocusMagicOnPartyAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "focus magic") {}
|
||||
Unit* GetTarget() override;
|
||||
};
|
||||
|
||||
class CastSummonWaterElementalAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastSummonWaterElementalAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "summon water elemental") {}
|
||||
};
|
||||
|
||||
// Boost Actions
|
||||
|
||||
class CastCombustionAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastCombustionAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "combustion") {}
|
||||
};
|
||||
|
||||
class CastArcanePowerAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastArcanePowerAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "arcane power") {}
|
||||
};
|
||||
|
||||
class CastPresenceOfMindAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastPresenceOfMindAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "presence of mind") {}
|
||||
};
|
||||
|
||||
class CastIcyVeinsAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastIcyVeinsAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "icy veins") {}
|
||||
};
|
||||
|
||||
class CastColdSnapAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastColdSnapAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "cold snap") {}
|
||||
};
|
||||
|
||||
// Defensive Actions
|
||||
|
||||
class CastFireWardAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastFireWardAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "fire ward") {}
|
||||
};
|
||||
|
||||
class CastFrostWardAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastFrostWardAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "frost ward") {}
|
||||
};
|
||||
|
||||
class CastIceBarrierAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastIceBarrierAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "ice barrier") {}
|
||||
};
|
||||
|
||||
class CastInvisibilityAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastInvisibilityAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "invisibility") {}
|
||||
};
|
||||
class CastIceBlockAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastIceBlockAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "ice block") {}
|
||||
};
|
||||
|
||||
class CastMirrorImageAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastMirrorImageAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mirror image") {}
|
||||
};
|
||||
|
||||
class CastBlinkBackAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastBlinkBackAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blink") {}
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
class CastManaShieldAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastManaShieldAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mana shield") {}
|
||||
};
|
||||
|
||||
// Utility Actions
|
||||
|
||||
class CastEvocationAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastEvocationAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "evocation") {}
|
||||
std::string const GetTargetName() override { return "self target"; }
|
||||
};
|
||||
|
||||
class CastConjureManaGemAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastConjureManaGemAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "conjure mana gem") {}
|
||||
};
|
||||
|
||||
class CastConjureFoodAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastConjureFoodAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "conjure food") {}
|
||||
};
|
||||
|
||||
class CastConjureWaterAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastConjureWaterAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "conjure water") {}
|
||||
};
|
||||
|
||||
class UseManaSapphireAction : public UseItemAction
|
||||
{
|
||||
public:
|
||||
UseManaSapphireAction(PlayerbotAI* botAI) : UseItemAction(botAI, "mana sapphire") {}
|
||||
bool isUseful() override;
|
||||
};
|
||||
class UseManaEmeraldAction : public UseItemAction
|
||||
{
|
||||
public:
|
||||
UseManaEmeraldAction(PlayerbotAI* botAI) : UseItemAction(botAI, "mana emerald") {}
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class UseManaRubyAction : public UseItemAction
|
||||
{
|
||||
public:
|
||||
UseManaRubyAction(PlayerbotAI* botAI) : UseItemAction(botAI, "mana ruby") {}
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class UseManaCitrineAction : public UseItemAction
|
||||
{
|
||||
public:
|
||||
UseManaCitrineAction(PlayerbotAI* botAI) : UseItemAction(botAI, "mana citrine") {}
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class UseManaJadeAction : public UseItemAction
|
||||
{
|
||||
public:
|
||||
UseManaJadeAction(PlayerbotAI* botAI) : UseItemAction(botAI, "mana jade") {}
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class UseManaAgateAction : public UseItemAction
|
||||
{
|
||||
public:
|
||||
UseManaAgateAction(PlayerbotAI* botAI) : UseItemAction(botAI, "mana agate") {}
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
// CC, Interrupt, and Dispel Actions
|
||||
|
||||
class CastPolymorphAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastPolymorphAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "polymorph") {}
|
||||
Value<Unit*>* GetTargetValue() override;
|
||||
};
|
||||
|
||||
class CastSpellstealAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastSpellstealAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "spellsteal") {}
|
||||
};
|
||||
|
||||
class CastCounterspellAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastCounterspellAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "counterspell") {}
|
||||
};
|
||||
|
||||
class CastCounterspellOnEnemyHealerAction : public CastSpellOnEnemyHealerAction
|
||||
{
|
||||
public:
|
||||
CastCounterspellOnEnemyHealerAction(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, "counterspell") {}
|
||||
};
|
||||
|
||||
class CastFrostNovaAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastFrostNovaAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "frost nova") {}
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastDeepFreezeAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastDeepFreezeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "deep freeze") {}
|
||||
bool isPossible() override { return true; }
|
||||
};
|
||||
|
||||
class CastRemoveCurseAction : public CastCureSpellAction
|
||||
{
|
||||
public:
|
||||
CastRemoveCurseAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "remove curse") {}
|
||||
};
|
||||
|
||||
class CastRemoveLesserCurseAction : public CastCureSpellAction
|
||||
{
|
||||
public:
|
||||
CastRemoveLesserCurseAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "remove lesser curse") {}
|
||||
};
|
||||
|
||||
class CastRemoveCurseOnPartyAction : public CurePartyMemberAction
|
||||
{
|
||||
public:
|
||||
CastRemoveCurseOnPartyAction(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "remove curse", DISPEL_CURSE) {}
|
||||
};
|
||||
|
||||
class CastRemoveLesserCurseOnPartyAction : public CurePartyMemberAction
|
||||
{
|
||||
public:
|
||||
CastRemoveLesserCurseOnPartyAction(PlayerbotAI* botAI)
|
||||
: CurePartyMemberAction(botAI, "remove lesser curse", DISPEL_CURSE)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// Damage and Debuff Actions
|
||||
|
||||
class CastFireballAction : public CastSpellAction
|
||||
{
|
||||
@@ -57,18 +326,26 @@ public:
|
||||
CastPyroblastAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "pyroblast") {}
|
||||
};
|
||||
|
||||
class CastFlamestrikeAction : public CastDebuffSpellAction
|
||||
class CastLivingBombAction : public CastDebuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastFlamestrikeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "flamestrike", true, 0.0f) {}
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||
CastLivingBombAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "living bomb", true) {}
|
||||
bool isUseful() override
|
||||
{
|
||||
// Bypass TTL check
|
||||
return CastAuraSpellAction::isUseful();
|
||||
}
|
||||
};
|
||||
|
||||
class CastFrostNovaAction : public CastSpellAction
|
||||
class CastLivingBombOnAttackersAction : public CastDebuffSpellOnAttackerAction
|
||||
{
|
||||
public:
|
||||
CastFrostNovaAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "frost nova") {}
|
||||
bool isUseful() override;
|
||||
CastLivingBombOnAttackersAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "living bomb", true) {}
|
||||
bool isUseful() override
|
||||
{
|
||||
// Bypass TTL check
|
||||
return CastAuraSpellAction::isUseful();
|
||||
}
|
||||
};
|
||||
|
||||
class CastFrostboltAction : public CastSpellAction
|
||||
@@ -89,12 +366,6 @@ public:
|
||||
CastIceLanceAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "ice lance") {}
|
||||
};
|
||||
|
||||
class CastDeepFreezeAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastDeepFreezeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "deep freeze") {}
|
||||
};
|
||||
|
||||
class CastBlizzardAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
@@ -110,143 +381,11 @@ public:
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastArcaneIntellectAction : public CastBuffSpellAction
|
||||
class CastFlamestrikeAction : public CastDebuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastArcaneIntellectAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "arcane intellect") {}
|
||||
};
|
||||
|
||||
class CastArcaneIntellectOnPartyAction : public BuffOnPartyAction
|
||||
{
|
||||
public:
|
||||
CastArcaneIntellectOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "arcane intellect") {}
|
||||
};
|
||||
|
||||
class CastRemoveCurseAction : public CastCureSpellAction
|
||||
{
|
||||
public:
|
||||
CastRemoveCurseAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "remove curse") {}
|
||||
};
|
||||
|
||||
class CastRemoveLesserCurseAction : public CastCureSpellAction
|
||||
{
|
||||
public:
|
||||
CastRemoveLesserCurseAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "remove lesser curse") {}
|
||||
};
|
||||
|
||||
class CastIcyVeinsAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastIcyVeinsAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "icy veins") {}
|
||||
};
|
||||
|
||||
class CastColdSnapAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastColdSnapAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "cold snap") {}
|
||||
};
|
||||
|
||||
class CastIceBarrierAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastIceBarrierAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "ice barrier") {}
|
||||
};
|
||||
|
||||
class CastSummonWaterElementalAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastSummonWaterElementalAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "summon water elemental") {}
|
||||
};
|
||||
|
||||
class CastCombustionAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastCombustionAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "combustion") {}
|
||||
};
|
||||
|
||||
BEGIN_SPELL_ACTION(CastCounterspellAction, "counterspell")
|
||||
END_SPELL_ACTION()
|
||||
|
||||
class CastRemoveCurseOnPartyAction : public CurePartyMemberAction
|
||||
{
|
||||
public:
|
||||
CastRemoveCurseOnPartyAction(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "remove curse", DISPEL_CURSE) {}
|
||||
};
|
||||
|
||||
class CastRemoveLesserCurseOnPartyAction : public CurePartyMemberAction
|
||||
{
|
||||
public:
|
||||
CastRemoveLesserCurseOnPartyAction(PlayerbotAI* botAI)
|
||||
: CurePartyMemberAction(botAI, "remove lesser curse", DISPEL_CURSE)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CastConjureFoodAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastConjureFoodAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "conjure food") {}
|
||||
};
|
||||
|
||||
class CastConjureWaterAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastConjureWaterAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "conjure water") {}
|
||||
};
|
||||
|
||||
class CastIceBlockAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastIceBlockAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "ice block") {}
|
||||
};
|
||||
|
||||
class CastMoltenArmorAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastMoltenArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "molten armor") {}
|
||||
};
|
||||
|
||||
class CastMageArmorAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastMageArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mage armor") {}
|
||||
};
|
||||
|
||||
class CastIceArmorAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastIceArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "ice armor") {}
|
||||
};
|
||||
|
||||
class CastFrostArmorAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastFrostArmorAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "frost armor") {}
|
||||
};
|
||||
|
||||
class CastPolymorphAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastPolymorphAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "polymorph") {}
|
||||
Value<Unit*>* GetTargetValue() override;
|
||||
};
|
||||
|
||||
class CastSpellstealAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastSpellstealAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "spellsteal") {}
|
||||
};
|
||||
|
||||
class CastLivingBombAction : public CastDebuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastLivingBombAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "living bomb", true) {}
|
||||
};
|
||||
|
||||
class CastLivingBombOnAttackersAction : public CastDebuffSpellOnAttackerAction
|
||||
{
|
||||
public:
|
||||
CastLivingBombOnAttackersAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "living bomb", true) {}
|
||||
CastFlamestrikeAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "flamestrike", true, 0.0f) {}
|
||||
ActionThreatType getThreatType() override { return ActionThreatType::Aoe; }
|
||||
};
|
||||
|
||||
class CastDragonsBreathAction : public CastSpellAction
|
||||
@@ -265,55 +404,12 @@ public:
|
||||
bool isUseful() override;
|
||||
};
|
||||
|
||||
class CastInvisibilityAction : public CastBuffSpellAction
|
||||
class CancelChannelAction : public Action
|
||||
{
|
||||
public:
|
||||
CastInvisibilityAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "invisibility") {}
|
||||
};
|
||||
CancelChannelAction(PlayerbotAI* botAI) : Action(botAI, "cancel channel") {}
|
||||
|
||||
class CastEvocationAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastEvocationAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "evocation") {}
|
||||
std::string const GetTargetName() override { return "self target"; }
|
||||
};
|
||||
|
||||
class CastCounterspellOnEnemyHealerAction : public CastSpellOnEnemyHealerAction
|
||||
{
|
||||
public:
|
||||
CastCounterspellOnEnemyHealerAction(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, "counterspell") {}
|
||||
};
|
||||
|
||||
class CastArcanePowerAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastArcanePowerAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "arcane power") {}
|
||||
};
|
||||
|
||||
class CastPresenceOfMindAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastPresenceOfMindAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "presence of mind") {}
|
||||
};
|
||||
|
||||
class CastMirrorImageAction : public CastBuffSpellAction
|
||||
{
|
||||
public:
|
||||
CastMirrorImageAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "mirror image") {}
|
||||
};
|
||||
|
||||
class CastFocusMagicOnPartyAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastFocusMagicOnPartyAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "focus magic") {}
|
||||
Unit* GetTarget() override;
|
||||
};
|
||||
|
||||
class CastBlinkBackAction : public CastSpellAction
|
||||
{
|
||||
public:
|
||||
CastBlinkBackAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "blink") {}
|
||||
|
||||
bool Execute(Event event) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
#include "MageAiObjectContext.h"
|
||||
|
||||
#include "ArcaneMageStrategy.h"
|
||||
#include "FireMageStrategy.h"
|
||||
#include "FrostFireMageStrategy.h"
|
||||
@@ -23,27 +22,23 @@ public:
|
||||
{
|
||||
creators["nc"] = &MageStrategyFactoryInternal::nc;
|
||||
creators["pull"] = &MageStrategyFactoryInternal::pull;
|
||||
creators["fire aoe"] = &MageStrategyFactoryInternal::fire_aoe;
|
||||
creators["frostfire aoe"] = &MageStrategyFactoryInternal::frostfire_aoe;
|
||||
creators["frost aoe"] = &MageStrategyFactoryInternal::frost_aoe;
|
||||
creators["arcane aoe"] = &MageStrategyFactoryInternal::arcane_aoe;
|
||||
creators["aoe"] = &MageStrategyFactoryInternal::aoe;
|
||||
creators["cure"] = &MageStrategyFactoryInternal::cure;
|
||||
creators["buff"] = &MageStrategyFactoryInternal::buff;
|
||||
creators["boost"] = &MageStrategyFactoryInternal::boost;
|
||||
creators["cc"] = &MageStrategyFactoryInternal::cc;
|
||||
creators["firestarter"] = &MageStrategyFactoryInternal::firestarter;
|
||||
}
|
||||
|
||||
private:
|
||||
static Strategy* nc(PlayerbotAI* botAI) { return new GenericMageNonCombatStrategy(botAI); }
|
||||
static Strategy* pull(PlayerbotAI* botAI) { return new PullStrategy(botAI, "shoot"); }
|
||||
static Strategy* fire_aoe(PlayerbotAI* botAI) { return new FireMageAoeStrategy(botAI); }
|
||||
static Strategy* frostfire_aoe(PlayerbotAI* botAI) { return new FrostFireMageAoeStrategy(botAI); }
|
||||
static Strategy* frost_aoe(PlayerbotAI* botAI) { return new FrostMageAoeStrategy(botAI); }
|
||||
static Strategy* arcane_aoe(PlayerbotAI* botAI) { return new ArcaneMageAoeStrategy(botAI); }
|
||||
static Strategy* aoe(PlayerbotAI* botAI) { return new MageAoeStrategy(botAI); }
|
||||
static Strategy* cure(PlayerbotAI* botAI) { return new MageCureStrategy(botAI); }
|
||||
static Strategy* buff(PlayerbotAI* botAI) { return new MageBuffStrategy(botAI); }
|
||||
static Strategy* boost(PlayerbotAI* botAI) { return new MageBoostStrategy(botAI); }
|
||||
static Strategy* cc(PlayerbotAI* botAI) { return new MageCcStrategy(botAI); }
|
||||
static Strategy* firestarter(PlayerbotAI* botAI) { return new FirestarterStrategy(botAI); }
|
||||
};
|
||||
|
||||
class MageCombatStrategyFactoryInternal : public NamedObjectContext<Strategy>
|
||||
@@ -86,8 +81,7 @@ public:
|
||||
creators["fireball"] = &MageTriggerFactoryInternal::fireball;
|
||||
creators["pyroblast"] = &MageTriggerFactoryInternal::pyroblast;
|
||||
creators["combustion"] = &MageTriggerFactoryInternal::combustion;
|
||||
creators["fingers of frost single"] = &MageTriggerFactoryInternal::fingers_of_frost_single;
|
||||
creators["fingers of frost double"] = &MageTriggerFactoryInternal::fingers_of_frost_double;
|
||||
creators["fingers of frost"] = &MageTriggerFactoryInternal::fingers_of_frost;
|
||||
creators["brain freeze"] = &MageTriggerFactoryInternal::brain_freeze;
|
||||
creators["icy veins"] = &MageTriggerFactoryInternal::icy_veins;
|
||||
creators["cold snap"] = &MageTriggerFactoryInternal::cold_snap;
|
||||
@@ -102,6 +96,7 @@ public:
|
||||
creators["spellsteal"] = &MageTriggerFactoryInternal::spellsteal;
|
||||
creators["hot streak"] = &MageTriggerFactoryInternal::hot_streak;
|
||||
creators["living bomb"] = &MageTriggerFactoryInternal::living_bomb;
|
||||
creators["living bomb on attackers"] = &MageTriggerFactoryInternal::living_bomb_on_attackers;
|
||||
creators["missile barrage"] = &MageTriggerFactoryInternal::missile_barrage;
|
||||
creators["arcane blast"] = &MageTriggerFactoryInternal::arcane_blast;
|
||||
creators["counterspell on enemy healer"] = &MageTriggerFactoryInternal::counterspell_enemy_healer;
|
||||
@@ -115,6 +110,20 @@ public:
|
||||
creators["frostbite on target"] = &MageTriggerFactoryInternal::frostbite_on_target;
|
||||
creators["no focus magic"] = &MageTriggerFactoryInternal::no_focus_magic;
|
||||
creators["frostfire bolt"] = &MageTriggerFactoryInternal::frostfire_bolt;
|
||||
creators["firestarter"] = &MageTriggerFactoryInternal::firestarter;
|
||||
creators["improved scorch"] = &MageTriggerFactoryInternal::improved_scorch;
|
||||
creators["flamestrike nearby"] = &MageTriggerFactoryInternal::flamestrike_nearby;
|
||||
creators["flamestrike active and medium aoe"] = &MageTriggerFactoryInternal::flamestrike_blizzard;
|
||||
creators["arcane blast 4 stacks and missile barrage"] = &MageTriggerFactoryInternal::arcane_blast_4_stacks_and_missile_barrage;
|
||||
creators["icy veins on cd"] = &MageTriggerFactoryInternal::icy_veins_on_cd;
|
||||
creators["deep freeze on cd"] = &MageTriggerFactoryInternal::deep_freeze_on_cd;
|
||||
creators["no mana gem"] = &MageTriggerFactoryInternal::NoManaGem;
|
||||
creators["blizzard channel check"] = &MageTriggerFactoryInternal::blizzard_channel_check;
|
||||
creators["blast wave off cd"] = &MageTriggerFactoryInternal::blast_wave_off_cd;
|
||||
creators["blast wave off cd and medium aoe"] = &MageTriggerFactoryInternal::blast_wave_off_cd_and_medium_aoe;
|
||||
creators["no firestarter strategy"] = &MageTriggerFactoryInternal::no_firestarter_strategy;
|
||||
creators["enemy is close and no firestarter strategy"] = &MageTriggerFactoryInternal::enemy_is_close_and_no_firestarter_strategy;
|
||||
creators["enemy too close for spell and no firestarter strategy"] = &MageTriggerFactoryInternal::enemy_too_close_for_spell_and_no_firestarter_strategy;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -126,8 +135,7 @@ private:
|
||||
static Trigger* fireball(PlayerbotAI* botAI) { return new FireballTrigger(botAI); }
|
||||
static Trigger* pyroblast(PlayerbotAI* botAI) { return new PyroblastTrigger(botAI); }
|
||||
static Trigger* combustion(PlayerbotAI* botAI) { return new CombustionTrigger(botAI); }
|
||||
static Trigger* fingers_of_frost_single(PlayerbotAI* botAI) { return new FingersOfFrostSingleTrigger(botAI); }
|
||||
static Trigger* fingers_of_frost_double(PlayerbotAI* botAI) { return new FingersOfFrostDoubleTrigger(botAI); }
|
||||
static Trigger* fingers_of_frost(PlayerbotAI* botAI) { return new FingersOfFrostTrigger(botAI); }
|
||||
static Trigger* brain_freeze(PlayerbotAI* botAI) { return new BrainFreezeTrigger(botAI); }
|
||||
static Trigger* icy_veins(PlayerbotAI* botAI) { return new IcyVeinsTrigger(botAI); }
|
||||
static Trigger* cold_snap(PlayerbotAI* botAI) { return new ColdSnapTrigger(botAI); }
|
||||
@@ -141,6 +149,7 @@ private:
|
||||
static Trigger* polymorph(PlayerbotAI* botAI) { return new PolymorphTrigger(botAI); }
|
||||
static Trigger* spellsteal(PlayerbotAI* botAI) { return new SpellstealTrigger(botAI); }
|
||||
static Trigger* living_bomb(PlayerbotAI* botAI) { return new LivingBombTrigger(botAI); }
|
||||
static Trigger* living_bomb_on_attackers(PlayerbotAI* botAI) { return new LivingBombOnAttackersTrigger(botAI); }
|
||||
static Trigger* missile_barrage(PlayerbotAI* botAI) { return new MissileBarrageTrigger(botAI); }
|
||||
static Trigger* arcane_blast(PlayerbotAI* botAI) { return new ArcaneBlastTrigger(botAI); }
|
||||
static Trigger* counterspell_enemy_healer(PlayerbotAI* botAI) { return new CounterspellEnemyHealerTrigger(botAI); }
|
||||
@@ -150,6 +159,20 @@ private:
|
||||
static Trigger* frostbite_on_target(PlayerbotAI* botAI) { return new FrostbiteOnTargetTrigger(botAI); }
|
||||
static Trigger* no_focus_magic(PlayerbotAI* botAI) { return new NoFocusMagicTrigger(botAI); }
|
||||
static Trigger* frostfire_bolt(PlayerbotAI* botAI) { return new FrostfireBoltTrigger(botAI); }
|
||||
static Trigger* improved_scorch(PlayerbotAI* botAI) { return new ImprovedScorchTrigger(botAI); }
|
||||
static Trigger* firestarter(PlayerbotAI* botAI) { return new FirestarterTrigger(botAI); }
|
||||
static Trigger* flamestrike_nearby(PlayerbotAI* botAI) { return new FlamestrikeNearbyTrigger(botAI); }
|
||||
static Trigger* flamestrike_blizzard(PlayerbotAI* botAI) { return new FlamestrikeBlizzardTrigger(botAI); }
|
||||
static Trigger* arcane_blast_4_stacks_and_missile_barrage(PlayerbotAI* botAI) { return new ArcaneBlast4StacksAndMissileBarrageTrigger(botAI); }
|
||||
static Trigger* icy_veins_on_cd(PlayerbotAI* botAI) { return new IcyVeinsCooldownTrigger(botAI); }
|
||||
static Trigger* deep_freeze_on_cd(PlayerbotAI* botAI) { return new DeepFreezeCooldownTrigger(botAI); }
|
||||
static Trigger* NoManaGem(PlayerbotAI* botAI) { return new NoManaGemTrigger(botAI); }
|
||||
static Trigger* blizzard_channel_check(PlayerbotAI* botAI) { return new BlizzardChannelCheckTrigger(botAI); }
|
||||
static Trigger* blast_wave_off_cd(PlayerbotAI* botAI) { return new BlastWaveOffCdTrigger(botAI); }
|
||||
static Trigger* blast_wave_off_cd_and_medium_aoe(PlayerbotAI* botAI) { return new BlastWaveOffCdTriggerAndMediumAoeTrigger(botAI); }
|
||||
static Trigger* no_firestarter_strategy(PlayerbotAI* botAI) { return new NoFirestarterStrategyTrigger(botAI); }
|
||||
static Trigger* enemy_is_close_and_no_firestarter_strategy(PlayerbotAI* botAI) { return new EnemyIsCloseAndNoFirestarterStrategyTrigger(botAI); }
|
||||
static Trigger* enemy_too_close_for_spell_and_no_firestarter_strategy(PlayerbotAI* botAI) { return new EnemyTooCloseForSpellAndNoFirestarterStrategyTrigger(botAI); }
|
||||
};
|
||||
|
||||
class MageAiObjectContextInternal : public NamedObjectContext<Action>
|
||||
@@ -170,6 +193,7 @@ public:
|
||||
creators["arcane intellect on party"] = &MageAiObjectContextInternal::arcane_intellect_on_party;
|
||||
creators["conjure water"] = &MageAiObjectContextInternal::conjure_water;
|
||||
creators["conjure food"] = &MageAiObjectContextInternal::conjure_food;
|
||||
creators["conjure mana gem"] = &MageAiObjectContextInternal::conjure_mana_gem;
|
||||
creators["molten armor"] = &MageAiObjectContextInternal::molten_armor;
|
||||
creators["mage armor"] = &MageAiObjectContextInternal::mage_armor;
|
||||
creators["ice armor"] = &MageAiObjectContextInternal::ice_armor;
|
||||
@@ -207,6 +231,14 @@ public:
|
||||
creators["mirror image"] = &MageAiObjectContextInternal::mirror_image;
|
||||
creators["focus magic on party"] = &MageAiObjectContextInternal::focus_magic_on_party;
|
||||
creators["blink back"] = &MageAiObjectContextInternal::blink_back;
|
||||
creators["use mana sapphire"] = &MageAiObjectContextInternal::use_mana_sapphire;
|
||||
creators["use mana emerald"] = &MageAiObjectContextInternal::use_mana_emerald;
|
||||
creators["use mana ruby"] = &MageAiObjectContextInternal::use_mana_ruby;
|
||||
creators["use mana citrine"] = &MageAiObjectContextInternal::use_mana_citrine;
|
||||
creators["use mana jade"] = &MageAiObjectContextInternal::use_mana_jade;
|
||||
creators["use mana agate"] = &MageAiObjectContextInternal::use_mana_agate;
|
||||
creators["cancel channel"] = &MageAiObjectContextInternal::cancel_channel;
|
||||
creators["mana shield"] = &MageAiObjectContextInternal::mana_shield;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -228,6 +260,7 @@ private:
|
||||
static Action* arcane_intellect_on_party(PlayerbotAI* botAI) { return new CastArcaneIntellectOnPartyAction(botAI); }
|
||||
static Action* conjure_water(PlayerbotAI* botAI) { return new CastConjureWaterAction(botAI); }
|
||||
static Action* conjure_food(PlayerbotAI* botAI) { return new CastConjureFoodAction(botAI); }
|
||||
static Action* conjure_mana_gem(PlayerbotAI* botAI) { return new CastConjureManaGemAction(botAI); }
|
||||
static Action* molten_armor(PlayerbotAI* botAI) { return new CastMoltenArmorAction(botAI); }
|
||||
static Action* mage_armor(PlayerbotAI* botAI) { return new CastMageArmorAction(botAI); }
|
||||
static Action* ice_armor(PlayerbotAI* botAI) { return new CastIceArmorAction(botAI); }
|
||||
@@ -241,10 +274,7 @@ private:
|
||||
static Action* remove_curse(PlayerbotAI* botAI) { return new CastRemoveCurseAction(botAI); }
|
||||
static Action* remove_curse_on_party(PlayerbotAI* botAI) { return new CastRemoveCurseOnPartyAction(botAI); }
|
||||
static Action* remove_lesser_curse(PlayerbotAI* botAI) { return new CastRemoveLesserCurseAction(botAI); }
|
||||
static Action* remove_lesser_curse_on_party(PlayerbotAI* botAI)
|
||||
{
|
||||
return new CastRemoveLesserCurseOnPartyAction(botAI);
|
||||
}
|
||||
static Action* remove_lesser_curse_on_party(PlayerbotAI* botAI) { return new CastRemoveLesserCurseOnPartyAction(botAI); }
|
||||
static Action* icy_veins(PlayerbotAI* botAI) { return new CastIcyVeinsAction(botAI); }
|
||||
static Action* cold_snap(PlayerbotAI* botAI) { return new CastColdSnapAction(botAI); }
|
||||
static Action* ice_barrier(PlayerbotAI* botAI) { return new CastIceBarrierAction(botAI); }
|
||||
@@ -259,13 +289,18 @@ private:
|
||||
static Action* blast_wave(PlayerbotAI* botAI) { return new CastBlastWaveAction(botAI); }
|
||||
static Action* invisibility(PlayerbotAI* botAI) { return new CastInvisibilityAction(botAI); }
|
||||
static Action* evocation(PlayerbotAI* botAI) { return new CastEvocationAction(botAI); }
|
||||
static Action* counterspell_on_enemy_healer(PlayerbotAI* botAI)
|
||||
{
|
||||
return new CastCounterspellOnEnemyHealerAction(botAI);
|
||||
}
|
||||
static Action* counterspell_on_enemy_healer(PlayerbotAI* botAI) { return new CastCounterspellOnEnemyHealerAction(botAI); }
|
||||
static Action* mirror_image(PlayerbotAI* botAI) { return new CastMirrorImageAction(botAI); }
|
||||
static Action* focus_magic_on_party(PlayerbotAI* botAI) { return new CastFocusMagicOnPartyAction(botAI); }
|
||||
static Action* blink_back(PlayerbotAI* botAI) { return new CastBlinkBackAction(botAI); }
|
||||
static Action* use_mana_sapphire(PlayerbotAI* botAI) { return new UseManaSapphireAction(botAI); }
|
||||
static Action* use_mana_emerald(PlayerbotAI* botAI) { return new UseManaEmeraldAction(botAI); }
|
||||
static Action* use_mana_ruby(PlayerbotAI* botAI) { return new UseManaRubyAction(botAI); }
|
||||
static Action* use_mana_citrine(PlayerbotAI* botAI) { return new UseManaCitrineAction(botAI); }
|
||||
static Action* use_mana_jade(PlayerbotAI* botAI) { return new UseManaJadeAction(botAI); }
|
||||
static Action* use_mana_agate(PlayerbotAI* botAI) { return new UseManaAgateAction(botAI); }
|
||||
static Action* cancel_channel(PlayerbotAI* botAI) { return new CancelChannelAction(botAI); }
|
||||
static Action* mana_shield(PlayerbotAI* botAI) { return new CastManaShieldAction(botAI); }
|
||||
};
|
||||
|
||||
SharedNamedObjectContextList<Strategy> MageAiObjectContext::sharedStrategyContexts;
|
||||
@@ -309,4 +344,4 @@ void MageAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextLis
|
||||
void MageAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList<UntypedValue>& valueContexts)
|
||||
{
|
||||
AiObjectContext::BuildSharedValueContexts(valueContexts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,33 @@
|
||||
*/
|
||||
|
||||
#include "MageTriggers.h"
|
||||
|
||||
#include "MageActions.h"
|
||||
#include "Playerbots.h"
|
||||
#include "Player.h"
|
||||
#include "Spell.h"
|
||||
#include "DynamicObject.h"
|
||||
#include "Value.h"
|
||||
#include "SpellAuraEffects.h"
|
||||
#include "ServerFacade.h"
|
||||
|
||||
bool NoManaGemTrigger::IsActive()
|
||||
{
|
||||
static const std::vector<uint32> gemIds = {
|
||||
33312, // Mana Sapphire
|
||||
22044, // Mana Emerald
|
||||
8008, // Mana Ruby
|
||||
8007, // Mana Citrine
|
||||
5513, // Mana Jade
|
||||
5514 // Mana Agate
|
||||
};
|
||||
Player* bot = botAI->GetBot();
|
||||
for (uint32 gemId : gemIds)
|
||||
{
|
||||
if (bot->GetItemCount(gemId, false) > 0) // false = only in bags
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ArcaneIntellectOnPartyTrigger::IsActive()
|
||||
{
|
||||
@@ -25,25 +49,6 @@ bool MageArmorTrigger::IsActive()
|
||||
!botAI->HasAura("molten armor", target) && !botAI->HasAura("mage armor", target);
|
||||
}
|
||||
|
||||
bool FingersOfFrostSingleTrigger::IsActive()
|
||||
{
|
||||
// Fingers of Frost "stack" count is always 1.
|
||||
// The value is instead stored in the charges.
|
||||
Aura* aura = botAI->GetAura("fingers of frost", bot, false, true, -1);
|
||||
return (aura && aura->GetCharges() == 1);
|
||||
}
|
||||
|
||||
bool ArcaneBlastStackTrigger::IsActive()
|
||||
{
|
||||
Aura* aura = botAI->GetAura(getName(), GetTarget(), false, true, 3);
|
||||
if (!aura)
|
||||
return false;
|
||||
if (aura->GetStackAmount() >= 4)
|
||||
return true;
|
||||
bool hasMissileBarrage = botAI->HasAura(44401, bot);
|
||||
return hasMissileBarrage;
|
||||
}
|
||||
|
||||
bool FrostNovaOnTargetTrigger::IsActive()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
@@ -84,3 +89,95 @@ bool NoFocusMagicTrigger::IsActive()
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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))
|
||||
return true;
|
||||
|
||||
// Otherwise, use the default cooldown logic
|
||||
return SpellCooldownTrigger::IsActive();
|
||||
}
|
||||
|
||||
const std::set<uint32> 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());
|
||||
if (!aura)
|
||||
continue;
|
||||
|
||||
DynamicObject* dynObj = aura->GetDynobjOwner();
|
||||
if (!dynObj)
|
||||
continue;
|
||||
|
||||
float dist = bot->GetDistance2d(dynObj->GetPositionX(), dynObj->GetPositionY());
|
||||
if (dist <= radius)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ImprovedScorchTrigger::IsActive()
|
||||
{
|
||||
Unit* target = GetTarget();
|
||||
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
|
||||
12579,
|
||||
// Improved Scorch
|
||||
22959};
|
||||
|
||||
for (uint32 spellId : ImprovedScorchExclusiveDebuffs)
|
||||
{
|
||||
if (target->HasAura(spellId))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use default DebuffTrigger logic for the rest (only trigger if debuff is missing or expiring)
|
||||
return DebuffTrigger::IsActive();
|
||||
}
|
||||
|
||||
const std::set<uint32> BlizzardChannelCheckTrigger::BLIZZARD_SPELL_IDS = {
|
||||
10, // Blizzard Rank 1
|
||||
6141, // Blizzard Rank 2
|
||||
8427, // Blizzard Rank 3
|
||||
10185, // Blizzard Rank 4
|
||||
10186, // Blizzard Rank 5
|
||||
10187, // Blizzard Rank 6
|
||||
27085, // Blizzard Rank 7
|
||||
42938, // Blizzard Rank 8
|
||||
42939 // Blizzard Rank 9
|
||||
};
|
||||
|
||||
bool BlizzardChannelCheckTrigger::IsActive()
|
||||
{
|
||||
Player* bot = botAI->GetBot();
|
||||
|
||||
// Check if the bot is channeling a spell
|
||||
if (Spell* spell = bot->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// Not channeling Blizzard
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9,11 +9,15 @@
|
||||
#include "CureTriggers.h"
|
||||
#include "GenericTriggers.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Trigger.h"
|
||||
#include "Playerbots.h"
|
||||
#include "PlayerbotAI.h"
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
|
||||
class PlayerbotAI;
|
||||
|
||||
DEFLECT_TRIGGER(FireWardTrigger, "fire ward");
|
||||
DEFLECT_TRIGGER(FrostWardTrigger, "frost ward");
|
||||
// Buff and Out of Combat Triggers
|
||||
|
||||
class ArcaneIntellectOnPartyTrigger : public BuffOnPartyTrigger
|
||||
{
|
||||
@@ -37,30 +41,53 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class LivingBombTrigger : public DebuffTrigger
|
||||
class NoFocusMagicTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
LivingBombTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "living bomb", 1, true) {}
|
||||
NoFocusMagicTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no focus magic") {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class FireballTrigger : public DebuffTrigger
|
||||
class IceBarrierTrigger : public BuffTrigger
|
||||
{
|
||||
public:
|
||||
FireballTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "fireball", 1, true) {}
|
||||
IceBarrierTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "ice barrier") {}
|
||||
};
|
||||
|
||||
class PyroblastTrigger : public DebuffTrigger
|
||||
class NoManaGemTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
PyroblastTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "pyroblast", 1, true) {}
|
||||
NoManaGemTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no mana gem") {}
|
||||
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class FireWardTrigger : public DeflectSpellTrigger
|
||||
{
|
||||
public:
|
||||
FireWardTrigger(PlayerbotAI* botAI) : DeflectSpellTrigger(botAI, "fire ward") {}
|
||||
};
|
||||
|
||||
class FrostWardTrigger : public DeflectSpellTrigger
|
||||
{
|
||||
public:
|
||||
FrostWardTrigger(PlayerbotAI* botAI) : DeflectSpellTrigger(botAI, "frost ward") {}
|
||||
};
|
||||
|
||||
// Proc and Boost Triggers
|
||||
|
||||
class HotStreakTrigger : public HasAuraTrigger
|
||||
{
|
||||
public:
|
||||
HotStreakTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "hot streak") {}
|
||||
};
|
||||
|
||||
class FirestarterTrigger : public HasAuraTrigger
|
||||
{
|
||||
public:
|
||||
FirestarterTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "firestarter") {}
|
||||
};
|
||||
|
||||
class MissileBarrageTrigger : public HasAuraTrigger
|
||||
{
|
||||
public:
|
||||
@@ -73,30 +100,19 @@ public:
|
||||
ArcaneBlastTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "arcane blast") {}
|
||||
};
|
||||
|
||||
class FingersOfFrostSingleTrigger : public HasAuraStackTrigger
|
||||
class ArcaneBlastStackTrigger : public HasAuraStackTrigger
|
||||
{
|
||||
public:
|
||||
FingersOfFrostSingleTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "fingers of frost", 1, 1) {}
|
||||
bool IsActive() override;
|
||||
ArcaneBlastStackTrigger(PlayerbotAI* botAI) : HasAuraStackTrigger(botAI, "arcane blast", 4, 1) {}
|
||||
};
|
||||
|
||||
class FingersOfFrostDoubleTrigger : public HasAuraStackTrigger
|
||||
class ArcaneBlast4StacksAndMissileBarrageTrigger : public TwoTriggers
|
||||
{
|
||||
public:
|
||||
FingersOfFrostDoubleTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "fingers of frost", 2, 1) {}
|
||||
// bool IsActive() override;
|
||||
};
|
||||
|
||||
class BrainFreezeTrigger : public HasAuraTrigger
|
||||
{
|
||||
public:
|
||||
BrainFreezeTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "fireball!") {}
|
||||
};
|
||||
|
||||
class CounterspellInterruptSpellTrigger : public InterruptSpellTrigger
|
||||
{
|
||||
public:
|
||||
CounterspellInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "counterspell") {}
|
||||
ArcaneBlast4StacksAndMissileBarrageTrigger(PlayerbotAI* ai)
|
||||
: TwoTriggers(ai, "arcane blast stack", "missile barrage")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CombustionTrigger : public BoostTrigger
|
||||
@@ -105,23 +121,50 @@ public:
|
||||
CombustionTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "combustion") {}
|
||||
};
|
||||
|
||||
class IcyVeinsCooldownTrigger : public SpellCooldownTrigger
|
||||
{
|
||||
public:
|
||||
IcyVeinsCooldownTrigger(PlayerbotAI* botAI) : SpellCooldownTrigger(botAI, "icy veins") {}
|
||||
};
|
||||
|
||||
class DeepFreezeCooldownTrigger : public SpellCooldownTrigger
|
||||
{
|
||||
public:
|
||||
DeepFreezeCooldownTrigger(PlayerbotAI* botAI) : SpellCooldownTrigger(botAI, "deep freeze") {}
|
||||
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class ColdSnapTrigger : public TwoTriggers
|
||||
{
|
||||
public:
|
||||
ColdSnapTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "icy veins on cd", "deep freeze on cd") {}
|
||||
};
|
||||
|
||||
class MirrorImageTrigger : public BoostTrigger
|
||||
{
|
||||
public:
|
||||
MirrorImageTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "mirror image") {}
|
||||
};
|
||||
|
||||
class IcyVeinsTrigger : public BoostTrigger
|
||||
{
|
||||
public:
|
||||
IcyVeinsTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "icy veins") {}
|
||||
};
|
||||
|
||||
class ColdSnapTrigger : public BoostTrigger
|
||||
class ArcanePowerTrigger : public BoostTrigger
|
||||
{
|
||||
public:
|
||||
ColdSnapTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "cold snap") {}
|
||||
ArcanePowerTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "arcane power") {}
|
||||
};
|
||||
class PresenceOfMindTrigger : public BoostTrigger
|
||||
{
|
||||
public:
|
||||
PresenceOfMindTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "presence of mind") {}
|
||||
};
|
||||
|
||||
class IceBarrierTrigger : public BuffTrigger
|
||||
{
|
||||
public:
|
||||
IceBarrierTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "ice barrier") {}
|
||||
};
|
||||
// CC, Interrupt, and Dispel Triggers
|
||||
|
||||
class PolymorphTrigger : public HasCcTargetTrigger
|
||||
{
|
||||
@@ -155,29 +198,63 @@ public:
|
||||
CounterspellEnemyHealerTrigger(PlayerbotAI* botAI) : InterruptEnemyHealerTrigger(botAI, "counterspell") {}
|
||||
};
|
||||
|
||||
class ArcanePowerTrigger : public BuffTrigger
|
||||
class CounterspellInterruptSpellTrigger : public InterruptSpellTrigger
|
||||
{
|
||||
public:
|
||||
ArcanePowerTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "arcane power") {}
|
||||
CounterspellInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "counterspell") {}
|
||||
};
|
||||
|
||||
class PresenceOfMindTrigger : public BuffTrigger
|
||||
// Damage and Debuff Triggers
|
||||
|
||||
class LivingBombTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
PresenceOfMindTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "presence of mind") {}
|
||||
LivingBombTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "living bomb", 1, true) {}
|
||||
bool IsActive() override { return BuffTrigger::IsActive(); }
|
||||
};
|
||||
|
||||
class ArcaneBlastStackTrigger : public HasAuraStackTrigger
|
||||
class LivingBombOnAttackersTrigger : public DebuffOnAttackerTrigger
|
||||
{
|
||||
public:
|
||||
ArcaneBlastStackTrigger(PlayerbotAI* botAI) : HasAuraStackTrigger(botAI, "arcane blast", 3, 1) {}
|
||||
LivingBombOnAttackersTrigger(PlayerbotAI* ai) : DebuffOnAttackerTrigger(ai, "living bomb", true) {}
|
||||
bool IsActive() override { return BuffTrigger::IsActive(); }
|
||||
};
|
||||
|
||||
class FireballTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
FireballTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "fireball", 1, true) {}
|
||||
};
|
||||
|
||||
class ImprovedScorchTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
ImprovedScorchTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "improved scorch", 1, true, 0.5f) {}
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class MirrorImageTrigger : public BoostTrigger
|
||||
class PyroblastTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
MirrorImageTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "mirror image") {}
|
||||
PyroblastTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "pyroblast", 1, true) {}
|
||||
};
|
||||
|
||||
class FrostfireBoltTrigger : public DebuffTrigger
|
||||
{
|
||||
public:
|
||||
FrostfireBoltTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frostfire bolt", 1, true) {}
|
||||
};
|
||||
|
||||
class FingersOfFrostTrigger : public HasAuraTrigger
|
||||
{
|
||||
public:
|
||||
FingersOfFrostTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "fingers of frost") {}
|
||||
};
|
||||
|
||||
class BrainFreezeTrigger : public HasAuraTrigger
|
||||
{
|
||||
public:
|
||||
BrainFreezeTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "fireball!") {}
|
||||
};
|
||||
|
||||
class FrostNovaOnTargetTrigger : public DebuffTrigger
|
||||
@@ -194,17 +271,74 @@ public:
|
||||
bool IsActive() override;
|
||||
};
|
||||
|
||||
class NoFocusMagicTrigger : public Trigger
|
||||
class FlamestrikeNearbyTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NoFocusMagicTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no focus magic") {}
|
||||
FlamestrikeNearbyTrigger(PlayerbotAI* botAI, float radius = 30.0f)
|
||||
: Trigger(botAI, "flamestrike nearby"), radius(radius)
|
||||
{
|
||||
}
|
||||
bool IsActive() override;
|
||||
|
||||
protected:
|
||||
float radius;
|
||||
static const std::set<uint32> FLAMESTRIKE_SPELL_IDS;
|
||||
};
|
||||
|
||||
class FrostfireBoltTrigger : public DebuffTrigger
|
||||
class FlamestrikeBlizzardTrigger : public TwoTriggers
|
||||
{
|
||||
public:
|
||||
FrostfireBoltTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frostfire bolt", 1, true) {}
|
||||
FlamestrikeBlizzardTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "flamestrike nearby", "medium aoe") {}
|
||||
};
|
||||
|
||||
class BlizzardChannelCheckTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
BlizzardChannelCheckTrigger(PlayerbotAI* botAI, uint32 minEnemies = 2)
|
||||
: Trigger(botAI, "blizzard channel check"), minEnemies(minEnemies) {}
|
||||
|
||||
bool IsActive() override;
|
||||
|
||||
protected:
|
||||
uint32 minEnemies;
|
||||
static const std::set<uint32> BLIZZARD_SPELL_IDS;
|
||||
};
|
||||
|
||||
class BlastWaveOffCdTrigger : public SpellNoCooldownTrigger
|
||||
{
|
||||
public:
|
||||
BlastWaveOffCdTrigger(PlayerbotAI* botAI) : SpellNoCooldownTrigger(botAI, "blast wave") {}
|
||||
};
|
||||
|
||||
class BlastWaveOffCdTriggerAndMediumAoeTrigger : public TwoTriggers
|
||||
{
|
||||
public:
|
||||
BlastWaveOffCdTriggerAndMediumAoeTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "blast wave off cd", "medium aoe") {}
|
||||
};
|
||||
|
||||
class NoFirestarterStrategyTrigger : public Trigger
|
||||
{
|
||||
public:
|
||||
NoFirestarterStrategyTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no firestarter strategy") {}
|
||||
|
||||
bool IsActive() override
|
||||
{
|
||||
return !botAI->HasStrategy("firestarter", BOT_STATE_COMBAT);
|
||||
}
|
||||
};
|
||||
|
||||
class EnemyIsCloseAndNoFirestarterStrategyTrigger : public TwoTriggers
|
||||
{
|
||||
public:
|
||||
EnemyIsCloseAndNoFirestarterStrategyTrigger(PlayerbotAI* botAI)
|
||||
: TwoTriggers(botAI, "enemy is close", "no firestarter strategy") {}
|
||||
};
|
||||
|
||||
class EnemyTooCloseForSpellAndNoFirestarterStrategyTrigger : public TwoTriggers
|
||||
{
|
||||
public:
|
||||
EnemyTooCloseForSpellAndNoFirestarterStrategyTrigger(PlayerbotAI* botAI)
|
||||
: TwoTriggers(botAI, "enemy too close for spell", "no firestarter strategy") {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user