From 8ca4ab1344527ae3136a078d0df4324fe3d68cbf Mon Sep 17 00:00:00 2001 From: ThePenguinMan96 Date: Fri, 11 Jul 2025 17:10:03 -0700 Subject: [PATCH] Hunter Overhaul Hello everybody, I saw that the hunter class had one strategy for all 3 specs, and decided to create specialized strategies for each one. Here is a list of the changes: conf\playerbots.conf.dist: Redid the talent trees and glyphs slightly, for more consistent dps src\AiFactory.cpp: Changed the default strategies assigned for each spec. src\strategy\hunter\BeastMasteryHunterStrategy.cpp and src\strategy\hunter\BeastMasteryHunterStrategy.h: Strategy for BM hunters. Includes all of the original logic from DpsHunterStrategy, with the addition of kill command, bestial wrath, and intimidation. src\strategy\hunter\DpsHunterStrategy.cpp and src\strategy\hunter\DpsHunterStrategy.h: Old Dps strategy used for all 3 specs - removed. src\strategy\hunter\GenericHunterStrategy.cpp and src\strategy\hunter\GenericHunterStrategy.h: Tidied up code, added Dragonhawk passthrough to hawk, moved rapid fire to inittriggers for generichunterstrategy and increased its priority (it is still a boost trigger, so it will function the same). src\strategy\hunter\HunterActions.cpp: Added isuseful check for aspect of the hawk, to ensure it is never cast if the bot knows aspect of the dragonhawk. Added isuseful check for arcane shot to never use it after explosive shot is learned (so the hunter can use it as it levels survival, but drops it after that). Also added a check for arcane shot, so it won't use it above 435 armor pen rating (steady shot is superior after this arp). Added isuseful check for immolation trap so it won't use it after explosive shot is learned. src\strategy\hunter\HunterActions.h: General cleanup/alignment of actions based on type. Added TTL checks to all DoTs and debuffs - hunters weren't using hunter's mark, serpent sting, black arrow, explosive shot on enemies that it thought would die too soon. Black Arrow - added a strategy check here as well so the bot won't use it at all if trap weave is enabled. There was already a check in the trigger, but it was still getting cast, so I added this check. Explosive Shot Rank 4, 3, 2, 1 actions- Added these so the hunter can downrank explosive shot dynamically based on the level when lock and load procs. So if the hunter is level 70, and a lock and load proc happens, it will fire rank 2 - rank 1 - rank 2, similar to how the level 80 version will fire 4-3-4. src\strategy\hunter\HunterAiObjectContext.cpp: Added strategy support for bm, mm, and surv (and their aoes) Added trigger support for kill command, explosive shot, lock and load, silencing shot (as an spellcasting interrupt), and intimidation Added action support for the 4 ranks of explosive shot and intimidation. src\strategy\hunter\HunterTriggers.cpp: Kill command was completely non-functional because there was no buff trigger associated with it. Adding this will correct that, and the hunter will use kill command. src\strategy\hunter\HunterTriggers.h: Added Kill command, silencing shot, intimidation, lock and load, and explosive shot triggers. src\strategy\hunter\MarksmanshipHunterStrategy.cpp and src\strategy\hunter\MarksmanshipHunterStrategy.h: Strategy for MM hunters. Includes all of the original logic from DpsHunterStrategy, with the addition of kill command, silencing shot, chimera shot, and aimed shot. src\strategy\hunter\SurvivalHunterStrategy.cpp and src\strategy\hunter\SurvivalHunterStrategy.h: Strategy for Survival hunters. Includes all of the original logic from DpsHunterStrategy, with the addition of kill command, explosive shot, black arrow, aimed shot, lock and load triggers + downranking explosive shot. --- conf/playerbots.conf.dist | 15 +- src/AiFactory.cpp | 14 +- .../hunter/BeastMasteryHunterStrategy.cpp | 78 +++ .../hunter/BeastMasteryHunterStrategy.h | 32 ++ src/strategy/hunter/DpsHunterStrategy.cpp | 89 ---- src/strategy/hunter/DpsHunterStrategy.h | 41 -- src/strategy/hunter/GenericHunterStrategy.cpp | 82 ++- src/strategy/hunter/GenericHunterStrategy.h | 1 - src/strategy/hunter/HunterActions.cpp | 42 +- src/strategy/hunter/HunterActions.h | 490 ++++++++++++------ src/strategy/hunter/HunterAiObjectContext.cpp | 49 +- src/strategy/hunter/HunterTriggers.cpp | 12 +- src/strategy/hunter/HunterTriggers.h | 195 ++++--- .../hunter/MarksmanshipHunterStrategy.cpp | 83 +++ .../hunter/MarksmanshipHunterStrategy.h | 32 ++ .../hunter/SurvivalHunterStrategy.cpp | 91 ++++ src/strategy/hunter/SurvivalHunterStrategy.h | 32 ++ 17 files changed, 938 insertions(+), 440 deletions(-) create mode 100644 src/strategy/hunter/BeastMasteryHunterStrategy.cpp create mode 100644 src/strategy/hunter/BeastMasteryHunterStrategy.h delete mode 100644 src/strategy/hunter/DpsHunterStrategy.cpp delete mode 100644 src/strategy/hunter/DpsHunterStrategy.h create mode 100644 src/strategy/hunter/MarksmanshipHunterStrategy.cpp create mode 100644 src/strategy/hunter/MarksmanshipHunterStrategy.h create mode 100644 src/strategy/hunter/SurvivalHunterStrategy.cpp create mode 100644 src/strategy/hunter/SurvivalHunterStrategy.h diff --git a/conf/playerbots.conf.dist b/conf/playerbots.conf.dist index e7233c2a..624cce51 100644 --- a/conf/playerbots.conf.dist +++ b/conf/playerbots.conf.dist @@ -1203,15 +1203,16 @@ AiPlayerbot.PremadeSpecLink.2.5.80 = -1532013022-05230250203331322133201321 # AiPlayerbot.PremadeSpecName.3.0 = bm pve -AiPlayerbot.PremadeSpecGlyph.3.0 = 42912,43350,42902,43351,43338,45732 -AiPlayerbot.PremadeSpecLink.3.0.60 = 51200201505112243110531051 -AiPlayerbot.PremadeSpecLink.3.0.80 = 51200201505112243120531251-025305101 +AiPlayerbot.PremadeSpecGlyph.3.0 = 42912,43350,42902,43351,43338,42914 +AiPlayerbot.PremadeSpecLink.3.0.40 = 512002015051122301 +AiPlayerbot.PremadeSpecLink.3.0.60 = 51200201505112233110531151 +AiPlayerbot.PremadeSpecLink.3.0.80 = 51200201505112243130531351-005305101 AiPlayerbot.PremadeSpecName.3.1 = mm pve -AiPlayerbot.PremadeSpecGlyph.3.1 = 42912,43350,42914,43351,43338,45732 -AiPlayerbot.PremadeSpecLink.3.1.60 = -025315101030013233125031051 -AiPlayerbot.PremadeSpecLink.3.1.80 = 502-025335101030013233135031351-5000002 +AiPlayerbot.PremadeSpecGlyph.3.1 = 42912,43350,45625,43351,43338,42914 +AiPlayerbot.PremadeSpecLink.3.1.60 = -035305101030013233115031151 +AiPlayerbot.PremadeSpecLink.3.1.80 = 502-035305101230013233135031351-5000002 AiPlayerbot.PremadeSpecName.3.2 = surv pve -AiPlayerbot.PremadeSpecGlyph.3.2 = 42912,43350,45731,43351,43338,45732 +AiPlayerbot.PremadeSpecGlyph.3.2 = 45733,43350,45731,43351,43338,45732 AiPlayerbot.PremadeSpecLink.3.2.60 = --5000032500033330502135201311 AiPlayerbot.PremadeSpecLink.3.2.80 = -005305101-5000032500033330532135301321 AiPlayerbot.PremadeSpecName.3.3 = bm pvp diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index b6693095..08cdc9a3 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -367,12 +367,14 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa } break; case CLASS_HUNTER: - engine->addStrategiesNoInit("dps", "aoe", "bdps", "dps assist", nullptr); - engine->addStrategy("dps debuff", false); - // if (tab == HUNTER_TAB_SURVIVAL) - // { - // engine->addStrategy("trap weave", false); - // } + if (tab == 0) // Beast Mastery + engine->addStrategiesNoInit("bm", "bm aoe", nullptr); + else if (tab == 1) // Marksmanship + engine->addStrategiesNoInit("mm", "mm aoe", nullptr); + else if (tab == 2) // Survival + engine->addStrategiesNoInit("surv", "surv aoe", "trap weave", nullptr); + + engine->addStrategiesNoInit("cc", "dps assist", nullptr); break; case CLASS_ROGUE: if (tab == ROGUE_TAB_ASSASSINATION || tab == ROGUE_TAB_SUBTLETY) diff --git a/src/strategy/hunter/BeastMasteryHunterStrategy.cpp b/src/strategy/hunter/BeastMasteryHunterStrategy.cpp new file mode 100644 index 00000000..787f95b4 --- /dev/null +++ b/src/strategy/hunter/BeastMasteryHunterStrategy.cpp @@ -0,0 +1,78 @@ +/* + * 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 "BeastMasteryHunterStrategy.h" +#include "Playerbots.h" + +// ===== Action Node Factory ===== +class BeastMasteryHunterStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + BeastMasteryHunterStrategyActionNodeFactory() + { + creators["auto shot"] = &auto_shot; + creators["kill command"] = &kill_command; + creators["kill shot"] = &kill_shot; + creators["viper sting"] = &viper_sting; + creators["serpent sting"] = serpent_sting; + creators["aimed shot"] = &aimed_shot; + creators["arcane shot"] = &arcane_shot; + creators["steady shot"] = &steady_shot; + creators["multi-shot"] = &multi_shot; + creators["volley"] = &volley; + } + +private: + static ActionNode* auto_shot(PlayerbotAI*) { return new ActionNode("auto shot", nullptr, nullptr, nullptr); } + static ActionNode* kill_command(PlayerbotAI*) { return new ActionNode("kill command", nullptr, nullptr, nullptr); } + static ActionNode* kill_shot(PlayerbotAI*) { return new ActionNode("kill shot", nullptr, nullptr, nullptr); } + static ActionNode* viper_sting(PlayerbotAI*) { return new ActionNode("viper sting", nullptr, nullptr, nullptr); } + static ActionNode* serpent_sting(PlayerbotAI*) { return new ActionNode("serpent sting", nullptr, nullptr, nullptr); } + static ActionNode* aimed_shot(PlayerbotAI*) { return new ActionNode("aimed shot", nullptr, nullptr, nullptr); } + static ActionNode* arcane_shot(PlayerbotAI*) { return new ActionNode("arcane shot", nullptr, nullptr, nullptr); } + static ActionNode* steady_shot(PlayerbotAI*) { return new ActionNode("steady shot", nullptr, nullptr, nullptr); } + static ActionNode* multi_shot(PlayerbotAI*) { return new ActionNode("multi shot", nullptr, nullptr, nullptr); } + static ActionNode* volley(PlayerbotAI*) { return new ActionNode("volley", nullptr, nullptr, nullptr); } +}; + +// ===== Single Target Strategy ===== +BeastMasteryHunterStrategy::BeastMasteryHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI) +{ + actionNodeFactories.Add(new BeastMasteryHunterStrategyActionNodeFactory()); +} + +// ===== Default Actions ===== +NextAction** BeastMasteryHunterStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("bestial wrath", 19.0f), + new NextAction("kill command", 5.7f), + new NextAction("kill shot", 5.6f), + new NextAction("serpent sting", 5.5f), + new NextAction("aimed shot", 5.4f), + new NextAction("arcane shot", 5.3f), + new NextAction("steady shot", 5.2f), + new NextAction("auto shot", 5.1f), nullptr); +} + +// ===== Trigger Initialization === +void BeastMasteryHunterStrategy::InitTriggers(std::vector& triggers) +{ + GenericHunterStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("intimidation", NextAction::array(0, new NextAction("intimidation", 40.0f), nullptr))); + triggers.push_back(new TriggerNode("kill command", NextAction::array(0, new NextAction("kill command", 18.5f), nullptr))); + triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("kill shot", 18.0f), nullptr))); + triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("viper sting", 17.5f), nullptr))); + triggers.push_back(new TriggerNode("no stings", NextAction::array(0, new NextAction("serpent sting", 17.0f), nullptr))); + triggers.push_back(new TriggerNode("serpent sting on attacker", NextAction::array(0, new NextAction("serpent sting on attacker", 16.5f), nullptr))); +} + +// ===== AoE Strategy, 2/3+ enemies ===== +BeastMasteryHunterAoeStrategy::BeastMasteryHunterAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {} + +void BeastMasteryHunterAoeStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("volley", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("multi-shot", 21.0f), nullptr))); +} diff --git a/src/strategy/hunter/BeastMasteryHunterStrategy.h b/src/strategy/hunter/BeastMasteryHunterStrategy.h new file mode 100644 index 00000000..78e99214 --- /dev/null +++ b/src/strategy/hunter/BeastMasteryHunterStrategy.h @@ -0,0 +1,32 @@ +/* + * 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_BEASTMASTERYHUNTERSTRATEGY_H +#define _PLAYERBOT_BEASTMASTERYHUNTERSTRATEGY_H + +#include "GenericHunterStrategy.h" +#include "CombatStrategy.h" + +class PlayerbotAI; + +class BeastMasteryHunterStrategy : public GenericHunterStrategy +{ +public: + BeastMasteryHunterStrategy(PlayerbotAI* botAI); + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "bm"; } + NextAction** getDefaultActions() override; +}; + +class BeastMasteryHunterAoeStrategy : public CombatStrategy +{ +public: + BeastMasteryHunterAoeStrategy(PlayerbotAI* botAI); + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "bm aoe"; } +}; +#endif diff --git a/src/strategy/hunter/DpsHunterStrategy.cpp b/src/strategy/hunter/DpsHunterStrategy.cpp deleted file mode 100644 index b8709378..00000000 --- a/src/strategy/hunter/DpsHunterStrategy.cpp +++ /dev/null @@ -1,89 +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 "DpsHunterStrategy.h" - -#include "Playerbots.h" - -class DpsHunterStrategyActionNodeFactory : public NamedObjectFactory -{ -public: - DpsHunterStrategyActionNodeFactory() - { - creators["aimed shot"] = &aimed_shot; - creators["steady shot"] = &steady_shot; - } - -private: - static ActionNode* aimed_shot([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("aimed shot", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("multi-shot"), nullptr), - /*C*/ nullptr); - } - static ActionNode* steady_shot([[maybe_unused]] PlayerbotAI* botAI) - { - return new ActionNode("steady shot", - /*P*/ nullptr, - /*A*/ NextAction::array(0, new NextAction("arcane shot"), nullptr), - /*C*/ nullptr); - } -}; - -DpsHunterStrategy::DpsHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI) -{ - actionNodeFactories.Add(new DpsHunterStrategyActionNodeFactory()); -} - -NextAction** DpsHunterStrategy::getDefaultActions() -{ - return NextAction::array( - 0, - new NextAction("explosive shot", ACTION_HIGH + 1.0f), - new NextAction("kill shot", ACTION_DEFAULT + 0.8f), - new NextAction("chimera shot", ACTION_DEFAULT + 0.6f), - new NextAction("aimed shot", ACTION_DEFAULT + 0.5f), - new NextAction("silencing shot", ACTION_DEFAULT + 0.4f), - new NextAction("kill command", ACTION_DEFAULT + 0.3f), - // new NextAction("arcane shot", ACTION_DEFAULT + 0.2f), - new NextAction("steady shot", ACTION_DEFAULT + 0.1f), - new NextAction("auto shot", ACTION_DEFAULT), nullptr); -} - -void DpsHunterStrategy::InitTriggers(std::vector& triggers) -{ - GenericHunterStrategy::InitTriggers(triggers); - - triggers.push_back( - new TriggerNode("black arrow", NextAction::array(0, new NextAction("black arrow", 19.0f), nullptr))); - triggers.push_back( - new TriggerNode("low mana", NextAction::array(0, new NextAction("viper sting", 23.0f), nullptr))); - triggers.push_back( - new TriggerNode("hunter's mark", NextAction::array(0, new NextAction("hunter's mark", 31.0f), nullptr))); - triggers.push_back(new TriggerNode("concussive shot on snare target", - NextAction::array(0, new NextAction("concussive shot", 20.0f), nullptr))); - // triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("call pet", 21.0f), NULL))); - // triggers.push_back(new TriggerNode("hunters pet low health", NextAction::array(0, new NextAction("mend - // pet", 21.0f), NULL))); - triggers.push_back( - new TriggerNode("has aggro", NextAction::array(0, new NextAction("concussive shot", 20.0f), nullptr))); -} - -void DpsAoeHunterStrategy::InitTriggers(std::vector& triggers) -{ - triggers.push_back( - new TriggerNode("light aoe", NextAction::array(0, new NextAction("multi-shot", 20.0f), nullptr))); - triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("volley", 21.0f), nullptr))); - triggers.push_back( - new TriggerNode("serpent sting on attacker", - NextAction::array(0, new NextAction("serpent sting on attacker", 17.0f), nullptr))); -} - -void DpsHunterDebuffStrategy::InitTriggers(std::vector& triggers) -{ - triggers.push_back( - new TriggerNode("no stings", NextAction::array(0, new NextAction("serpent sting", 18.0f), nullptr))); -} diff --git a/src/strategy/hunter/DpsHunterStrategy.h b/src/strategy/hunter/DpsHunterStrategy.h deleted file mode 100644 index 2cf8707c..00000000 --- a/src/strategy/hunter/DpsHunterStrategy.h +++ /dev/null @@ -1,41 +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_DPSHUNTERSTRATEGY_H -#define _PLAYERBOT_DPSHUNTERSTRATEGY_H - -#include "GenericHunterStrategy.h" - -class PlayerbotAI; - -class DpsHunterStrategy : public GenericHunterStrategy -{ -public: - DpsHunterStrategy(PlayerbotAI* botAI); - - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "dps"; } - NextAction** getDefaultActions() override; -}; - -class DpsAoeHunterStrategy : public CombatStrategy -{ -public: - DpsAoeHunterStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {} - - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "aoe"; } -}; - -class DpsHunterDebuffStrategy : public CombatStrategy -{ -public: - DpsHunterDebuffStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {} - - void InitTriggers(std::vector& triggers) override; - std::string const getName() override { return "dps debuff"; } -}; - -#endif diff --git a/src/strategy/hunter/GenericHunterStrategy.cpp b/src/strategy/hunter/GenericHunterStrategy.cpp index 9e32b4ee..4c4763f9 100644 --- a/src/strategy/hunter/GenericHunterStrategy.cpp +++ b/src/strategy/hunter/GenericHunterStrategy.cpp @@ -16,6 +16,7 @@ public: creators["rapid fire"] = &rapid_fire; creators["boost"] = &rapid_fire; creators["aspect of the pack"] = &aspect_of_the_pack; + creators["aspect of the dragonhawk"] = &aspect_of_the_dragonhawk; creators["feign death"] = &feign_death; creators["wing clip"] = &wing_clip; creators["mongoose bite"] = &mongoose_bite; @@ -40,6 +41,14 @@ private: /*C*/ nullptr); } + static ActionNode* aspect_of_the_dragonhawk([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("aspect of the dragonhawk", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("aspect of the hawk"), nullptr), + /*C*/ nullptr); + } + static ActionNode* feign_death([[maybe_unused]] PlayerbotAI* botAI) { return new ActionNode("feign death", @@ -80,7 +89,6 @@ private: /*A*/ NextAction::array(0, new NextAction("immolation trap"), nullptr), /*C*/ nullptr); } - }; GenericHunterStrategy::GenericHunterStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) @@ -92,58 +100,48 @@ void GenericHunterStrategy::InitTriggers(std::vector& triggers) { CombatStrategy::InitTriggers(triggers); - triggers.push_back(new TriggerNode("enemy within melee", - NextAction::array(0, - new NextAction("explosive trap", ACTION_MOVE + 7), - new NextAction("mongoose bite", ACTION_HIGH + 2), - new NextAction("wing clip", ACTION_HIGH + 1), - nullptr))); - triggers.push_back( - new TriggerNode("medium threat", NextAction::array(0, new NextAction("feign death", 35.0f), nullptr))); - triggers.push_back(new TriggerNode("hunters pet medium health", - NextAction::array(0, new NextAction("mend pet", ACTION_HIGH + 2), nullptr))); - triggers.push_back(new TriggerNode("no ammo", - NextAction::array(0, new NextAction("equip upgrades", ACTION_HIGH + 9), nullptr))); - triggers.push_back(new TriggerNode("aspect of the viper", - NextAction::array(0, new NextAction("aspect of the viper", ACTION_HIGH), NULL))); - triggers.push_back(new TriggerNode("enemy too close for auto shot", - NextAction::array(0, - new NextAction("disengage", ACTION_MOVE + 5), - new NextAction("flee", ACTION_MOVE + 4), - nullptr))); - triggers.push_back( - new TriggerNode("low tank threat", - NextAction::array(0, new NextAction("misdirection on main tank", ACTION_HIGH + 7), NULL))); - triggers.push_back( - new TriggerNode("low health", NextAction::array(0, new NextAction("deterrence", ACTION_HIGH + 5), nullptr))); - - triggers.push_back(new TriggerNode("tranquilizing shot enrage", - NextAction::array(0, new NextAction("tranquilizing shot", 61.0f), NULL))); - triggers.push_back(new TriggerNode("tranquilizing shot magic", - NextAction::array(0, new NextAction("tranquilizing shot", 61.0f), NULL))); -} + // Mark/Ammo/Mana Triggers + triggers.push_back(new TriggerNode("no ammo", NextAction::array(0, new NextAction("equip upgrades", 30.0f), nullptr))); + triggers.push_back(new TriggerNode("hunter's mark", NextAction::array(0, new NextAction("hunter's mark", 29.5f), nullptr))); + triggers.push_back(new TriggerNode("rapid fire", NextAction::array(0, new NextAction("rapid fire", 29.0f), nullptr))); + triggers.push_back(new TriggerNode("aspect of the viper", NextAction::array(0, new NextAction("aspect of the viper", 28.0f), NULL))); + triggers.push_back(new TriggerNode("aspect of the hawk", NextAction::array(0, new NextAction("aspect of the dragonhawk", 27.5f), nullptr))); -NextAction** HunterBoostStrategy::getDefaultActions() -{ - return NextAction::array(0, new NextAction("bestial wrath", 15.0f), nullptr); + // Aggro/Threat/Defensive Triggers + triggers.push_back(new TriggerNode("has aggro", NextAction::array(0, new NextAction("concussive shot", 20.0f), nullptr))); + triggers.push_back(new TriggerNode("low tank threat", NextAction::array(0, new NextAction("misdirection on main tank", 27.0f), NULL))); + triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("deterrence", 35.0f), nullptr))); + triggers.push_back(new TriggerNode("concussive shot on snare target", NextAction::array(0, new NextAction("concussive shot", 20.0f), nullptr))); + triggers.push_back(new TriggerNode("medium threat", NextAction::array(0, new NextAction("feign death", 35.0f), nullptr))); + triggers.push_back(new TriggerNode("hunters pet medium health", NextAction::array(0, new NextAction("mend pet", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("hunters pet low health", NextAction::array(0, new NextAction("mend pet", 21.0f), nullptr))); + + // Dispel Triggers + triggers.push_back(new TriggerNode("tranquilizing shot enrage", NextAction::array(0, new NextAction("tranquilizing shot", 61.0f), NULL))); + triggers.push_back(new TriggerNode("tranquilizing shot magic", NextAction::array(0, new NextAction("tranquilizing shot", 61.0f), NULL))); + + // Ranged-based Triggers + triggers.push_back(new TriggerNode("enemy within melee", NextAction::array(0, + new NextAction("explosive trap", 37.0f), + new NextAction("mongoose bite", 22.0f), + new NextAction("wing clip", 21.0f), nullptr))); + + triggers.push_back(new TriggerNode("enemy too close for auto shot", NextAction::array(0, + new NextAction("disengage", 35.0f), + new NextAction("flee", 34.0f), nullptr))); } void HunterBoostStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back( - new TriggerNode("rapid fire", NextAction::array(0, new NextAction("rapid fire", 16.0f), nullptr))); } void HunterCcStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back(new TriggerNode( - "scare beast", NextAction::array(0, new NextAction("scare beast on cc", ACTION_HIGH + 3), nullptr))); - triggers.push_back(new TriggerNode( - "freezing trap", NextAction::array(0, new NextAction("freezing trap on cc", ACTION_HIGH + 3), nullptr))); + triggers.push_back(new TriggerNode("scare beast", NextAction::array(0, new NextAction("scare beast on cc", 23.0f), nullptr))); + triggers.push_back(new TriggerNode("freezing trap", NextAction::array(0, new NextAction("freezing trap on cc", 23.0f), nullptr))); } void HunterTrapWeaveStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back(new TriggerNode( - "immolation trap no cd", NextAction::array(0, new NextAction("reach melee", ACTION_HIGH + 3), nullptr))); + triggers.push_back(new TriggerNode("immolation trap no cd", NextAction::array(0, new NextAction("reach melee", 23.0f), nullptr))); } diff --git a/src/strategy/hunter/GenericHunterStrategy.h b/src/strategy/hunter/GenericHunterStrategy.h index 52148eed..ea4f2b9c 100644 --- a/src/strategy/hunter/GenericHunterStrategy.h +++ b/src/strategy/hunter/GenericHunterStrategy.h @@ -27,7 +27,6 @@ public: HunterBoostStrategy(PlayerbotAI* botAI) : Strategy(botAI) {} std::string const getName() override { return "boost"; } - NextAction** getDefaultActions() override; void InitTriggers(std::vector& triggers) override; }; diff --git a/src/strategy/hunter/HunterActions.cpp b/src/strategy/hunter/HunterActions.cpp index 074a9bbd..b0351cf6 100644 --- a/src/strategy/hunter/HunterActions.cpp +++ b/src/strategy/hunter/HunterActions.cpp @@ -10,11 +10,10 @@ #include "PlayerbotAI.h" #include "Playerbots.h" -bool CastHuntersMarkAction::isUseful() { return CastDebuffSpellAction::isUseful(); } - bool CastViperStingAction::isUseful() { - return AI_VALUE2(uint8, "mana", "self target") < 50 && AI_VALUE2(uint8, "mana", "current target") >= 30; + return CastAuraSpellAction::isUseful() && AI_VALUE2(uint8, "mana", "self target") < 50 && + AI_VALUE2(uint8, "mana", "current target") >= 30; } bool CastAspectOfTheCheetahAction::isUseful() @@ -22,6 +21,42 @@ bool CastAspectOfTheCheetahAction::isUseful() return !botAI->HasAnyAuraOf(GetTarget(), "aspect of the cheetah", "aspect of the pack", nullptr); } +bool CastAspectOfTheHawkAction::isUseful() +{ + Unit* target = GetTarget(); + if (!target) + return false; + if (bot->HasSpell(61846) || bot->HasSpell(61847)) // Aspect of the Dragonhawk spell IDs + return false; + return true; +} + +bool CastArcaneShotAction::isUseful() +{ + Unit* target = GetTarget(); + if (!target) + return false; + if (bot->HasSpell(53301) || bot->HasSpell(60051) || bot->HasSpell(60052) || bot->HasSpell(60053)) // Explosive Shot spell IDs + return false; + + // Armor Penetration rating check - will not cast Arcane Shot above 435 ArP + int32 armorPenRating = bot->GetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + CR_ARMOR_PENETRATION); + if (armorPenRating > 435) + return false; + + return true; +} + +bool CastImmolationTrapAction::isUseful() +{ + Unit* target = GetTarget(); + if (!target) + return false; + if (bot->HasSpell(13813) || bot->HasSpell(14316) || bot->HasSpell(14317) || bot->HasSpell(27025) || bot->HasSpell(49066) || bot->HasSpell(49067)) // Explosive Trap spell IDs + return false; + return true; +} + Value* CastFreezingTrap::GetTargetValue() { return context->GetValue("cc target", "freezing trap"); } bool FeedPetAction::Execute(Event event) @@ -62,7 +97,6 @@ bool CastDisengageAction::isUseful() return !botAI->HasStrategy("trap weave", BOT_STATE_COMBAT); } - Value* CastScareBeastCcAction::GetTargetValue() { return context->GetValue("cc target", "scare beast"); } bool CastScareBeastCcAction::Execute(Event event) { return botAI->CastSpell("scare beast", GetTarget()); } diff --git a/src/strategy/hunter/HunterActions.h b/src/strategy/hunter/HunterActions.h index d8618c42..752577c5 100644 --- a/src/strategy/hunter/HunterActions.h +++ b/src/strategy/hunter/HunterActions.h @@ -9,107 +9,24 @@ #include "AiObject.h" #include "Event.h" #include "GenericSpellActions.h" +#include "Unit.h" class PlayerbotAI; class Unit; -// BEGIN_RANGED_SPELL_ACTION(CastHuntersMarkAction, "hunter's mark") -// END_SPELL_ACTION() +// Buff and Out of Combat Spells -class CastHuntersMarkAction : public CastDebuffSpellAction +class CastTrueshotAuraAction : public CastBuffSpellAction { public: - CastHuntersMarkAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "hunter's mark") {} - bool isUseful() override; -}; -class CastAutoShotAction : public CastSpellAction -{ -public: - CastAutoShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "auto shot") {} - ActionThreatType getThreatType() override { return ActionThreatType::None; } - bool isUseful() override; -}; - -BEGIN_RANGED_SPELL_ACTION(CastArcaneShotAction, "arcane shot") -END_SPELL_ACTION() - -class CastExplosiveShotAction : public CastDebuffSpellAction -{ -public: - CastExplosiveShotAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {} -}; - -BEGIN_RANGED_SPELL_ACTION(CastAimedShotAction, "aimed shot") -END_SPELL_ACTION() - -BEGIN_RANGED_SPELL_ACTION(CastChimeraShotAction, "chimera shot") -END_SPELL_ACTION() - -class CastConcussiveShotAction : public CastSnareSpellAction -{ -public: - CastConcussiveShotAction(PlayerbotAI* botAI) : CastSnareSpellAction(botAI, "concussive shot") {} -}; - -BEGIN_RANGED_SPELL_ACTION(CastDistractingShotAction, "distracting shot") -END_SPELL_ACTION() - -BEGIN_RANGED_SPELL_ACTION(CastMultiShotAction, "multi-shot") -END_SPELL_ACTION() - -BEGIN_RANGED_SPELL_ACTION(CastVolleyAction, "volley") -ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } -END_SPELL_ACTION() - -DEBUFF_CHECKISOWNER_ACTION(CastSerpentStingAction, "serpent sting"); - -BEGIN_RANGED_SPELL_ACTION(CastWyvernStingAction, "wyvern sting") -END_SPELL_ACTION() - -BEGIN_RANGED_SPELL_ACTION(CastViperStingAction, "viper sting") -bool isUseful() override; -END_SPELL_ACTION() - -BEGIN_RANGED_SPELL_ACTION(CastScorpidStingAction, "scorpid sting") -END_SPELL_ACTION() - -BEGIN_RANGED_SPELL_ACTION(CastSteadyShotAction, "steady shot") -END_SPELL_ACTION() - -BEGIN_RANGED_SPELL_ACTION(CastKillShotAction, "kill shot") -END_SPELL_ACTION() - -BEGIN_RANGED_SPELL_ACTION(CastSilencingShotAction, "silencing shot") -END_SPELL_ACTION() - -BEGIN_RANGED_SPELL_ACTION(CastTranquilizingShotAction, "tranquilizing shot") -END_SPELL_ACTION() - -class CastDisengageAction : public CastSpellAction -{ -public: - CastDisengageAction(PlayerbotAI* botAI): CastSpellAction(botAI, "disengage") {} - - bool Execute(Event event) override; - bool isUseful() override; -}; - -class CastImmolationTrapAction : public CastSpellAction -{ -public: - CastImmolationTrapAction(PlayerbotAI* botAI): CastSpellAction(botAI, "immolation trap") {} -}; - -class CastExplosiveTrapAction : public CastSpellAction -{ -public: - CastExplosiveTrapAction(PlayerbotAI* botAI): CastSpellAction(botAI, "explosive trap") {} + CastTrueshotAuraAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "trueshot aura") {} }; class CastAspectOfTheHawkAction : public CastBuffSpellAction { public: CastAspectOfTheHawkAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "aspect of the hawk") {} + bool isUseful() override; }; class CastAspectOfTheMonkeyAction : public CastBuffSpellAction @@ -150,45 +67,7 @@ public: CastAspectOfTheViperAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "aspect of the viper") {} }; -class CastCallPetAction : public CastBuffSpellAction -{ -public: - CastCallPetAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "call pet") {} -}; - -class CastMendPetAction : public CastAuraSpellAction -{ -public: - CastMendPetAction(PlayerbotAI* botAI) : CastAuraSpellAction(botAI, "mend pet") {} - - std::string const GetTargetName() override { return "pet target"; } -}; - -class CastKillCommandAction : public CastAuraSpellAction -{ -public: - CastKillCommandAction(PlayerbotAI* botAI) : CastAuraSpellAction(botAI, "kill command") {} - - std::string const GetTargetName() override { return "pet target"; } -}; - -class CastRevivePetAction : public CastBuffSpellAction -{ -public: - CastRevivePetAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "revive pet") {} -}; - -class CastTrueshotAuraAction : public CastBuffSpellAction -{ -public: - CastTrueshotAuraAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "trueshot aura") {} -}; - -class CastFeignDeathAction : public CastBuffSpellAction -{ -public: - CastFeignDeathAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "feign death") {} -}; +// Cooldown Spells class CastRapidFireAction : public CastBuffSpellAction { @@ -208,10 +87,30 @@ public: CastReadinessAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "readiness") {} }; -class CastBlackArrow : public CastDebuffSpellAction +class CastDisengageAction : public CastSpellAction { public: - CastBlackArrow(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "black arrow", true) {} + CastDisengageAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "disengage") {} + + bool Execute(Event event) override; + bool isUseful() override; +}; + +// CC Spells + +class CastScareBeastAction : public CastSpellAction +{ +public: + CastScareBeastAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "scare beast") {} +}; + +class CastScareBeastCcAction : public CastSpellAction +{ +public: + CastScareBeastCcAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "scare beast on cc") {} + + Value* GetTargetValue() override; + bool Execute(Event event) override; }; class CastFreezingTrap : public CastDebuffSpellAction @@ -222,6 +121,297 @@ public: Value* GetTargetValue() override; }; +class CastWyvernStingAction : public CastDebuffSpellAction +{ +public: + CastWyvernStingAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "wyvern sting", true) {} +}; + +class CastSilencingShotAction : public CastSpellAction +{ +public: + CastSilencingShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "silencing shot") {} +}; + +class CastConcussiveShotAction : public CastSnareSpellAction +{ +public: + CastConcussiveShotAction(PlayerbotAI* botAI) : CastSnareSpellAction(botAI, "concussive shot") {} +}; + +class CastIntimidationAction : public CastBuffSpellAction +{ +public: + CastIntimidationAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "intimidation", false, 5000) {} + std::string const GetTargetName() override { return "pet target"; } +}; + +// Threat Spells + +class CastDistractingShotAction : public CastSpellAction +{ +public: + CastDistractingShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "distracting shot") {} +}; + +class CastMisdirectionOnMainTankAction : public BuffOnMainTankAction +{ +public: + CastMisdirectionOnMainTankAction(PlayerbotAI* ai) : BuffOnMainTankAction(ai, "misdirection", true) {} +}; + +class CastFeignDeathAction : public CastBuffSpellAction +{ +public: + CastFeignDeathAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "feign death") {} +}; + +// Pet Spells + +class FeedPetAction : public Action +{ +public: + FeedPetAction(PlayerbotAI* botAI) : Action(botAI, "feed pet") {} + + bool Execute(Event event) override; +}; + +class CastCallPetAction : public CastBuffSpellAction +{ +public: + CastCallPetAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "call pet") {} +}; + +class CastMendPetAction : public CastAuraSpellAction +{ +public: + CastMendPetAction(PlayerbotAI* botAI) : CastAuraSpellAction(botAI, "mend pet") {} + std::string const GetTargetName() override { return "pet target"; } +}; + +class CastRevivePetAction : public CastBuffSpellAction +{ +public: + CastRevivePetAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "revive pet") {} +}; + +class CastKillCommandAction : public CastBuffSpellAction +{ +public: + CastKillCommandAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "kill command", false, 5000) {} + std::string const GetTargetName() override { return "pet target"; } +}; + +class CastBestialWrathAction : public CastBuffSpellAction +{ +public: + CastBestialWrathAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "bestial wrath", false, 5000) {} + std::string const GetTargetName() override { return "pet target"; } +}; + +// Direct Damage Spells + +class CastAutoShotAction : public CastSpellAction +{ +public: + CastAutoShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "auto shot") {} + ActionThreatType getThreatType() override { return ActionThreatType::None; } + bool isUseful() override; +}; + +class CastArcaneShotAction : public CastSpellAction +{ +public: + CastArcaneShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "arcane shot") {} + bool isUseful() override; +}; + +class CastAimedShotAction : public CastSpellAction +{ +public: + CastAimedShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "aimed shot") {} +}; + +class CastChimeraShotAction : public CastSpellAction +{ +public: + CastChimeraShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "chimera shot") {} +}; + +class CastSteadyShotAction : public CastSpellAction +{ +public: + CastSteadyShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "steady shot") {} +}; + +class CastKillShotAction : public CastSpellAction +{ +public: + CastKillShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "kill shot") {} +}; + +// DoT/Debuff Spells + +class CastHuntersMarkAction : public CastDebuffSpellAction +{ +public: + CastHuntersMarkAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "hunter's mark") {} + bool isUseful() override + { + // Bypass TTL check + return CastAuraSpellAction::isUseful(); + } +}; + +class CastTranquilizingShotAction : public CastSpellAction +{ +public: + CastTranquilizingShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "tranquilizing shot") {} +}; + +class CastViperStingAction : public CastDebuffSpellAction +{ +public: + CastViperStingAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "viper sting", true) {} + bool isUseful() override; +}; + +class CastSerpentStingAction : public CastDebuffSpellAction +{ +public: + CastSerpentStingAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "serpent sting", true) {} + bool isUseful() override + { + // Bypass TTL check + return CastAuraSpellAction::isUseful(); + } +}; + +class CastScorpidStingAction : public CastDebuffSpellAction +{ +public: + CastScorpidStingAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "scorpid sting", true) {} + bool isUseful() override + { + // Bypass TTL check + return CastAuraSpellAction::isUseful(); + } +}; + +class CastSerpentStingOnAttackerAction : public CastDebuffSpellOnAttackerAction +{ +public: + CastSerpentStingOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "serpent sting", true) {} + bool isUseful() override + { + // Bypass TTL check + return CastAuraSpellAction::isUseful(); + } +}; + +class CastImmolationTrapAction : public CastSpellAction +{ +public: + CastImmolationTrapAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "immolation trap") {} + bool isUseful() override; +}; + +class CastExplosiveTrapAction : public CastSpellAction +{ +public: + CastExplosiveTrapAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "explosive trap") {} +}; + +class CastBlackArrow : public CastDebuffSpellAction +{ +public: + CastBlackArrow(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "black arrow", true) {} + bool isUseful() override + { + if (botAI->HasStrategy("trap weave", BOT_STATE_COMBAT)) + return false; + // Bypass TTL check + return CastAuraSpellAction::isUseful(); + } +}; + +class CastExplosiveShotAction : public CastDebuffSpellAction +{ +public: + CastExplosiveShotAction(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {} + bool isUseful() override + { + // Bypass TTL check + return CastAuraSpellAction::isUseful(); + } +}; + +// Rank 4 +class CastExplosiveShotRank4Action : public CastDebuffSpellAction +{ +public: + CastExplosiveShotRank4Action(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {} + + bool Execute(Event event) override { return botAI->CastSpell(60053, GetTarget()); } + bool isUseful() override + { + Unit* target = GetTarget(); + if (!target) + return false; + return !target->HasAura(60053); + } +}; + +// Rank 3 +class CastExplosiveShotRank3Action : public CastDebuffSpellAction +{ +public: + CastExplosiveShotRank3Action(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {} + + bool Execute(Event event) override { return botAI->CastSpell(60052, GetTarget()); } + bool isUseful() override + { + Unit* target = GetTarget(); + if (!target) + return false; + return !target->HasAura(60052); + } +}; + +// Rank 2 +class CastExplosiveShotRank2Action : public CastDebuffSpellAction +{ +public: + CastExplosiveShotRank2Action(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {} + + bool Execute(Event event) override { return botAI->CastSpell(60051, GetTarget()); } + bool isUseful() override + { + Unit* target = GetTarget(); + if (!target) + return false; + return !target->HasAura(60051); + } +}; + +// Rank 1 +class CastExplosiveShotRank1Action : public CastDebuffSpellAction +{ +public: + CastExplosiveShotRank1Action(PlayerbotAI* botAI) : CastDebuffSpellAction(botAI, "explosive shot", true, 0.0f) {} + + bool Execute(Event event) override { return botAI->CastSpell(53301, GetTarget()); } + bool isUseful() override + { + Unit* target = GetTarget(); + if (!target) + return false; + return !target->HasAura(53301); + } +}; + +// Melee Spells + class CastWingClipAction : public CastSpellAction { public: @@ -243,47 +433,19 @@ public: CastMongooseBiteAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "mongoose bite") {} }; -class CastSerpentStingOnAttackerAction : public CastDebuffSpellOnAttackerAction +// AoE Spells + +class CastMultiShotAction : public CastSpellAction { public: - CastSerpentStingOnAttackerAction(PlayerbotAI* botAI) : CastDebuffSpellOnAttackerAction(botAI, "serpent sting", true) - { - } + CastMultiShotAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "multi-shot") {} }; -class FeedPetAction : public Action +class CastVolleyAction : public CastSpellAction { public: - FeedPetAction(PlayerbotAI* botAI) : Action(botAI, "feed pet") {} - - bool Execute(Event event) override; + CastVolleyAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "volley") {} + ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } }; -class CastBestialWrathAction : public CastBuffSpellAction -{ -public: - CastBestialWrathAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "bestial wrath") {} - std::string const GetTargetName() override { return "pet target"; } -}; - -class CastScareBeastAction : public CastSpellAction -{ -public: - CastScareBeastAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "scare beast") {} -}; - -class CastScareBeastCcAction : public CastSpellAction -{ -public: - CastScareBeastCcAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "scare beast on cc") {} - - Value* GetTargetValue() override; - bool Execute(Event event) override; -}; - -class CastMisdirectionOnMainTankAction : public BuffOnMainTankAction -{ -public: - CastMisdirectionOnMainTankAction(PlayerbotAI* ai) : BuffOnMainTankAction(ai, "misdirection", true) {} -}; #endif diff --git a/src/strategy/hunter/HunterAiObjectContext.cpp b/src/strategy/hunter/HunterAiObjectContext.cpp index 9b89b651..35c94813 100644 --- a/src/strategy/hunter/HunterAiObjectContext.cpp +++ b/src/strategy/hunter/HunterAiObjectContext.cpp @@ -4,9 +4,11 @@ */ #include "HunterAiObjectContext.h" - -#include "DpsHunterStrategy.h" +#include "BeastMasteryHunterStrategy.h" +#include "MarksmanshipHunterStrategy.h" +#include "SurvivalHunterStrategy.h" #include "GenericHunterNonCombatStrategy.h" +#include "GenericHunterStrategy.h" #include "HunterActions.h" #include "HunterBuffStrategies.h" #include "HunterTriggers.h" @@ -18,25 +20,31 @@ class HunterStrategyFactoryInternal : public NamedObjectContext public: HunterStrategyFactoryInternal() { - creators["dps"] = &HunterStrategyFactoryInternal::dps; creators["nc"] = &HunterStrategyFactoryInternal::nc; - creators["aoe"] = &HunterStrategyFactoryInternal::aoe; - creators["dps debuff"] = &HunterStrategyFactoryInternal::dps_debuff; creators["boost"] = &HunterStrategyFactoryInternal::boost; creators["pet"] = &HunterStrategyFactoryInternal::pet; creators["cc"] = &HunterStrategyFactoryInternal::cc; creators["trap weave"] = &HunterStrategyFactoryInternal::trap_weave; + creators["bm"] = &HunterStrategyFactoryInternal::beast_mastery; + creators["mm"] = &HunterStrategyFactoryInternal::marksmanship; + creators["surv"] = &HunterStrategyFactoryInternal::survival; + creators["bm aoe"] = &HunterStrategyFactoryInternal::beast_mastery_aoe; + creators["mm aoe"] = &HunterStrategyFactoryInternal::marksmanship_aoe; + creators["surv aoe"] = &HunterStrategyFactoryInternal::survival_aoe; } private: - static Strategy* aoe(PlayerbotAI* botAI) { return new DpsAoeHunterStrategy(botAI); } - static Strategy* dps(PlayerbotAI* botAI) { return new DpsHunterStrategy(botAI); } static Strategy* nc(PlayerbotAI* botAI) { return new GenericHunterNonCombatStrategy(botAI); } - static Strategy* dps_debuff(PlayerbotAI* botAI) { return new DpsHunterDebuffStrategy(botAI); } static Strategy* boost(PlayerbotAI* botAI) { return new HunterBoostStrategy(botAI); } static Strategy* pet(PlayerbotAI* botAI) { return new HunterPetStrategy(botAI); } static Strategy* cc(PlayerbotAI* botAI) { return new HunterCcStrategy(botAI); } static Strategy* trap_weave(PlayerbotAI* botAI) { return new HunterTrapWeaveStrategy(botAI); } + static Strategy* beast_mastery(PlayerbotAI* botAI) { return new BeastMasteryHunterStrategy(botAI); } + static Strategy* marksmanship(PlayerbotAI* botAI) { return new MarksmanshipHunterStrategy(botAI); } + static Strategy* survival(PlayerbotAI* botAI) { return new SurvivalHunterStrategy(botAI); } + static Strategy* beast_mastery_aoe(PlayerbotAI* botAI) { return new BeastMasteryHunterAoeStrategy(botAI); } + static Strategy* marksmanship_aoe(PlayerbotAI* botAI) { return new MarksmanshipHunterAoeStrategy(botAI); } + static Strategy* survival_aoe(PlayerbotAI* botAI) { return new SurvivalHunterAoeStrategy(botAI); } }; class HunterBuffStrategyFactoryInternal : public NamedObjectContext @@ -91,15 +99,17 @@ public: creators["tranquilizing shot enrage"] = &HunterTriggerFactoryInternal::remove_enrage; creators["tranquilizing shot magic"] = &HunterTriggerFactoryInternal::remove_magic; creators["immolation trap no cd"] = &HunterTriggerFactoryInternal::immolation_trap_no_cd; + creators["kill command"] = &HunterTriggerFactoryInternal::kill_command; + creators["explosive shot"] = &HunterTriggerFactoryInternal::explosive_shot; + creators["lock and load"] = &HunterTriggerFactoryInternal::lock_and_load; + creators["silencing shot"] = &HunterTriggerFactoryInternal::silencing_shot; + creators["intimidation"] = &HunterTriggerFactoryInternal::intimidation; } private: static Trigger* auto_shot(PlayerbotAI* botAI) { return new AutoShotTrigger(botAI); } static Trigger* scare_beast(PlayerbotAI* botAI) { return new ScareBeastTrigger(botAI); } - static Trigger* concussive_shot_on_snare_target(PlayerbotAI* botAI) - { - return new ConsussiveShotSnareTrigger(botAI); - } + static Trigger* concussive_shot_on_snare_target(PlayerbotAI* botAI) { return new ConsussiveShotSnareTrigger(botAI); } static Trigger* pet_not_happy(PlayerbotAI* botAI) { return new HunterPetNotHappy(botAI); } static Trigger* serpent_sting_on_attacker(PlayerbotAI* botAI) { return new SerpentStingOnAttackerTrigger(botAI); } static Trigger* trueshot_aura(PlayerbotAI* botAI) { return new TrueshotAuraTrigger(botAI); } @@ -126,6 +136,11 @@ private: static Trigger* remove_enrage(PlayerbotAI* ai) { return new TargetRemoveEnrageTrigger(ai); } static Trigger* remove_magic(PlayerbotAI* ai) { return new TargetRemoveMagicTrigger(ai); } static Trigger* immolation_trap_no_cd(PlayerbotAI* ai) { return new ImmolationTrapNoCdTrigger(ai); } + static Trigger* kill_command(PlayerbotAI* botAI) { return new KillCommandTrigger(botAI); } + static Trigger* explosive_shot(PlayerbotAI* botAI) { return new ExplosiveShotTrigger(botAI); } + static Trigger* lock_and_load(PlayerbotAI* botAI) { return new LockAndLoadTrigger(botAI); } + static Trigger* silencing_shot(PlayerbotAI* botAI) { return new SilencingShotTrigger(botAI); } + static Trigger* intimidation(PlayerbotAI* botAI) { return new IntimidationTrigger(botAI); } }; class HunterAiObjectContextInternal : public NamedObjectContext @@ -183,6 +198,11 @@ public: creators["disengage"] = &HunterAiObjectContextInternal::disengage; creators["immolation trap"] = &HunterAiObjectContextInternal::immolation_trap; creators["explosive trap"] = &HunterAiObjectContextInternal::explosive_trap; + creators["explosive shot rank 4"] = &HunterAiObjectContextInternal::explosive_shot_rank_4; + creators["explosive shot rank 3"] = &HunterAiObjectContextInternal::explosive_shot_rank_3; + creators["explosive shot rank 2"] = &HunterAiObjectContextInternal::explosive_shot_rank_2; + creators["explosive shot rank 1"] = &HunterAiObjectContextInternal::explosive_shot_rank_1; + creators["intimidation"] = &HunterAiObjectContextInternal::intimidation; } private: @@ -235,6 +255,11 @@ private: static Action* disengage(PlayerbotAI* ai) { return new CastDisengageAction(ai); } static Action* immolation_trap(PlayerbotAI* ai) { return new CastImmolationTrapAction(ai); } static Action* explosive_trap(PlayerbotAI* ai) { return new CastExplosiveTrapAction(ai); } + static Action* explosive_shot_rank_4(PlayerbotAI* ai) { return new CastExplosiveShotRank4Action(ai); } + static Action* explosive_shot_rank_3(PlayerbotAI* ai) { return new CastExplosiveShotRank3Action(ai); } + static Action* explosive_shot_rank_2(PlayerbotAI* ai) { return new CastExplosiveShotRank2Action(ai); } + static Action* explosive_shot_rank_1(PlayerbotAI* ai) { return new CastExplosiveShotRank1Action(ai); } + static Action* intimidation(PlayerbotAI* ai) { return new CastIntimidationAction(ai); } }; HunterAiObjectContext::HunterAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) diff --git a/src/strategy/hunter/HunterTriggers.cpp b/src/strategy/hunter/HunterTriggers.cpp index 4d0c26c2..6a79b7eb 100644 --- a/src/strategy/hunter/HunterTriggers.cpp +++ b/src/strategy/hunter/HunterTriggers.cpp @@ -4,7 +4,6 @@ */ #include "HunterTriggers.h" - #include "GenericSpellActions.h" #include "GenericTriggers.h" #include "HunterActions.h" @@ -14,12 +13,19 @@ #include "ServerFacade.h" #include "SharedDefines.h" +bool KillCommandTrigger::IsActive() +{ + Unit* target = GetTarget(); + return !botAI->HasAura("kill command", target); +} + bool BlackArrowTrigger::IsActive() { if (botAI->HasStrategy("trap weave", BOT_STATE_COMBAT)) return false; return DebuffTrigger::IsActive(); + return BuffTrigger::IsActive(); } bool HunterAspectOfTheHawkTrigger::IsActive() @@ -35,6 +41,7 @@ bool HunterNoStingsActiveTrigger::IsActive() Unit* target = AI_VALUE(Unit*, "current target"); return DebuffTrigger::IsActive() && target && !botAI->HasAura("serpent sting", target, false, true) && !botAI->HasAura("scorpid sting", target, false, true) && !botAI->HasAura("viper sting", target, false, true); + return BuffTrigger::IsActive(); } bool HuntersPetDeadTrigger::IsActive() @@ -130,4 +137,5 @@ bool SerpentStingOnAttackerTrigger::IsActive() } return !botAI->HasAura("scorpid sting", target, false, true) && !botAI->HasAura("viper sting", target, false, true); -} \ No newline at end of file + return BuffTrigger::IsActive(); +} diff --git a/src/strategy/hunter/HunterTriggers.h b/src/strategy/hunter/HunterTriggers.h index d0d4db9c..c0d18ddc 100644 --- a/src/strategy/hunter/HunterTriggers.h +++ b/src/strategy/hunter/HunterTriggers.h @@ -9,23 +9,11 @@ #include "CureTriggers.h" #include "GenericTriggers.h" #include "Trigger.h" +#include "PlayerbotAI.h" class PlayerbotAI; -class HunterNoStingsActiveTrigger : public DebuffTrigger -{ -public: - HunterNoStingsActiveTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "no stings") {} - bool IsActive() override; -}; - -class AutoShotTrigger : public Trigger -{ -public: - AutoShotTrigger(PlayerbotAI* botAI) : Trigger(botAI, "auto shot") {} - - bool IsActive() override; -}; +// Buff and Out of Combat Triggers class HunterAspectOfTheMonkeyTrigger : public BuffTrigger { @@ -50,7 +38,6 @@ class HunterAspectOfTheViperTrigger : public BuffTrigger { public: HunterAspectOfTheViperTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "aspect of the viper") {} - bool IsActive() override; }; @@ -58,44 +45,9 @@ class HunterAspectOfThePackTrigger : public BuffTrigger { public: HunterAspectOfThePackTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "aspect of the pack") {} - bool IsActive() override; }; -BEGIN_TRIGGER(HuntersPetDeadTrigger, Trigger) -END_TRIGGER() - -BEGIN_TRIGGER(HuntersPetLowHealthTrigger, Trigger) -END_TRIGGER() - -BEGIN_TRIGGER(HuntersPetMediumHealthTrigger, Trigger) -END_TRIGGER() - -class BlackArrowTrigger : public DebuffTrigger -{ -public: - BlackArrowTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "black arrow", 1, true) {} - bool IsActive() override; -}; - -class HuntersMarkTrigger : public DebuffTrigger -{ -public: - HuntersMarkTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "hunter's mark", 1, false, 25.0f) {} -}; - -class FreezingTrapTrigger : public HasCcTargetTrigger -{ -public: - FreezingTrapTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "freezing trap") {} -}; - -class RapidFireTrigger : public BoostTrigger -{ -public: - RapidFireTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "rapid fire") {} -}; - class TrueshotAuraTrigger : public BuffTrigger { public: @@ -109,28 +61,6 @@ public: bool IsActive() override; }; -class SerpentStingOnAttackerTrigger : public DebuffOnAttackerTrigger -{ -public: - SerpentStingOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "serpent sting", true) {} - bool IsActive() override; -}; - -BEGIN_TRIGGER(HunterPetNotHappy, Trigger) -END_TRIGGER() - -class ConsussiveShotSnareTrigger : public SnareTargetTrigger -{ -public: - ConsussiveShotSnareTrigger(PlayerbotAI* botAI) : SnareTargetTrigger(botAI, "concussive shot") {} -}; - -class ScareBeastTrigger : public HasCcTargetTrigger -{ -public: - ScareBeastTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "scare beast") {} -}; - class HunterLowAmmoTrigger : public AmmoCountTrigger { public: @@ -153,6 +83,115 @@ public: bool IsActive() override; }; +// Cooldown Triggers + +class RapidFireTrigger : public BoostTrigger +{ +public: + RapidFireTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "rapid fire") {} +}; + +class BestialWrathTrigger : public BuffTrigger +{ +public: + BestialWrathTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "bestial wrath") {} +}; + +class IntimidationTrigger : public BuffTrigger +{ +public: + IntimidationTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "intimidation") {} +}; + +class KillCommandTrigger : public BuffTrigger +{ +public: + KillCommandTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "kill command") {} + bool IsActive() override; +}; + +class LockAndLoadTrigger : public BuffTrigger +{ +public: + LockAndLoadTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "lock and load") {} + + bool IsActive() override + { + return botAI->HasAura("lock and load", botAI->GetBot()); + } +}; + +// CC Triggers + +class FreezingTrapTrigger : public HasCcTargetTrigger +{ +public: + FreezingTrapTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "freezing trap") {} +}; + +class ConsussiveShotSnareTrigger : public SnareTargetTrigger +{ +public: + ConsussiveShotSnareTrigger(PlayerbotAI* botAI) : SnareTargetTrigger(botAI, "concussive shot") {} +}; + +class ScareBeastTrigger : public HasCcTargetTrigger +{ +public: + ScareBeastTrigger(PlayerbotAI* botAI) : HasCcTargetTrigger(botAI, "scare beast") {} +}; + +class SilencingShotTrigger : public InterruptSpellTrigger +{ +public: + SilencingShotTrigger(PlayerbotAI* botAI) : InterruptSpellTrigger(botAI, "silencing shot") {} +}; + +// DoT/Debuff Triggers + +class HuntersMarkTrigger : public DebuffTrigger +{ +public: + HuntersMarkTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "hunter's mark", 1, true, 0.5f) {} + bool IsActive() override { return BuffTrigger::IsActive(); } +}; + +class ExplosiveShotTrigger : public DebuffTrigger +{ +public: + ExplosiveShotTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "explosive shot", 1, true) {} + bool IsActive() override { return BuffTrigger::IsActive(); } +}; + +class BlackArrowTrigger : public DebuffTrigger +{ +public: + BlackArrowTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "black arrow", 1, true) {} + bool IsActive() override; +}; + +class HunterNoStingsActiveTrigger : public DebuffTrigger +{ +public: + HunterNoStingsActiveTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "no stings") {} + bool IsActive() override; +}; + +class SerpentStingOnAttackerTrigger : public DebuffOnAttackerTrigger +{ +public: + SerpentStingOnAttackerTrigger(PlayerbotAI* botAI) : DebuffOnAttackerTrigger(botAI, "serpent sting", true) {} + bool IsActive() override; +}; + +// Damage/Combat Triggers + +class AutoShotTrigger : public Trigger +{ +public: + AutoShotTrigger(PlayerbotAI* botAI) : Trigger(botAI, "auto shot") {} +}; + class SwitchToRangedTrigger : public Trigger { public: @@ -193,4 +232,16 @@ public: ImmolationTrapNoCdTrigger(PlayerbotAI* ai) : SpellNoCooldownTrigger(ai, "immolation trap") {} }; +BEGIN_TRIGGER(HuntersPetDeadTrigger, Trigger) +END_TRIGGER() + +BEGIN_TRIGGER(HuntersPetLowHealthTrigger, Trigger) +END_TRIGGER() + +BEGIN_TRIGGER(HuntersPetMediumHealthTrigger, Trigger) +END_TRIGGER() + +BEGIN_TRIGGER(HunterPetNotHappy, Trigger) +END_TRIGGER() + #endif diff --git a/src/strategy/hunter/MarksmanshipHunterStrategy.cpp b/src/strategy/hunter/MarksmanshipHunterStrategy.cpp new file mode 100644 index 00000000..f9619656 --- /dev/null +++ b/src/strategy/hunter/MarksmanshipHunterStrategy.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 "MarksmanshipHunterStrategy.h" +#include "Playerbots.h" + +// ===== Action Node Factory ===== +class MarksmanshipHunterStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + MarksmanshipHunterStrategyActionNodeFactory() + { + creators["auto shot"] = &auto_shot; + creators["silencing shot"] = &silencing_shot; + creators["kill command"] = &kill_command; + creators["kill shot"] = &kill_shot; + creators["viper sting"] = &viper_sting; + creators["serpent sting"] = serpent_sting; + creators["chimera shot"] = &chimera_shot; + creators["aimed shot"] = &aimed_shot; + creators["arcane shot"] = &arcane_shot; + creators["steady shot"] = &steady_shot; + creators["multi-shot"] = &multi_shot; + creators["volley"] = &volley; + } + +private: + static ActionNode* auto_shot(PlayerbotAI*) { return new ActionNode("auto shot", nullptr, nullptr, nullptr); } + static ActionNode* silencing_shot(PlayerbotAI*) { return new ActionNode("silencing shot", nullptr, nullptr, nullptr); } + static ActionNode* kill_command(PlayerbotAI*) { return new ActionNode("kill command", nullptr, nullptr, nullptr); } + static ActionNode* kill_shot(PlayerbotAI*) { return new ActionNode("kill shot", nullptr, nullptr, nullptr); } + static ActionNode* viper_sting(PlayerbotAI*) { return new ActionNode("viper sting", nullptr, nullptr, nullptr); } + static ActionNode* serpent_sting(PlayerbotAI*) { return new ActionNode("serpent sting", nullptr, nullptr, nullptr); } + static ActionNode* chimera_shot(PlayerbotAI*) { return new ActionNode("chimera shot", nullptr, nullptr, nullptr); } + static ActionNode* aimed_shot(PlayerbotAI*) { return new ActionNode("aimed shot", nullptr, nullptr, nullptr); } + static ActionNode* arcane_shot(PlayerbotAI*) { return new ActionNode("arcane shot", nullptr, nullptr, nullptr); } + static ActionNode* steady_shot(PlayerbotAI*) { return new ActionNode("steady shot", nullptr, nullptr, nullptr); } + static ActionNode* multi_shot(PlayerbotAI*) { return new ActionNode("multi shot", nullptr, nullptr, nullptr); } + static ActionNode* volley(PlayerbotAI*) { return new ActionNode("volley", nullptr, nullptr, nullptr); } +}; + +// ===== Single Target Strategy ===== +MarksmanshipHunterStrategy::MarksmanshipHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI) +{ + actionNodeFactories.Add(new MarksmanshipHunterStrategyActionNodeFactory()); +} + +// ===== Default Actions ===== +NextAction** MarksmanshipHunterStrategy::getDefaultActions() +{ + return NextAction::array(0, + new NextAction("kill command", 5.8f), + new NextAction("kill shot", 5.7f), + new NextAction("serpent sting", 5.6f), + new NextAction("chimera shot", 5.5f), + new NextAction("aimed shot", 5.4f), + new NextAction("arcane shot", 5.3f), + new NextAction("steady shot", 5.2f), + new NextAction("auto shot", 5.1f), nullptr); +} + +// ===== Trigger Initialization === +void MarksmanshipHunterStrategy::InitTriggers(std::vector& triggers) +{ + GenericHunterStrategy::InitTriggers(triggers); + triggers.push_back(new TriggerNode("silencing shot", NextAction::array(0, new NextAction("silencing shot", 40.0f), nullptr))); + triggers.push_back(new TriggerNode("kill command", NextAction::array(0, new NextAction("kill command", 18.5f), nullptr))); + triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("kill shot", 18.0f), nullptr))); + triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("viper sting", 17.5f), nullptr))); + triggers.push_back(new TriggerNode("no stings", NextAction::array(0, new NextAction("serpent sting", 17.0f), nullptr))); + triggers.push_back(new TriggerNode("serpent sting on attacker", NextAction::array(0, new NextAction("serpent sting on attacker", 16.5f), nullptr))); +} + +// ===== AoE Strategy, 2/3+ enemies ===== +MarksmanshipHunterAoeStrategy::MarksmanshipHunterAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {} + +void MarksmanshipHunterAoeStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("volley", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("multi-shot", 21.0f), nullptr))); +} diff --git a/src/strategy/hunter/MarksmanshipHunterStrategy.h b/src/strategy/hunter/MarksmanshipHunterStrategy.h new file mode 100644 index 00000000..83a24cef --- /dev/null +++ b/src/strategy/hunter/MarksmanshipHunterStrategy.h @@ -0,0 +1,32 @@ +/* + * 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_MARKSMANSHIPHUNTERSTRATEGY_H +#define _PLAYERBOT_MARKSMANSHIPHUNTERSTRATEGY_H + +#include "GenericHunterStrategy.h" +#include "CombatStrategy.h" + +class PlayerbotAI; + +class MarksmanshipHunterStrategy : public GenericHunterStrategy +{ +public: + MarksmanshipHunterStrategy(PlayerbotAI* botAI); + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "mm"; } + NextAction** getDefaultActions() override; +}; + +class MarksmanshipHunterAoeStrategy : public CombatStrategy +{ +public: + MarksmanshipHunterAoeStrategy(PlayerbotAI* botAI); + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "mm aoe"; } +}; +#endif diff --git a/src/strategy/hunter/SurvivalHunterStrategy.cpp b/src/strategy/hunter/SurvivalHunterStrategy.cpp new file mode 100644 index 00000000..475db2dd --- /dev/null +++ b/src/strategy/hunter/SurvivalHunterStrategy.cpp @@ -0,0 +1,91 @@ +/* + * 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 "SurvivalHunterStrategy.h" +#include "Playerbots.h" + +// ===== Action Node Factory ===== +class SurvivalHunterStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + SurvivalHunterStrategyActionNodeFactory() + { + creators["auto shot"] = &auto_shot; + creators["kill command"] = &kill_command; + creators["kill shot"] = &kill_shot; + creators["explosive shot"] = &explosive_shot; + creators["black arrow"] = &black_arrow; + creators["viper sting"] = &viper_sting; + creators["serpent sting"] = serpent_sting; + creators["aimed shot"] = &aimed_shot; + creators["arcane shot"] = &arcane_shot; + creators["steady shot"] = &steady_shot; + creators["multi-shot"] = &multi_shot; + creators["volley"] = &volley; + } + +private: + static ActionNode* auto_shot(PlayerbotAI*) { return new ActionNode("auto shot", nullptr, nullptr, nullptr); } + static ActionNode* kill_command(PlayerbotAI*) { return new ActionNode("kill command", nullptr, nullptr, nullptr); } + static ActionNode* kill_shot(PlayerbotAI*) { return new ActionNode("kill shot", nullptr, nullptr, nullptr); } + static ActionNode* explosive_shot(PlayerbotAI*) { return new ActionNode("explosive shot", nullptr, nullptr, nullptr); } + static ActionNode* black_arrow(PlayerbotAI*) { return new ActionNode("black arrow", nullptr, nullptr, nullptr); } + static ActionNode* viper_sting(PlayerbotAI*) { return new ActionNode("viper sting", nullptr, nullptr, nullptr); } + static ActionNode* serpent_sting(PlayerbotAI*) { return new ActionNode("serpent sting", nullptr, nullptr, nullptr); } + static ActionNode* aimed_shot(PlayerbotAI*) { return new ActionNode("aimed shot", nullptr, nullptr, nullptr); } + static ActionNode* arcane_shot(PlayerbotAI*) { return new ActionNode("arcane shot", nullptr, nullptr, nullptr); } + static ActionNode* steady_shot(PlayerbotAI*) { return new ActionNode("steady shot", nullptr, nullptr, nullptr); } + static ActionNode* multi_shot(PlayerbotAI*) { return new ActionNode("multi shot", nullptr, nullptr, nullptr); } + static ActionNode* volley(PlayerbotAI*) { return new ActionNode("volley", nullptr, nullptr, nullptr); } +}; + +// ===== Single Target Strategy ===== +SurvivalHunterStrategy::SurvivalHunterStrategy(PlayerbotAI* botAI) : GenericHunterStrategy(botAI) +{ + actionNodeFactories.Add(new SurvivalHunterStrategyActionNodeFactory()); +} + +// ===== Default Actions ===== +NextAction** SurvivalHunterStrategy::getDefaultActions() +{ + return NextAction::array(0, + new NextAction("kill command", 5.9f), + new NextAction("kill shot", 5.8f), + new NextAction("explosive shot", 5.7f), + new NextAction("black arrow", 5.6f), + new NextAction("serpent sting", 5.5f), + new NextAction("aimed shot", 5.4f), + new NextAction("arcane shot", 5.3f), + new NextAction("steady shot", 5.2f), + new NextAction("auto shot", 5.1f), nullptr); +} + +// ===== Trigger Initialization === +void SurvivalHunterStrategy::InitTriggers(std::vector& triggers) +{ + GenericHunterStrategy::InitTriggers(triggers); + + triggers.push_back(new TriggerNode("lock and load", NextAction::array(0, new NextAction("explosive shot rank 4", 28.0f), nullptr))); + triggers.push_back(new TriggerNode("lock and load", NextAction::array(0, new NextAction("explosive shot rank 3", 27.5f), nullptr))); + triggers.push_back(new TriggerNode("lock and load", NextAction::array(0, new NextAction("explosive shot rank 2", 27.0f), nullptr))); + triggers.push_back(new TriggerNode("lock and load", NextAction::array(0, new NextAction("explosive shot rank 1", 26.5f), nullptr))); + + triggers.push_back(new TriggerNode("kill command", NextAction::array(0, new NextAction("kill command", 18.5f), nullptr))); + triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("kill shot", 18.0f), nullptr))); + triggers.push_back(new TriggerNode("explosive shot", NextAction::array(0, new NextAction("explosive shot", 17.5f), nullptr))); + triggers.push_back(new TriggerNode("black arrow", NextAction::array(0, new NextAction("black arrow", 16.5f), nullptr))); + triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("viper sting", 16.0f), nullptr))); + triggers.push_back(new TriggerNode("no stings", NextAction::array(0, new NextAction("serpent sting", 15.5f), nullptr))); + triggers.push_back(new TriggerNode("serpent sting on attacker", NextAction::array(0, new NextAction("serpent sting on attacker", 15.0f), nullptr))); +} + +// ===== AoE Strategy, 2/3+ enemies ===== +SurvivalHunterAoeStrategy::SurvivalHunterAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(botAI) {} + +void SurvivalHunterAoeStrategy::InitTriggers(std::vector& triggers) +{ + triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("volley", 22.0f), nullptr))); + triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("multi-shot", 21.0f), nullptr))); +} diff --git a/src/strategy/hunter/SurvivalHunterStrategy.h b/src/strategy/hunter/SurvivalHunterStrategy.h new file mode 100644 index 00000000..73eadb06 --- /dev/null +++ b/src/strategy/hunter/SurvivalHunterStrategy.h @@ -0,0 +1,32 @@ +/* + * 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_SURVIVALHUNTERSTRATEGY_H +#define _PLAYERBOT_SURVIVALHUNTERSTRATEGY_H + +#include "GenericHunterStrategy.h" +#include "CombatStrategy.h" + +class PlayerbotAI; + +class SurvivalHunterStrategy : public GenericHunterStrategy +{ +public: + SurvivalHunterStrategy(PlayerbotAI* botAI); + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "surv"; } + NextAction** getDefaultActions() override; +}; + +class SurvivalHunterAoeStrategy : public CombatStrategy +{ +public: + SurvivalHunterAoeStrategy(PlayerbotAI* botAI); + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "surv aoe"; } +}; +#endif