diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index fdc2e1c6..8f5fd926 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1429,11 +1429,11 @@ AiPlayerbot.PremadeSpecGlyph.7.0 = 41536,43385,41532,43386,44923,45776 AiPlayerbot.PremadeSpecLink.7.0.60 = 4530001520213351102301351 AiPlayerbot.PremadeSpecLink.7.0.80 = 3530001523213351322301351-005050031 AiPlayerbot.PremadeSpecName.7.1 = enh pve -AiPlayerbot.PremadeSpecGlyph.7.1 = 41542,43385,41539,43386,44923,45771 -AiPlayerbot.PremadeSpecLink.7.1.60 = -30205033005001333031131131051 -AiPlayerbot.PremadeSpecLink.7.1.80 = 053030052-30205033005021333031131131051 +AiPlayerbot.PremadeSpecGlyph.7.1 = 41530,43385,41539,43386,44923,45771 +AiPlayerbot.PremadeSpecLink.7.1.60 = -30305003105021333031121131051 +AiPlayerbot.PremadeSpecLink.7.1.80 = 053030152-30305003105021333031131131051 AiPlayerbot.PremadeSpecName.7.2 = resto pve -AiPlayerbot.PremadeSpecGlyph.7.2 = 41517,43385,41527,43386,44923,45775 +AiPlayerbot.PremadeSpecGlyph.7.2 = 41527,43385,41517,43386,44923,45775 AiPlayerbot.PremadeSpecLink.7.2.60 = --50005301235310501102321251 AiPlayerbot.PremadeSpecLink.7.2.80 = -00502033-50005331335310501122331251 AiPlayerbot.PremadeSpecName.7.3 = ele pvp diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index c9202a71..63d380e6 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -91,6 +91,9 @@ uint8 AiFactory::GetPlayerSpecTab(Player* bot) case CLASS_WARLOCK: tab = WARLOCK_TAB_DEMONOLOGY; break; + case CLASS_SHAMAN: + tab = SHAMAN_TAB_ELEMENTAL; + break; } return tab; @@ -304,9 +307,9 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa engine->addStrategiesNoInit("dps assist", "cure", nullptr); break; case CLASS_MAGE: - if (tab == 0) + if (tab == 0) // Arcane engine->addStrategiesNoInit("arcane", nullptr); - else if (tab == 1) + else if (tab == 1) // Fire { if (player->HasSpell(44614) /*Frostfire Bolt*/ && player->HasAura(15047) /*Ice Shards*/) { @@ -317,7 +320,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa engine->addStrategiesNoInit("fire", nullptr); } } - else + else // Frost engine->addStrategiesNoInit("frost", nullptr); engine->addStrategiesNoInit("dps", "dps assist", "cure", "aoe", nullptr); @@ -331,14 +334,14 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa engine->addStrategiesNoInit("fury", "aoe", "dps assist", /*"behind",*/ nullptr); break; case CLASS_SHAMAN: - if (tab == 0) - engine->addStrategiesNoInit("caster", "caster aoe", "bmana", nullptr); - else if (tab == 2) - engine->addStrategiesNoInit("heal", "bmana", nullptr); - else - engine->addStrategiesNoInit("melee", "melee aoe", "bdps", nullptr); + if (tab == 0) // Elemental + engine->addStrategiesNoInit("ele", "stoneskin", "wrath", "mana spring", "wrath of air", nullptr); + else if (tab == 2) // Restoration + engine->addStrategiesNoInit("resto", "stoneskin", "flametongue", "mana spring", "wrath of air", nullptr); + else // Enhancement + engine->addStrategiesNoInit("enh", "strength of earth", "magma", "healing stream", "windfury", nullptr); - engine->addStrategiesNoInit("dps assist", "cure", "totems", nullptr); + engine->addStrategiesNoInit("dps assist", "cure", "aoe", nullptr); break; case CLASS_PALADIN: if (tab == 1) diff --git a/src/strategy/shaman/CasterShamanStrategy.cpp b/src/strategy/shaman/CasterShamanStrategy.cpp deleted file mode 100644 index 903b873f..00000000 --- a/src/strategy/shaman/CasterShamanStrategy.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it - * and/or modify it under version 2 of the License, or (at your option), any later version. - */ - -#include "CasterShamanStrategy.h" - -#include "Playerbots.h" - -class CasterShamanStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - CasterShamanStrategyActionNodeFactory() - { - creators["magma totem"] = &magma_totem; - creators["totem of wrath"] = &totem_of_wrath; - } - -private: - static ActionNode* magma_totem([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("magma totem", - /*P*/ nullptr, - /*A*/ nullptr, - /*C*/ NextAction::array(0, new NextAction("fire nova"), nullptr)); - } - static ActionNode* totem_of_wrath([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("totem of wrath", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("flametongue totem"), nullptr), - /*C*/ nullptr); - } -}; - -CasterShamanStrategy::CasterShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) -{ - actionNodeFactories.Add(new CasterShamanStrategyActionNodeFactory()); -} - -NextAction** CasterShamanStrategy::getDefaultActions() -{ - return NextAction::array(0, new NextAction("lava burst", ACTION_DEFAULT + 0.2f), - new NextAction("lightning bolt", ACTION_DEFAULT + 0.1f), - // new NextAction("earth shock", ACTION_DEFAULT), // cast during movement - nullptr); -} - -void CasterShamanStrategy::InitTriggers(std::vector& triggers) -{ - GenericShamanStrategy::InitTriggers(triggers); - - // triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", - // ACTION_NORMAL + 9), nullptr))); triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new - // NextAction("flametongue weapon", 23.0f), nullptr))); - triggers.push_back(new TriggerNode( - "enough mana", NextAction::array(0, new NextAction("chain lightning", ACTION_DEFAULT + 0.1f), nullptr))); - - triggers.push_back(new TriggerNode("main hand weapon no imbue", - NextAction::array(0, new NextAction("flametongue weapon", 22.0f), nullptr))); - // triggers.push_back(new TriggerNode("searing totem", NextAction::array(0, new NextAction("searing totem", 19.0f), - // nullptr))); - triggers.push_back( - new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 20.0f), nullptr))); - triggers.push_back(new TriggerNode("elemental mastery", - NextAction::array(0, new NextAction("elemental mastery", 27.0f), nullptr))); - // triggers.push_back(new TriggerNode("frost shock snare", NextAction::array(0, new NextAction("frost - // shock", 21.0f), nullptr))); - triggers.push_back( - new TriggerNode("no fire totem", NextAction::array(0, - new NextAction("totem of wrath", 15.0f), - new NextAction("searing totem", 6.0f), - nullptr))); - - triggers.push_back(new TriggerNode("fire elemental totem", - NextAction::array(0, new NextAction("fire elemental totem", 32.0f), nullptr))); - - triggers.push_back( - new TriggerNode("medium mana", NextAction::array(0, new NextAction("thunderstorm", ACTION_HIGH + 1), nullptr))); - - - triggers.push_back(new TriggerNode("enemy is close", - NextAction::array(0, new NextAction("thunderstorm", ACTION_HIGH + 1), nullptr))); - - triggers.push_back(new TriggerNode("enemy too close for spell", - NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr))); -} - -void CasterAoeShamanStrategy::InitTriggers(std::vector& triggers) -{ - triggers.push_back( - new TriggerNode("light aoe", NextAction::array(0, new NextAction("chain lightning", 25.0f), nullptr))); - - triggers.push_back( - new TriggerNode("medium aoe", NextAction::array(0, new NextAction("fire nova", 24.0f), nullptr))); -} diff --git a/src/strategy/shaman/CasterShamanStrategy.h b/src/strategy/shaman/CasterShamanStrategy.h deleted file mode 100644 index dd568290..00000000 --- a/src/strategy/shaman/CasterShamanStrategy.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it - * and/or modify it under version 2 of the License, or (at your option), any later version. - */ - -#ifndef _PLAYERBOT_CASTSHAMANSTRATEGY_H -#define _PLAYERBOT_CASTSHAMANSTRATEGY_H - -#include "GenericShamanStrategy.h" - -class PlayerbotAI; - -class CasterShamanStrategy : public GenericShamanStrategy -{ -public: - CasterShamanStrategy(PlayerbotAI* botAI); - - void InitTriggers(std::vector& triggers) override; - NextAction** getDefaultActions() override; - std::string const getName() override { return "caster"; } - uint32 GetType() const override { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_RANGED; } -}; - -class CasterAoeShamanStrategy : public CombatStrategy -{ -public: - CasterAoeShamanStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {} - - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "caster aoe"; } -}; - -#endif diff --git a/src/strategy/shaman/ElementalShamanStrategy.cpp b/src/strategy/shaman/ElementalShamanStrategy.cpp new file mode 100644 index 00000000..055c3e6d --- /dev/null +++ b/src/strategy/shaman/ElementalShamanStrategy.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it + * and/or modify it under version 2 of the License, or (at your option), any later version. + */ + +#include "ElementalShamanStrategy.h" + +#include "Playerbots.h" + +// ===== Action Node Factory ===== +class ElementalShamanStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + ElementalShamanStrategyActionNodeFactory() + { + creators["flame shock"] = &flame_shock; + creators["earth shock"] = &earth_shock; + creators["lava burst"] = &lava_burst; + creators["lightning bolt"] = &lightning_bolt; + creators["call of the elements"] = &call_of_the_elements; + creators["elemental mastery"] = &elemental_mastery; + creators["stoneclaw totem"] = &stoneclaw_totem; + creators["water shield"] = &water_shield; + creators["thunderstorm"] = &thunderstorm; + } + +private: + static ActionNode* flame_shock(PlayerbotAI*) { return new ActionNode("flame shock", nullptr, nullptr, nullptr); } + static ActionNode* earth_shock(PlayerbotAI*) { return new ActionNode("earth shock", nullptr, nullptr, nullptr); } + static ActionNode* lava_burst(PlayerbotAI*) { return new ActionNode("lava burst", nullptr, nullptr, nullptr); } + static ActionNode* lightning_bolt(PlayerbotAI*) { return new ActionNode("lightning bolt", nullptr, nullptr, nullptr); } + static ActionNode* call_of_the_elements(PlayerbotAI*) { return new ActionNode("call of the elements", nullptr, nullptr, nullptr); } + static ActionNode* elemental_mastery(PlayerbotAI*) { return new ActionNode("elemental mastery", nullptr, nullptr, nullptr); } + static ActionNode* stoneclaw_totem(PlayerbotAI*) { return new ActionNode("stoneclaw totem", nullptr, nullptr, nullptr); } + static ActionNode* water_shield(PlayerbotAI*) { return new ActionNode("water shield", nullptr, nullptr, nullptr); } + static ActionNode* thunderstorm(PlayerbotAI*) { return new ActionNode("thunderstorm", nullptr, nullptr, nullptr); } +}; + +// ===== Single Target Strategy ===== +ElementalShamanStrategy::ElementalShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) +{ + actionNodeFactories.Add(new ElementalShamanStrategyActionNodeFactory()); +} + +// ===== Default Actions ===== +NextAction** ElementalShamanStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("lava burst", 5.2f), + new NextAction("lightning bolt", 5.0f), + nullptr); +} + +// ===== Trigger Initialization === +void ElementalShamanStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + + // Totem Triggers + triggers.push_back(new TriggerNode("call of the elements", NextAction::array(0, new NextAction("call of the elements", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("stoneclaw totem", 40.0f), nullptr))); + + // Cooldown Trigger + triggers.push_back(new TriggerNode("elemental mastery", NextAction::array(0, new NextAction("elemental mastery", 29.0f), nullptr))); + + // Damage Triggers + triggers.push_back(new TriggerNode("earth shock execute", NextAction::array(0, new NextAction("earth shock", 5.5f), nullptr))); + triggers.push_back(new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 5.3f), nullptr))); + + // Mana Triggers + triggers.push_back(new TriggerNode("water shield", NextAction::array(0, new NextAction("water shield", 19.5f), nullptr))); + triggers.push_back(new TriggerNode("high mana", NextAction::array(0, new NextAction("thunderstorm", 19.0f), nullptr))); + + // Range Triggers + triggers.push_back(new TriggerNode("enemy is close", NextAction::array(0, new NextAction("thunderstorm", 19.0f), nullptr))); +} + diff --git a/src/strategy/shaman/ElementalShamanStrategy.h b/src/strategy/shaman/ElementalShamanStrategy.h new file mode 100644 index 00000000..2aba120a --- /dev/null +++ b/src/strategy/shaman/ElementalShamanStrategy.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it + * and/or modify it under version 2 of the License, or (at your option), any later version. + */ + +#ifndef _PLAYERBOT_ELEMENTALSHAMANSTRATEGY_H +#define _PLAYERBOT_ELEMENTALSHAMANSTRATEGY_H + +#include "GenericShamanStrategy.h" + +class PlayerbotAI; + +class ElementalShamanStrategy : public GenericShamanStrategy +{ +public: + ElementalShamanStrategy(PlayerbotAI* botAI); + + void InitTriggers(std::vector& triggers) override; + NextAction** getDefaultActions() override; + std::string const getName() override { return "ele"; } + uint32 GetType() const override { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_RANGED; } +}; + +#endif diff --git a/src/strategy/shaman/EnhancementShamanStrategy.cpp b/src/strategy/shaman/EnhancementShamanStrategy.cpp new file mode 100644 index 00000000..224b01a4 --- /dev/null +++ b/src/strategy/shaman/EnhancementShamanStrategy.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it + * and/or modify it under version 2 of the License, or (at your option), any later version. + */ + +#include "EnhancementShamanStrategy.h" + +#include "Playerbots.h" + +// ===== Action Node Factory ===== +class EnhancementShamanStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + EnhancementShamanStrategyActionNodeFactory() + { + creators["stormstrike"] = &stormstrike; + creators["lava lash"] = &lava_lash; + creators["feral spirit"] = &feral_spirit; + creators["lightning bolt"] = &lightning_bolt; + creators["earth shock"] = &earth_shock; + creators["flame shock"] = &flame_shock; + creators["shamanistic rage"] = &shamanistic_rage; + creators["call of the elements"] = &call_of_the_elements; + creators["lightning shield"] = &lightning_shield; + } + +private: + static ActionNode* stormstrike(PlayerbotAI*) { return new ActionNode("stormstrike", nullptr, nullptr, nullptr); } + static ActionNode* lava_lash([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("lava lash", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("melee"), nullptr), + /*C*/ nullptr); + } + static ActionNode* feral_spirit(PlayerbotAI*) { return new ActionNode("feral spirit", nullptr, nullptr, nullptr); } + static ActionNode* lightning_bolt(PlayerbotAI*) { return new ActionNode("lightning bolt", nullptr, nullptr, nullptr); } + static ActionNode* earth_shock(PlayerbotAI*) { return new ActionNode("earth shock", nullptr, nullptr, nullptr); } + static ActionNode* flame_shock(PlayerbotAI*) { return new ActionNode("flame shock", nullptr, nullptr, nullptr); } + static ActionNode* shamanistic_rage(PlayerbotAI*) { return new ActionNode("shamanistic rage", nullptr, nullptr, nullptr); } + static ActionNode* call_of_the_elements(PlayerbotAI*) { return new ActionNode("call of the elements", nullptr, nullptr, nullptr); } + static ActionNode* lightning_shield(PlayerbotAI*) { return new ActionNode("lightning shield", nullptr, nullptr, nullptr); } +}; + +// ===== Single Target Strategy ===== +EnhancementShamanStrategy::EnhancementShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) +{ + actionNodeFactories.Add(new EnhancementShamanStrategyActionNodeFactory()); +} + +// ===== Default Actions ===== +NextAction** EnhancementShamanStrategy::getDefaultActions() +{ + return NextAction::array(0, + new NextAction("stormstrike", 5.5f), + new NextAction("feral spirit", 5.4f), + new NextAction("earth shock", 5.3f), + new NextAction("lava lash", 5.2f), + new NextAction("melee", 5.0f), NULL); +} + +// ===== Trigger Initialization === +void EnhancementShamanStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + + // Totem Trigger + triggers.push_back(new TriggerNode("call of the elements and enemy within melee", NextAction::array(0, new NextAction("call of the elements", 60.0f), nullptr))); + + // Spirit Walk Trigger + triggers.push_back(new TriggerNode("spirit walk ready", NextAction::array(0, new NextAction("spirit walk", 50.0f), nullptr))); + + // Damage Triggers + triggers.push_back(new TriggerNode("enemy out of melee", NextAction::array(0, new NextAction("reach melee", 40.0f), nullptr))); + triggers.push_back(new TriggerNode("maelstrom weapon 5", NextAction::array(0, new NextAction("lightning bolt", 20.0f), nullptr))); + triggers.push_back(new TriggerNode("maelstrom weapon 4", NextAction::array(0, new NextAction("lightning bolt", 19.5f), nullptr))); + triggers.push_back(new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 19.0f), nullptr))); + triggers.push_back(new TriggerNode("lightning shield", NextAction::array(0, new NextAction("lightning shield", 18.5f), nullptr))); + + // Health/Mana Triggers + triggers.push_back(new TriggerNode("medium mana", NextAction::array(0, new NextAction("shamanistic rage", 23.0f), nullptr))); + triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("shamanistic rage", 23.0f), nullptr))); +} diff --git a/src/strategy/shaman/MeleeShamanStrategy.h b/src/strategy/shaman/EnhancementShamanStrategy.h similarity index 50% rename from src/strategy/shaman/MeleeShamanStrategy.h rename to src/strategy/shaman/EnhancementShamanStrategy.h index dd324f85..c683407f 100644 --- a/src/strategy/shaman/MeleeShamanStrategy.h +++ b/src/strategy/shaman/EnhancementShamanStrategy.h @@ -3,31 +3,22 @@ * and/or modify it under version 2 of the License, or (at your option), any later version. */ -#ifndef _PLAYERBOT_MELEESHAMANSTRATEGY_H -#define _PLAYERBOT_MELEESHAMANSTRATEGY_H +#ifndef _PLAYERBOT_ENHANCEMENTSHAMANSTRATEGY_H +#define _PLAYERBOT_ENHANCEMENTSHAMANSTRATEGY_H #include "GenericShamanStrategy.h" class PlayerbotAI; -class MeleeShamanStrategy : public GenericShamanStrategy +class EnhancementShamanStrategy : public GenericShamanStrategy { public: - MeleeShamanStrategy(PlayerbotAI* botAI); + EnhancementShamanStrategy(PlayerbotAI* botAI); void InitTriggers(std::vector& triggers) override; NextAction** getDefaultActions() override; - std::string const getName() override { return "melee"; } + std::string const getName() override { return "enh"; } uint32 GetType() const override { return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_MELEE; } }; -class MeleeAoeShamanStrategy : public CombatStrategy -{ -public: - MeleeAoeShamanStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {} - - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "melee aoe"; } -}; - #endif diff --git a/src/strategy/shaman/GenericShamanStrategy.cpp b/src/strategy/shaman/GenericShamanStrategy.cpp index 8f8aabe7..b130587f 100644 --- a/src/strategy/shaman/GenericShamanStrategy.cpp +++ b/src/strategy/shaman/GenericShamanStrategy.cpp @@ -4,109 +4,95 @@ */ #include "GenericShamanStrategy.h" -#include "HealShamanStrategy.h" #include "Playerbots.h" #include "Strategy.h" +#include "AiFactory.h" class GenericShamanStrategyActionNodeFactory : public NamedObjectFactory { public: GenericShamanStrategyActionNodeFactory() { - creators["flametongue weapon"] = &flametongue_weapon; - creators["frostbrand weapon"] = &frostbrand_weapon; - creators["windfury weapon"] = &windfury_weapon; - creators["lesser healing wave"] = &lesser_healing_wave; - creators["lesser healing wave on party"] = &lesser_healing_wave_on_party; - creators["chain heal on party"] = &chain_heal; - creators["riptide"] = &riptide; - creators["riptide on party"] = &riptide_on_party; - creators["earth shock"] = &earth_shock; - creators["water shield"] = &water_shield; + creators["totem of wrath"] = &totem_of_wrath; + creators["flametongue totem"] = &flametongue_totem; + creators["magma totem"] = &magma_totem; + creators["searing totem"] = &searing_totem; + creators["strength of earth totem"] = &strength_of_earth_totem; + creators["stoneskin totem"] = &stoneskin_totem; + creators["cleansing totem"] = &cleansing_totem; + creators["mana spring totem"] = &mana_spring_totem; + creators["healing stream totem"] = &healing_stream_totem; + creators["wrath of air totem"] = &wrath_of_air_totem; + creators["windfury totem"] = &windfury_totem; + creators["grounding totem"] = &grounding_totem; + creators["wind shear"] = &wind_shear; + creators["purge"] = &purge; } private: - static ActionNode* earth_shock([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("earth shock", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("flame shock"), nullptr), - /*C*/ nullptr); - } - - static ActionNode* flametongue_weapon([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("flametongue weapon", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("rockbiter weapon"), nullptr), - /*C*/ nullptr); - } - - static ActionNode* frostbrand_weapon([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("frostbrand weapon", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("flametongue weapon"), nullptr), - /*C*/ nullptr); - } - - static ActionNode* windfury_weapon([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("windfury weapon", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("flametongue weapon"), nullptr), - /*C*/ nullptr); - } - - static ActionNode* lesser_healing_wave([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("lesser healing wave", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("healing wave"), nullptr), - /*C*/ nullptr); - } - - static ActionNode* lesser_healing_wave_on_party([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("lesser healing wave on party", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("healing wave on party"), nullptr), - /*C*/ nullptr); - } - - static ActionNode* chain_heal([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("chain heal on party", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("lesser healing wave on party"), nullptr), - /*C*/ nullptr); - } - - static ActionNode* riptide([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("riptide", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("healing wave"), nullptr), - /*C*/ nullptr); - } - - static ActionNode* riptide_on_party([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("riptide on party", - /*P*/ nullptr, - // /*A*/ NextAction::array(0, new NextAction("healing wave on party"), nullptr), - /*A*/ nullptr, - /*C*/ nullptr); - } - - static ActionNode* water_shield([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("water shield", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("lightning shield"), nullptr), - /*C*/ nullptr); - } + // Passthrough totems are set up so lower level shamans will still cast totems. + // Totem of Wrath -> Flametongue Totem -> Searing Totem + // Magma Totem -> Searing Totem + // Strength of Earth Totem -> Stoneskin Totem + // Cleansing Totem -> Mana Spring Totem + // Wrath of Air Totem -> Windfury Totem -> Grounding Totem + static ActionNode* totem_of_wrath([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("totem of wrath", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("flametongue totem"), nullptr), + /*C*/ nullptr); + } + static ActionNode* flametongue_totem([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("flametongue totem", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("searing totem"), nullptr), + /*C*/ nullptr); + } + static ActionNode* magma_totem([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("magma totem", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("searing totem"), nullptr), + /*C*/ nullptr); + } + static ActionNode* searing_totem(PlayerbotAI*) { return new ActionNode("searing totem", nullptr, nullptr, nullptr); } + static ActionNode* strength_of_earth_totem([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("strength of earth totem", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("stoneskin totem"), nullptr), + /*C*/ nullptr); + } + static ActionNode* stoneskin_totem(PlayerbotAI*) { return new ActionNode("stoneskin totem", nullptr, nullptr, nullptr); } + static ActionNode* cleansing_totem([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("cleansing totem", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("mana spring totem"), nullptr), + /*C*/ nullptr); + } + static ActionNode* mana_spring_totem(PlayerbotAI*) { return new ActionNode("mana spring totem", nullptr, nullptr, nullptr); } + static ActionNode* healing_stream_totem(PlayerbotAI*) { return new ActionNode("healing stream totem", nullptr, nullptr, nullptr); } + static ActionNode* wrath_of_air_totem([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("wrath of air totem", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("windfury totem"), nullptr), + /*C*/ nullptr); + } + static ActionNode* windfury_totem([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("windfury totem", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("grounding totem"), nullptr), + /*C*/ nullptr); + } + static ActionNode* grounding_totem(PlayerbotAI*) { return new ActionNode("grounding totem", nullptr, nullptr, nullptr); } + static ActionNode* wind_shear(PlayerbotAI*) { return new ActionNode("wind shear", nullptr, nullptr, nullptr); } + static ActionNode* purge(PlayerbotAI*) { return new ActionNode("purge", nullptr, nullptr, nullptr); } }; GenericShamanStrategy::GenericShamanStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) @@ -118,75 +104,68 @@ void GenericShamanStrategy::InitTriggers(std::vector& triggers) { CombatStrategy::InitTriggers(triggers); - triggers.push_back( - new TriggerNode("wind shear", NextAction::array(0, new NextAction("wind shear", 23.0f), nullptr))); - triggers.push_back( - new TriggerNode("wind shear on enemy healer", - NextAction::array(0, new NextAction("wind shear on enemy healer", 23.0f), nullptr))); + triggers.push_back(new TriggerNode("wind shear", NextAction::array(0, new NextAction("wind shear", 23.0f), nullptr))); + triggers.push_back(new TriggerNode("wind shear on enemy healer", NextAction::array(0, new NextAction("wind shear on enemy healer", 23.0f), nullptr))); triggers.push_back(new TriggerNode("purge", NextAction::array(0, new NextAction("purge", ACTION_DISPEL), nullptr))); - // triggers.push_back(new TriggerNode("party member medium health", NextAction::array(0, new NextAction("lesser - // healing wave on party", 25.0f), nullptr))); triggers.push_back(new TriggerNode("party member low health", - // NextAction::array(0, new NextAction("riptide on party", 25.0f), nullptr))); triggers.push_back(new - // TriggerNode("medium aoe heal", NextAction::array(0, new NextAction("chain heal on party", 27.0f), nullptr))); - // triggers.push_back(new TriggerNode("medium health", NextAction::array(0, new NextAction("lesser healing - // wave", 26.0f), nullptr))); triggers.push_back(new TriggerNode("low health", NextAction::array(0, new - // NextAction("riptide", 26.0f), nullptr))); - triggers.push_back(new TriggerNode("heroism", NextAction::array(0, new NextAction("heroism", 31.0f), nullptr))); - triggers.push_back(new TriggerNode("bloodlust", NextAction::array(0, new NextAction("bloodlust", 30.0f), nullptr))); - triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", 60.0f), nullptr))); - triggers.push_back(new TriggerNode("new pet", NextAction::array(0, new NextAction("set pet stance", 65.0f), nullptr))); -} - -void ShamanBuffDpsStrategy::InitTriggers(std::vector& triggers) -{ - triggers.push_back( - new TriggerNode("lightning shield", NextAction::array(0, new NextAction("lightning shield", 22.0f), nullptr))); -} - -void ShamanBuffManaStrategy::InitTriggers(std::vector& triggers) -{ - triggers.push_back( - new TriggerNode("water shield", NextAction::array(0, new NextAction("water shield", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("medium mana", NextAction::array(0, new NextAction("mana potion", ACTION_DISPEL), nullptr))); + triggers.push_back(new TriggerNode("new pet", NextAction::array(0, new NextAction("set pet stance", 65.0f), nullptr))); } void ShamanCureStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back( - new TriggerNode("cure poison", NextAction::array(0, new NextAction("cure poison", 21.0f), nullptr))); - triggers.push_back(new TriggerNode("party member cure poison", - NextAction::array(0, new NextAction("cure poison on party", 21.0f), nullptr))); - triggers.push_back(new TriggerNode("cleanse spirit poison", - NextAction::array(0, new NextAction("cleanse spirit", 24.0f), nullptr))); - triggers.push_back( - new TriggerNode("party member cleanse spirit poison", - NextAction::array(0, new NextAction("cleanse spirit poison on party", 23.0f), nullptr))); - triggers.push_back( - new TriggerNode("cure disease", NextAction::array(0, new NextAction("cure disease", 31.0f), nullptr))); - triggers.push_back(new TriggerNode("party member cure disease", - NextAction::array(0, new NextAction("cure disease on party", 30.0f), nullptr))); - triggers.push_back(new TriggerNode("cleanse spirit disease", - NextAction::array(0, new NextAction("cleanse spirit", 24.0f), nullptr))); - triggers.push_back( - new TriggerNode("party member cleanse spirit disease", - NextAction::array(0, new NextAction("cleanse spirit disease on party", 23.0f), nullptr))); - triggers.push_back(new TriggerNode("cleanse spirit curse", - NextAction::array(0, new NextAction("cleanse spirit", 24.0f), nullptr))); - triggers.push_back( - new TriggerNode("party member cleanse spirit curse", - NextAction::array(0, new NextAction("cleanse spirit curse on party", 23.0f), nullptr))); + triggers.push_back(new TriggerNode("cure poison", NextAction::array(0, new NextAction("cure poison", 21.0f), nullptr))); + triggers.push_back(new TriggerNode("party member cure poison", NextAction::array(0, new NextAction("cure poison on party", 21.0f), nullptr))); + triggers.push_back(new TriggerNode("cleanse spirit poison", NextAction::array(0, new NextAction("cleanse spirit", 24.0f), nullptr))); + triggers.push_back(new TriggerNode("party member cleanse spirit poison", NextAction::array(0, new NextAction("cleanse spirit poison on party", 23.0f), nullptr))); + triggers.push_back(new TriggerNode("cure disease", NextAction::array(0, new NextAction("cure disease", 31.0f), nullptr))); + triggers.push_back(new TriggerNode("party member cure disease", NextAction::array(0, new NextAction("cure disease on party", 30.0f), nullptr))); + triggers.push_back(new TriggerNode("cleanse spirit disease", NextAction::array(0, new NextAction("cleanse spirit", 24.0f), nullptr))); + triggers.push_back(new TriggerNode("party member cleanse spirit disease", NextAction::array(0, new NextAction("cleanse spirit disease on party", 23.0f), nullptr))); + triggers.push_back(new TriggerNode("cleanse spirit curse", NextAction::array(0, new NextAction("cleanse spirit", 24.0f), nullptr))); + triggers.push_back(new TriggerNode("party member cleanse spirit curse", NextAction::array(0, new NextAction("cleanse spirit curse on party", 23.0f), nullptr))); } -void ShamanHealerDpsStrategy::InitTriggers(std::vector& triggers) +void ShamanBoostStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back( - new TriggerNode("healer should attack", - NextAction::array(0, - new NextAction("flame shock", ACTION_DEFAULT + 0.2f), - new NextAction("lava burst", ACTION_DEFAULT + 0.1f), - new NextAction("lightning bolt", ACTION_DEFAULT), nullptr))); - - triggers.push_back( - new TriggerNode("medium aoe and healer should attack", - NextAction::array(0, - new NextAction("chain lightning", ACTION_DEFAULT + 0.3f), nullptr))); + triggers.push_back(new TriggerNode("heroism", NextAction::array(0, new NextAction("heroism", 30.0f), nullptr))); + triggers.push_back(new TriggerNode("bloodlust", NextAction::array(0, new NextAction("bloodlust", 30.0f), nullptr))); + + Player* bot = botAI->GetBot(); + int tab = AiFactory::GetPlayerSpecTab(bot); + + if (tab == 0) // Elemental + { + triggers.push_back(new TriggerNode("fire elemental totem", NextAction::array(0, new NextAction("fire elemental totem", 23.0f), nullptr))); + } + else if (tab == 1) // Enhancement + { + triggers.push_back(new TriggerNode("fire elemental totem", NextAction::array(0, new NextAction("fire elemental totem melee", 24.0f), nullptr))); + } +} + +void ShamanAoeStrategy::InitTriggers(std::vector& triggers) +{ + + Player* bot = botAI->GetBot(); + int tab = AiFactory::GetPlayerSpecTab(bot); + + if (tab == 0) // Elemental + { + triggers.push_back(new TriggerNode("medium aoe",NextAction::array(0, new NextAction("fire nova", 23.0f), nullptr))); + triggers.push_back(new TriggerNode("chain lightning no cd", NextAction::array(0, new NextAction("chain lightning", 5.6f), nullptr))); + } + else if (tab == 1) // Enhancement + { + triggers.push_back(new TriggerNode("medium aoe",NextAction::array(0, + new NextAction("magma totem", 24.0f), + new NextAction("fire nova", 23.0f), nullptr))); + + triggers.push_back(new TriggerNode("maelstrom weapon 5 and medium aoe", NextAction::array(0, new NextAction("chain lightning", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("maelstrom weapon 4 and medium aoe", NextAction::array(0, new NextAction("chain lightning", 21.0f), nullptr))); + triggers.push_back(new TriggerNode("enemy within melee", NextAction::array(0, new NextAction("fire nova", 5.1f), nullptr))); + } + else if (tab == 2) // Restoration + { + // Handled by "Healer DPS" Strategy + } } diff --git a/src/strategy/shaman/GenericShamanStrategy.h b/src/strategy/shaman/GenericShamanStrategy.h index 5fa0ff83..fab343a0 100644 --- a/src/strategy/shaman/GenericShamanStrategy.h +++ b/src/strategy/shaman/GenericShamanStrategy.h @@ -18,24 +18,6 @@ public: void InitTriggers(std::vector& triggers) override; }; -class ShamanBuffDpsStrategy : public Strategy -{ -public: - ShamanBuffDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} - - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "bdps"; } -}; - -class ShamanBuffManaStrategy : public Strategy -{ -public: - ShamanBuffManaStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} - - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "bmana"; } -}; - class ShamanCureStrategy : public Strategy { public: @@ -45,13 +27,22 @@ public: std::string const getName() override { return "cure"; } }; -class ShamanHealerDpsStrategy : public Strategy +class ShamanBoostStrategy : public Strategy { public: - ShamanHealerDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} + ShamanBoostStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "healer dps"; } + std::string const getName() override { return "boost"; } +}; + +class ShamanAoeStrategy : public CombatStrategy +{ +public: + ShamanAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {} + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "aoe"; } }; #endif diff --git a/src/strategy/shaman/HealShamanStrategy.cpp b/src/strategy/shaman/HealShamanStrategy.cpp deleted file mode 100644 index c71f5f90..00000000 --- a/src/strategy/shaman/HealShamanStrategy.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it - * and/or modify it under version 2 of the License, or (at your option), any later version. - */ - -#include "HealShamanStrategy.h" - -#include "Playerbots.h" - -class HealShamanStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - HealShamanStrategyActionNodeFactory() - { - creators["earthliving weapon"] = &earthliving_weapon; - creators["mana tide totem"] = &mana_tide_totem; - } - -private: - static ActionNode* earthliving_weapon([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("earthliving weapon", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("flametongue weapon"), nullptr), - /*C*/ nullptr); - } - - static ActionNode* mana_tide_totem([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("mana tide totem", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("mana potion"), nullptr), - /*C*/ nullptr); - } -}; - -HealShamanStrategy::HealShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) -{ - actionNodeFactories.Add(new HealShamanStrategyActionNodeFactory()); -} - -void HealShamanStrategy::InitTriggers(std::vector& triggers) -{ - GenericShamanStrategy::InitTriggers(triggers); - - // triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", - // ACTION_NORMAL + 9), nullptr))); triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new - // NextAction("earthliving weapon", 22.0f), nullptr))); - triggers.push_back(new TriggerNode("main hand weapon no imbue", - NextAction::array(0, new NextAction("earthliving weapon", 22.0f), nullptr))); - triggers.push_back(new TriggerNode( - "group heal setting", - NextAction::array(0, new NextAction("riptide on party", 27.0f), new NextAction("chain heal on party", 26.0f), NULL))); - - triggers.push_back(new TriggerNode( - "party member critical health", - NextAction::array(0, new NextAction("riptide on party", 25.0f), new NextAction("healing wave on party", 24.0f), - new NextAction("lesser healing wave on party", 23.0f), nullptr))); - - triggers.push_back(new TriggerNode( - "party member low health", - NextAction::array(0, new NextAction("riptide on party", 19.0f), new NextAction("healing wave on party", 18.0f), - new NextAction("lesser healing wave on party", 17.0f), nullptr))); - - triggers.push_back(new TriggerNode( - "party member medium health", - NextAction::array(0, new NextAction("riptide on party", 16.0f), new NextAction("healing wave on party", 15.0f), - new NextAction("lesser healing wave on party", 14.0f), nullptr))); - - triggers.push_back( - new TriggerNode("party member almost full health", - NextAction::array(0, new NextAction("riptide on party", 12.0f), - new NextAction("lesser healing wave on party", 11.0f), nullptr))); - - triggers.push_back( - new TriggerNode("party member cleanse spirit poison", - NextAction::array(0, new NextAction("cleanse spirit poison on party", ACTION_DISPEL + 2), - new NextAction("cleansing totem", ACTION_DISPEL + 2), NULL))); - - triggers.push_back( - new TriggerNode("party member cleanse spirit disease", - NextAction::array(0, new NextAction("cleanse spirit disease on party", ACTION_DISPEL + 2), - new NextAction("cleansing totem", ACTION_DISPEL + 1), NULL))); - - triggers.push_back(new TriggerNode( - "party member cleanse spirit curse", - NextAction::array(0, new NextAction("cleanse spirit curse on party", ACTION_DISPEL + 2), NULL))); - - // triggers.push_back(new TriggerNode( - // "no fire totem", - // NextAction::array(0, new NextAction("flametongue totem", 10.0f), NULL))); - - // triggers.push_back(new TriggerNode( - // "no water totem", - // NextAction::array(0, new NextAction("healing stream totem", 13.0f), NULL))); - - triggers.push_back( - new TriggerNode("earth shield on main tank", - NextAction::array(0, new NextAction("earth shield on main tank", ACTION_HIGH + 7), NULL))); - - triggers.push_back(new TriggerNode("enemy too close for spell", - NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr))); - - triggers.push_back( - new TriggerNode("medium mana", NextAction::array(0, new NextAction("mana tide totem", ACTION_HIGH + 5), NULL))); - - triggers.push_back( - new TriggerNode("no fire totem", NextAction::array(0, new NextAction("flametongue totem", 7.0f), - new NextAction("searing totem", 6.0f), nullptr))); - triggers.push_back(new TriggerNode("fire elemental totem", - NextAction::array(0, new NextAction("fire elemental totem", 32.0f), nullptr))); - triggers.push_back(new TriggerNode( - "party member to heal out of spell range", - NextAction::array(0, new NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 1), nullptr))); -} diff --git a/src/strategy/shaman/HealShamanStrategy.h b/src/strategy/shaman/HealShamanStrategy.h deleted file mode 100644 index b4068f0f..00000000 --- a/src/strategy/shaman/HealShamanStrategy.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it - * and/or modify it under version 2 of the License, or (at your option), any later version. - */ - -#ifndef _PLAYERBOT_HEALSHAMANSTRATEGY_H -#define _PLAYERBOT_HEALSHAMANSTRATEGY_H - -#include "GenericShamanStrategy.h" -#include "Strategy.h" - -class PlayerbotAI; - -class HealShamanStrategy : public GenericShamanStrategy -{ -public: - HealShamanStrategy(PlayerbotAI* botAI); - - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "heal"; } - uint32 GetType() const override { return STRATEGY_TYPE_RANGED | STRATEGY_TYPE_HEAL; } -}; - -#endif diff --git a/src/strategy/shaman/MeleeShamanStrategy.cpp b/src/strategy/shaman/MeleeShamanStrategy.cpp deleted file mode 100644 index 96cea7b7..00000000 --- a/src/strategy/shaman/MeleeShamanStrategy.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it - * and/or modify it under version 2 of the License, or (at your option), any later version. - */ - -#include "MeleeShamanStrategy.h" - -#include "Playerbots.h" - -class MeleeShamanStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - MeleeShamanStrategyActionNodeFactory() - { - creators["stormstrike"] = &stormstrike; - creators["lava lash"] = &lava_lash; - creators["magma totem"] = &magma_totem; - } - -private: - static ActionNode* stormstrike([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("stormstrike", - /*P*/ nullptr, - // /*A*/ NextAction::array(0, new NextAction("lava lash"), nullptr), - nullptr, - /*C*/ nullptr); - } - - static ActionNode* lava_lash([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("lava lash", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("melee"), nullptr), - /*C*/ nullptr); - } - - static ActionNode* magma_totem([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("magma totem", - /*P*/ NULL, - /*A*/ NextAction::array(0, new NextAction("searing totem"), NULL), - /*C*/ NULL); - } -}; - -MeleeShamanStrategy::MeleeShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) -{ - actionNodeFactories.Add(new MeleeShamanStrategyActionNodeFactory()); -} - -NextAction** MeleeShamanStrategy::getDefaultActions() -{ - return NextAction::array( - 0, new NextAction("stormstrike", ACTION_DEFAULT + 0.5f), new NextAction("earth shock", ACTION_DEFAULT + 0.4f), - new NextAction("feral spirit", ACTION_DEFAULT + 0.3f), new NextAction("fire nova", ACTION_DEFAULT + 0.2f), - new NextAction("lava lash", ACTION_DEFAULT + 0.1f), new NextAction("melee", ACTION_DEFAULT), NULL); -} - -void MeleeShamanStrategy::InitTriggers(std::vector& triggers) -{ - GenericShamanStrategy::InitTriggers(triggers); - - // triggers.push_back(new TriggerNode("shaman weapon", NextAction::array(0, new NextAction("flametongue - // weapon", 22.0f), nullptr))); - triggers.push_back(new TriggerNode("main hand weapon no imbue", - NextAction::array(0, new NextAction("windfury weapon", 22.0f), nullptr))); - triggers.push_back(new TriggerNode("off hand weapon no imbue", - NextAction::array(0, new NextAction("flametongue weapon", 21.0f), nullptr))); - // triggers.push_back(new TriggerNode("searing totem", NextAction::array(0, new NextAction("reach melee", 22.0f), - // new NextAction("searing totem", 22.0f), nullptr))); - triggers.push_back( - new TriggerNode("flame shock", NextAction::array(0, new NextAction("flame shock", 20.0f), nullptr))); - triggers.push_back( - new TriggerNode("maelstrom weapon 4", NextAction::array(0, new NextAction("lightning bolt", 25.0f), nullptr))); - - triggers.push_back(new TriggerNode( - "medium aoe", NextAction::array(0, new NextAction("strength of earth totem", ACTION_LIGHT_HEAL), nullptr))); - triggers.push_back(new TriggerNode( - "enemy out of melee", NextAction::array(0, new NextAction("reach melee", ACTION_HIGH + 1), nullptr))); - - triggers.push_back(new TriggerNode( - "no fire totem", - NextAction::array(0, new NextAction("reach melee", 23.0f), new NextAction("magma totem", 22.0f), nullptr))); - - triggers.push_back(new TriggerNode( - "fire elemental totem", NextAction::array(0, new NextAction("fire elemental totem melee", 32.0f), nullptr))); - - triggers.push_back( - new TriggerNode("no air totem", NextAction::array(0, new NextAction("windfury totem", 20.0f), nullptr))); - - triggers.push_back( - new TriggerNode("medium mana", NextAction::array(0, new NextAction("shamanistic rage", 23.0f), nullptr))); - - triggers.push_back( - new TriggerNode("low health", NextAction::array(0, new NextAction("shamanistic rage", 23.0f), nullptr))); -} - -void MeleeAoeShamanStrategy::InitTriggers(std::vector& triggers) -{ - // triggers.push_back(new TriggerNode("magma totem", NextAction::array(0, new NextAction("magma totem", 26.0f), - // nullptr))); - triggers.push_back( - new TriggerNode("medium aoe", NextAction::array(0, new NextAction("fire nova", 25.0f), nullptr))); -} diff --git a/src/strategy/shaman/RestoShamanStrategy.cpp b/src/strategy/shaman/RestoShamanStrategy.cpp new file mode 100644 index 00000000..04eb2e78 --- /dev/null +++ b/src/strategy/shaman/RestoShamanStrategy.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it + * and/or modify it under version 2 of the License, or (at your option), any later version. + */ + +#include "RestoShamanStrategy.h" + +#include "Playerbots.h" + +// ===== Action Node Factory ===== +class RestoShamanStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + RestoShamanStrategyActionNodeFactory() + { + creators["mana tide totem"] = &mana_tide_totem; + creators["call of the elements"] = &call_of_the_elements; + creators["stoneclaw totem"] = &stoneclaw_totem; + creators["riptide on party"] = &riptide_on_party; + creators["chain heal on party"] = &chain_heal_on_party; + creators["healing wave on party"] = &healing_wave_on_party; + creators["lesser healing wave on party"] = &lesser_healing_wave_on_party; + creators["earth shield on main tank"] = &earth_shield_on_main_tank; + creators["cleanse spirit poison on party"] = &cleanse_spirit_poison_on_party; + creators["cleanse spirit disease on party"] = &cleanse_spirit_disease_on_party; + creators["cleanse spirit curse on party"] = &cleanse_spirit_curse_on_party; + creators["cleansing totem"] = &cleansing_totem; + creators["water shield"] = &water_shield; + creators["flame shock"] = &flame_shock; + creators["lava burst"] = &lava_burst; + creators["lightning bolt"] = &lightning_bolt; + creators["chain lightning"] = &chain_lightning; + } + +private: + static ActionNode* mana_tide_totem([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("mana tide totem", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("mana potion"), nullptr), + /*C*/ nullptr); + } + static ActionNode* call_of_the_elements(PlayerbotAI*) { return new ActionNode("call of the elements", nullptr, nullptr, nullptr); } + static ActionNode* stoneclaw_totem(PlayerbotAI*) { return new ActionNode("stoneclaw totem", nullptr, nullptr, nullptr); } + static ActionNode* riptide_on_party(PlayerbotAI*) { return new ActionNode("riptide on party", nullptr, nullptr, nullptr); } + static ActionNode* chain_heal_on_party(PlayerbotAI*) { return new ActionNode("chain heal on party", nullptr, nullptr, nullptr); } + static ActionNode* healing_wave_on_party(PlayerbotAI*) { return new ActionNode("healing wave on party", nullptr, nullptr, nullptr); } + static ActionNode* lesser_healing_wave_on_party(PlayerbotAI*) { return new ActionNode("lesser healing wave on party", nullptr, nullptr, nullptr); } + static ActionNode* earth_shield_on_main_tank(PlayerbotAI*) { return new ActionNode("earth shield on main tank", nullptr, nullptr, nullptr); } + static ActionNode* cleanse_spirit_poison_on_party(PlayerbotAI*) { return new ActionNode("cleanse spirit poison on party", nullptr, nullptr, nullptr); } + static ActionNode* cleanse_spirit_disease_on_party(PlayerbotAI*) { return new ActionNode("cleanse spirit disease on party", nullptr, nullptr, nullptr); } + static ActionNode* cleanse_spirit_curse_on_party(PlayerbotAI*) { return new ActionNode("cleanse spirit curse on party", nullptr, nullptr, nullptr); } + static ActionNode* cleansing_totem(PlayerbotAI*) { return new ActionNode("cleansing totem", nullptr, nullptr, nullptr); } + static ActionNode* water_shield(PlayerbotAI*) { return new ActionNode("water shield", nullptr, nullptr, nullptr); } + static ActionNode* flame_shock(PlayerbotAI*) { return new ActionNode("flame shock", nullptr, nullptr, nullptr); } + static ActionNode* lava_burst(PlayerbotAI*) { return new ActionNode("lava burst", nullptr, nullptr, nullptr); } + static ActionNode* lightning_bolt(PlayerbotAI*) { return new ActionNode("lightning bolt", nullptr, nullptr, nullptr); } + static ActionNode* chain_lightning(PlayerbotAI*) { return new ActionNode("chain lightning", nullptr, nullptr, nullptr); } +}; + +// ===== Single Target Strategy ===== +RestoShamanStrategy::RestoShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) +{ + actionNodeFactories.Add(new RestoShamanStrategyActionNodeFactory()); +} + +// ===== Trigger Initialization === +void RestoShamanStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + + // Totem Triggers + triggers.push_back(new TriggerNode("call of the elements", NextAction::array(0, new NextAction("call of the elements", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("stoneclaw totem", 40.0f), nullptr))); + triggers.push_back(new TriggerNode("medium mana", NextAction::array(0, new NextAction("mana tide totem", ACTION_HIGH + 5), NULL))); + + // Healing Triggers + triggers.push_back(new TriggerNode("group heal setting", NextAction::array(0, + new NextAction("riptide on party", 27.0f), + new NextAction("chain heal on party", 26.0f), NULL))); + + triggers.push_back(new TriggerNode("party member critical health", NextAction::array(0, + new NextAction("riptide on party", 25.0f), + new NextAction("healing wave on party", 24.0f), + new NextAction("lesser healing wave on party", 23.0f), nullptr))); + + triggers.push_back(new TriggerNode("party member low health", NextAction::array(0, + new NextAction("riptide on party", 19.0f), + new NextAction("healing wave on party", 18.0f), + new NextAction("lesser healing wave on party", 17.0f), nullptr))); + + triggers.push_back(new TriggerNode("party member medium health", NextAction::array(0, + new NextAction("riptide on party", 16.0f), + new NextAction("healing wave on party", 15.0f), + new NextAction("lesser healing wave on party", 14.0f), nullptr))); + + triggers.push_back(new TriggerNode("party member almost full health", NextAction::array(0, + new NextAction("riptide on party", 12.0f), + new NextAction("lesser healing wave on party", 11.0f), nullptr))); + + triggers.push_back(new TriggerNode("earth shield on main tank", NextAction::array(0, new NextAction("earth shield on main tank", ACTION_HIGH + 7), NULL))); + + // Dispel Triggers + triggers.push_back(new TriggerNode("party member cleanse spirit poison", NextAction::array(0, new NextAction("cleanse spirit poison on party", ACTION_DISPEL + 2), nullptr))); + triggers.push_back(new TriggerNode("party member cleanse spirit disease", NextAction::array(0, new NextAction("cleanse spirit disease on party", ACTION_DISPEL + 2), nullptr))); + triggers.push_back(new TriggerNode("party member cleanse spirit curse",NextAction::array(0, new NextAction("cleanse spirit curse on party", ACTION_DISPEL + 2), NULL))); + + // Range/Mana Triggers + triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("flee", ACTION_MOVE + 9), nullptr))); + triggers.push_back(new TriggerNode("party member to heal out of spell range", NextAction::array(0, new NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 1), nullptr))); + triggers.push_back(new TriggerNode("water shield", NextAction::array(0, new NextAction("water shield", 19.5f), nullptr))); +} + +void ShamanHealerDpsStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back(new TriggerNode("healer should attack", + NextAction::array(0, new NextAction("flame shock", ACTION_DEFAULT + 0.2f), + new NextAction("lava burst", ACTION_DEFAULT + 0.1f), + new NextAction("lightning bolt", ACTION_DEFAULT), nullptr))); + + triggers.push_back( + new TriggerNode("medium aoe and healer should attack", + NextAction::array(0, new NextAction("chain lightning", ACTION_DEFAULT + 0.3f), nullptr))); +} diff --git a/src/strategy/shaman/RestoShamanStrategy.h b/src/strategy/shaman/RestoShamanStrategy.h new file mode 100644 index 00000000..1b8d46d4 --- /dev/null +++ b/src/strategy/shaman/RestoShamanStrategy.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license, you may redistribute it + * and/or modify it under version 2 of the License, or (at your option), any later version. + */ + +#ifndef _PLAYERBOT_RESTOSHAMANSTRATEGY_H +#define _PLAYERBOT_RESTOSHAMANSTRATEGY_H + +#include "GenericShamanStrategy.h" +#include "Strategy.h" + +class PlayerbotAI; + +class RestoShamanStrategy : public GenericShamanStrategy +{ +public: + RestoShamanStrategy(PlayerbotAI* botAI); + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "resto"; } + uint32 GetType() const override { return STRATEGY_TYPE_RANGED | STRATEGY_TYPE_HEAL; } +}; + +class ShamanHealerDpsStrategy : public Strategy +{ +public: + ShamanHealerDpsStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "healer dps"; } +}; + +#endif diff --git a/src/strategy/shaman/ShamanActions.cpp b/src/strategy/shaman/ShamanActions.cpp index 95426d24..51f2d78b 100644 --- a/src/strategy/shaman/ShamanActions.cpp +++ b/src/strategy/shaman/ShamanActions.cpp @@ -4,42 +4,17 @@ */ #include "ShamanActions.h" - +#include "TotemsShamanStrategy.h" #include "Playerbots.h" #include "Totem.h" +#include "PlayerbotAI.h" +#include "Action.h" bool CastTotemAction::isUseful() { - if (needLifeTime > 0.1f && AI_VALUE(uint8, "attacker count") < 3) - { - Unit* target = AI_VALUE(Unit*, "current target"); - if (!target) - { - return false; - } - float dps = AI_VALUE(float, "estimated group dps"); - if (target->GetHealth() / dps < needLifeTime) - { - return false; - } - } - return CastBuffSpellAction::isUseful() && !AI_VALUE2(bool, "has totem", name) && !botAI->HasAura(buff, bot); -} - -bool CastManaSpringTotemAction::isUseful() -{ - return CastTotemAction::isUseful() && !AI_VALUE2(bool, "has totem", "healing stream totem"); -} - -bool CastFlametongueTotemAction::isUseful() -{ - return CastTotemAction::isUseful() && !AI_VALUE2(bool, "has totem", "magma totem") && - !botAI->HasAura("totem of wrath", bot); -} - -bool CastSearingTotemAction::isUseful() -{ - return CastTotemAction::isUseful() && !AI_VALUE2(bool, "has totem", "flametongue totem"); + return CastBuffSpellAction::isUseful() + && !AI_VALUE2(bool, "has totem", name) + && !botAI->HasAura(buff, bot); } bool CastMagmaTotemAction::isUseful() { @@ -67,4 +42,70 @@ bool CastFireNovaAction::isUseful() { bool CastCleansingTotemAction::isUseful() { return CastTotemAction::isUseful() && !AI_VALUE2(bool, "has totem", "mana tide totem"); -} \ No newline at end of file +} + +// Will only cast Stoneclaw Totem if low on health and not in a group +bool CastStoneclawTotemAction::isUseful() { return !botAI->GetBot()->GetGroup(); } + +// Will only cast Lava Burst if Flame Shock is on the target +bool CastLavaBurstAction::isUseful() +{ + Unit* target = GetTarget(); + if (!target) + return false; + + static const uint32 FLAME_SHOCK_IDS[] = {8050, 8052, 8053, 10447, 10448, 29228, 25457, 49232, 49233}; + + ObjectGuid botGuid = botAI->GetBot()->GetGUID(); + for (uint32 spellId : FLAME_SHOCK_IDS) + { + if (target->HasAura(spellId, botGuid)) + return true; + } + return false; +} + +// Logic for making a guardian (spirit wolf) use a spell (spirit walk) +// There is no existing code for guardians casting spells in the AC/Playerbots repo. +bool CastSpiritWalkAction::Execute(Event event) +{ + Player* bot = botAI->GetBot(); + constexpr uint32 SPIRIT_WOLF = 29264; + constexpr uint32 SPIRIT_WALK_SPELL = 58875; + + for (Unit* unit : bot->m_Controlled) + { + if (unit->GetEntry() == SPIRIT_WOLF) + { + if (unit->HasSpell(SPIRIT_WALK_SPELL)) + { + unit->CastSpell(unit, SPIRIT_WALK_SPELL, false); + return true; + } + } + } + return false; +} + +// Set Strategy Assigned Totems (Actions) - First, it checks +// the highest-rank spell the bot knows for each totem type, +// then adds it to the Call of the Elements bar. + +bool SetTotemAction::Execute(Event event) +{ + size_t spellIdsCount = sizeof(totemSpellIds) / sizeof(uint32); + + uint32 totemSpell = 0; + for (int i = spellIdsCount - 1; i >= 0; --i) + { + if (bot->HasSpell(totemSpellIds[i])) + { + totemSpell = totemSpellIds[i]; + break; + } + } + if (!totemSpell) + return false; + bot->addActionButton(actionButtonId, totemSpell, ACTION_BUTTON_SPELL); + return true; +} diff --git a/src/strategy/shaman/ShamanActions.h b/src/strategy/shaman/ShamanActions.h index 2d110e51..4d64bb1d 100644 --- a/src/strategy/shaman/ShamanActions.h +++ b/src/strategy/shaman/ShamanActions.h @@ -9,9 +9,286 @@ #include "GenericSpellActions.h" #include "Playerbots.h" #include "SharedDefines.h" +#include "TotemsShamanStrategy.h" class PlayerbotAI; +// Buff and Out of Combat Actions + +class CastWaterShieldAction : public CastBuffSpellAction +{ +public: + CastWaterShieldAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "water shield") {} +}; + +class CastLightningShieldAction : public CastBuffSpellAction +{ +public: + CastLightningShieldAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "lightning shield") {} +}; + +class CastEarthlivingWeaponAction : public CastEnchantItemAction +{ +public: + CastEarthlivingWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "earthliving weapon") {} +}; + +class CastRockbiterWeaponAction : public CastEnchantItemAction +{ +public: + CastRockbiterWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "rockbiter weapon") {} +}; + +class CastFlametongueWeaponAction : public CastEnchantItemAction +{ +public: + CastFlametongueWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "flametongue weapon") {} +}; + +class CastFrostbrandWeaponAction : public CastEnchantItemAction +{ +public: + CastFrostbrandWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "frostbrand weapon") {} +}; + +class CastWindfuryWeaponAction : public CastEnchantItemAction +{ +public: + CastWindfuryWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "windfury weapon") {} +}; + +class CastAncestralSpiritAction : public ResurrectPartyMemberAction +{ +public: + CastAncestralSpiritAction(PlayerbotAI* botAI) : ResurrectPartyMemberAction(botAI, "ancestral spirit") {} +}; + +class CastWaterBreathingAction : public CastBuffSpellAction +{ +public: + CastWaterBreathingAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "water breathing") {} +}; + +class CastWaterWalkingAction : public CastBuffSpellAction +{ +public: + CastWaterWalkingAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "water walking") {} +}; + +class CastWaterBreathingOnPartyAction : public BuffOnPartyAction +{ +public: + CastWaterBreathingOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "water breathing") {} +}; + +class CastWaterWalkingOnPartyAction : public BuffOnPartyAction +{ +public: + CastWaterWalkingOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "water walking") {} +}; + +// Boost Actions + +class CastHeroismAction : public CastBuffSpellAction +{ +public: + CastHeroismAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "heroism") {} +}; + +class CastBloodlustAction : public CastBuffSpellAction +{ +public: + CastBloodlustAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "bloodlust") {} +}; + +class CastElementalMasteryAction : public CastBuffSpellAction +{ +public: + CastElementalMasteryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "elemental mastery") {} +}; + +class CastShamanisticRageAction : public CastBuffSpellAction +{ +public: + CastShamanisticRageAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "shamanistic rage") {} +}; + +class CastFeralSpiritAction : public CastSpellAction +{ +public: + CastFeralSpiritAction(PlayerbotAI* ai) : CastSpellAction(ai, "feral spirit") {} +}; + +class CastSpiritWalkAction : public Action +{ +public: + CastSpiritWalkAction(PlayerbotAI* botAI) : Action(botAI, "spirit walk") {} + + bool Execute(Event event) override; +}; + +// CC, Interrupt, and Dispel Actions + +class CastWindShearAction : public CastSpellAction +{ +public: + CastWindShearAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "wind shear") {} +}; + +class CastWindShearOnEnemyHealerAction : public CastSpellOnEnemyHealerAction +{ +public: + CastWindShearOnEnemyHealerAction(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, "wind shear") {} +}; + +class CastPurgeAction : public CastSpellAction +{ +public: + CastPurgeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "purge") {} +}; + +class CastCleanseSpiritAction : public CastCureSpellAction +{ +public: + CastCleanseSpiritAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cleanse spirit") {} +}; + +class CastCleanseSpiritPoisonOnPartyAction : public CurePartyMemberAction +{ +public: + CastCleanseSpiritPoisonOnPartyAction(PlayerbotAI* botAI) + : CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_POISON) + { + } + + std::string const getName() override { return "cleanse spirit poison on party"; } +}; + +class CastCleanseSpiritCurseOnPartyAction : public CurePartyMemberAction +{ +public: + CastCleanseSpiritCurseOnPartyAction(PlayerbotAI* botAI) + : CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_CURSE) + { + } + + std::string const getName() override { return "cleanse spirit curse on party"; } +}; + +class CastCleanseSpiritDiseaseOnPartyAction : public CurePartyMemberAction +{ +public: + CastCleanseSpiritDiseaseOnPartyAction(PlayerbotAI* botAI) + : CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_DISEASE) + { + } + + std::string const getName() override { return "cleanse spirit disease on party"; } +}; + +class CastCurePoisonActionSham : public CastCureSpellAction +{ +public: + CastCurePoisonActionSham(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure poison") {} +}; + +class CastCurePoisonOnPartyActionSham : public CurePartyMemberAction +{ +public: + CastCurePoisonOnPartyActionSham(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure poison", DISPEL_POISON) {} + + std::string const getName() override { return "cure poison on party"; } +}; + +class CastCureDiseaseActionSham : public CastCureSpellAction +{ +public: + CastCureDiseaseActionSham(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cure disease") {} +}; + +class CastCureDiseaseOnPartyActionSham : public CurePartyMemberAction +{ +public: + CastCureDiseaseOnPartyActionSham(PlayerbotAI* botAI) : CurePartyMemberAction(botAI, "cure disease", DISPEL_DISEASE) + { + } + + std::string const getName() override { return "cure disease on party"; } +}; + +// Damage and Debuff Actions + +class CastFireNovaAction : public CastMeleeSpellAction +{ +public: + CastFireNovaAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "fire nova") {} + bool isUseful() override; +}; + +class CastStormstrikeAction : public CastMeleeSpellAction +{ +public: + CastStormstrikeAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "stormstrike") {} +}; + +class CastLavaLashAction : public CastMeleeSpellAction +{ +public: + CastLavaLashAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "lava lash") {} +}; + +class CastFlameShockAction : public CastDebuffSpellAction +{ +public: + CastFlameShockAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "flame shock", true, 6.0f) {} + bool isUseful() override + { + // Bypass TTL check + return CastAuraSpellAction::isUseful(); + } +}; + +class CastEarthShockAction : public CastSpellAction +{ +public: + CastEarthShockAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "earth shock") {} +}; + +class CastFrostShockAction : public CastSnareSpellAction +{ +public: + CastFrostShockAction(PlayerbotAI* botAI) : CastSnareSpellAction(botAI, "frost shock") {} +}; + +class CastChainLightningAction : public CastSpellAction +{ +public: + CastChainLightningAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "chain lightning") {} + ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } +}; + +class CastLightningBoltAction : public CastSpellAction +{ +public: + CastLightningBoltAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "lightning bolt") {} +}; + +class CastThunderstormAction : public CastSpellAction +{ +public: + CastThunderstormAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "thunderstorm") {} +}; + +class CastLavaBurstAction : public CastSpellAction +{ +public: + CastLavaBurstAction(PlayerbotAI* ai) : CastSpellAction(ai, "lava burst") {} + bool isUseful() override; +}; + + +// Healing Actions + class CastLesserHealingWaveAction : public CastHealingSpellAction { public: @@ -78,351 +355,109 @@ public: CastEarthShieldOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "earth shield") {} }; -class CastWaterShieldAction : public CastBuffSpellAction -{ -public: - CastWaterShieldAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "water shield") {} -}; - -class CastLightningShieldAction : public CastBuffSpellAction -{ -public: - CastLightningShieldAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "lightning shield") {} -}; - -class CastEarthlivingWeaponAction : public CastEnchantItemAction -{ -public: - CastEarthlivingWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "earthliving weapon") {} -}; - -class CastRockbiterWeaponAction : public CastEnchantItemAction -{ -public: - CastRockbiterWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "rockbiter weapon") {} -}; - -class CastFlametongueWeaponAction : public CastEnchantItemAction -{ -public: - CastFlametongueWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "flametongue weapon") {} -}; - -class CastFrostbrandWeaponAction : public CastEnchantItemAction -{ -public: - CastFrostbrandWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "frostbrand weapon") {} -}; - -class CastWindfuryWeaponAction : public CastEnchantItemAction -{ -public: - CastWindfuryWeaponAction(PlayerbotAI* botAI) : CastEnchantItemAction(botAI, "windfury weapon") {} -}; - -class CastTotemAction : public CastBuffSpellAction -{ -public: - CastTotemAction(PlayerbotAI* botAI, std::string const spell, std::string const buffName = "", - float needLifeTime = 8.0f) - : CastBuffSpellAction(botAI, spell), needLifeTime(needLifeTime) - { - if (buffName == "") - { - buff = spell; - } - else - { - buff = buffName; - } - } - - bool isUseful() override; - -protected: - float needLifeTime; - std::string buff; -}; - -class CastStoneskinTotemAction : public CastTotemAction -{ -public: - CastStoneskinTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "stoneskin totem") {} -}; - -class CastEarthbindTotemAction : public CastTotemAction -{ -public: - CastEarthbindTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "earthbind totem") {} -}; - -class CastStrengthOfEarthTotemAction : public CastTotemAction -{ -public: - CastStrengthOfEarthTotemAction(PlayerbotAI* botAI) - : CastTotemAction(botAI, "strength of earth totem", "strength of earth", 20.0f) - { - } -}; - -class CastManaSpringTotemAction : public CastTotemAction -{ -public: - CastManaSpringTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "mana spring totem", "mana spring", 0.0f) {} - - bool isUseful() override; -}; - -class CastManaTideTotemAction : public CastTotemAction -{ -public: - CastManaTideTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "mana tide totem") {} - - std::string const GetTargetName() override { return "self target"; } -}; - -class CastHealingStreamTotemAction : public CastTotemAction -{ -public: - CastHealingStreamTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "healing stream totem") {} -}; - -class CastCleansingTotemAction : public CastTotemAction -{ -public: - CastCleansingTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "cleansing totem") {} - virtual bool isUseful(); -}; - -class CastFlametongueTotemAction : public CastTotemAction -{ -public: - CastFlametongueTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "flametongue totem", "", 20.0f) {} - - bool isUseful() override; -}; - -class CastWindfuryTotemAction : public CastTotemAction -{ -public: - CastWindfuryTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "windfury totem") {} -}; - -class CastGraceOfAirTotemAction : public CastTotemAction -{ -public: - CastGraceOfAirTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "grace of air totem") {} -}; - -class CastSearingTotemAction : public CastTotemAction -{ -public: - CastSearingTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "searing totem", "", 0.0f) {} - - std::string const GetTargetName() override { return "self target"; } - bool isUseful() override; -}; - -class CastMagmaTotemAction : public CastTotemAction -{ -public: - CastMagmaTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "magma totem", "", 0.0f) {} - - std::string const GetTargetName() override { return "self target"; } - bool isUseful() override; -}; - -class CastFireNovaAction : public CastMeleeSpellAction -{ -public: - CastFireNovaAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "fire nova") {} - bool isUseful() override; -}; - -class CastWindShearAction : public CastSpellAction -{ -public: - CastWindShearAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "wind shear") {} -}; - -class CastAncestralSpiritAction : public ResurrectPartyMemberAction -{ -public: - CastAncestralSpiritAction(PlayerbotAI* botAI) : ResurrectPartyMemberAction(botAI, "ancestral spirit") {} -}; - -class CastPurgeAction : public CastSpellAction -{ -public: - CastPurgeAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "purge") {} -}; - -class CastStormstrikeAction : public CastMeleeSpellAction -{ -public: - CastStormstrikeAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "stormstrike") {} -}; - -class CastLavaLashAction : public CastMeleeSpellAction -{ -public: - CastLavaLashAction(PlayerbotAI* botAI) : CastMeleeSpellAction(botAI, "lava lash") {} -}; - -class CastWaterBreathingAction : public CastBuffSpellAction -{ -public: - CastWaterBreathingAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "water breathing") {} -}; - -class CastWaterWalkingAction : public CastBuffSpellAction -{ -public: - CastWaterWalkingAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "water walking") {} -}; - -class CastWaterBreathingOnPartyAction : public BuffOnPartyAction -{ -public: - CastWaterBreathingOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "water breathing") {} -}; - -class CastWaterWalkingOnPartyAction : public BuffOnPartyAction -{ -public: - CastWaterWalkingOnPartyAction(PlayerbotAI* botAI) : BuffOnPartyAction(botAI, "water walking") {} -}; - -class CastCleanseSpiritAction : public CastCureSpellAction -{ -public: - CastCleanseSpiritAction(PlayerbotAI* botAI) : CastCureSpellAction(botAI, "cleanse spirit") {} -}; - -class CastCleanseSpiritPoisonOnPartyAction : public CurePartyMemberAction -{ -public: - CastCleanseSpiritPoisonOnPartyAction(PlayerbotAI* botAI) - : CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_POISON) - { - } - - std::string const getName() override { return "cleanse spirit poison on party"; } -}; - -class CastCleanseSpiritCurseOnPartyAction : public CurePartyMemberAction -{ -public: - CastCleanseSpiritCurseOnPartyAction(PlayerbotAI* botAI) - : CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_CURSE) - { - } - - std::string const getName() override { return "cleanse spirit curse on party"; } -}; - -class CastCleanseSpiritDiseaseOnPartyAction : public CurePartyMemberAction -{ -public: - CastCleanseSpiritDiseaseOnPartyAction(PlayerbotAI* botAI) - : CurePartyMemberAction(botAI, "cleanse spirit", DISPEL_DISEASE) - { - } - - std::string const getName() override { return "cleanse spirit disease on party"; } -}; - -class CastFlameShockAction : public CastDebuffSpellAction -{ -public: - CastFlameShockAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "flame shock", true, 6.0f) {} -}; - -class CastEarthShockAction : public CastSpellAction -{ -public: - CastEarthShockAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "earth shock") {} -}; - -class CastFrostShockAction : public CastSnareSpellAction -{ -public: - CastFrostShockAction(PlayerbotAI* botAI) : CastSnareSpellAction(botAI, "frost shock") {} -}; - -class CastChainLightningAction : public CastSpellAction -{ -public: - CastChainLightningAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "chain lightning") {} - ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } -}; - -class CastLightningBoltAction : public CastSpellAction -{ -public: - CastLightningBoltAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "lightning bolt") {} -}; - -class CastThunderstormAction : public CastSpellAction -{ -public: - CastThunderstormAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "thunderstorm") {} -}; - -class CastHeroismAction : public CastBuffSpellAction -{ -public: - CastHeroismAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "heroism") {} -}; - -class CastBloodlustAction : public CastBuffSpellAction -{ -public: - CastBloodlustAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "bloodlust") {} -}; - -class CastElementalMasteryAction : public CastBuffSpellAction -{ -public: - CastElementalMasteryAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "elemental mastery") {} -}; - -class CastWindShearOnEnemyHealerAction : public CastSpellOnEnemyHealerAction -{ -public: - CastWindShearOnEnemyHealerAction(PlayerbotAI* botAI) : CastSpellOnEnemyHealerAction(botAI, "wind shear") {} -}; - -CURE_ACTION(CastCurePoisonActionSham, "cure disease"); -CURE_PARTY_ACTION(CastCurePoisonOnPartyActionSham, "cure poison", DISPEL_POISON); - -CURE_ACTION(CastCureDiseaseActionSham, "cure disease"); -CURE_PARTY_ACTION(CastCureDiseaseOnPartyActionSham, "cure disease", DISPEL_DISEASE); - -class CastLavaBurstAction : public CastSpellAction -{ -public: - CastLavaBurstAction(PlayerbotAI* ai) : CastSpellAction(ai, "lava burst") {} -}; - class CastEarthShieldOnMainTankAction : public BuffOnMainTankAction { public: CastEarthShieldOnMainTankAction(PlayerbotAI* ai) : BuffOnMainTankAction(ai, "earth shield", false) {} }; +// Totem Spells + +class CastTotemAction : public CastBuffSpellAction +{ +public: + CastTotemAction(PlayerbotAI* botAI, std::string const spell, std::string const buffName = "") + : CastBuffSpellAction(botAI, spell) + { + buff = (buffName == "") ? spell : buffName; + } + + bool isUseful() override; + +protected: + std::string buff; +}; + +class CastCallOfTheElementsAction : public CastSpellAction +{ +public: + CastCallOfTheElementsAction(PlayerbotAI* ai) : CastSpellAction(ai, "call of the elements") {} +}; + +class CastTotemicRecallAction : public CastSpellAction +{ +public: + CastTotemicRecallAction(PlayerbotAI* ai) : CastSpellAction(ai, "totemic recall") {} +}; + +class CastStrengthOfEarthTotemAction : public CastTotemAction +{ +public: + CastStrengthOfEarthTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "strength of earth totem", "strength of earth") {} +}; + +class CastStoneskinTotemAction : public CastTotemAction +{ +public: + CastStoneskinTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "stoneskin totem", "stoneskin") {} +}; + +class CastTremorTotemAction : public CastTotemAction +{ +public: + CastTremorTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "tremor totem", "") {} +}; + +class CastEarthbindTotemAction : public CastTotemAction +{ +public: + CastEarthbindTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "earthbind totem", "") {} +}; + +class CastStoneclawTotemAction : public CastTotemAction +{ +public: + CastStoneclawTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "stoneclaw totem", "") {} + bool isUseful() override; +}; + +class CastSearingTotemAction : public CastTotemAction +{ +public: + CastSearingTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "searing totem", "") {} +}; + +class CastMagmaTotemAction : public CastTotemAction +{ +public: + CastMagmaTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "magma totem", "") {} + std::string const GetTargetName() override { return "self target"; } + bool isUseful() override; +}; + +class CastFlametongueTotemAction : public CastTotemAction +{ +public: + CastFlametongueTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "flametongue totem", "flametongue totem") {} +}; + class CastTotemOfWrathAction : public CastTotemAction { public: - CastTotemOfWrathAction(PlayerbotAI* ai) : CastTotemAction(ai, "totem of wrath") {} - virtual std::string const GetTargetName() override { return "self target"; } - virtual bool isUseful() override { return CastTotemAction::isUseful(); } + CastTotemOfWrathAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "totem of wrath", "totem of wrath") {} +}; + +class CastFrostResistanceTotemAction : public CastTotemAction +{ +public: + CastFrostResistanceTotemAction(PlayerbotAI* botAI) + : CastTotemAction(botAI, "frost resistance totem", "frost resistance") {} }; class CastFireElementalTotemAction : public CastTotemAction { public: - CastFireElementalTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "fire elemental totem", "", 0.0f) {} + CastFireElementalTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "fire elemental totem", "") {} virtual std::string const GetTargetName() override { return "self target"; } virtual bool isUseful() override { return CastTotemAction::isUseful(); } }; @@ -430,7 +465,7 @@ public: class CastFireElementalTotemMeleeAction : public CastTotemAction { public: - CastFireElementalTotemMeleeAction(PlayerbotAI* ai) : CastTotemAction(ai, "fire elemental totem", "", 0.0f) {} + CastFireElementalTotemMeleeAction(PlayerbotAI* ai) : CastTotemAction(ai, "fire elemental totem", "") {} virtual std::string const GetTargetName() override { return "self target"; } virtual bool isUseful() override { @@ -441,21 +476,187 @@ public: } }; +class CastHealingStreamTotemAction : public CastTotemAction +{ +public: + CastHealingStreamTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "healing stream totem", "") {} +}; + +class CastManaSpringTotemAction : public CastTotemAction +{ +public: + CastManaSpringTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "mana spring totem", "mana spring") {} +}; + +class CastCleansingTotemAction : public CastTotemAction +{ +public: + CastCleansingTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "cleansing totem", "") {} + virtual bool isUseful(); +}; + +class CastManaTideTotemAction : public CastTotemAction +{ +public: + CastManaTideTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "mana tide totem", "") {} + std::string const GetTargetName() override { return "self target"; } +}; + +class CastFireResistanceTotemAction : public CastTotemAction +{ +public: + CastFireResistanceTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "fire resistance totem", "fire resistance") {} +}; + class CastWrathOfAirTotemAction : public CastTotemAction { public: CastWrathOfAirTotemAction(PlayerbotAI* ai) : CastTotemAction(ai, "wrath of air totem", "wrath of air totem") {} }; -class CastShamanisticRageAction : public CastBuffSpellAction +class CastWindfuryTotemAction : public CastTotemAction { public: - CastShamanisticRageAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "shamanistic rage") {} + CastWindfuryTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "windfury totem", "windfury totem") {} }; -class CastFeralSpiritAction : public CastSpellAction +class CastNatureResistanceTotemAction : public CastTotemAction { public: - CastFeralSpiritAction(PlayerbotAI* ai) : CastSpellAction(ai, "feral spirit") {} + CastNatureResistanceTotemAction(PlayerbotAI* botAI) : CastTotemAction(botAI, "nature resistance totem", "nature resistance") {} }; + +// Set Strategy Assigned Totems + +class SetTotemAction : public Action +{ +public: + SetTotemAction(PlayerbotAI* botAI, std::string const totemName, const uint32 totemSpellIds[], int actionButtonId) + : Action(botAI, "set " + totemName), totemSpellIds(totemSpellIds), actionButtonId(actionButtonId) + { + } + bool Execute(Event event) override; + uint32 const* totemSpellIds; + int actionButtonId; +}; + +class SetStrengthOfEarthTotemAction : public SetTotemAction +{ +public: + SetStrengthOfEarthTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "strength of earth totem", STRENGTH_OF_EARTH_TOTEM, TOTEM_BAR_SLOT_EARTH) {} +}; + +class SetStoneskinTotemAction : public SetTotemAction +{ +public: + SetStoneskinTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "stoneskin totem", STONESKIN_TOTEM, TOTEM_BAR_SLOT_EARTH) {} +}; + +class SetTremorTotemAction : public SetTotemAction +{ +public: + SetTremorTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "tremor totem", TREMOR_TOTEM, TOTEM_BAR_SLOT_EARTH) {} +}; + +class SetEarthbindTotemAction : public SetTotemAction +{ +public: + SetEarthbindTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "earthbind totem", EARTHBIND_TOTEM, TOTEM_BAR_SLOT_EARTH) {} +}; + +class SetSearingTotemAction : public SetTotemAction +{ +public: + SetSearingTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "searing totem", SEARING_TOTEM, TOTEM_BAR_SLOT_FIRE) {} +}; + +class SetMagmaTotemAction : public SetTotemAction +{ +public: + SetMagmaTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "magma totem", MAGMA_TOTEM, TOTEM_BAR_SLOT_FIRE) {} +}; + +class SetFlametongueTotemAction : public SetTotemAction +{ +public: + SetFlametongueTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "flametongue totem", FLAMETONGUE_TOTEM, TOTEM_BAR_SLOT_FIRE) {} +}; + +class SetTotemOfWrathAction : public SetTotemAction +{ +public: + SetTotemOfWrathAction(PlayerbotAI* ai) + : SetTotemAction(ai, "totem of wrath", TOTEM_OF_WRATH, TOTEM_BAR_SLOT_FIRE) {} +}; + +class SetFrostResistanceTotemAction : public SetTotemAction +{ +public: + SetFrostResistanceTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "frost resistance totem", FROST_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_FIRE) {} +}; + +class SetHealingStreamTotemAction : public SetTotemAction +{ +public: + SetHealingStreamTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "healing stream totem", HEALING_STREAM_TOTEM, TOTEM_BAR_SLOT_WATER) {} +}; + +class SetManaSpringTotemAction : public SetTotemAction +{ +public: + SetManaSpringTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "mana spring totem", MANA_SPRING_TOTEM, TOTEM_BAR_SLOT_WATER) {} +}; + +class SetCleansingTotemAction : public SetTotemAction +{ +public: + SetCleansingTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "cleansing totem", CLEANSING_TOTEM, TOTEM_BAR_SLOT_WATER) {} +}; + +class SetFireResistanceTotemAction : public SetTotemAction +{ +public: + SetFireResistanceTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "fire resistance totem", FIRE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_WATER) {} +}; + +class SetWrathOfAirTotemAction : public SetTotemAction +{ +public: + SetWrathOfAirTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "wrath of air totem", WRATH_OF_AIR_TOTEM, TOTEM_BAR_SLOT_AIR) {} +}; + +class SetWindfuryTotemAction : public SetTotemAction +{ +public: + SetWindfuryTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "windfury totem", WINDFURY_TOTEM, TOTEM_BAR_SLOT_AIR) {} +}; + +class SetNatureResistanceTotemAction : public SetTotemAction +{ +public: + SetNatureResistanceTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "nature resistance totem", NATURE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_AIR) {} +}; + +class SetGroundingTotemAction : public SetTotemAction +{ +public: + SetGroundingTotemAction(PlayerbotAI* ai) + : SetTotemAction(ai, "grounding totem", GROUNDING_TOTEM, TOTEM_BAR_SLOT_AIR) {} +}; + #endif diff --git a/src/strategy/shaman/ShamanAiObjectContext.cpp b/src/strategy/shaman/ShamanAiObjectContext.cpp index 182251d1..0c307f44 100644 --- a/src/strategy/shaman/ShamanAiObjectContext.cpp +++ b/src/strategy/shaman/ShamanAiObjectContext.cpp @@ -5,10 +5,10 @@ #include "ShamanAiObjectContext.h" -#include "CasterShamanStrategy.h" +#include "ElementalShamanStrategy.h" #include "GenericShamanStrategy.h" -#include "HealShamanStrategy.h" -#include "MeleeShamanStrategy.h" +#include "RestoShamanStrategy.h" +#include "EnhancementShamanStrategy.h" #include "NamedObjectContext.h" #include "Playerbots.h" #include "ShamanActions.h" @@ -22,34 +22,18 @@ public: ShamanStrategyFactoryInternal() { creators["nc"] = &ShamanStrategyFactoryInternal::nc; - creators["totems"] = &ShamanStrategyFactoryInternal::totems; - creators["melee aoe"] = &ShamanStrategyFactoryInternal::melee_aoe; - creators["caster aoe"] = &ShamanStrategyFactoryInternal::caster_aoe; + creators["aoe"] = &ShamanStrategyFactoryInternal::aoe; creators["cure"] = &ShamanStrategyFactoryInternal::cure; creators["healer dps"] = &ShamanStrategyFactoryInternal::healer_dps; + creators["boost"] = &ShamanStrategyFactoryInternal::boost; } private: static Strategy* nc(PlayerbotAI* botAI) { return new ShamanNonCombatStrategy(botAI); } - static Strategy* totems(PlayerbotAI* botAI) { return new TotemsShamanStrategy(botAI); } - static Strategy* melee_aoe(PlayerbotAI* botAI) { return new MeleeAoeShamanStrategy(botAI); } - static Strategy* caster_aoe(PlayerbotAI* botAI) { return new CasterAoeShamanStrategy(botAI); } + static Strategy* aoe(PlayerbotAI* botAI) { return new ShamanAoeStrategy(botAI); } static Strategy* cure(PlayerbotAI* botAI) { return new ShamanCureStrategy(botAI); } static Strategy* healer_dps(PlayerbotAI* botAI) { return new ShamanHealerDpsStrategy(botAI); } -}; - -class ShamanBuffStrategyFactoryInternal : public NamedObjectContext -{ -public: - ShamanBuffStrategyFactoryInternal() : NamedObjectContext(false, true) - { - creators["bmana"] = &ShamanBuffStrategyFactoryInternal::bmana; - creators["bdps"] = &ShamanBuffStrategyFactoryInternal::bdps; - } - -private: - static Strategy* bmana(PlayerbotAI* botAI) { return new ShamanBuffManaStrategy(botAI); } - static Strategy* bdps(PlayerbotAI* botAI) { return new ShamanBuffDpsStrategy(botAI); } + static Strategy* boost(PlayerbotAI* botAI) { return new ShamanBoostStrategy(botAI); } }; class ShamanCombatStrategyFactoryInternal : public NamedObjectContext @@ -57,16 +41,89 @@ class ShamanCombatStrategyFactoryInternal : public NamedObjectContext public: ShamanCombatStrategyFactoryInternal() : NamedObjectContext(false, true) { - creators["heal"] = &ShamanCombatStrategyFactoryInternal::heal; - creators["melee"] = &ShamanCombatStrategyFactoryInternal::dps; - creators["dps"] = &ShamanCombatStrategyFactoryInternal::dps; - creators["caster"] = &ShamanCombatStrategyFactoryInternal::caster; + creators["resto"] = &ShamanCombatStrategyFactoryInternal::resto; + creators["enh"] = &ShamanCombatStrategyFactoryInternal::enh; + creators["ele"] = &ShamanCombatStrategyFactoryInternal::ele; } private: - static Strategy* heal(PlayerbotAI* botAI) { return new HealShamanStrategy(botAI); } - static Strategy* dps(PlayerbotAI* botAI) { return new MeleeShamanStrategy(botAI); } - static Strategy* caster(PlayerbotAI* botAI) { return new CasterShamanStrategy(botAI); } + static Strategy* resto(PlayerbotAI* botAI) { return new RestoShamanStrategy(botAI); } + static Strategy* enh(PlayerbotAI* botAI) { return new EnhancementShamanStrategy(botAI); } + static Strategy* ele(PlayerbotAI* botAI) { return new ElementalShamanStrategy(botAI); } +}; + +class ShamanEarthTotemStrategyFactoryInternal : public NamedObjectContext +{ +public: + ShamanEarthTotemStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["strength of earth"] = &ShamanEarthTotemStrategyFactoryInternal::strength_of_earth_totem; + creators["stoneskin"] = &ShamanEarthTotemStrategyFactoryInternal::stoneclaw_totem; + creators["tremor"] = &ShamanEarthTotemStrategyFactoryInternal::earth_totem; + creators["earthbind"] = &ShamanEarthTotemStrategyFactoryInternal::earthbind_totem; + } + +private: + static Strategy* strength_of_earth_totem(PlayerbotAI* botAI) { return new StrengthOfEarthTotemStrategy(botAI); } + static Strategy* stoneclaw_totem(PlayerbotAI* botAI) { return new StoneclawTotemStrategy(botAI); } + static Strategy* earth_totem(PlayerbotAI* botAI) { return new EarthTotemStrategy(botAI); } + static Strategy* earthbind_totem(PlayerbotAI* botAI) { return new EarthbindTotemStrategy(botAI); } +}; + +class ShamanFireTotemStrategyFactoryInternal : public NamedObjectContext +{ +public: + ShamanFireTotemStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["searing"] = &ShamanFireTotemStrategyFactoryInternal::searing_totem; + creators["magma"] = &ShamanFireTotemStrategyFactoryInternal::magma_totem; + creators["flametongue"] = &ShamanFireTotemStrategyFactoryInternal::flametongue_totem; + creators["wrath"] = &ShamanFireTotemStrategyFactoryInternal::totem_of_wrath; + creators["frost resistance"] = &ShamanFireTotemStrategyFactoryInternal::frost_resistance_totem; + } + +private: + static Strategy* searing_totem(PlayerbotAI* botAI) { return new SearingTotemStrategy(botAI); } + static Strategy* magma_totem(PlayerbotAI* botAI) { return new MagmaTotemStrategy(botAI); } + static Strategy* flametongue_totem(PlayerbotAI* botAI) { return new FlametongueTotemStrategy(botAI); } + static Strategy* totem_of_wrath(PlayerbotAI* botAI) { return new TotemOfWrathStrategy(botAI); } + static Strategy* frost_resistance_totem(PlayerbotAI* botAI) { return new FrostResistanceTotemStrategy(botAI); } +}; + +class ShamanWaterTotemStrategyFactoryInternal : public NamedObjectContext +{ +public: + ShamanWaterTotemStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["healing stream"] = &ShamanWaterTotemStrategyFactoryInternal::healing_stream_totem; + creators["mana spring"] = &ShamanWaterTotemStrategyFactoryInternal::mana_spring_totem; + creators["cleansing"] = &ShamanWaterTotemStrategyFactoryInternal::cleansing_totem; + creators["fire resistance"] = &ShamanWaterTotemStrategyFactoryInternal::fire_resistance_totem; + } + +private: + static Strategy* healing_stream_totem(PlayerbotAI* botAI) { return new HealingStreamTotemStrategy(botAI); } + static Strategy* mana_spring_totem(PlayerbotAI* botAI) { return new ManaSpringTotemStrategy(botAI); } + static Strategy* cleansing_totem(PlayerbotAI* botAI) { return new CleansingTotemStrategy(botAI); } + static Strategy* fire_resistance_totem(PlayerbotAI* botAI) { return new FireResistanceTotemStrategy(botAI); } +}; + +class ShamanAirTotemStrategyFactoryInternal : public NamedObjectContext +{ +public: + ShamanAirTotemStrategyFactoryInternal() : NamedObjectContext(false, true) + { + creators["wrath of air"] = &ShamanAirTotemStrategyFactoryInternal::wrath_of_air_totem; + creators["windfury"] = &ShamanAirTotemStrategyFactoryInternal::windfury_totem; + creators["nature resistance"] = &ShamanAirTotemStrategyFactoryInternal::nature_resistance_totem; + creators["grounding"] = &ShamanAirTotemStrategyFactoryInternal::grounding_totem; + } + +private: + static Strategy* wrath_of_air_totem(PlayerbotAI* botAI) { return new WrathOfAirTotemStrategy(botAI); } + static Strategy* windfury_totem(PlayerbotAI* botAI) { return new WindfuryTotemStrategy(botAI); } + static Strategy* nature_resistance_totem(PlayerbotAI* botAI) { return new NatureResistanceTotemStrategy(botAI); } + static Strategy* grounding_totem(PlayerbotAI* botAI) { return new GroundingTotemStrategy(botAI); } }; class ShamanATriggerFactoryInternal : public NamedObjectContext @@ -74,17 +131,8 @@ class ShamanATriggerFactoryInternal : public NamedObjectContext public: ShamanATriggerFactoryInternal() { - creators["grace of air totem"] = &ShamanATriggerFactoryInternal::grace_of_air_totem; - creators["windfury totem"] = &ShamanATriggerFactoryInternal::windfury_totem; - creators["mana spring totem"] = &ShamanATriggerFactoryInternal::mana_spring_totem; - creators["flametongue totem"] = &ShamanATriggerFactoryInternal::flametongue_totem; - creators["strength of earth totem"] = &ShamanATriggerFactoryInternal::strength_of_earth_totem; - creators["fire elemental totem"] = &ShamanATriggerFactoryInternal::fire_elemental_totem; - creators["magma totem"] = &ShamanATriggerFactoryInternal::magma_totem; - creators["searing totem"] = &ShamanATriggerFactoryInternal::searing_totem; creators["wind shear"] = &ShamanATriggerFactoryInternal::wind_shear; creators["purge"] = &ShamanATriggerFactoryInternal::purge; - // creators["shaman weapon"] = &ShamanATriggerFactoryInternal::shaman_weapon; creators["main hand weapon no imbue"] = &ShamanATriggerFactoryInternal::main_hand_weapon_no_imbue; creators["off hand weapon no imbue"] = &ShamanATriggerFactoryInternal::off_hand_weapon_no_imbue; creators["water shield"] = &ShamanATriggerFactoryInternal::water_shield; @@ -109,15 +157,41 @@ public: creators["party member cure poison"] = &ShamanATriggerFactoryInternal::party_member_cure_poison; creators["cure disease"] = &ShamanATriggerFactoryInternal::cure_disease; creators["party member cure disease"] = &ShamanATriggerFactoryInternal::party_member_cure_disease; - creators["no fire totem"] = &ShamanATriggerFactoryInternal::no_fire_totem; - creators["no water totem"] = &ShamanATriggerFactoryInternal::no_water_totem; - creators["no air totem"] = &ShamanATriggerFactoryInternal::no_air_totem; creators["earth shield on main tank"] = &ShamanATriggerFactoryInternal::earth_shield_on_main_tank; creators["maelstrom weapon 3"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_3; creators["maelstrom weapon 4"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_4; creators["maelstrom weapon 5"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_5; creators["flame shock"] = &ShamanATriggerFactoryInternal::flame_shock; - creators["wrath of air totem"] = &ShamanATriggerFactoryInternal::wrath_of_air_totem; + creators["fire elemental totem"] = &ShamanATriggerFactoryInternal::fire_elemental_totem; + creators["earth shock execute"] = &ShamanATriggerFactoryInternal::earth_shock_execute; + creators["spirit walk ready"] = &ShamanATriggerFactoryInternal::spirit_walk_ready; + creators["chain lightning no cd"] = &ShamanATriggerFactoryInternal::chain_lightning_no_cd; + creators["call of the elements and enemy within melee"] = &ShamanATriggerFactoryInternal::call_of_the_elements_and_enemy_within_melee; + creators["maelstrom weapon 5 and medium aoe"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_5_and_medium_aoe; + creators["maelstrom weapon 4 and medium aoe"] = &ShamanATriggerFactoryInternal::maelstrom_weapon_4_and_medium_aoe; + creators["call of the elements"] = &ShamanATriggerFactoryInternal::call_of_the_elements; + creators["totemic recall"] = &ShamanATriggerFactoryInternal::totemic_recall; + creators["no earth totem"] = &ShamanATriggerFactoryInternal::no_earth_totem; + creators["no fire totem"] = &ShamanATriggerFactoryInternal::no_fire_totem; + creators["no water totem"] = &ShamanATriggerFactoryInternal::no_water_totem; + creators["no air totem"] = &ShamanATriggerFactoryInternal::no_air_totem; + creators["set strength of earth totem"] = &ShamanATriggerFactoryInternal::set_strength_of_earth_totem; + creators["set stoneskin totem"] = &ShamanATriggerFactoryInternal::set_stoneskin_totem; + creators["set tremor totem"] = &ShamanATriggerFactoryInternal::set_tremor_totem; + creators["set earthbind totem"] = &ShamanATriggerFactoryInternal::set_earthbind_totem; + creators["set searing totem"] = &ShamanATriggerFactoryInternal::set_searing_totem; + creators["set magma totem"] = &ShamanATriggerFactoryInternal::set_magma_totem; + creators["set flametongue totem"] = &ShamanATriggerFactoryInternal::set_flametongue_totem; + creators["set totem of wrath"] = &ShamanATriggerFactoryInternal::set_totem_of_wrath; + creators["set frost resistance totem"] = &ShamanATriggerFactoryInternal::set_frost_resistance_totem; + creators["set healing stream totem"] = &ShamanATriggerFactoryInternal::set_healing_stream_totem; + creators["set mana spring totem"] = &ShamanATriggerFactoryInternal::set_mana_spring_totem; + creators["set cleansing totem"] = &ShamanATriggerFactoryInternal::set_cleansing_totem; + creators["set fire resistance totem"] = &ShamanATriggerFactoryInternal::set_fire_resistance_totem; + creators["set wrath of air totem"] = &ShamanATriggerFactoryInternal::set_wrath_of_air_totem; + creators["set windfury totem"] = &ShamanATriggerFactoryInternal::set_windfury_totem; + creators["set nature resistance totem"] = &ShamanATriggerFactoryInternal::set_nature_resistance_totem; + creators["set grounding totem"] = &ShamanATriggerFactoryInternal::set_grounding_totem; } private: @@ -127,18 +201,9 @@ private: static Trigger* heroism(PlayerbotAI* botAI) { return new HeroismTrigger(botAI); } static Trigger* bloodlust(PlayerbotAI* botAI) { return new BloodlustTrigger(botAI); } static Trigger* elemental_mastery(PlayerbotAI* botAI) { return new ElementalMasteryTrigger(botAI); } - static Trigger* party_member_cleanse_disease(PlayerbotAI* botAI) - { - return new PartyMemberCleanseSpiritDiseaseTrigger(botAI); - } - static Trigger* party_member_cleanse_curse(PlayerbotAI* botAI) - { - return new PartyMemberCleanseSpiritCurseTrigger(botAI); - } - static Trigger* party_member_cleanse_poison(PlayerbotAI* botAI) - { - return new PartyMemberCleanseSpiritPoisonTrigger(botAI); - } + static Trigger* party_member_cleanse_disease(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritDiseaseTrigger(botAI); } + static Trigger* party_member_cleanse_curse(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritCurseTrigger(botAI); } + static Trigger* party_member_cleanse_poison(PlayerbotAI* botAI) { return new PartyMemberCleanseSpiritPoisonTrigger(botAI); } static Trigger* cleanse_disease(PlayerbotAI* botAI) { return new CleanseSpiritDiseaseTrigger(botAI); } static Trigger* cleanse_curse(PlayerbotAI* botAI) { return new CleanseSpiritCurseTrigger(botAI); } static Trigger* cleanse_poison(PlayerbotAI* botAI) { return new CleanseSpiritPoisonTrigger(botAI); } @@ -146,37 +211,51 @@ private: static Trigger* water_walking(PlayerbotAI* botAI) { return new WaterWalkingTrigger(botAI); } static Trigger* water_breathing_on_party(PlayerbotAI* botAI) { return new WaterBreathingOnPartyTrigger(botAI); } static Trigger* water_walking_on_party(PlayerbotAI* botAI) { return new WaterWalkingOnPartyTrigger(botAI); } - static Trigger* windfury_totem(PlayerbotAI* botAI) { return new WindfuryTotemTrigger(botAI); } - static Trigger* grace_of_air_totem(PlayerbotAI* botAI) { return new GraceOfAirTotemTrigger(botAI); } - static Trigger* mana_spring_totem(PlayerbotAI* botAI) { return new ManaSpringTotemTrigger(botAI); } - static Trigger* flametongue_totem(PlayerbotAI* botAI) { return new FlametongueTotemTrigger(botAI); } - static Trigger* strength_of_earth_totem(PlayerbotAI* botAI) { return new StrengthOfEarthTotemTrigger(botAI); } - static Trigger* fire_elemental_totem(PlayerbotAI* botAI) { return new FireElementalTotemTrigger(botAI); } - static Trigger* magma_totem(PlayerbotAI* botAI) { return new MagmaTotemTrigger(botAI); } - static Trigger* searing_totem(PlayerbotAI* botAI) { return new SearingTotemTrigger(botAI); } static Trigger* wind_shear(PlayerbotAI* botAI) { return new WindShearInterruptSpellTrigger(botAI); } static Trigger* purge(PlayerbotAI* botAI) { return new PurgeTrigger(botAI); } - // static Trigger* shaman_weapon(PlayerbotAI* botAI) { return new ShamanWeaponTrigger(botAI); } static Trigger* main_hand_weapon_no_imbue(PlayerbotAI* botAI) { return new MainHandWeaponNoImbueTrigger(botAI); } static Trigger* off_hand_weapon_no_imbue(PlayerbotAI* botAI) { return new OffHandWeaponNoImbueTrigger(botAI); } static Trigger* water_shield(PlayerbotAI* botAI) { return new WaterShieldTrigger(botAI); } static Trigger* lightning_shield(PlayerbotAI* botAI) { return new LightningShieldTrigger(botAI); } static Trigger* shock(PlayerbotAI* botAI) { return new ShockTrigger(botAI); } static Trigger* frost_shock_snare(PlayerbotAI* botAI) { return new FrostShockSnareTrigger(botAI); } - static Trigger* wind_shear_on_enemy_healer(PlayerbotAI* botAI) - { - return new WindShearInterruptEnemyHealerSpellTrigger(botAI); - } + static Trigger* wind_shear_on_enemy_healer(PlayerbotAI* botAI) { return new WindShearInterruptEnemyHealerSpellTrigger(botAI); } static Trigger* cure_poison(PlayerbotAI* botAI) { return new CurePoisonTrigger(botAI); } static Trigger* party_member_cure_poison(PlayerbotAI* botAI) { return new PartyMemberCurePoisonTrigger(botAI); } static Trigger* cure_disease(PlayerbotAI* botAI) { return new CureDiseaseTrigger(botAI); } static Trigger* party_member_cure_disease(PlayerbotAI* botAI) { return new PartyMemberCureDiseaseTrigger(botAI); } + static Trigger* earth_shield_on_main_tank(PlayerbotAI* ai) { return new EarthShieldOnMainTankTrigger(ai); } + static Trigger* flame_shock(PlayerbotAI* ai) { return new FlameShockTrigger(ai); } + static Trigger* fire_elemental_totem(PlayerbotAI* botAI) { return new FireElementalTotemTrigger(botAI); } + static Trigger* earth_shock_execute(PlayerbotAI* botAI) { return new EarthShockExecuteTrigger(botAI); } + static Trigger* spirit_walk_ready(PlayerbotAI* ai) { return new SpiritWalkTrigger(ai); } + static Trigger* chain_lightning_no_cd(PlayerbotAI* ai) { return new ChainLightningNoCdTrigger(ai); } + static Trigger* call_of_the_elements_and_enemy_within_melee(PlayerbotAI* ai) { return new CallOfTheElementsAndEnemyWithinMeleeTrigger(ai); } + static Trigger* maelstrom_weapon_5_and_medium_aoe(PlayerbotAI* ai) { return new MaelstromWeapon5AndMediumAoeTrigger(ai); } + static Trigger* maelstrom_weapon_4_and_medium_aoe(PlayerbotAI* ai) { return new MaelstromWeapon4AndMediumAoeTrigger(ai); } + static Trigger* call_of_the_elements(PlayerbotAI* ai) { return new CallOfTheElementsTrigger(ai); } + static Trigger* totemic_recall(PlayerbotAI* ai) { return new TotemicRecallTrigger(ai); } + static Trigger* no_earth_totem(PlayerbotAI* ai) { return new NoEarthTotemTrigger(ai); } static Trigger* no_fire_totem(PlayerbotAI* ai) { return new NoFireTotemTrigger(ai); } static Trigger* no_water_totem(PlayerbotAI* ai) { return new NoWaterTotemTrigger(ai); } static Trigger* no_air_totem(PlayerbotAI* ai) { return new NoAirTotemTrigger(ai); } - static Trigger* earth_shield_on_main_tank(PlayerbotAI* ai) { return new EarthShieldOnMainTankTrigger(ai); } - static Trigger* flame_shock(PlayerbotAI* ai) { return new FlameShockTrigger(ai); } - static Trigger* wrath_of_air_totem(PlayerbotAI* ai) { return new WrathOfAirTotemTrigger(ai); } + static Trigger* set_strength_of_earth_totem(PlayerbotAI* ai) { return new SetStrengthOfEarthTotemTrigger(ai); } + static Trigger* set_stoneskin_totem(PlayerbotAI* ai) { return new SetStoneskinTotemTrigger(ai); } + static Trigger* set_tremor_totem(PlayerbotAI* ai) { return new SetTremorTotemTrigger(ai); } + static Trigger* set_earthbind_totem(PlayerbotAI* ai) { return new SetEarthbindTotemTrigger(ai); } + static Trigger* set_searing_totem(PlayerbotAI* ai) { return new SetSearingTotemTrigger(ai); } + static Trigger* set_magma_totem(PlayerbotAI* ai) { return new SetMagmaTotemTrigger(ai); } + static Trigger* set_flametongue_totem(PlayerbotAI* ai) { return new SetFlametongueTotemTrigger(ai); } + static Trigger* set_totem_of_wrath(PlayerbotAI* ai) { return new SetTotemOfWrathTrigger(ai); } + static Trigger* set_frost_resistance_totem(PlayerbotAI* ai) { return new SetFrostResistanceTotemTrigger(ai); } + static Trigger* set_healing_stream_totem(PlayerbotAI* ai) { return new SetHealingStreamTotemTrigger(ai); } + static Trigger* set_mana_spring_totem(PlayerbotAI* ai) { return new SetManaSpringTotemTrigger(ai); } + static Trigger* set_cleansing_totem(PlayerbotAI* ai) { return new SetCleansingTotemTrigger(ai); } + static Trigger* set_fire_resistance_totem(PlayerbotAI* ai) { return new SetFireResistanceTotemTrigger(ai); } + static Trigger* set_wrath_of_air_totem(PlayerbotAI* ai) { return new SetWrathOfAirTotemTrigger(ai); } + static Trigger* set_windfury_totem(PlayerbotAI* ai) { return new SetWindfuryTotemTrigger(ai); } + static Trigger* set_nature_resistance_totem(PlayerbotAI* ai) { return new SetNatureResistanceTotemTrigger(ai); } + static Trigger* set_grounding_totem(PlayerbotAI* ai) { return new SetGroundingTotemTrigger(ai); } }; class ShamanAiObjectContextInternal : public NamedObjectContext @@ -186,16 +265,6 @@ public: { creators["water shield"] = &ShamanAiObjectContextInternal::water_shield; creators["lightning shield"] = &ShamanAiObjectContextInternal::lightning_shield; - creators["strength of earth totem"] = &ShamanAiObjectContextInternal::strength_of_earth_totem; - creators["flametongue totem"] = &ShamanAiObjectContextInternal::flametongue_totem; - creators["searing totem"] = &ShamanAiObjectContextInternal::searing_totem; - creators["magma totem"] = &ShamanAiObjectContextInternal::magma_totem; - creators["windfury totem"] = &ShamanAiObjectContextInternal::windfury_totem; - creators["grace of air totem"] = &ShamanAiObjectContextInternal::grace_of_air_totem; - creators["mana spring totem"] = &ShamanAiObjectContextInternal::mana_spring_totem; - creators["mana tide totem"] = &ShamanAiObjectContextInternal::mana_tide_totem; - creators["earthbind totem"] = &ShamanAiObjectContextInternal::earthbind_totem; - creators["healing stream totem"] = &ShamanAiObjectContextInternal::healing_stream_totem; creators["wind shear"] = &ShamanAiObjectContextInternal::wind_shear; creators["wind shear on enemy healer"] = &ShamanAiObjectContextInternal::wind_shear_on_enemy_healer; creators["rockbiter weapon"] = &ShamanAiObjectContextInternal::rockbiter_weapon; @@ -240,12 +309,48 @@ public: creators["cure poison on party"] = &ShamanAiObjectContextInternal::cure_poison_on_party; creators["lava burst"] = &ShamanAiObjectContextInternal::lava_burst; creators["earth shield on main tank"] = &ShamanAiObjectContextInternal::earth_shield_on_main_tank; - creators["fire elemental totem"] = &ShamanAiObjectContextInternal::fire_elemental_totem; - creators["fire elemental totem melee"] = &ShamanAiObjectContextInternal::fire_elemental_totem_melee; - creators["totem of wrath"] = &ShamanAiObjectContextInternal::totem_of_wrath; - creators["wrath of air totem"] = &ShamanAiObjectContextInternal::wrath_of_air_totem; creators["shamanistic rage"] = &ShamanAiObjectContextInternal::shamanistic_rage; creators["feral spirit"] = &ShamanAiObjectContextInternal::feral_spirit; + creators["spirit walk"] = &ShamanAiObjectContextInternal::spirit_walk; + creators["call of the elements"] = &ShamanAiObjectContextInternal::call_of_the_elements; + creators["totemic recall"] = &ShamanAiObjectContextInternal::totemic_recall; + creators["strength of earth totem"] = &ShamanAiObjectContextInternal::strength_of_earth_totem; + creators["stoneskin totem"] = &ShamanAiObjectContextInternal::stoneskin_totem; + creators["tremor totem"] = &ShamanAiObjectContextInternal::tremor_totem; + creators["earthbind totem"] = &ShamanAiObjectContextInternal::earthbind_totem; + creators["stoneclaw totem"] = &ShamanAiObjectContextInternal::stoneclaw_totem; + creators["searing totem"] = &ShamanAiObjectContextInternal::searing_totem; + creators["magma totem"] = &ShamanAiObjectContextInternal::magma_totem; + creators["flametongue totem"] = &ShamanAiObjectContextInternal::flametongue_totem; + creators["totem of wrath"] = &ShamanAiObjectContextInternal::totem_of_wrath; + creators["frost resistance totem"] = &ShamanAiObjectContextInternal::frost_resistance_totem; + creators["fire elemental totem"] = &ShamanAiObjectContextInternal::fire_elemental_totem; + creators["fire elemental totem melee"] = &ShamanAiObjectContextInternal::fire_elemental_totem_melee; + creators["healing stream totem"] = &ShamanAiObjectContextInternal::healing_stream_totem; + creators["mana spring totem"] = &ShamanAiObjectContextInternal::mana_spring_totem; + creators["cleansing totem"] = &ShamanAiObjectContextInternal::cleansing_totem; + creators["mana tide totem"] = &ShamanAiObjectContextInternal::mana_tide_totem; + creators["fire resistance totem"] = &ShamanAiObjectContextInternal::fire_resistance_totem; + creators["wrath of air totem"] = &ShamanAiObjectContextInternal::wrath_of_air_totem; + creators["windfury totem"] = &ShamanAiObjectContextInternal::windfury_totem; + creators["nature resistance totem"] = &ShamanAiObjectContextInternal::nature_resistance_totem; + creators["set strength of earth totem"] = &ShamanAiObjectContextInternal::set_strength_of_earth_totem; + creators["set stoneskin totem"] = &ShamanAiObjectContextInternal::set_stoneskin_totem; + creators["set tremor totem"] = &ShamanAiObjectContextInternal::set_tremor_totem; + creators["set earthbind totem"] = &ShamanAiObjectContextInternal::set_earthbind_totem; + creators["set searing totem"] = &ShamanAiObjectContextInternal::set_searing_totem; + creators["set magma totem"] = &ShamanAiObjectContextInternal::set_magma_totem; + creators["set flametongue totem"] = &ShamanAiObjectContextInternal::set_flametongue_totem; + creators["set totem of wrath"] = &ShamanAiObjectContextInternal::set_totem_of_wrath; + creators["set frost resistance totem"] = &ShamanAiObjectContextInternal::set_frost_resistance_totem; + creators["set healing stream totem"] = &ShamanAiObjectContextInternal::set_healing_stream_totem; + creators["set mana spring totem"] = &ShamanAiObjectContextInternal::set_mana_spring_totem; + creators["set cleansing totem"] = &ShamanAiObjectContextInternal::set_cleansing_totem; + creators["set fire resistance totem"] = &ShamanAiObjectContextInternal::set_fire_resistance_totem; + creators["set wrath of air totem"] = &ShamanAiObjectContextInternal::set_wrath_of_air_totem; + creators["set windfury totem"] = &ShamanAiObjectContextInternal::set_windfury_totem; + creators["set nature resistance totem"] = &ShamanAiObjectContextInternal::set_nature_resistance_totem; + creators["set grounding totem"] = &ShamanAiObjectContextInternal::set_grounding_totem; } private: @@ -258,18 +363,9 @@ private: static Action* frost_shock(PlayerbotAI* botAI) { return new CastFrostShockAction(botAI); } static Action* earth_shock(PlayerbotAI* botAI) { return new CastEarthShockAction(botAI); } static Action* flame_shock(PlayerbotAI* botAI) { return new CastFlameShockAction(botAI); } - static Action* cleanse_spirit_poison_on_party(PlayerbotAI* botAI) - { - return new CastCleanseSpiritPoisonOnPartyAction(botAI); - } - static Action* cleanse_spirit_disease_on_party(PlayerbotAI* botAI) - { - return new CastCleanseSpiritDiseaseOnPartyAction(botAI); - } - static Action* cleanse_spirit_curse_on_party(PlayerbotAI* botAI) - { - return new CastCleanseSpiritCurseOnPartyAction(botAI); - } + static Action* cleanse_spirit_poison_on_party(PlayerbotAI* botAI) { return new CastCleanseSpiritPoisonOnPartyAction(botAI); } + static Action* cleanse_spirit_disease_on_party(PlayerbotAI* botAI) { return new CastCleanseSpiritDiseaseOnPartyAction(botAI); } + static Action* cleanse_spirit_curse_on_party(PlayerbotAI* botAI) { return new CastCleanseSpiritCurseOnPartyAction(botAI); } static Action* cleanse_spirit(PlayerbotAI* botAI) { return new CastCleanseSpiritAction(botAI); } static Action* water_walking(PlayerbotAI* botAI) { return new CastWaterWalkingAction(botAI); } static Action* water_breathing(PlayerbotAI* botAI) { return new CastWaterBreathingAction(botAI); } @@ -277,17 +373,7 @@ private: static Action* water_breathing_on_party(PlayerbotAI* botAI) { return new CastWaterBreathingOnPartyAction(botAI); } static Action* water_shield(PlayerbotAI* botAI) { return new CastWaterShieldAction(botAI); } static Action* lightning_shield(PlayerbotAI* botAI) { return new CastLightningShieldAction(botAI); } - static Action* strength_of_earth_totem(PlayerbotAI* botAI) { return new CastStrengthOfEarthTotemAction(botAI); } - static Action* flametongue_totem(PlayerbotAI* botAI) { return new CastFlametongueTotemAction(botAI); } - static Action* magma_totem(PlayerbotAI* botAI) { return new CastMagmaTotemAction(botAI); } - static Action* searing_totem(PlayerbotAI* botAI) { return new CastSearingTotemAction(botAI); } static Action* fire_nova(PlayerbotAI* botAI) { return new CastFireNovaAction(botAI); } - static Action* windfury_totem(PlayerbotAI* botAI) { return new CastWindfuryTotemAction(botAI); } - static Action* grace_of_air_totem(PlayerbotAI* botAI) { return new CastGraceOfAirTotemAction(botAI); } - static Action* mana_spring_totem(PlayerbotAI* botAI) { return new CastManaSpringTotemAction(botAI); } - static Action* mana_tide_totem(PlayerbotAI* botAI) { return new CastManaTideTotemAction(botAI); } - static Action* earthbind_totem(PlayerbotAI* botAI) { return new CastEarthbindTotemAction(botAI); } - static Action* healing_stream_totem(PlayerbotAI* botAI) { return new CastHealingStreamTotemAction(botAI); } static Action* wind_shear(PlayerbotAI* botAI) { return new CastWindShearAction(botAI); } static Action* rockbiter_weapon(PlayerbotAI* botAI) { return new CastRockbiterWeaponAction(botAI); } static Action* flametongue_weapon(PlayerbotAI* botAI) { return new CastFlametongueWeaponAction(botAI); } @@ -298,10 +384,7 @@ private: static Action* healing_wave(PlayerbotAI* botAI) { return new CastHealingWaveAction(botAI); } static Action* lesser_healing_wave(PlayerbotAI* botAI) { return new CastLesserHealingWaveAction(botAI); } static Action* healing_wave_on_party(PlayerbotAI* botAI) { return new CastHealingWaveOnPartyAction(botAI); } - static Action* lesser_healing_wave_on_party(PlayerbotAI* botAI) - { - return new CastLesserHealingWaveOnPartyAction(botAI); - } + static Action* lesser_healing_wave_on_party(PlayerbotAI* botAI) { return new CastLesserHealingWaveOnPartyAction(botAI); } static Action* earth_shield(PlayerbotAI* botAI) { return new CastEarthShieldAction(botAI); } static Action* earth_shield_on_party(PlayerbotAI* botAI) { return new CastEarthShieldOnPartyAction(botAI); } static Action* chain_heal(PlayerbotAI* botAI) { return new CastChainHealAction(botAI); } @@ -310,22 +393,55 @@ private: static Action* stormstrike(PlayerbotAI* botAI) { return new CastStormstrikeAction(botAI); } static Action* lava_lash(PlayerbotAI* botAI) { return new CastLavaLashAction(botAI); } static Action* ancestral_spirit(PlayerbotAI* botAI) { return new CastAncestralSpiritAction(botAI); } - static Action* wind_shear_on_enemy_healer(PlayerbotAI* botAI) - { - return new CastWindShearOnEnemyHealerAction(botAI); - } + static Action* wind_shear_on_enemy_healer(PlayerbotAI* botAI) { return new CastWindShearOnEnemyHealerAction(botAI); } static Action* cure_poison(PlayerbotAI* botAI) { return new CastCurePoisonActionSham(botAI); } static Action* cure_poison_on_party(PlayerbotAI* botAI) { return new CastCurePoisonOnPartyActionSham(botAI); } static Action* cure_disease(PlayerbotAI* botAI) { return new CastCureDiseaseActionSham(botAI); } static Action* cure_disease_on_party(PlayerbotAI* botAI) { return new CastCureDiseaseOnPartyActionSham(botAI); } static Action* lava_burst(PlayerbotAI* ai) { return new CastLavaBurstAction(ai); } static Action* earth_shield_on_main_tank(PlayerbotAI* ai) { return new CastEarthShieldOnMainTankAction(ai); } - static Action* totem_of_wrath(PlayerbotAI* ai) { return new CastTotemOfWrathAction(ai); } - static Action* fire_elemental_totem(PlayerbotAI* ai) { return new CastFireElementalTotemAction(ai); } - static Action* fire_elemental_totem_melee(PlayerbotAI* ai) { return new CastFireElementalTotemMeleeAction(ai); } - static Action* wrath_of_air_totem(PlayerbotAI* ai) { return new CastWrathOfAirTotemAction(ai); } static Action* shamanistic_rage(PlayerbotAI* ai) { return new CastShamanisticRageAction(ai); } static Action* feral_spirit(PlayerbotAI* ai) { return new CastFeralSpiritAction(ai); } + static Action* spirit_walk(PlayerbotAI* ai) { return new CastSpiritWalkAction(ai); } + static Action* call_of_the_elements(PlayerbotAI* ai) { return new CastCallOfTheElementsAction(ai); } + static Action* totemic_recall(PlayerbotAI* ai) { return new CastTotemicRecallAction(ai); } + static Action* strength_of_earth_totem(PlayerbotAI* ai) { return new CastStrengthOfEarthTotemAction(ai); } + static Action* stoneskin_totem(PlayerbotAI* ai) { return new CastStoneskinTotemAction(ai); } + static Action* tremor_totem(PlayerbotAI* ai) { return new CastTremorTotemAction(ai); } + static Action* earthbind_totem(PlayerbotAI* ai) { return new CastEarthbindTotemAction(ai); } + static Action* stoneclaw_totem(PlayerbotAI* ai) { return new CastStoneclawTotemAction(ai); } + static Action* searing_totem(PlayerbotAI* ai) { return new CastSearingTotemAction(ai); } + static Action* magma_totem(PlayerbotAI* ai) { return new CastMagmaTotemAction(ai); } + static Action* flametongue_totem(PlayerbotAI* ai) { return new CastFlametongueTotemAction(ai); } + static Action* totem_of_wrath(PlayerbotAI* ai) { return new CastTotemOfWrathAction(ai); } + static Action* frost_resistance_totem(PlayerbotAI* ai) { return new CastFrostResistanceTotemAction(ai); } + static Action* fire_elemental_totem(PlayerbotAI* ai) { return new CastFireElementalTotemAction(ai); } + static Action* fire_elemental_totem_melee(PlayerbotAI* ai) { return new CastFireElementalTotemMeleeAction(ai); } + static Action* healing_stream_totem(PlayerbotAI* ai) { return new CastHealingStreamTotemAction(ai); } + static Action* mana_spring_totem(PlayerbotAI* ai) { return new CastManaSpringTotemAction(ai); } + static Action* cleansing_totem(PlayerbotAI* ai) { return new CastCleansingTotemAction(ai); } + static Action* mana_tide_totem(PlayerbotAI* ai) { return new CastManaTideTotemAction(ai); } + static Action* fire_resistance_totem(PlayerbotAI* ai) { return new CastFireResistanceTotemAction(ai); } + static Action* wrath_of_air_totem(PlayerbotAI* ai) { return new CastWrathOfAirTotemAction(ai); } + static Action* windfury_totem(PlayerbotAI* ai) { return new CastWindfuryTotemAction(ai); } + static Action* nature_resistance_totem(PlayerbotAI* ai) { return new CastNatureResistanceTotemAction(ai); } + static Action* set_strength_of_earth_totem(PlayerbotAI* ai) { return new SetStrengthOfEarthTotemAction(ai); } + static Action* set_stoneskin_totem(PlayerbotAI* ai) { return new SetStoneskinTotemAction(ai); } + static Action* set_tremor_totem(PlayerbotAI* ai) { return new SetTremorTotemAction(ai); } + static Action* set_earthbind_totem(PlayerbotAI* ai) { return new SetEarthbindTotemAction(ai); } + static Action* set_searing_totem(PlayerbotAI* ai) { return new SetSearingTotemAction(ai); } + static Action* set_magma_totem(PlayerbotAI* ai) { return new SetMagmaTotemAction(ai); } + static Action* set_flametongue_totem(PlayerbotAI* ai) { return new SetFlametongueTotemAction(ai); } + static Action* set_totem_of_wrath(PlayerbotAI* ai) { return new SetTotemOfWrathAction(ai); } + static Action* set_frost_resistance_totem(PlayerbotAI* ai) { return new SetFrostResistanceTotemAction(ai); } + static Action* set_healing_stream_totem(PlayerbotAI* ai) { return new SetHealingStreamTotemAction(ai); } + static Action* set_mana_spring_totem(PlayerbotAI* ai) { return new SetManaSpringTotemAction(ai); } + static Action* set_cleansing_totem(PlayerbotAI* ai) { return new SetCleansingTotemAction(ai); } + static Action* set_fire_resistance_totem(PlayerbotAI* ai) { return new SetFireResistanceTotemAction(ai); } + static Action* set_wrath_of_air_totem(PlayerbotAI* ai) { return new SetWrathOfAirTotemAction(ai); } + static Action* set_windfury_totem(PlayerbotAI* ai) { return new SetWindfuryTotemAction(ai); } + static Action* set_nature_resistance_totem(PlayerbotAI* ai) { return new SetNatureResistanceTotemAction(ai); } + static Action* set_grounding_totem(PlayerbotAI* ai) { return new SetGroundingTotemAction(ai); } }; SharedNamedObjectContextList ShamanAiObjectContext::sharedStrategyContexts; @@ -351,7 +467,10 @@ void ShamanAiObjectContext::BuildSharedStrategyContexts(SharedNamedObjectContext AiObjectContext::BuildSharedStrategyContexts(strategyContexts); strategyContexts.Add(new ShamanStrategyFactoryInternal()); strategyContexts.Add(new ShamanCombatStrategyFactoryInternal()); - strategyContexts.Add(new ShamanBuffStrategyFactoryInternal()); + strategyContexts.Add(new ShamanEarthTotemStrategyFactoryInternal()); + strategyContexts.Add(new ShamanFireTotemStrategyFactoryInternal()); + strategyContexts.Add(new ShamanWaterTotemStrategyFactoryInternal()); + strategyContexts.Add(new ShamanAirTotemStrategyFactoryInternal()); } void ShamanAiObjectContext::BuildSharedActionContexts(SharedNamedObjectContextList& actionContexts) @@ -369,4 +488,4 @@ void ShamanAiObjectContext::BuildSharedTriggerContexts(SharedNamedObjectContextL void ShamanAiObjectContext::BuildSharedValueContexts(SharedNamedObjectContextList& valueContexts) { AiObjectContext::BuildSharedValueContexts(valueContexts); -} \ No newline at end of file +} diff --git a/src/strategy/shaman/ShamanNonCombatStrategy.cpp b/src/strategy/shaman/ShamanNonCombatStrategy.cpp index 7e6df52c..0515bda0 100644 --- a/src/strategy/shaman/ShamanNonCombatStrategy.cpp +++ b/src/strategy/shaman/ShamanNonCombatStrategy.cpp @@ -4,55 +4,120 @@ */ #include "ShamanNonCombatStrategy.h" - +#include "AiFactory.h" +#include "Strategy.h" #include "Playerbots.h" +class ShamanNonCombatStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + ShamanNonCombatStrategyActionNodeFactory() + { + creators["flametongue weapon"] = &flametongue_weapon; + creators["frostbrand weapon"] = &frostbrand_weapon; + creators["windfury weapon"] = &windfury_weapon; + creators["earthliving weapon"] = &earthliving_weapon; + creators["wind shear"] = &wind_shear; + creators["purge"] = &purge; + } + +private: + static ActionNode* flametongue_weapon([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("flametongue weapon", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("rockbiter weapon"), nullptr), + /*C*/ nullptr); + } + static ActionNode* frostbrand_weapon([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("frostbrand weapon", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("flametongue weapon"), nullptr), + /*C*/ nullptr); + } + static ActionNode* windfury_weapon([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("windfury weapon", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("flametongue weapon"), nullptr), + /*C*/ nullptr); + } + static ActionNode* earthliving_weapon([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("earthliving weapon", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("flametongue weapon"), nullptr), + /*C*/ nullptr); + } + static ActionNode* wind_shear(PlayerbotAI*) { return new ActionNode("wind shear", nullptr, nullptr, nullptr); } + static ActionNode* purge(PlayerbotAI*) { return new ActionNode("purge", nullptr, nullptr, nullptr); } +}; + +ShamanNonCombatStrategy::ShamanNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) +{ + actionNodeFactories.Add(new ShamanNonCombatStrategyActionNodeFactory()); +} + void ShamanNonCombatStrategy::InitTriggers(std::vector& triggers) { NonCombatStrategy::InitTriggers(triggers); - triggers.push_back( - new TriggerNode("party member dead", - NextAction::array(0, new NextAction("ancestral spirit", ACTION_CRITICAL_HEAL + 10), nullptr))); - triggers.push_back( - new TriggerNode("water breathing", NextAction::array(0, new NextAction("water breathing", 12.0f), nullptr))); - triggers.push_back( - new TriggerNode("water walking", NextAction::array(0, new NextAction("water walking", 12.0f), nullptr))); - triggers.push_back(new TriggerNode( - "water breathing on party", NextAction::array(0, new NextAction("water breathing on party", 11.0f), nullptr))); - triggers.push_back(new TriggerNode("water walking on party", - NextAction::array(0, new NextAction("water walking on party", 11.0f), nullptr))); - triggers.push_back(new TriggerNode("party member critical health", - NextAction::array(0, new NextAction("riptide on party", 31.0f), - new NextAction("healing wave on party", 30.0f), NULL))); + // Totemic Recall + triggers.push_back(new TriggerNode("totemic recall", NextAction::array(0, new NextAction("totemic recall", 60.0f), nullptr))); - triggers.push_back(new TriggerNode("party member low health", - NextAction::array(0, new NextAction("riptide on party", 29.0f), - new NextAction("healing wave on party", 28.0f), NULL))); + // Healing/Resurrect Triggers + triggers.push_back(new TriggerNode("party member dead", NextAction::array(0, new NextAction("ancestral spirit", ACTION_CRITICAL_HEAL + 10), nullptr))); + triggers.push_back(new TriggerNode("party member critical health", NextAction::array(0, + new NextAction("riptide on party", 31.0f), + new NextAction("healing wave on party", 30.0f), NULL))); + triggers.push_back(new TriggerNode("party member low health",NextAction::array(0, + new NextAction("riptide on party", 29.0f), + new NextAction("healing wave on party", 28.0f), NULL))); + triggers.push_back(new TriggerNode("party member medium health",NextAction::array(0, + new NextAction("riptide on party", 27.0f), + new NextAction("healing wave on party", 26.0f), NULL))); + triggers.push_back(new TriggerNode("party member almost full health",NextAction::array(0, + new NextAction("riptide on party", 25.0f), + new NextAction("lesser healing wave on party", 24.0f), NULL))); + triggers.push_back(new TriggerNode("group heal setting",NextAction::array(0, new NextAction("chain heal on party", 27.0f), NULL))); - triggers.push_back(new TriggerNode("party member medium health", - NextAction::array(0, new NextAction("riptide on party", 27.0f), - new NextAction("healing wave on party", 26.0f), NULL))); + // Cure Triggers + triggers.push_back(new TriggerNode("cure poison", NextAction::array(0, new NextAction("cure poison", 21.0f), nullptr))); + triggers.push_back(new TriggerNode("party member cure poison", NextAction::array(0, new NextAction("cure poison on party", 21.0f), nullptr))); + triggers.push_back(new TriggerNode("cure disease", NextAction::array(0, new NextAction("cure disease", 31.0f), nullptr))); + triggers.push_back(new TriggerNode("party member cure disease", NextAction::array(0, new NextAction("cure disease on party", 30.0f), nullptr))); - triggers.push_back(new TriggerNode("party member almost full health", - NextAction::array(0, new NextAction("riptide on party", 25.0f), - new NextAction("lesser healing wave on party", 24.0f), NULL))); + // Out of Combat Buff Triggers + Player* bot = botAI->GetBot(); + int tab = AiFactory::GetPlayerSpecTab(bot); - triggers.push_back( - new TriggerNode("group heal setting", NextAction::array(0, new NextAction("chain heal on party", 27.0f), NULL))); + if (tab == 0) // Elemental + { + triggers.push_back(new TriggerNode("main hand weapon no imbue", NextAction::array(0, new NextAction("flametongue weapon", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("water shield", NextAction::array(0, new NextAction("water shield", 21.0f), nullptr))); + } + else if (tab == 1) // Enhancement + { + triggers.push_back(new TriggerNode("main hand weapon no imbue", NextAction::array(0, new NextAction("windfury weapon", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("off hand weapon no imbue", NextAction::array(0, new NextAction("flametongue weapon", 21.0f), nullptr))); + triggers.push_back(new TriggerNode("lightning shield", NextAction::array(0, new NextAction("lightning shield", 20.0f), nullptr))); + } + else if (tab == 2) // Restoration + { + triggers.push_back(new TriggerNode("main hand weapon no imbue",NextAction::array(0, new NextAction("earthliving weapon", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("water shield", NextAction::array(0, new NextAction("water shield", 20.0f), nullptr))); + } - triggers.push_back( - new TriggerNode("cure poison", NextAction::array(0, new NextAction("cure poison", 21.0f), nullptr))); - triggers.push_back(new TriggerNode("party member cure poison", - NextAction::array(0, new NextAction("cure poison on party", 21.0f), nullptr))); - triggers.push_back( - new TriggerNode("cure disease", NextAction::array(0, new NextAction("cure disease", 31.0f), nullptr))); - triggers.push_back(new TriggerNode("party member cure disease", - NextAction::array(0, new NextAction("cure disease on party", 30.0f), nullptr))); - triggers.push_back( - new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", 60.0f), nullptr))); - triggers.push_back( - new TriggerNode("new pet", NextAction::array(0, new NextAction("set pet stance", 65.0f), nullptr))); + // Buff Triggers while swimming + triggers.push_back(new TriggerNode("water breathing", NextAction::array(0, new NextAction("water breathing", 12.0f), nullptr))); + triggers.push_back(new TriggerNode("water walking", NextAction::array(0, new NextAction("water walking", 12.0f), nullptr))); + triggers.push_back(new TriggerNode("water breathing on party", NextAction::array(0, new NextAction("water breathing on party", 11.0f), nullptr))); + triggers.push_back(new TriggerNode("water walking on party", NextAction::array(0, new NextAction("water walking on party", 11.0f), nullptr))); + + // Pet Triggers + triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("new pet", NextAction::array(0, new NextAction("set pet stance", 65.0f), nullptr))); } void ShamanNonCombatStrategy::InitMultipliers(std::vector& multipliers) diff --git a/src/strategy/shaman/ShamanNonCombatStrategy.h b/src/strategy/shaman/ShamanNonCombatStrategy.h index 93e9b2f0..bee40f2d 100644 --- a/src/strategy/shaman/ShamanNonCombatStrategy.h +++ b/src/strategy/shaman/ShamanNonCombatStrategy.h @@ -13,7 +13,7 @@ class PlayerbotAI; class ShamanNonCombatStrategy : public NonCombatStrategy { public: - ShamanNonCombatStrategy(PlayerbotAI* botAI) : NonCombatStrategy(botAI) {} + ShamanNonCombatStrategy(PlayerbotAI* botAI); void InitTriggers(std::vector& triggers) override; void InitMultipliers(std::vector& multipliers) override; diff --git a/src/strategy/shaman/ShamanTriggers.cpp b/src/strategy/shaman/ShamanTriggers.cpp index e8c569f3..7ebe62de 100644 --- a/src/strategy/shaman/ShamanTriggers.cpp +++ b/src/strategy/shaman/ShamanTriggers.cpp @@ -4,37 +4,15 @@ */ #include "ShamanTriggers.h" - +#include "Player.h" +#include "PlayerbotAI.h" #include "ItemTemplate.h" #include "Playerbots.h" - -/* -std::vector ShamanWeaponTrigger::spells; - -bool ShamanWeaponTrigger::IsActive() -{ - if (spells.empty()) - { - spells.push_back("frostbrand weapon"); - spells.push_back("rockbiter weapon"); - spells.push_back("flametongue weapon"); - spells.push_back("earthliving weapon"); - spells.push_back("windfury weapon"); - } - - for (std::vector::iterator i = spells.begin(); i != spells.end(); ++i) - { - uint32 spellId = AI_VALUE2(uint32, "spell id", spell); - if (!spellId) - continue; - - if (AI_VALUE2(Item*, "item for spell", spellId)) - return true; - } - - return false; -} -*/ +#include "TotemsShamanStrategy.h" +#include "InstanceScript.h" +#include "Creature.h" +#include "Unit.h" +#include bool MainHandWeaponNoImbueTrigger::IsActive() { @@ -63,18 +41,30 @@ bool ShockTrigger::IsActive() !botAI->HasAura("frost shock", GetTarget(), false, true); } +// Checks if the target's health is above 25%/1500 hp. Returns false if either are true. +// This logic exists to prevent the use of Earth Shock on bosses as an Elemental Shaman. +bool EarthShockExecuteTrigger::IsActive() +{ + Unit* target = AI_VALUE(Unit*, "current target"); + if (!target) + return false; + + float percent = 100.0f * target->GetHealth() / target->GetMaxHealth(); + if (percent >= 25.0f) + return false; + + if (target->GetHealth() >= 1500) + return false; + + return true; +} + bool TotemTrigger::IsActive() { return AI_VALUE(uint8, "attacker count") >= attackerCount && !AI_VALUE2(bool, "has totem", name) && !botAI->HasAura(name, bot); } -bool ManaSpringTotemTrigger::IsActive() -{ - return AI_VALUE(uint8, "attacker count") >= attackerCount && !AI_VALUE2(bool, "has totem", "mana tide totem") && - !AI_VALUE2(bool, "has totem", name); -} - bool WaterWalkingTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE2(bool, "swimming", "self target"); } bool WaterBreathingTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE2(bool, "swimming", "self target"); } @@ -89,21 +79,352 @@ bool WaterBreathingOnPartyTrigger::IsActive() return BuffOnPartyTrigger::IsActive() && AI_VALUE2(bool, "swimming", "self target"); } +// Checks if Chain Lightning is on Cooldown, and prevents activation if it is. +// This is to ensure that Elemental Mastery is used on Lava Burst (2.0 second cast), +// and not on Chain Lightning (1.5 second cast with talents). +bool ElementalMasteryTrigger::IsActive() +{ + return bot->HasSpellCooldown(421); +} + +// Checks if Sprit Wolves are out/if Spirit Walk buff is not on the bot/if the cooldown for Spirit Walk is ready. +// There is custom code for the Spirit Walk cooldown (32 seconds), since no working +// code exists in the AC/Playerbots repo for checking if a guardian's spell is on cooldown. +bool SpiritWalkTrigger::IsActive() +{ + Player* bot = botAI->GetBot(); + constexpr uint32 SPIRIT_WOLF = 29264; + constexpr uint32 SPIRIT_WALK = 58875; + constexpr int COOLDOWN_SECONDS = 32; + + time_t now = time(nullptr); + + if ((now - lastSpiritWalkTime) < COOLDOWN_SECONDS) + return false; + + for (Unit* unit : bot->m_Controlled) + { + Creature* wolf = dynamic_cast(unit); + if (wolf && wolf->GetEntry() == SPIRIT_WOLF && wolf->IsAlive()) + { + if (!bot->HasAura(SPIRIT_WALK)) + { + lastSpiritWalkTime = now; + return true; + } + } + } + return false; +} + +// Checks if the bot knows Call of the Elements, and prevents the trigger firing if it doesn't. +// Fires the trigger if at least 2 of the totem slots are empty or out of range. +bool CallOfTheElementsTrigger::IsActive() +{ + Player* bot = botAI->GetBot(); + if (!bot->HasSpell(66842)) + return false; + + int emptyCount = 0; + static const uint8 slots[] = {SUMMON_SLOT_TOTEM_EARTH, SUMMON_SLOT_TOTEM_FIRE, SUMMON_SLOT_TOTEM_WATER, + SUMMON_SLOT_TOTEM_AIR}; + + for (uint8 slot : slots) + { + ObjectGuid guid = bot->m_SummonSlot[slot]; + if (guid.IsEmpty()) + { + ++emptyCount; + continue; + } + + Creature* totem = bot->GetMap()->GetCreature(guid); + if (!totem || totem->GetDistance(bot) > 30.0f) + { + ++emptyCount; + } + } + + return emptyCount >= 2; +} + +// Totemic Recall - Prevents the trigger firing under the following circumstances: +// 1. The bot does not have Totemic Recall (level 30). +// 2. The bot is in an instance and any boss encounter is in progress. +// 3. Any group member or their pet is in combat. +// 4. If Mana Tide Totem or Fire Elemental Totem is active and within 30 yards of the bot. +// 5. Finally, if any totem summon slot is not empty, the trigger will fire. +bool TotemicRecallTrigger::IsActive() +{ + Player* bot = botAI->GetBot(); + + if (!bot->HasSpell(SPELL_TOTEMIC_RECALL)) + return false; + + Map* map = bot->GetMap(); + if (map->IsDungeon()) + { + InstanceScript* instance = ((InstanceMap*)map)->GetInstanceScript(); + if (instance) + { + for (uint32 i = 0; i < instance->GetEncounterCount(); ++i) + { + if (instance->GetBossState(i) == IN_PROGRESS) + return false; + } + } + } + + Group* group = bot->GetGroup(); + if (group) + { + for (GroupReference* ref = group->GetFirstMember(); ref; ref = ref->next()) + { + Player* member = ref->GetSource(); + if (!member) + continue; + if (member->IsInCombat()) + return false; + Pet* pet = member->GetPet(); + if (pet && pet->IsInCombat()) + return false; + } + } + + { + ObjectGuid guid = bot->m_SummonSlot[SUMMON_SLOT_TOTEM_WATER]; + if (!guid.IsEmpty()) + { + Creature* totem = bot->GetMap()->GetCreature(guid); + uint32 currentSpell = 0; + if (totem) + currentSpell = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); + + for (size_t i = 0; i < MANA_TIDE_TOTEM_COUNT; ++i) + { + if (currentSpell == MANA_TIDE_TOTEM[i] && totem && totem->GetDistance(bot) <= 30.0f) + return false; + } + } + } + + { + ObjectGuid guid = bot->m_SummonSlot[SUMMON_SLOT_TOTEM_FIRE]; + if (!guid.IsEmpty()) + { + Creature* totem = bot->GetMap()->GetCreature(guid); + uint32 currentSpell = 0; + if (totem) + currentSpell = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); + + for (size_t i = 0; i < FIRE_ELEMENTAL_TOTEM_COUNT; ++i) + { + if (currentSpell == FIRE_ELEMENTAL_TOTEM[i] && totem && totem->GetDistance(bot) <= 30.0f) + return false; + } + } + } + + return !bot->m_SummonSlot[SUMMON_SLOT_TOTEM_EARTH].IsEmpty() || + !bot->m_SummonSlot[SUMMON_SLOT_TOTEM_FIRE].IsEmpty() || + !bot->m_SummonSlot[SUMMON_SLOT_TOTEM_WATER].IsEmpty() || + !bot->m_SummonSlot[SUMMON_SLOT_TOTEM_AIR].IsEmpty(); +} + +// Find the active totem strategy for this slot, and return the highest-rank spellId the bot knows for it +static uint32 GetRequiredTotemSpellId(PlayerbotAI* ai, const char* strategies[], const uint32* spellList[], + const size_t spellCounts[], size_t numStrategies) +{ + Player* bot = ai->GetBot(); + for (size_t i = 0; i < numStrategies; ++i) + { + if (ai->HasStrategy(strategies[i], BOT_STATE_COMBAT)) + { + // Find the highest-rank spell the bot knows + for (size_t j = 0; j < spellCounts[i]; ++j) + { + if (bot->HasSpell(spellList[i][j])) + return spellList[i][j]; + } + } + } + return 0; // No relevant strategy active, or bot doesn't know any rank +} + +// Get the spellId of the currently summoned totem in the slot +static uint32 GetSummonedTotemSpellId(Player* bot, uint8 slot) +{ + ObjectGuid guid = bot->m_SummonSlot[slot]; + if (guid.IsEmpty()) + return 0; + Creature* totem = bot->GetMap()->GetCreature(guid); + if (!totem) + return 0; + return totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); +} + +bool NoEarthTotemTrigger::IsActive() +{ + // Check if the bot has Stoneskin Totem (required level 4) and prevents the trigger firing if it doesn't + if (!bot->HasSpell(SPELL_STONESKIN_TOTEM_RANK_1)) + return false; + + ObjectGuid guid = bot->m_SummonSlot[SUMMON_SLOT_TOTEM_EARTH]; + Creature* totem = nullptr; + uint32 currentSpell = 0; + if (!guid.IsEmpty()) + { + totem = bot->GetMap()->GetCreature(guid); + if (totem) + currentSpell = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); + } + + // Define supported earth totem strategies for this slot: + static const char* names[] = {"strength of earth", "stoneskin", "tremor", "earthbind"}; + static const uint32* spells[] = {STRENGTH_OF_EARTH_TOTEM, STONESKIN_TOTEM, TREMOR_TOTEM, EARTHBIND_TOTEM}; + static const size_t counts[] = {STRENGTH_OF_EARTH_TOTEM_COUNT, STONESKIN_TOTEM_COUNT, TREMOR_TOTEM_COUNT, + EARTHBIND_TOTEM_COUNT}; + + uint32 requiredSpell = GetRequiredTotemSpellId(botAI, names, spells, counts, 4); + + // EXCEPTION: If Stoneclaw Totem is out and in range, consider the slot "occupied" (do not fire the trigger) + for (size_t i = 0; i < STONECLAW_TOTEM_COUNT; ++i) + if (currentSpell == STONECLAW_TOTEM[i] && totem && totem->GetDistance(bot) <= 30.0f) + return false; + + // If no relevant strategy, only care if the slot is empty or totem is too far away + if (!requiredSpell) + return guid.IsEmpty() || !totem || totem->GetDistance(bot) > 30.0f; + + // Fire if slot is empty or wrong totem or totem is too far away + return !currentSpell || currentSpell != requiredSpell || !totem || totem->GetDistance(bot) > 30.0f; +} + bool NoFireTotemTrigger::IsActive() { - return !AI_VALUE2(bool, "has totem", "magma totem") && !AI_VALUE2(bool, "has totem", "flametongue totem") && - !AI_VALUE2(bool, "has totem", "searing totem") && !AI_VALUE2(bool, "has totem", "fire elemental totem") && - !AI_VALUE2(bool, "has totem", "frost resistance totem") && !AI_VALUE2(bool, "has totem", "totem of wrath"); + // Check if the bot has Searing Totem (required level 10) and prevents the trigger firing if it doesn't + if (!bot->HasSpell(SPELL_SEARING_TOTEM_RANK_1)) + return false; + + ObjectGuid guid = bot->m_SummonSlot[SUMMON_SLOT_TOTEM_FIRE]; + Creature* totem = nullptr; + uint32 currentSpell = 0; + if (!guid.IsEmpty()) + { + totem = bot->GetMap()->GetCreature(guid); + if (totem) + currentSpell = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); + } + + // Define supported fire totem strategies for this slot: + static const char* names[] = {"searing", "magma", "flametongue", "wrath", "frost resistance"}; + static const uint32* spells[] = {SEARING_TOTEM, MAGMA_TOTEM, FLAMETONGUE_TOTEM, TOTEM_OF_WRATH, + FROST_RESISTANCE_TOTEM}; + static const size_t counts[] = {SEARING_TOTEM_COUNT, MAGMA_TOTEM_COUNT, FLAMETONGUE_TOTEM_COUNT, TOTEM_OF_WRATH_COUNT, + FROST_RESISTANCE_TOTEM_COUNT}; + + uint32 requiredSpell = GetRequiredTotemSpellId(botAI, names, spells, counts, 5); + + // EXCEPTION: If Fire Elemental is out and in range, consider the slot "occupied" (do not fire the trigger) + for (size_t i = 0; i < FIRE_ELEMENTAL_TOTEM_COUNT; ++i) + if (currentSpell == FIRE_ELEMENTAL_TOTEM[i] && totem && totem->GetDistance(bot) <= 30.0f) + return false; + + // If no relevant strategy, only care if the slot is empty or totem is too far away + if (!requiredSpell) + return guid.IsEmpty() || !totem || totem->GetDistance(bot) > 30.0f; + + // Fire if slot is empty or wrong totem or totem is too far away + return !currentSpell || currentSpell != requiredSpell || !totem || totem->GetDistance(bot) > 30.0f; } bool NoWaterTotemTrigger::IsActive() { - return !AI_VALUE2(bool, "has totem", "fire resistance totem") && !AI_VALUE2(bool, "has totem", "mana tide totem") && - !AI_VALUE2(bool, "has totem", "cleansing totem") && !AI_VALUE2(bool, "has totem", "mana spring totem") && - !AI_VALUE2(bool, "has totem", "healing stream totem"); + // Check if the bot has Healing Stream Totem (required level 20) and prevents the trigger firing if it doesn't + if (!bot->HasSpell(SPELL_HEALING_STREAM_TOTEM_RANK_1)) + return false; + + ObjectGuid guid = bot->m_SummonSlot[SUMMON_SLOT_TOTEM_WATER]; + Creature* totem = nullptr; + uint32 currentSpell = 0; + if (!guid.IsEmpty()) + { + totem = bot->GetMap()->GetCreature(guid); + if (totem) + currentSpell = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); + } + + // Define supported water totem strategies for this slot: + static const char* names[] = {"healing stream", "mana spring", "cleansing", "fire resistance"}; + static const uint32* spells[] = {HEALING_STREAM_TOTEM, MANA_SPRING_TOTEM, CLEANSING_TOTEM, FIRE_RESISTANCE_TOTEM}; + static const size_t counts[] = {HEALING_STREAM_TOTEM_COUNT, MANA_SPRING_TOTEM_COUNT, CLEANSING_TOTEM_COUNT, + FIRE_RESISTANCE_TOTEM_COUNT}; + + uint32 requiredSpell = GetRequiredTotemSpellId(botAI, names, spells, counts, 4); + + // EXCEPTION: If Mana Tide is out and in range, consider the slot "occupied" (do not fire the trigger) + for (size_t i = 0; i < MANA_TIDE_TOTEM_COUNT; ++i) + if (currentSpell == MANA_TIDE_TOTEM[i] && totem && totem->GetDistance(bot) <= 30.0f) + return false; + + // If no relevant strategy, only care if the slot is empty or totem is too far away + if (!requiredSpell) + return guid.IsEmpty() || !totem || totem->GetDistance(bot) > 30.0f; + + // Fire if slot is empty or wrong totem or totem is too far away + return !currentSpell || currentSpell != requiredSpell || !totem || totem->GetDistance(bot) > 30.0f; } bool NoAirTotemTrigger::IsActive() { - return !AI_VALUE2(bool, "has totem", "wrath of air totem") && !AI_VALUE2(bool, "has totem", "windfury totem"); + // Check if the bot has Nature Resistance Totem (required level 30) and prevents the trigger firing if it doesn't + if (!bot->HasSpell(SPELL_NATURE_RESISTANCE_TOTEM_RANK_1)) + return false; + + ObjectGuid guid = bot->m_SummonSlot[SUMMON_SLOT_TOTEM_AIR]; + Creature* totem = nullptr; + uint32 currentSpell = 0; + if (!guid.IsEmpty()) + { + totem = bot->GetMap()->GetCreature(guid); + if (totem) + currentSpell = totem->GetUInt32Value(UNIT_CREATED_BY_SPELL); + } + + // Define supported air totem strategies for this slot: + static const char* names[] = {"wrath of air", "windfury", "nature resistance", "grounding totem"}; + static const uint32* spells[] = {WRATH_OF_AIR_TOTEM, WINDFURY_TOTEM, NATURE_RESISTANCE_TOTEM, GROUNDING_TOTEM}; + static const size_t counts[] = {WRATH_OF_AIR_TOTEM_COUNT, WINDFURY_TOTEM_COUNT, NATURE_RESISTANCE_TOTEM_COUNT, + GROUNDING_TOTEM_COUNT}; + + uint32 requiredSpell = GetRequiredTotemSpellId(botAI, names, spells, counts, 3); + + // If no relevant strategy, only care if the slot is empty or totem is too far away + if (!requiredSpell) + return guid.IsEmpty() || !totem || totem->GetDistance(bot) > 30.0f; + + // Fire if slot is empty or wrong totem or totem is too far away + return !currentSpell || currentSpell != requiredSpell || !totem || totem->GetDistance(bot) > 30.0f; +} + +bool SetTotemTrigger::IsActive() +{ + if (!bot->HasSpell(66842)) + return false; + if (!bot->HasSpell(requiredSpellId)) + return false; + + ActionButton const* button = bot->GetActionButton(actionButtonId); + if (!button || button->GetType() != ACTION_BUTTON_SPELL || button->GetAction() == 0) + return true; + + size_t totemSpellIdsCount = sizeof(totemSpellIds) / sizeof(uint32); + for (size_t i = 0; i < totemSpellIdsCount; ++i) + { + if (button->GetAction() == totemSpellIds[i]) + { + return false; + } + } + return true; } diff --git a/src/strategy/shaman/ShamanTriggers.h b/src/strategy/shaman/ShamanTriggers.h index 94102e7b..4c4c9838 100644 --- a/src/strategy/shaman/ShamanTriggers.h +++ b/src/strategy/shaman/ShamanTriggers.h @@ -9,21 +9,35 @@ #include "CureTriggers.h" #include "GenericTriggers.h" #include "SharedDefines.h" +#include "Trigger.h" +#include +#include "TotemsShamanStrategy.h" +#include "Player.h" +#include "PlayerbotAI.h" +#include class PlayerbotAI; -/* -class ShamanWeaponTrigger : public BuffTrigger -{ - public: - ShamanWeaponTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "rockbiter weapon", 2 * 2000) { } +// Buff and Out of Combat Triggers - bool IsActive() override; - - private: - static std::vector spells; -}; -*/ +const uint32 SPELL_EARTHBIND_TOTEM_RANK_1 = 2484; +const uint32 SPELL_SEARING_TOTEM_RANK_1 = 3599; +const uint32 SPELL_WRATH_OF_AIR_TOTEM_RANK_1 = 3738; +const uint32 SPELL_HEALING_STREAM_TOTEM_RANK_1 = 5394; +const uint32 SPELL_MANA_SPRING_TOTEM_RANK_1 = 5675; +const uint32 SPELL_STONESKIN_TOTEM_RANK_1 = 8071; +const uint32 SPELL_STRENGTH_OF_EARTH_TOTEM_RANK_1 = 8075; +const uint32 SPELL_TREMOR_TOTEM_RANK_1 = 8143; +const uint32 SPELL_CLEANSING_TOTEM_RANK_1 = 8170; +const uint32 SPELL_GROUNDING_TOTEM_RANK_1 = 8177; +const uint32 SPELL_FROST_RESISTANCE_TOTEM_RANK_1 = 8181; +const uint32 SPELL_FIRE_RESISTANCE_TOTEM_RANK_1 = 8184; +const uint32 SPELL_MAGMA_TOTEM_RANK_1 = 8190; +const uint32 SPELL_FLAMETONGUE_TOTEM_RANK_1 = 8227; +const uint32 SPELL_WINDFURY_TOTEM_RANK_1 = 8512; +const uint32 SPELL_NATURE_RESISTANCE_TOTEM_RANK_1 = 10595; +const uint32 SPELL_TOTEM_OF_WRATH_RANK_1 = 30706; +const uint32 SPELL_TOTEMIC_RECALL = 36936; class MainHandWeaponNoImbueTrigger : public BuffTrigger { @@ -39,76 +53,6 @@ public: virtual bool IsActive(); }; -class TotemTrigger : public Trigger -{ -public: - TotemTrigger(PlayerbotAI* botAI, std::string const spell, uint32 attackerCount = 0) - : Trigger(botAI, spell), attackerCount(attackerCount) - { - } - - bool IsActive() override; - -protected: - uint32 attackerCount; -}; - -class WindfuryTotemTrigger : public TotemTrigger -{ -public: - WindfuryTotemTrigger(PlayerbotAI* botAI) : TotemTrigger(botAI, "windfury totem") {} -}; - -class GraceOfAirTotemTrigger : public TotemTrigger -{ -public: - GraceOfAirTotemTrigger(PlayerbotAI* botAI) : TotemTrigger(botAI, "grace of air totem") {} -}; - -class ManaSpringTotemTrigger : public TotemTrigger -{ -public: - ManaSpringTotemTrigger(PlayerbotAI* botAI) : TotemTrigger(botAI, "mana spring totem") {} - - bool IsActive() override; -}; - -class FlametongueTotemTrigger : public TotemTrigger -{ -public: - FlametongueTotemTrigger(PlayerbotAI* botAI) : TotemTrigger(botAI, "flametongue totem") {} -}; - -class StrengthOfEarthTotemTrigger : public TotemTrigger -{ -public: - StrengthOfEarthTotemTrigger(PlayerbotAI* botAI) : TotemTrigger(botAI, "strength of earth totem") {} -}; - -class FireElementalTotemTrigger : public BoostTrigger -{ -public: - FireElementalTotemTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "fire elemental totem") {} -}; - -class MagmaTotemTrigger : public TotemTrigger -{ -public: - MagmaTotemTrigger(PlayerbotAI* botAI) : TotemTrigger(botAI, "magma totem", 3) {} -}; - -class SearingTotemTrigger : public TotemTrigger -{ -public: - SearingTotemTrigger(PlayerbotAI* botAI) : TotemTrigger(botAI, "searing totem", 1) {} -}; - -class WindShearInterruptSpellTrigger : public InterruptSpellTrigger -{ -public: - WindShearInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "wind shear") {} -}; - class WaterShieldTrigger : public BuffTrigger { public: @@ -121,12 +65,6 @@ public: LightningShieldTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "lightning shield") {} }; -class PurgeTrigger : public TargetAuraDispelTrigger -{ -public: - PurgeTrigger(PlayerbotAI* botAI) : TargetAuraDispelTrigger(botAI, "purge", DISPEL_MAGIC) {} -}; - class WaterWalkingTrigger : public BuffTrigger { public: @@ -154,13 +92,70 @@ public: class WaterBreathingOnPartyTrigger : public BuffOnPartyTrigger { public: - WaterBreathingOnPartyTrigger(PlayerbotAI* botAI) : BuffOnPartyTrigger(botAI, "water breathing on party", 2 * 2000) - { - } + WaterBreathingOnPartyTrigger(PlayerbotAI* botAI) : BuffOnPartyTrigger(botAI, "water breathing on party", 2 * 2000) {} bool IsActive() override; }; +// Boost Triggers + +class HeroismTrigger : public BoostTrigger +{ +public: + HeroismTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "heroism") {} +}; + +class BloodlustTrigger : public BoostTrigger +{ +public: + BloodlustTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "bloodlust") {} +}; + +class ElementalMasteryTrigger : public BuffTrigger +{ +public: + ElementalMasteryTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "elemental mastery") {} + + bool IsActive() override; +}; + +class SpiritWalkTrigger : public Trigger +{ +public: + SpiritWalkTrigger(PlayerbotAI* ai) : Trigger(ai, "spirit walk ready") {} + + bool IsActive() override; + +private: + time_t lastSpiritWalkTime = 0; +}; + +class FireElementalTotemTrigger : public BoostTrigger +{ +public: + FireElementalTotemTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "fire elemental totem") {} +}; + + // CC, Interrupt, and Dispel Triggers + +class WindShearInterruptSpellTrigger : public InterruptSpellTrigger +{ +public: + WindShearInterruptSpellTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "wind shear") {} +}; + +class WindShearInterruptEnemyHealerSpellTrigger : public InterruptEnemyHealerTrigger +{ +public: + WindShearInterruptEnemyHealerSpellTrigger(PlayerbotAI* botAI) : InterruptEnemyHealerTrigger(botAI, "wind shear") {} +}; + +class PurgeTrigger : public TargetAuraDispelTrigger +{ +public: + PurgeTrigger(PlayerbotAI* botAI) : TargetAuraDispelTrigger(botAI, "purge", DISPEL_MAGIC) {} +}; + class CleanseSpiritPoisonTrigger : public NeedCureTrigger { public: @@ -206,6 +201,33 @@ public: } }; +class CurePoisonTrigger : public NeedCureTrigger +{ +public: + CurePoisonTrigger(PlayerbotAI* botAI) : NeedCureTrigger(botAI, "cure poison", DISPEL_POISON) {} +}; + +class PartyMemberCurePoisonTrigger : public PartyMemberNeedCureTrigger +{ +public: + PartyMemberCurePoisonTrigger(PlayerbotAI* botAI) : PartyMemberNeedCureTrigger(botAI, "cure poison", DISPEL_POISON) {} +}; + +class CureDiseaseTrigger : public NeedCureTrigger +{ +public: + CureDiseaseTrigger(PlayerbotAI* botAI) : NeedCureTrigger(botAI, "cure disease", DISPEL_DISEASE) {} +}; + +class PartyMemberCureDiseaseTrigger : public PartyMemberNeedCureTrigger +{ +public: + PartyMemberCureDiseaseTrigger(PlayerbotAI* botAI) + : PartyMemberNeedCureTrigger(botAI, "cure disease", DISPEL_DISEASE) {} +}; + +// Damage and Debuff Triggers + class ShockTrigger : public DebuffTrigger { public: @@ -220,63 +242,88 @@ public: FrostShockSnareTrigger(PlayerbotAI* botAI) : SnareTargetTrigger(botAI, "frost shock") {} }; -class HeroismTrigger : public BoostTrigger -{ -public: - HeroismTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "heroism") {} -}; - -class BloodlustTrigger : public BoostTrigger -{ -public: - BloodlustTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "bloodlust") {} -}; - -class ElementalMasteryTrigger : public BoostTrigger -{ -public: - ElementalMasteryTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "elemental mastery") {} -}; - class MaelstromWeaponTrigger : public HasAuraStackTrigger { public: MaelstromWeaponTrigger(PlayerbotAI* botAI, int stack = 5) : HasAuraStackTrigger(botAI, "maelstrom weapon", stack) {} }; -class WindShearInterruptEnemyHealerSpellTrigger : public InterruptEnemyHealerTrigger +class FlameShockTrigger : public DebuffTrigger { public: - WindShearInterruptEnemyHealerSpellTrigger(PlayerbotAI* botAI) : InterruptEnemyHealerTrigger(botAI, "wind shear") {} + FlameShockTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "flame shock", 1, true, 6.0f) {} + bool IsActive() override { return BuffTrigger::IsActive(); } }; -class CurePoisonTrigger : public NeedCureTrigger +class EarthShockExecuteTrigger : public Trigger { public: - CurePoisonTrigger(PlayerbotAI* botAI) : NeedCureTrigger(botAI, "cure poison", DISPEL_POISON) {} + EarthShockExecuteTrigger(PlayerbotAI* botAI) : Trigger(botAI, "earth shock execute") {} + + bool IsActive() override; }; -class PartyMemberCurePoisonTrigger : public PartyMemberNeedCureTrigger +class MaelstromWeapon5AndMediumAoeTrigger : public TwoTriggers { public: - PartyMemberCurePoisonTrigger(PlayerbotAI* botAI) : PartyMemberNeedCureTrigger(botAI, "cure poison", DISPEL_POISON) + MaelstromWeapon5AndMediumAoeTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "maelstrom weapon 5", "medium aoe") {} +}; + +class MaelstromWeapon4AndMediumAoeTrigger : public TwoTriggers +{ +public: + MaelstromWeapon4AndMediumAoeTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "maelstrom weapon 4", "medium aoe") {} +}; + +class ChainLightningNoCdTrigger : public SpellNoCooldownTrigger +{ +public: + ChainLightningNoCdTrigger(PlayerbotAI* ai) : SpellNoCooldownTrigger(ai, "chain lightning") {} +}; + +// Healing Triggers + +class EarthShieldOnMainTankTrigger : public BuffOnMainTankTrigger +{ +public: + EarthShieldOnMainTankTrigger(PlayerbotAI* botAI) : BuffOnMainTankTrigger(botAI, "earth shield", false) {} +}; + +// Totem Triggers + +class TotemTrigger : public Trigger +{ +public: + TotemTrigger(PlayerbotAI* botAI, std::string const spell, uint32 attackerCount = 0) + : Trigger(botAI, spell), attackerCount(attackerCount) { } + + bool IsActive() override; + +protected: + uint32 attackerCount; }; -class CureDiseaseTrigger : public NeedCureTrigger +class CallOfTheElementsTrigger : public Trigger { public: - CureDiseaseTrigger(PlayerbotAI* botAI) : NeedCureTrigger(botAI, "cure disease", DISPEL_DISEASE) {} + CallOfTheElementsTrigger(PlayerbotAI* ai) : Trigger(ai, "call of the elements") {} + bool IsActive() override; }; -class PartyMemberCureDiseaseTrigger : public PartyMemberNeedCureTrigger +class TotemicRecallTrigger : public Trigger { public: - PartyMemberCureDiseaseTrigger(PlayerbotAI* botAI) - : PartyMemberNeedCureTrigger(botAI, "cure disease", DISPEL_DISEASE) - { - } + TotemicRecallTrigger(PlayerbotAI* ai) : Trigger(ai, "totemic recall") {} + bool IsActive() override; +}; + +class NoEarthTotemTrigger : public Trigger +{ +public: + NoEarthTotemTrigger(PlayerbotAI* ai) : Trigger(ai, "no earth totem") {} + bool IsActive() override; }; class NoFireTotemTrigger : public Trigger @@ -293,28 +340,155 @@ public: bool IsActive() override; }; -class EarthShieldOnMainTankTrigger : public BuffOnMainTankTrigger +class NoAirTotemTrigger : public Trigger { public: - EarthShieldOnMainTankTrigger(PlayerbotAI* botAI) : BuffOnMainTankTrigger(botAI, "earth shield", false) {} -}; - -class FlameShockTrigger : public DebuffTrigger -{ -public: - FlameShockTrigger(PlayerbotAI* ai) : DebuffTrigger(ai, "flame shock", 1, true, 6.0f) {} -}; - -class WrathOfAirTotemTrigger : public TotemTrigger -{ -public: - WrathOfAirTotemTrigger(PlayerbotAI* ai) : TotemTrigger(ai, "wrath of air totem") {} -}; - -class NoAirTotemTrigger : public TotemTrigger -{ -public: - NoAirTotemTrigger(PlayerbotAI* ai) : TotemTrigger(ai, "no air totem") {} + NoAirTotemTrigger(PlayerbotAI* ai) : Trigger(ai, "no air totem") {} bool IsActive() override; }; + +class CallOfTheElementsAndEnemyWithinMeleeTrigger : public TwoTriggers +{ +public: + CallOfTheElementsAndEnemyWithinMeleeTrigger(PlayerbotAI* ai) : TwoTriggers(ai, "call of the elements", "enemy within melee") {} +}; + +// Set Strategy Assigned Totems + +class SetTotemTrigger : public Trigger +{ +public: + SetTotemTrigger(PlayerbotAI* ai, std::string const spellName, const uint32 requiredSpellId, + const uint32 totemSpellIds[], int actionButtonId) + : Trigger(ai, "set " + spellName), + requiredSpellId(requiredSpellId), + totemSpellIds(totemSpellIds), + actionButtonId(actionButtonId) {} + bool IsActive() override; + +private: + uint32 requiredSpellId; + uint32 const* totemSpellIds; + int actionButtonId; +}; + +class SetStrengthOfEarthTotemTrigger : public SetTotemTrigger +{ +public: + SetStrengthOfEarthTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "strength of earth totem", SPELL_STRENGTH_OF_EARTH_TOTEM_RANK_1, STRENGTH_OF_EARTH_TOTEM, TOTEM_BAR_SLOT_EARTH) {} +}; + +class SetStoneskinTotemTrigger : public SetTotemTrigger +{ +public: + SetStoneskinTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "stoneskin totem", SPELL_STONESKIN_TOTEM_RANK_1, STONESKIN_TOTEM, TOTEM_BAR_SLOT_EARTH) {} +}; + +class SetTremorTotemTrigger : public SetTotemTrigger +{ +public: + SetTremorTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "tremor totem", SPELL_TREMOR_TOTEM_RANK_1, TREMOR_TOTEM, TOTEM_BAR_SLOT_EARTH) {} +}; + +class SetEarthbindTotemTrigger : public SetTotemTrigger +{ +public: + SetEarthbindTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "earthbind totem", SPELL_EARTHBIND_TOTEM_RANK_1, EARTHBIND_TOTEM, TOTEM_BAR_SLOT_EARTH) {} +}; + +class SetSearingTotemTrigger : public SetTotemTrigger +{ +public: + SetSearingTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "searing totem", SPELL_SEARING_TOTEM_RANK_1, SEARING_TOTEM, TOTEM_BAR_SLOT_FIRE) {} +}; + +class SetMagmaTotemTrigger : public SetTotemTrigger +{ +public: + SetMagmaTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "magma totem", SPELL_MAGMA_TOTEM_RANK_1, MAGMA_TOTEM, TOTEM_BAR_SLOT_FIRE) {} +}; + +class SetFlametongueTotemTrigger : public SetTotemTrigger +{ +public: + SetFlametongueTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "flametongue totem", SPELL_FLAMETONGUE_TOTEM_RANK_1, FLAMETONGUE_TOTEM, TOTEM_BAR_SLOT_FIRE) {} +}; + +class SetTotemOfWrathTrigger : public SetTotemTrigger +{ +public: + SetTotemOfWrathTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "totem of wrath", SPELL_TOTEM_OF_WRATH_RANK_1, TOTEM_OF_WRATH, TOTEM_BAR_SLOT_FIRE) {} +}; + +class SetFrostResistanceTotemTrigger : public SetTotemTrigger +{ +public: + SetFrostResistanceTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "frost resistance totem", SPELL_FROST_RESISTANCE_TOTEM_RANK_1, FROST_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_FIRE) {} +}; + +class SetHealingStreamTotemTrigger : public SetTotemTrigger +{ +public: + SetHealingStreamTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "healing stream totem", SPELL_HEALING_STREAM_TOTEM_RANK_1, HEALING_STREAM_TOTEM, TOTEM_BAR_SLOT_WATER) {} +}; + +class SetManaSpringTotemTrigger : public SetTotemTrigger +{ +public: + SetManaSpringTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "mana spring totem", SPELL_MANA_SPRING_TOTEM_RANK_1, MANA_SPRING_TOTEM, TOTEM_BAR_SLOT_WATER) {} +}; + +class SetCleansingTotemTrigger : public SetTotemTrigger +{ +public: + SetCleansingTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "cleansing totem", SPELL_CLEANSING_TOTEM_RANK_1, CLEANSING_TOTEM, TOTEM_BAR_SLOT_WATER) {} +}; + +class SetFireResistanceTotemTrigger : public SetTotemTrigger +{ +public: + SetFireResistanceTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "fire resistance totem", SPELL_FIRE_RESISTANCE_TOTEM_RANK_1, FIRE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_WATER) {} +}; + +class SetWrathOfAirTotemTrigger : public SetTotemTrigger +{ +public: + SetWrathOfAirTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "wrath of air totem", SPELL_WRATH_OF_AIR_TOTEM_RANK_1, WRATH_OF_AIR_TOTEM, TOTEM_BAR_SLOT_AIR) {} +}; + +class SetWindfuryTotemTrigger : public SetTotemTrigger +{ +public: + SetWindfuryTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "windfury totem", SPELL_WINDFURY_TOTEM_RANK_1, WINDFURY_TOTEM, TOTEM_BAR_SLOT_AIR) {} +}; + +class SetNatureResistanceTotemTrigger : public SetTotemTrigger +{ +public: + SetNatureResistanceTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "nature resistance totem", SPELL_NATURE_RESISTANCE_TOTEM_RANK_1, NATURE_RESISTANCE_TOTEM, TOTEM_BAR_SLOT_AIR) {} +}; + +class SetGroundingTotemTrigger : public SetTotemTrigger +{ +public: + SetGroundingTotemTrigger(PlayerbotAI* ai) + : SetTotemTrigger(ai, "grounding totem", SPELL_GROUNDING_TOTEM_RANK_1, GROUNDING_TOTEM, TOTEM_BAR_SLOT_AIR) {} +}; + #endif diff --git a/src/strategy/shaman/TotemsShamanStrategy.cpp b/src/strategy/shaman/TotemsShamanStrategy.cpp index f3346a5c..12f433f7 100644 --- a/src/strategy/shaman/TotemsShamanStrategy.cpp +++ b/src/strategy/shaman/TotemsShamanStrategy.cpp @@ -4,22 +4,185 @@ */ #include "TotemsShamanStrategy.h" - #include "Playerbots.h" -TotemsShamanStrategy::TotemsShamanStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +// These combat strategies are used to set the corresponding totems on the bar, and cast the totem when it's missing. +// There are special cases for Totem of Wrath, Windfury Totem, Wrath of Air totem, and Cleansing totem - these totems +// aren't learned at level 30, and have fallbacks in order to prevent the trigger from continuously firing. -void TotemsShamanStrategy::InitTriggers(std::vector& triggers) +// Earth Totems +StrengthOfEarthTotemStrategy::StrengthOfEarthTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void StrengthOfEarthTotemStrategy::InitTriggers(std::vector& triggers) { GenericShamanStrategy::InitTriggers(triggers); - - triggers.push_back( - new TriggerNode("no air totem", NextAction::array(0, new NextAction("wrath of air totem", 8.0f), nullptr))); - - triggers.push_back( - new TriggerNode("no water totem", NextAction::array(0, new NextAction("mana spring totem", 7.0f), - new NextAction("healing stream totem", 6.0f), nullptr))); - - triggers.push_back(new TriggerNode("strength of earth totem", - NextAction::array(0, new NextAction("strength of earth totem", 6.0f), nullptr))); + triggers.push_back(new TriggerNode("set strength of earth totem", NextAction::array(0, new NextAction("set strength of earth totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no earth totem", NextAction::array(0, new NextAction("strength of earth totem", 55.0f), nullptr))); +} + +StoneclawTotemStrategy::StoneclawTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void StoneclawTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set stoneskin totem", NextAction::array(0, new NextAction("set stoneskin totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no earth totem", NextAction::array(0, new NextAction("stoneskin totem", 55.0f), nullptr))); +} + +EarthTotemStrategy::EarthTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void EarthTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set tremor totem", NextAction::array(0, new NextAction("set tremor totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no earth totem", NextAction::array(0, new NextAction("tremor totem", 55.0f), nullptr))); +} + +EarthbindTotemStrategy::EarthbindTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void EarthbindTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set earthbind totem", NextAction::array(0, new NextAction("set earthbind totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no earth totem", NextAction::array(0, new NextAction("earthbind totem", 55.0f), nullptr))); +} + +// Fire Totems +SearingTotemStrategy::SearingTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void SearingTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set searing totem", NextAction::array(0, new NextAction("set searing totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no fire totem", NextAction::array(0, new NextAction("searing totem", 55.0f), nullptr))); +} + +MagmaTotemStrategy::MagmaTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void MagmaTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set magma totem", NextAction::array(0, new NextAction("set magma totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no fire totem", NextAction::array(0, new NextAction("magma totem", 55.0f), nullptr))); +} + +FlametongueTotemStrategy::FlametongueTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void FlametongueTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set flametongue totem", NextAction::array(0, new NextAction("set flametongue totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no fire totem", NextAction::array(0, new NextAction("flametongue totem", 55.0f), nullptr))); +} + +TotemOfWrathStrategy::TotemOfWrathStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void TotemOfWrathStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + // If the bot hasn't learned Totem of Wrath yet, set Flametongue Totem instead. + Player* bot = botAI->GetBot(); + if (bot->HasSpell(30706)) + { + triggers.push_back(new TriggerNode("set totem of wrath", NextAction::array(0, new NextAction("set totem of wrath", 60.0f), nullptr))); + } + else if (bot->HasSpell(8227)) + { + triggers.push_back(new TriggerNode("set flametongue totem", NextAction::array(0, new NextAction("set flametongue totem", 60.0f), nullptr))); + } + triggers.push_back(new TriggerNode("no fire totem", NextAction::array(0, new NextAction("totem of wrath", 55.0f), nullptr))); +} + +FrostResistanceTotemStrategy::FrostResistanceTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void FrostResistanceTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set frost resistance totem", NextAction::array(0, new NextAction("set frost resistance totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no fire totem", NextAction::array(0, new NextAction("frost resistance totem", 55.0f), nullptr))); +} + +// Water Totems +HealingStreamTotemStrategy::HealingStreamTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void HealingStreamTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set healing stream totem", NextAction::array(0, new NextAction("set healing stream totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no water totem", NextAction::array(0, new NextAction("healing stream totem", 55.0f), nullptr))); +} + +ManaSpringTotemStrategy::ManaSpringTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void ManaSpringTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set mana spring totem", NextAction::array(0, new NextAction("set mana spring totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no water totem", NextAction::array(0, new NextAction("mana spring totem", 55.0f), nullptr))); +} + +CleansingTotemStrategy::CleansingTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void CleansingTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + // If the bot hasn't learned Cleansing Totem yet, set Mana Spring Totem instead. + Player* bot = botAI->GetBot(); + if (bot->HasSpell(8170)) + { + triggers.push_back(new TriggerNode("set cleansing totem", NextAction::array(0, new NextAction("set cleansing totem", 60.0f), nullptr))); + } + else if (bot->HasSpell(5675)) + { + triggers.push_back(new TriggerNode("set mana spring totem", NextAction::array(0, new NextAction("set mana spring totem", 60.0f), nullptr))); + } + triggers.push_back(new TriggerNode("no water totem", NextAction::array(0, new NextAction("cleansing totem", 55.0f), nullptr))); +} + +FireResistanceTotemStrategy::FireResistanceTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void FireResistanceTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set fire resistance totem", NextAction::array(0, new NextAction("set fire resistance totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no water totem", NextAction::array(0, new NextAction("fire resistance totem", 55.0f), nullptr))); +} + +// Air Totems +WrathOfAirTotemStrategy::WrathOfAirTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void WrathOfAirTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + // If the bot hasn't learned Wrath of Air Totem yet, set Grounding Totem instead. + Player* bot = botAI->GetBot(); + if (bot->HasSpell(3738)) + { + triggers.push_back(new TriggerNode("set wrath of air totem", NextAction::array(0, new NextAction("set wrath of air totem", 60.0f), nullptr))); + } + else if (bot->HasSpell(8177)) + { + triggers.push_back(new TriggerNode("set grounding totem", NextAction::array(0, new NextAction("set grounding totem", 60.0f), nullptr))); + } + triggers.push_back( + new TriggerNode("no air totem", NextAction::array(0, new NextAction("wrath of air totem", 55.0f), nullptr))); +} + +WindfuryTotemStrategy::WindfuryTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void WindfuryTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + // If the bot hasn't learned Windfury Totem yet, set Grounding Totem instead. + Player* bot = botAI->GetBot(); + if (bot->HasSpell(8512)) + { + triggers.push_back(new TriggerNode("set windfury totem", NextAction::array(0, new NextAction("set windfury totem", 60.0f), nullptr))); + } + else if (bot->HasSpell(8177)) + { + triggers.push_back(new TriggerNode("set grounding totem", NextAction::array(0, new NextAction("set grounding totem", 60.0f), nullptr))); + } + triggers.push_back(new TriggerNode("no air totem", NextAction::array(0, new NextAction("windfury totem", 55.0f), nullptr))); +} + +NatureResistanceTotemStrategy::NatureResistanceTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void NatureResistanceTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set nature resistance totem", NextAction::array(0, new NextAction("set nature resistance totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no air totem", NextAction::array(0, new NextAction("nature resistance totem", 55.0f), nullptr))); +} + +GroundingTotemStrategy::GroundingTotemStrategy(PlayerbotAI* botAI) : GenericShamanStrategy(botAI) {} +void GroundingTotemStrategy::InitTriggers(std::vector& triggers) +{ + GenericShamanStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("set grounding totem", NextAction::array(0, new NextAction("set grounding totem", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("no air totem", NextAction::array(0, new NextAction("grounding totem", 55.0f), nullptr))); } diff --git a/src/strategy/shaman/TotemsShamanStrategy.h b/src/strategy/shaman/TotemsShamanStrategy.h index 5c19a5ce..5bfb5e63 100644 --- a/src/strategy/shaman/TotemsShamanStrategy.h +++ b/src/strategy/shaman/TotemsShamanStrategy.h @@ -7,16 +7,358 @@ #define _PLAYERBOT_TOTEMSSHAMANSTRATEGY_H #include "GenericShamanStrategy.h" +#include +#include +#include + +// This is the header with all of the totem-related constants and arrays used in the Shaman strategies. + +// Totem Bar Slot Constants +#define TOTEM_BAR_SLOT_FIRE 132 +#define TOTEM_BAR_SLOT_EARTH 133 +#define TOTEM_BAR_SLOT_WATER 134 +#define TOTEM_BAR_SLOT_AIR 135 + +// Strength of Earth Totem +static const uint32 STRENGTH_OF_EARTH_TOTEM[] = { + 58643, // Rank 8 + 57622, // Rank 7 + 25528, // Rank 6 + 25361, // Rank 5 + 10442, // Rank 4 + 8161, // Rank 3 + 8160, // Rank 2 + 8075 // Rank 1 +}; +static const size_t STRENGTH_OF_EARTH_TOTEM_COUNT = sizeof(STRENGTH_OF_EARTH_TOTEM) / sizeof(uint32); + +// Stoneskin Totem +static const uint32 STONESKIN_TOTEM[] = { + 58753, // Rank 10 + 58751, // Rank 9 + 25509, // Rank 8 + 25508, // Rank 7 + 10408, // Rank 6 + 10407, // Rank 5 + 10406, // Rank 4 + 8155, // Rank 3 + 8154, // Rank 2 + 8071 // Rank 1 +}; +static const size_t STONESKIN_TOTEM_COUNT = sizeof(STONESKIN_TOTEM) / sizeof(uint32); + +// Tremor Totem +static const uint32 TREMOR_TOTEM[] = { + 8143 // Rank 1 +}; +static const size_t TREMOR_TOTEM_COUNT = sizeof(TREMOR_TOTEM) / sizeof(uint32); + +// Earthbind Totem +static const uint32 EARTHBIND_TOTEM[] = { + 2484 // Rank 1 +}; +static const size_t EARTHBIND_TOTEM_COUNT = sizeof(EARTHBIND_TOTEM) / sizeof(uint32); + +// Stoneclaw Totem +static const uint32 STONECLAW_TOTEM[] = { + 58582, // Rank 10 + 58581, // Rank 9 + 58580, // Rank 8 + 25525, // Rank 7 + 10428, // Rank 6 + 10427, // Rank 5 + 6392, // Rank 4 + 6391, // Rank 3 + 6390, // Rank 2 + 5730 // Rank 1 +}; +static const size_t STONECLAW_TOTEM_COUNT = sizeof(STONECLAW_TOTEM) / sizeof(uint32); + +// Searing Totem +static const uint32 SEARING_TOTEM[] = { + 58704, // Rank 10 + 58703, // Rank 9 + 58699, // Rank 8 + 25533, // Rank 7 + 10438, // Rank 6 + 10437, // Rank 5 + 6365, // Rank 4 + 6364, // Rank 3 + 6363, // Rank 2 + 3599 // Rank 1 +}; +static const size_t SEARING_TOTEM_COUNT = sizeof(SEARING_TOTEM) / sizeof(uint32); + +// Magma Totem +static const uint32 MAGMA_TOTEM[] = { + 58734, // Rank 7 + 58731, // Rank 6 + 25552, // Rank 5 + 10587, // Rank 4 + 10586, // Rank 3 + 10585, // Rank 2 + 8190 // Rank 1 +}; +static const size_t MAGMA_TOTEM_COUNT = sizeof(MAGMA_TOTEM) / sizeof(uint32); + +// Flametongue Totem +static const uint32 FLAMETONGUE_TOTEM[] = { + 58656, // Rank 8 + 58652, // Rank 7 + 58649, // Rank 6 + 25557, // Rank 5 + 16387, // Rank 4 + 10526, // Rank 3 + 8249, // Rank 2 + 8227 // Rank 1 +}; +static const size_t FLAMETONGUE_TOTEM_COUNT = sizeof(FLAMETONGUE_TOTEM) / sizeof(uint32); + +// Totem of Wrath +static const uint32 TOTEM_OF_WRATH[] = { + 57722, // Rank 4 + 57721, // Rank 3 + 57720, // Rank 2 + 30706 // Rank 1 +}; +static const size_t TOTEM_OF_WRATH_COUNT = sizeof(TOTEM_OF_WRATH) / sizeof(uint32); + +// Frost Resistance Totem +static const uint32 FROST_RESISTANCE_TOTEM[] = { + 58745, // Rank 6 + 58741, // Rank 5 + 25560, // Rank 4 + 10479, // Rank 3 + 10478, // Rank 2 + 8181 // Rank 1 +}; +static const size_t FROST_RESISTANCE_TOTEM_COUNT = sizeof(FROST_RESISTANCE_TOTEM) / sizeof(uint32); + +// Fire Elemental Totem +static const uint32 FIRE_ELEMENTAL_TOTEM[] = { + 2894 // Rank 1 +}; +static const size_t FIRE_ELEMENTAL_TOTEM_COUNT = sizeof(FIRE_ELEMENTAL_TOTEM) / sizeof(uint32); + +// Healing Stream Totem +static const uint32 HEALING_STREAM_TOTEM[] = { + 58757, // Rank 9 + 58756, // Rank 8 + 58755, // Rank 7 + 25567, // Rank 6 + 10463, // Rank 5 + 10462, // Rank 4 + 6377, // Rank 3 + 6375, // Rank 2 + 5394 // Rank 1 +}; +static const size_t HEALING_STREAM_TOTEM_COUNT = sizeof(HEALING_STREAM_TOTEM) / sizeof(uint32); + +// Mana Spring Totem +static const uint32 MANA_SPRING_TOTEM[] = { + 58774, // Rank 8 + 58773, // Rank 7 + 58771, // Rank 6 + 25570, // Rank 5 + 10497, // Rank 4 + 10496, // Rank 3 + 10495, // Rank 2 + 5675 // Rank 1 +}; +static const size_t MANA_SPRING_TOTEM_COUNT = sizeof(MANA_SPRING_TOTEM) / sizeof(uint32); + +// Cleansing Totem +static const uint32 CLEANSING_TOTEM[] = { + 8170 // Rank 1 +}; +static const size_t CLEANSING_TOTEM_COUNT = sizeof(CLEANSING_TOTEM) / sizeof(uint32); + +// Fire Resistance Totem +static const uint32 FIRE_RESISTANCE_TOTEM[] = { + 58739, // Rank 6 + 58737, // Rank 5 + 25563, // Rank 4 + 10538, // Rank 3 + 10537, // Rank 2 + 8184 // Rank 1 +}; +static const size_t FIRE_RESISTANCE_TOTEM_COUNT = sizeof(FIRE_RESISTANCE_TOTEM) / sizeof(uint32); + +// Mana Tide Totem +static const uint32 MANA_TIDE_TOTEM[] = { + 16190 // Rank 1 +}; +static const size_t MANA_TIDE_TOTEM_COUNT = sizeof(MANA_TIDE_TOTEM) / sizeof(uint32); + +// Wrath of Air Totem +static const uint32 WRATH_OF_AIR_TOTEM[] = { + 3738 // Rank 1 +}; +static const size_t WRATH_OF_AIR_TOTEM_COUNT = sizeof(WRATH_OF_AIR_TOTEM) / sizeof(uint32); + +// Windfury Totem +static const uint32 WINDFURY_TOTEM[] = { + 8512 // Rank 1 +}; +static const size_t WINDFURY_TOTEM_COUNT = sizeof(WINDFURY_TOTEM) / sizeof(uint32); + +// Nature Resistance Totem +static const uint32 NATURE_RESISTANCE_TOTEM[] = { + 58749, // Rank 6 + 58746, // Rank 5 + 25574, // Rank 4 + 10601, // Rank 3 + 10600, // Rank 2 + 10595 // Rank 1 +}; +static const size_t NATURE_RESISTANCE_TOTEM_COUNT = sizeof(NATURE_RESISTANCE_TOTEM) / sizeof(uint32); + +// Grounding Totem +static const uint32 GROUNDING_TOTEM[] = { + 8177 // Rank 1 +}; +static const size_t GROUNDING_TOTEM_COUNT = sizeof(GROUNDING_TOTEM) / sizeof(uint32); class PlayerbotAI; -class TotemsShamanStrategy : public GenericShamanStrategy +// Earth Totem Strategies +class StrengthOfEarthTotemStrategy : public GenericShamanStrategy { public: - TotemsShamanStrategy(PlayerbotAI* botAI); - + StrengthOfEarthTotemStrategy(PlayerbotAI* botAI); void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "totems"; } + std::string const getName() override { return "strength of earth"; } +}; + +class StoneclawTotemStrategy : public GenericShamanStrategy +{ +public: + StoneclawTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "stoneskin"; } +}; + +class EarthTotemStrategy : public GenericShamanStrategy +{ +public: + EarthTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "tremor"; } +}; + +class EarthbindTotemStrategy : public GenericShamanStrategy +{ +public: + EarthbindTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "earthbind"; } +}; + +// Fire Totem Strategies +class SearingTotemStrategy : public GenericShamanStrategy +{ +public: + SearingTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "searing"; } +}; + +class MagmaTotemStrategy : public GenericShamanStrategy +{ +public: + MagmaTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "magma"; } +}; + +class FlametongueTotemStrategy : public GenericShamanStrategy +{ +public: + FlametongueTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "flametongue"; } +}; + +class TotemOfWrathStrategy : public GenericShamanStrategy +{ +public: + TotemOfWrathStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "wrath"; } +}; + +class FrostResistanceTotemStrategy : public GenericShamanStrategy +{ +public: + FrostResistanceTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "frost resistance"; } +}; + +// Water Totem Strategies +class HealingStreamTotemStrategy : public GenericShamanStrategy +{ +public: + HealingStreamTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "healing stream"; } +}; + +class ManaSpringTotemStrategy : public GenericShamanStrategy +{ +public: + ManaSpringTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "mana spring"; } +}; + +class CleansingTotemStrategy : public GenericShamanStrategy +{ +public: + CleansingTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "cleansing"; } +}; + +class FireResistanceTotemStrategy : public GenericShamanStrategy +{ +public: + FireResistanceTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "fire resistance"; } +}; + +// Air Totem Strategies +class WrathOfAirTotemStrategy : public GenericShamanStrategy +{ +public: + WrathOfAirTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "wrath of air"; } +}; + +class WindfuryTotemStrategy : public GenericShamanStrategy +{ +public: + WindfuryTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "windfury"; } +}; + +class NatureResistanceTotemStrategy : public GenericShamanStrategy +{ +public: + NatureResistanceTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "nature resistance"; } +}; + +class GroundingTotemStrategy : public GenericShamanStrategy +{ +public: + GroundingTotemStrategy(PlayerbotAI* botAI); + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "grounding"; } }; #endif