From 36adb62f2a46898f18474792e65368e3edf7b67e Mon Sep 17 00:00:00 2001 From: NotCronky <72783562+NotCronky@users.noreply.github.com> Date: Sat, 17 May 2025 15:33:55 +0100 Subject: [PATCH] druid cat and ret pally offheal strat (#1298) co +offheal to either cat druid or ret pally with disable dps mode and enable offheal where the bots will now focus damage but heal when necessary. --- src/strategy/druid/DruidAiObjectContext.cpp | 3 + .../druid/OffhealDruidCatStrategy.cpp | 179 ++++++++++++++++++ src/strategy/druid/OffhealDruidCatStrategy.h | 27 +++ .../paladin/OffhealRetPaladinStrategy.cpp | 143 ++++++++++++++ .../paladin/OffhealRetPaladinStrategy.h | 27 +++ .../paladin/PaladinAiObjectContext.cpp | 3 + 6 files changed, 382 insertions(+) create mode 100644 src/strategy/druid/OffhealDruidCatStrategy.cpp create mode 100644 src/strategy/druid/OffhealDruidCatStrategy.h create mode 100644 src/strategy/paladin/OffhealRetPaladinStrategy.cpp create mode 100644 src/strategy/paladin/OffhealRetPaladinStrategy.h diff --git a/src/strategy/druid/DruidAiObjectContext.cpp b/src/strategy/druid/DruidAiObjectContext.cpp index 631824b4..cec9eeb0 100644 --- a/src/strategy/druid/DruidAiObjectContext.cpp +++ b/src/strategy/druid/DruidAiObjectContext.cpp @@ -8,6 +8,7 @@ #include "BearTankDruidStrategy.h" #include "CasterDruidStrategy.h" #include "CatDpsDruidStrategy.h" +#include "OffhealDruidCatStrategy.h" #include "DruidActions.h" #include "DruidBearActions.h" #include "DruidCatActions.h" @@ -61,6 +62,7 @@ public: creators["caster"] = &DruidDruidStrategyFactoryInternal::caster; creators["dps"] = &DruidDruidStrategyFactoryInternal::cat; creators["heal"] = &DruidDruidStrategyFactoryInternal::heal; + creators["offheal"] = &DruidDruidStrategyFactoryInternal::offheal; } private: @@ -68,6 +70,7 @@ private: static Strategy* cat(PlayerbotAI* botAI) { return new CatDpsDruidStrategy(botAI); } static Strategy* caster(PlayerbotAI* botAI) { return new CasterDruidStrategy(botAI); } static Strategy* heal(PlayerbotAI* botAI) { return new HealDruidStrategy(botAI); } + static Strategy* offheal(PlayerbotAI* botAI) { return new OffhealDruidCatStrategy(botAI); } }; class DruidTriggerFactoryInternal : public NamedObjectContext diff --git a/src/strategy/druid/OffhealDruidCatStrategy.cpp b/src/strategy/druid/OffhealDruidCatStrategy.cpp new file mode 100644 index 00000000..8cfef7f7 --- /dev/null +++ b/src/strategy/druid/OffhealDruidCatStrategy.cpp @@ -0,0 +1,179 @@ +/* + * 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 "OffhealDruidCatStrategy.h" + + #include "Playerbots.h" + #include "Strategy.h" + + class OffhealDruidCatStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + OffhealDruidCatStrategyActionNodeFactory() + { + creators["cat form"] = &cat_form; + creators["mangle (cat)"] = &mangle_cat; + creators["shred"] = &shred; + creators["rake"] = &rake; + creators["rip"] = &rip; + creators["ferocious bite"] = &ferocious_bite; + creators["savage roar"] = &savage_roar; + creators["faerie fire (feral)"] = &faerie_fire_feral; + creators["healing touch on party"] = &healing_touch_on_party; + creators["regrowth on party"] = ®rowth_on_party; + creators["rejuvenation on party"] = &rejuvenation_on_party; + } + +private: + static ActionNode* cat_form([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("cat form", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ nullptr); + } + + static ActionNode* mangle_cat([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("mangle (cat)", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ nullptr); + } + + static ActionNode* shred([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("shred", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("claw"), nullptr), + /*C*/ nullptr); + } + + static ActionNode* rake([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("rake", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ nullptr); + } + + static ActionNode* rip([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("rip", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ nullptr); + } + + static ActionNode* ferocious_bite([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("ferocious bite", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("rip"), nullptr), + /*C*/ nullptr); + } + + static ActionNode* savage_roar([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("savage roar", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ nullptr); + } + + static ActionNode* faerie_fire_feral([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("faerie fire (feral)", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ nullptr); + } + + static ActionNode* healing_touch_on_party([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("healing touch on party", + /*P*/ NextAction::array(0, new NextAction("caster form"), nullptr), + /*A*/ nullptr, + /*C*/ NextAction::array(0, new NextAction("cat form"), nullptr)); + } + + static ActionNode* regrowth_on_party([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("regrowth on party", + /*P*/ NextAction::array(0, new NextAction("caster form"), nullptr), + /*A*/ nullptr, + /*C*/ NextAction::array(0, new NextAction("cat form"), nullptr)); + } + + static ActionNode* rejuvenation_on_party([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("rejuvenation on party", + /*P*/ NextAction::array(0, new NextAction("caster form"), nullptr), + /*A*/ nullptr, + /*C*/ NextAction::array(0, new NextAction("cat form"), nullptr)); + } +}; + +OffhealDruidCatStrategy::OffhealDruidCatStrategy(PlayerbotAI* botAI) : FeralDruidStrategy(botAI) +{ + actionNodeFactories.Add(new OffhealDruidCatStrategyActionNodeFactory()); +} + +NextAction** OffhealDruidCatStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("mangle (cat)", ACTION_DEFAULT + 0.5f), + new NextAction("shred", ACTION_DEFAULT + 0.4f), + new NextAction("rake", ACTION_DEFAULT + 0.3f), new NextAction("melee", ACTION_DEFAULT), + new NextAction("cat form", ACTION_DEFAULT - 0.1f), nullptr); +} + +void OffhealDruidCatStrategy::InitTriggers(std::vector& triggers) +{ + FeralDruidStrategy::InitTriggers(triggers); + + triggers.push_back( + new TriggerNode("cat form", NextAction::array(0, new NextAction("cat form", ACTION_HIGH + 8), nullptr))); + triggers.push_back( + new TriggerNode("savage roar", NextAction::array(0, new NextAction("savage roar", ACTION_HIGH + 7), nullptr))); + triggers.push_back(new TriggerNode("combo points available", + NextAction::array(0, new NextAction("rip", ACTION_HIGH + 6), nullptr))); + triggers.push_back(new TriggerNode( + "ferocious bite time", NextAction::array(0, new NextAction("ferocious bite", ACTION_HIGH + 5), nullptr))); + triggers.push_back( + new TriggerNode("target with combo points almost dead", + NextAction::array(0, new NextAction("ferocious bite", ACTION_HIGH + 4), nullptr))); + triggers.push_back(new TriggerNode("mangle (cat)", + NextAction::array(0, new NextAction("mangle (cat)", ACTION_HIGH + 3), nullptr))); + triggers.push_back(new TriggerNode("rake", NextAction::array(0, new NextAction("rake", ACTION_HIGH + 2), nullptr))); + triggers.push_back(new TriggerNode("almost full energy available", + NextAction::array(0, new NextAction("shred", ACTION_DEFAULT + 0.4f), nullptr))); + triggers.push_back(new TriggerNode("combo points not full", + NextAction::array(0, new NextAction("shred", ACTION_DEFAULT + 0.4f), nullptr))); + triggers.push_back(new TriggerNode( + "faerie fire (feral)", NextAction::array(0, new NextAction("faerie fire (feral)", ACTION_NORMAL), nullptr))); + triggers.push_back(new TriggerNode("enemy out of melee", + NextAction::array(0, new NextAction("feral charge - cat", ACTION_HIGH + 9), + new NextAction("dash", ACTION_HIGH + 8), nullptr))); + triggers.push_back( + new TriggerNode("medium aoe", NextAction::array(0, new NextAction("swipe (cat)", ACTION_HIGH + 3), nullptr))); + triggers.push_back(new TriggerNode( + "low energy", NextAction::array(0, new NextAction("tiger's fury", ACTION_NORMAL + 1), nullptr))); + + triggers.push_back(new TriggerNode( + "party member critical health", + NextAction::array(0, new NextAction("regrowth on party", ACTION_CRITICAL_HEAL + 6), + new NextAction("healing touch on party", ACTION_CRITICAL_HEAL + 5), nullptr))); + triggers.push_back(new TriggerNode( + "party member low health", + NextAction::array(0, new NextAction("healing touch on party", ACTION_MEDIUM_HEAL + 5), nullptr))); + triggers.push_back( + new TriggerNode("party member medium health", + NextAction::array(0, new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 8), 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_EMERGENCY + 3), nullptr))); + triggers.push_back( + new TriggerNode("low mana", NextAction::array(0, new NextAction("innervate", ACTION_HIGH + 4), nullptr))); +} diff --git a/src/strategy/druid/OffhealDruidCatStrategy.h b/src/strategy/druid/OffhealDruidCatStrategy.h new file mode 100644 index 00000000..d180743a --- /dev/null +++ b/src/strategy/druid/OffhealDruidCatStrategy.h @@ -0,0 +1,27 @@ +/* + * 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_OFFHEALDRUIDCATSTRATEGY_H + #define _PLAYERBOT_OFFHEALDRUIDCATSTRATEGY_H + + #include "FeralDruidStrategy.h" + + class PlayerbotAI; + + class OffhealDruidCatStrategy : public FeralDruidStrategy + { + public: + OffhealDruidCatStrategy(PlayerbotAI* botAI); + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "offheal"; } + NextAction** getDefaultActions() override; + uint32 GetType() const override + { + return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_HEAL | STRATEGY_TYPE_MELEE; + } + }; + + #endif \ No newline at end of file diff --git a/src/strategy/paladin/OffhealRetPaladinStrategy.cpp b/src/strategy/paladin/OffhealRetPaladinStrategy.cpp new file mode 100644 index 00000000..e8675c8c --- /dev/null +++ b/src/strategy/paladin/OffhealRetPaladinStrategy.cpp @@ -0,0 +1,143 @@ +/* + * 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 "OffhealRetPaladinStrategy.h" + +#include "Playerbots.h" +#include "Strategy.h" + +class OffhealRetPaladinStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + OffhealRetPaladinStrategyActionNodeFactory() + { + creators["retribution aura"] = &retribution_aura; + creators["seal of corruption"] = &seal_of_corruption; + creators["seal of vengeance"] = &seal_of_vengeance; + creators["seal of command"] = &seal_of_command; + creators["blessing of might"] = &blessing_of_might; + creators["crusader strike"] = &crusader_strike; + creators["divine plea"] = &divine_plea; + } + +private: + static ActionNode* retribution_aura([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("retribution aura", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("devotion aura"), nullptr), + /*C*/ nullptr); + } + + static ActionNode* seal_of_corruption([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("seal of corruption", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("seal of vengeance"), nullptr), + /*C*/ nullptr); + } + + static ActionNode* seal_of_vengeance([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("seal of vengeance", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("seal of command"), nullptr), + /*C*/ nullptr); + } + + static ActionNode* seal_of_command([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("seal of command", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("seal of righteousness"), nullptr), + /*C*/ nullptr); + } + + static ActionNode* blessing_of_might([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("blessing of might", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("blessing of kings"), nullptr), + /*C*/ nullptr); + } + + static ActionNode* crusader_strike([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("crusader strike", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ nullptr); + } + + static ActionNode* divine_plea([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode("divine plea", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ nullptr); + } +}; + +OffhealRetPaladinStrategy::OffhealRetPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStrategy(botAI) +{ + actionNodeFactories.Add(new OffhealRetPaladinStrategyActionNodeFactory()); +} + +NextAction** OffhealRetPaladinStrategy::getDefaultActions() +{ + return NextAction::array(0, new NextAction("hammer of wrath", ACTION_DEFAULT + 0.6f), + new NextAction("judgement of wisdom", ACTION_DEFAULT + 0.5f), + new NextAction("crusader strike", ACTION_DEFAULT + 0.4f), + new NextAction("divine storm", ACTION_DEFAULT + 0.3f), + new NextAction("melee", ACTION_DEFAULT), nullptr); +} + +void OffhealRetPaladinStrategy::InitTriggers(std::vector& triggers) +{ + GenericPaladinStrategy::InitTriggers(triggers); + + // Damage Triggers + triggers.push_back( + new TriggerNode("seal", NextAction::array(0, new NextAction("seal of corruption", ACTION_HIGH), nullptr))); + triggers.push_back( + new TriggerNode("low mana", NextAction::array(0, new NextAction("seal of wisdom", ACTION_HIGH + 5), + new NextAction("divine plea", ACTION_HIGH + 4), nullptr))); + triggers.push_back( + new TriggerNode("art of war", NextAction::array(0, new NextAction("exorcism", ACTION_HIGH + 1), nullptr))); + triggers.push_back(new TriggerNode( + "avenging wrath", NextAction::array(0, new NextAction("avenging wrath", ACTION_HIGH + 2), nullptr))); + triggers.push_back( + new TriggerNode("medium aoe", NextAction::array(0, new NextAction("divine storm", ACTION_HIGH + 4), + new NextAction("consecration", ACTION_HIGH + 3), 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( + "retribution aura", NextAction::array(0, new NextAction("retribution aura", ACTION_NORMAL), nullptr))); + triggers.push_back(new TriggerNode( + "blessing of might", NextAction::array(0, new NextAction("blessing of might", ACTION_NORMAL + 1), nullptr))); + triggers.push_back(new TriggerNode( + "low health", NextAction::array(0, new NextAction("holy light", ACTION_CRITICAL_HEAL + 2), nullptr))); + + // Healing Triggers + triggers.push_back( + new TriggerNode("party member critical health", + NextAction::array(0, new NextAction("holy shock on party", ACTION_CRITICAL_HEAL + 6), + new NextAction("holy light on party", ACTION_CRITICAL_HEAL + 4), nullptr))); + triggers.push_back( + new TriggerNode("party member low health", + NextAction::array(0, new NextAction("holy light on party", ACTION_MEDIUM_HEAL + 5), nullptr))); + triggers.push_back(new TriggerNode( + "party member medium health", + NextAction::array(0, new NextAction("flash of light on party", ACTION_LIGHT_HEAL + 8), nullptr))); + triggers.push_back(new TriggerNode( + "party member almost full health", + NextAction::array(0, new NextAction("flash of light on party", ACTION_LIGHT_HEAL + 3), 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_EMERGENCY + 3), nullptr))); + triggers.push_back(new TriggerNode( + "beacon of light on main tank", + NextAction::array(0, new NextAction("beacon of light on main tank", ACTION_CRITICAL_HEAL + 7), nullptr))); +} diff --git a/src/strategy/paladin/OffhealRetPaladinStrategy.h b/src/strategy/paladin/OffhealRetPaladinStrategy.h new file mode 100644 index 00000000..258331c6 --- /dev/null +++ b/src/strategy/paladin/OffhealRetPaladinStrategy.h @@ -0,0 +1,27 @@ +/* + * 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_OFFHEALRETPALADINSTRATEGY_H +#define _PLAYERBOT_OFFHEALRETPALADINSTRATEGY_H + +#include "GenericPaladinStrategy.h" + +class PlayerbotAI; + +class OffhealRetPaladinStrategy : public GenericPaladinStrategy +{ +public: + OffhealRetPaladinStrategy(PlayerbotAI* botAI); + + void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "offheal"; } + NextAction** getDefaultActions() override; + uint32 GetType() const override + { + return STRATEGY_TYPE_COMBAT | STRATEGY_TYPE_DPS | STRATEGY_TYPE_HEAL | STRATEGY_TYPE_MELEE; + } +}; + +#endif \ No newline at end of file diff --git a/src/strategy/paladin/PaladinAiObjectContext.cpp b/src/strategy/paladin/PaladinAiObjectContext.cpp index 690dc3d8..40410a78 100644 --- a/src/strategy/paladin/PaladinAiObjectContext.cpp +++ b/src/strategy/paladin/PaladinAiObjectContext.cpp @@ -8,6 +8,7 @@ #include "DpsPaladinStrategy.h" #include "GenericPaladinNonCombatStrategy.h" #include "HealPaladinStrategy.h" +#include "OffhealRetPaladinStrategy.h" #include "NamedObjectContext.h" #include "PaladinActions.h" #include "PaladinBuffStrategies.h" @@ -87,12 +88,14 @@ public: creators["tank"] = &PaladinCombatStrategyFactoryInternal::tank; creators["dps"] = &PaladinCombatStrategyFactoryInternal::dps; creators["heal"] = &PaladinCombatStrategyFactoryInternal::heal; + creators["offheal"] = &PaladinCombatStrategyFactoryInternal::offheal; } private: static Strategy* tank(PlayerbotAI* botAI) { return new TankPaladinStrategy(botAI); } static Strategy* dps(PlayerbotAI* botAI) { return new DpsPaladinStrategy(botAI); } static Strategy* heal(PlayerbotAI* botAI) { return new HealPaladinStrategy(botAI); } + static Strategy* offheal(PlayerbotAI* botAI) { return new OffhealRetPaladinStrategy(botAI); } }; class PaladinTriggerFactoryInternal : public NamedObjectContext