mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
Mage Overhaul
Hello everyone, Back again with another class overhaul. Here is a list of what changes have been made: 1. Consolidated the AoE strategies into "aoe". For light aoe (2+ enemies) the mage will use Cone of Cold (frost)/Arcane Explosion (Arcane)/Multi-Dot with Living Bomb (Fire/Frostfire). For medium aoe (3+ enemies) they will use Flamestrike -> Blizzard. Also, the mage will automatically cancel channeling their blizzard if there is less than 2 enemies around. This is huge, since the mage would often stand there and finish their entire channel during a boss fight after the adds died. 2. Organized actions, triggers, and the aiobjectcontext 3. Enabled Deep Freeze to be casted on bosses regardless of their immune status. Big benefit for frost dps on boss fights. 4. Slight tweaks in the conf so Arcane gets Arcane Barrage and Frostfire gets 2/2 Firestarter 5. Streamlined Arcane DPS to use Missile Barrage proc when at 4 stacks of Arcane Blast 5. Streamlined Fire/Frostfire DPS to keep Improved Scorch active (5% spell crit) unless there is a debuff of equal type 6. Added "firestarter" strategy, that utilizes the Fire talent Firestarter better. The mage will multi-dot Living Bomb while running towards melee, and cast Dragon's Breath -> instant cast Flamestrike -> Blast Wave -> instant cast Flamestrike -> Blizzard for bonkers damage. Disabled by default - not everyone wants their mages running into melee. Enable by typing "co +firestarter" on fire and frostfire mages. 7. Streamlined Frost DPS by finally adding support for Cold Snap for mages. It will proc when both Icy Veins and Deep Freeze are on cooldown. There is an exception to this - if the mage is level 30-59, it will not check for Deep Freeze - only Icy Veins. 8. Added Conjure Mana Gem support in the generic non-combat strategy and Use Mana Gem support in the generic combat strategy. This might be the biggest benefit of the overhaul - the gem has a 90 second cooldown, not shared with mana potions. It really prevents the mage from gassing out in longer fights. And the mana gem has 3 charges! 9. Added Mana Shield ability, which triggers on low health. 10. Changed Mirror Image from a boost ability to an anti-threat tool. Not many people know this, but it's best use in PvE is it's anti-threat modifier: "Mod Total Threat - Temporary Value: -90000000". It also doesn't do good damage, and is essentially used best as a pre-pull spell. But until the mages know how to react to a pull-timer, it's going to be used to reduce threat. Let me know what y'all think!
This commit is contained in:
@@ -1427,8 +1427,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
|
||||
@@ -1440,7 +1440,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
|
||||
|
||||
@@ -302,22 +302,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,48 @@ 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)));
|
||||
// Cooldown Triggers
|
||||
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)));
|
||||
|
||||
// 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,74 @@
|
||||
*/
|
||||
|
||||
#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)));
|
||||
// Cooldown Trigger
|
||||
triggers.push_back(new TriggerNode("combustion", NextAction::array(0, new NextAction("combustion", 18.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,60 @@
|
||||
*/
|
||||
|
||||
#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)));
|
||||
}
|
||||
// Cooldown Triggers
|
||||
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)));
|
||||
|
||||
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)));
|
||||
// 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)));
|
||||
}
|
||||
|
||||
@@ -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,70 @@ 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)));
|
||||
// Cooldown triggers
|
||||
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)));
|
||||
|
||||
// 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)));
|
||||
// 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)));
|
||||
|
||||
// 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,90 @@ 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)));
|
||||
}
|
||||
|
||||
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,55 +100,71 @@ 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) {}
|
||||
ArcaneBlastStackTrigger(PlayerbotAI* botAI) : HasAuraStackTrigger(botAI, "arcane blast", 4, 1) {}
|
||||
};
|
||||
|
||||
class ArcaneBlast4StacksAndMissileBarrageTrigger : public TwoTriggers
|
||||
{
|
||||
public:
|
||||
ArcaneBlast4StacksAndMissileBarrageTrigger(PlayerbotAI* ai)
|
||||
: TwoTriggers(ai, "arcane blast stack", "missile barrage")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CombustionTrigger : public BuffTrigger
|
||||
{
|
||||
public:
|
||||
CombustionTrigger(PlayerbotAI* botAI) : BuffTrigger(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 FingersOfFrostDoubleTrigger : public HasAuraStackTrigger
|
||||
class ColdSnapTrigger : public TwoTriggers
|
||||
{
|
||||
public:
|
||||
FingersOfFrostDoubleTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "fingers of frost", 2, 1) {}
|
||||
// bool IsActive() override;
|
||||
ColdSnapTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "icy veins on cd", "deep freeze on cd") {}
|
||||
};
|
||||
|
||||
class BrainFreezeTrigger : public HasAuraTrigger
|
||||
class MirrorImageTrigger : public BuffTrigger
|
||||
{
|
||||
public:
|
||||
BrainFreezeTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "fireball!") {}
|
||||
MirrorImageTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "mirror image") {}
|
||||
};
|
||||
|
||||
class CounterspellInterruptSpellTrigger : public InterruptSpellTrigger
|
||||
class IcyVeinsTrigger : public BuffTrigger
|
||||
{
|
||||
public:
|
||||
CounterspellInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "counterspell") {}
|
||||
IcyVeinsTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "icy veins") {}
|
||||
};
|
||||
|
||||
class CombustionTrigger : public BoostTrigger
|
||||
class ArcanePowerTrigger : public BuffTrigger
|
||||
{
|
||||
public:
|
||||
CombustionTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "combustion") {}
|
||||
ArcanePowerTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "arcane power") {}
|
||||
};
|
||||
class PresenceOfMindTrigger : public BuffTrigger
|
||||
{
|
||||
public:
|
||||
PresenceOfMindTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "presence of mind") {}
|
||||
};
|
||||
|
||||
class IcyVeinsTrigger : public BoostTrigger
|
||||
{
|
||||
public:
|
||||
IcyVeinsTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "icy veins") {}
|
||||
};
|
||||
|
||||
class ColdSnapTrigger : public BoostTrigger
|
||||
{
|
||||
public:
|
||||
ColdSnapTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "cold snap") {}
|
||||
};
|
||||
|
||||
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