From e68a22d9680907a4e651c64d02cb2281b2c2c93b Mon Sep 17 00:00:00 2001 From: Yunfan Li Date: Sat, 3 Jun 2023 20:16:35 +0800 Subject: [PATCH] mage and paladin strategy port --- src/AiFactory.cpp | 2 +- src/strategy/actions/GenericSpellActions.cpp | 8 +- src/strategy/actions/GenericSpellActions.h | 24 +- src/strategy/druid/CasterDruidStrategy.cpp | 16 +- src/strategy/mage/ArcaneMageStrategy.cpp | 17 +- src/strategy/mage/ArcaneMageStrategy.h | 9 + src/strategy/mage/FireMageStrategy.cpp | 6 +- src/strategy/mage/MageAiObjectContext.cpp | 5 +- src/strategy/mage/MageTriggers.h | 4 + src/strategy/paladin/DpsPaladinStrategy.cpp | 30 ++- .../GenericPaladinNonCombatStrategy.cpp | 7 +- .../paladin/GenericPaladinStrategy.cpp | 3 + .../GenericPaladinStrategyActionNodeFactory.h | 238 +++++++++--------- src/strategy/paladin/HealPaladinStrategy.cpp | 49 +++- src/strategy/paladin/HealPaladinStrategy.h | 2 +- src/strategy/paladin/PaladinActions.cpp | 11 +- src/strategy/paladin/PaladinActions.h | 24 ++ .../paladin/PaladinAiObjectContext.cpp | 12 + src/strategy/paladin/PaladinTriggers.h | 11 + src/strategy/paladin/TankPaladinStrategy.cpp | 33 ++- src/strategy/triggers/GenericTriggers.cpp | 21 +- src/strategy/triggers/GenericTriggers.h | 18 ++ src/strategy/values/PartyMemberValue.cpp | 24 ++ src/strategy/values/PartyMemberValue.h | 7 + src/strategy/values/ValueContext.h | 4 + src/strategy/warlock/WarlockActions.h | 1 + 26 files changed, 414 insertions(+), 172 deletions(-) diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index f57d425c..9a22cd99 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -278,7 +278,7 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa break; case CLASS_MAGE: if (tab == 0) - engine->addStrategies("arcane", "threat", nullptr); + engine->addStrategies("arcane", "arcane aoe", "threat", nullptr); else if (tab == 1) engine->addStrategies("fire", "fire aoe", "threat", nullptr); else diff --git a/src/strategy/actions/GenericSpellActions.cpp b/src/strategy/actions/GenericSpellActions.cpp index e3900e5e..d01105dd 100644 --- a/src/strategy/actions/GenericSpellActions.cpp +++ b/src/strategy/actions/GenericSpellActions.cpp @@ -213,7 +213,7 @@ Value* CastDebuffSpellOnAttackerAction::GetTargetValue() return context->GetValue("attacker without aura", spell); } -CastBuffSpellAction::CastBuffSpellAction(PlayerbotAI* botAI, std::string const spell) : CastAuraSpellAction(botAI, spell) +CastBuffSpellAction::CastBuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool checkIsOwner) : CastAuraSpellAction(botAI, spell, checkIsOwner) { range = botAI->GetRange("spell"); } @@ -274,3 +274,9 @@ bool CastVehicleSpellAction::Execute(Event event) uint32 spellId = AI_VALUE2(uint32, "vehicle spell id", spell); return botAI->CastVehicleSpell(spellId, GetTarget()); } + +Value* BuffOnMainTankAction::GetTargetValue() +{ + return context->GetValue("main tank", spell); +} + diff --git a/src/strategy/actions/GenericSpellActions.h b/src/strategy/actions/GenericSpellActions.h index db1f393c..d94532fb 100644 --- a/src/strategy/actions/GenericSpellActions.h +++ b/src/strategy/actions/GenericSpellActions.h @@ -66,7 +66,7 @@ class CastDebuffSpellOnAttackerAction : public CastAuraSpellAction class CastBuffSpellAction : public CastAuraSpellAction { public: - CastBuffSpellAction(PlayerbotAI* botAI, std::string const spell); + CastBuffSpellAction(PlayerbotAI* botAI, std::string const spell, bool checkIsOwner = false); std::string const GetTargetName() override { return "self target"; } }; @@ -322,4 +322,26 @@ class CastBladeSalvoAction : public CastVehicleSpellAction CastBladeSalvoAction(PlayerbotAI* botAI) : CastVehicleSpellAction(botAI, "blade salvo") { } }; +class MainTankActionNameSupport { +public: + MainTankActionNameSupport(std::string spell) + { + name = std::string(spell) + " on main tank"; + } + + virtual std::string const getName() { return name; } + +private: + std::string name; +}; + +class BuffOnMainTankAction : public CastBuffSpellAction, public MainTankActionNameSupport +{ +public: + BuffOnMainTankAction(PlayerbotAI* ai, std::string spell, bool checkIsOwner = false) : + CastBuffSpellAction(ai, spell, checkIsOwner), MainTankActionNameSupport(spell) {} +public: + virtual Value* GetTargetValue(); + virtual std::string const getName() { return MainTankActionNameSupport::getName(); } +}; #endif diff --git a/src/strategy/druid/CasterDruidStrategy.cpp b/src/strategy/druid/CasterDruidStrategy.cpp index c969962e..b65e40d1 100644 --- a/src/strategy/druid/CasterDruidStrategy.cpp +++ b/src/strategy/druid/CasterDruidStrategy.cpp @@ -67,7 +67,7 @@ class CasterDruidStrategyActionNodeFactory : public NamedObjectFactory& triggers) @@ -112,16 +115,13 @@ void CasterDruidStrategy::InitTriggers(std::vector& triggers) GenericDruidStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode("enemy out of spell", NextAction::array(0, new NextAction("reach spell", ACTION_MOVE), nullptr))); - triggers.push_back(new TriggerNode("medium health", NextAction::array(0, new NextAction("regrowth", ACTION_MEDIUM_HEAL + 2), nullptr))); - triggers.push_back(new TriggerNode("party member medium health", NextAction::array(0, new NextAction("regrowth on party", ACTION_MEDIUM_HEAL + 1), nullptr))); - triggers.push_back(new TriggerNode("almost full health", NextAction::array(0, new NextAction("rejuvenation", ACTION_LIGHT_HEAL + 2), nullptr))); - triggers.push_back(new TriggerNode("party member almost full health", NextAction::array(0, new NextAction("rejuvenation on party", ACTION_LIGHT_HEAL + 1), nullptr))); - triggers.push_back(new TriggerNode("insect swarm", NextAction::array(0, new NextAction("insect swarm", ACTION_NORMAL + 5), nullptr))); + triggers.push_back(new TriggerNode("insect swarm", NextAction::array(0, new NextAction("insect swarm", ACTION_NORMAL + 5), nullptr))); triggers.push_back(new TriggerNode("moonfire", NextAction::array(0, new NextAction("moonfire", ACTION_NORMAL + 4), nullptr))); triggers.push_back(new TriggerNode("eclipse (solar)", NextAction::array(0, new NextAction("wrath", ACTION_NORMAL + 6), nullptr))); triggers.push_back(new TriggerNode("eclipse (lunar)", NextAction::array(0, new NextAction("starfire", ACTION_NORMAL + 6), nullptr))); triggers.push_back(new TriggerNode("moonfire", NextAction::array(0, new NextAction("moonfire", ACTION_NORMAL + 4), nullptr))); - triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("nature's grasp", ACTION_EMERGENCY), nullptr))); + triggers.push_back(new TriggerNode("medium mana", NextAction::array(0, new NextAction("innervate", ACTION_HIGH + 5), NULL))); + triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("flee", 49.0f), NULL))); } void CasterDruidAoeStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/mage/ArcaneMageStrategy.cpp b/src/strategy/mage/ArcaneMageStrategy.cpp index eecac1aa..11131b5b 100644 --- a/src/strategy/mage/ArcaneMageStrategy.cpp +++ b/src/strategy/mage/ArcaneMageStrategy.cpp @@ -48,13 +48,24 @@ ArcaneMageStrategy::ArcaneMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy NextAction** ArcaneMageStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("arcane barrage", 10.0f), nullptr); + return NextAction::array(0, new NextAction("arcane blast", 10.0f), NULL); } void ArcaneMageStrategy::InitTriggers(std::vector& triggers) { GenericMageStrategy::InitTriggers(triggers); - triggers.push_back(new TriggerNode("arcane blast", NextAction::array(0, new NextAction("arcane blast", 15.0f), nullptr))); - triggers.push_back(new TriggerNode("missile barrage", NextAction::array(0, new NextAction("arcane missiles", 15.0f), nullptr))); + triggers.push_back(new TriggerNode("arcane blast stack", NextAction::array(0, new NextAction("arcane missiles", 15.0f), NULL))); } + +void ArcaneMageAoeStrategy::InitTriggers(std::vector& triggers) +{ + // triggers.push_back(new TriggerNode( + // "high aoe", + // NextAction::array(0, new NextAction("arcane explosion", 39.0f), NULL))); + + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("blizzard", 40.0f), NULL))); + +} \ No newline at end of file diff --git a/src/strategy/mage/ArcaneMageStrategy.h b/src/strategy/mage/ArcaneMageStrategy.h index 5927f69c..73bd10ae 100644 --- a/src/strategy/mage/ArcaneMageStrategy.h +++ b/src/strategy/mage/ArcaneMageStrategy.h @@ -19,4 +19,13 @@ class ArcaneMageStrategy : public GenericMageStrategy NextAction** getDefaultActions() override; }; +class ArcaneMageAoeStrategy : public CombatStrategy +{ +public: + ArcaneMageAoeStrategy(PlayerbotAI* ai) : CombatStrategy(ai) {} + +public: + virtual void InitTriggers(std::vector& triggers) override; + std::string const getName() override { return "arcane aoe"; } +}; #endif diff --git a/src/strategy/mage/FireMageStrategy.cpp b/src/strategy/mage/FireMageStrategy.cpp index 968f148a..56503175 100644 --- a/src/strategy/mage/FireMageStrategy.cpp +++ b/src/strategy/mage/FireMageStrategy.cpp @@ -7,17 +7,17 @@ NextAction** FireMageStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("scorch", 7.0f), new NextAction("fireball", 6.0f), new NextAction("fire blast", 5.0f), nullptr); + return NextAction::array(0, new NextAction("fireball", ACTION_NORMAL + 1), NULL); } void FireMageStrategy::InitTriggers(std::vector& triggers) { GenericMageStrategy::InitTriggers(triggers); - triggers.push_back(new TriggerNode("pyroblast", NextAction::array(0, new NextAction("pyroblast", 10.0f), nullptr))); + // triggers.push_back(new TriggerNode("pyroblast", NextAction::array(0, new NextAction("pyroblast", 10.0f), nullptr))); triggers.push_back(new TriggerNode("hot streak", NextAction::array(0, new NextAction("pyroblast", 25.0f), nullptr))); triggers.push_back(new TriggerNode("combustion", NextAction::array(0, new NextAction("combustion", 50.0f), nullptr))); - triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("dragon's breath", 70.0f), nullptr))); + // triggers.push_back(new TriggerNode("enemy too close for spell", NextAction::array(0, new NextAction("dragon's breath", 70.0f), nullptr))); } void FireMageAoeStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/mage/MageAiObjectContext.cpp b/src/strategy/mage/MageAiObjectContext.cpp index 4e76715c..0fcf7555 100644 --- a/src/strategy/mage/MageAiObjectContext.cpp +++ b/src/strategy/mage/MageAiObjectContext.cpp @@ -22,6 +22,7 @@ class MageStrategyFactoryInternal : public NamedObjectContext creators["pull"] = &MageStrategyFactoryInternal::pull; creators["fire aoe"] = &MageStrategyFactoryInternal::fire_aoe; creators["frost aoe"] = &MageStrategyFactoryInternal::frost_aoe; + creators["arcane aoe"] = &MageStrategyFactoryInternal::arcane_aoe; creators["cure"] = &MageStrategyFactoryInternal::cure; creators["buff"] = &MageStrategyFactoryInternal::buff; creators["boost"] = &MageStrategyFactoryInternal::boost; @@ -33,6 +34,7 @@ class MageStrategyFactoryInternal : public NamedObjectContext static Strategy* pull(PlayerbotAI* botAI) { return new PullStrategy(botAI, "shoot"); } static Strategy* fire_aoe(PlayerbotAI* botAI) { return new FireMageAoeStrategy(botAI); } static Strategy* frost_aoe(PlayerbotAI* botAI) { return new FrostMageAoeStrategy(botAI); } + static Strategy* arcane_aoe(PlayerbotAI* botAI) { return new ArcaneMageAoeStrategy(botAI); } static Strategy* cure(PlayerbotAI* botAI) { return new MageCureStrategy(botAI); } static Strategy* buff(PlayerbotAI* botAI) { return new MageBuffStrategy(botAI); } static Strategy* boost(PlayerbotAI* botAI) { return new MageBoostStrategy(botAI); } @@ -95,7 +97,7 @@ class MageTriggerFactoryInternal : public NamedObjectContext creators["presence of mind"] = &MageTriggerFactoryInternal::presence_of_mind; creators["fire ward"] = &MageTriggerFactoryInternal::fire_ward; creators["frost ward"] = &MageTriggerFactoryInternal::frost_ward; - + creators["arcane blast stack"] = &MageTriggerFactoryInternal::arcane_blast_stack; } private: @@ -120,6 +122,7 @@ class MageTriggerFactoryInternal : public NamedObjectContext static Trigger* missile_barrage(PlayerbotAI* botAI) { return new MissileBarrageTrigger(botAI); } static Trigger* arcane_blast(PlayerbotAI* botAI) { return new ArcaneBlastTrigger(botAI); } static Trigger* counterspell_enemy_healer(PlayerbotAI* botAI) { return new CounterspellEnemyHealerTrigger(botAI); } + static Trigger* arcane_blast_stack(PlayerbotAI* botAI) { return new ArcaneBlastStackTrigger(botAI); } }; class MageAiObjectContextInternal : public NamedObjectContext diff --git a/src/strategy/mage/MageTriggers.h b/src/strategy/mage/MageTriggers.h index e1de795b..3696180f 100644 --- a/src/strategy/mage/MageTriggers.h +++ b/src/strategy/mage/MageTriggers.h @@ -133,4 +133,8 @@ class PresenceOfMindTrigger : public BuffTrigger PresenceOfMindTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "presence of mind") { } }; +class ArcaneBlastStackTrigger : public HasAuraStackTrigger { +public: + ArcaneBlastStackTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "arcane blast", 3, 1) {} +}; #endif diff --git a/src/strategy/paladin/DpsPaladinStrategy.cpp b/src/strategy/paladin/DpsPaladinStrategy.cpp index f3814520..390c0221 100644 --- a/src/strategy/paladin/DpsPaladinStrategy.cpp +++ b/src/strategy/paladin/DpsPaladinStrategy.cpp @@ -69,7 +69,12 @@ DpsPaladinStrategy::DpsPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStrat NextAction** DpsPaladinStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("crusader strike", ACTION_NORMAL + 1), nullptr); + return NextAction::array(0, new NextAction("crusader strike", ACTION_NORMAL + 6), + new NextAction("judgement of wisdom", ACTION_NORMAL + 5), + new NextAction("divine storm", ACTION_NORMAL + 4), + new NextAction("consecration", ACTION_NORMAL + 3), + new NextAction("melee", ACTION_NORMAL), + NULL); } void DpsPaladinStrategy::InitTriggers(std::vector& triggers) @@ -79,14 +84,21 @@ void DpsPaladinStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("seal", NextAction::array(0, new NextAction("seal of command", 90.0f), nullptr))); triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("seal of wisdom", 91.0f), nullptr))); triggers.push_back(new TriggerNode("sanctity aura", NextAction::array(0, new NextAction("sanctity aura", 90.0f), nullptr))); - triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("repentance or shield", ACTION_CRITICAL_HEAL + 3), new NextAction("holy light", ACTION_CRITICAL_HEAL + 2), nullptr))); - triggers.push_back(new TriggerNode("judgement of wisdom", NextAction::array(0, new NextAction("judgement of wisdom", ACTION_NORMAL + 10), nullptr))); - triggers.push_back(new TriggerNode("judgement", NextAction::array(0, new NextAction("judgement", ACTION_HIGH + 10), nullptr))); - triggers.push_back(new TriggerNode("enemy is close", NextAction::array(0, new NextAction("consecration", ACTION_INTERRUPT), nullptr))); - triggers.push_back(new TriggerNode("repentance on enemy healer", NextAction::array(0, new NextAction("repentance on enemy healer", ACTION_INTERRUPT + 2), nullptr))); - triggers.push_back(new TriggerNode("repentance on snare target", NextAction::array(0, new NextAction("repentance on snare target", ACTION_INTERRUPT + 2), nullptr))); - triggers.push_back(new TriggerNode("repentance", NextAction::array(0, new NextAction("repentance", ACTION_INTERRUPT + 2), nullptr))); - triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("divine storm", ACTION_HIGH + 1), new NextAction("consecration", ACTION_HIGH + 1), nullptr))); + // triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("repentance or shield", ACTION_CRITICAL_HEAL + 3), new NextAction("holy light", ACTION_CRITICAL_HEAL + 2), nullptr))); + // triggers.push_back(new TriggerNode("judgement of wisdom", NextAction::array(0, new NextAction("judgement of wisdom", ACTION_NORMAL + 10), nullptr))); + // triggers.push_back(new TriggerNode("judgement", NextAction::array(0, new NextAction("judgement", ACTION_HIGH + 10), nullptr))); + // triggers.push_back(new TriggerNode("enemy is close", NextAction::array(0, new NextAction("consecration", ACTION_INTERRUPT), nullptr))); + // triggers.push_back(new TriggerNode("repentance on enemy healer", NextAction::array(0, new NextAction("repentance on enemy healer", ACTION_INTERRUPT + 2), nullptr))); + // triggers.push_back(new TriggerNode("repentance on snare target", NextAction::array(0, new NextAction("repentance on snare target", ACTION_INTERRUPT + 2), nullptr))); + // triggers.push_back(new TriggerNode("repentance", NextAction::array(0, new NextAction("repentance", ACTION_INTERRUPT + 2), nullptr))); + // triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("divine storm", ACTION_HIGH + 1), new NextAction("consecration", ACTION_HIGH + 1), nullptr))); triggers.push_back(new TriggerNode("art of war", NextAction::array(0, new NextAction("exorcism", ACTION_HIGH + 2), nullptr))); triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("hammer of wrath", ACTION_CRITICAL_HEAL), nullptr))); + triggers.push_back(new TriggerNode( + "not facing target", + NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), NULL))); + + triggers.push_back(new TriggerNode( + "enemy out of melee", + NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), NULL))); } diff --git a/src/strategy/paladin/GenericPaladinNonCombatStrategy.cpp b/src/strategy/paladin/GenericPaladinNonCombatStrategy.cpp index 448e8b32..d17f41a1 100644 --- a/src/strategy/paladin/GenericPaladinNonCombatStrategy.cpp +++ b/src/strategy/paladin/GenericPaladinNonCombatStrategy.cpp @@ -16,6 +16,9 @@ void GenericPaladinNonCombatStrategy::InitTriggers(std::vector& tr NonCombatStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode("party member dead", NextAction::array(0, new NextAction("redemption", 30.0f), nullptr))); - triggers.push_back(new TriggerNode("almost full health", NextAction::array(0, new NextAction("flash of light", 23.0f), nullptr))); - triggers.push_back(new TriggerNode("party member almost full health", NextAction::array(0, new NextAction("flash of light on party", 24.0f), nullptr))); + triggers.push_back(new TriggerNode("party member almost full health", NextAction::array(0, new NextAction("flash of light on party", 25.0f), NULL))); + triggers.push_back(new TriggerNode("party member medium health", NextAction::array(0, new NextAction("holy light on party", 26.0f), NULL))); + triggers.push_back(new TriggerNode("party member low health", NextAction::array(0, new NextAction("holy light on party", 27.0f), NULL))); + triggers.push_back(new TriggerNode("party member critical health", NextAction::array(0, new NextAction("holy light on party", 28.0f), NULL))); + } diff --git a/src/strategy/paladin/GenericPaladinStrategy.cpp b/src/strategy/paladin/GenericPaladinStrategy.cpp index 2a28539f..ddb025b5 100644 --- a/src/strategy/paladin/GenericPaladinStrategy.cpp +++ b/src/strategy/paladin/GenericPaladinStrategy.cpp @@ -22,6 +22,9 @@ void GenericPaladinStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("lay on hands", ACTION_EMERGENCY), nullptr))); triggers.push_back(new TriggerNode("party member critical health", NextAction::array(0, new NextAction("lay on hands on party", ACTION_EMERGENCY + 1), nullptr))); triggers.push_back(new TriggerNode("protect party member", NextAction::array(0, new NextAction("blessing of protection on party", ACTION_EMERGENCY + 2), nullptr))); + triggers.push_back(new TriggerNode( + "medium mana", + NextAction::array(0, new NextAction("divine plea", ACTION_HIGH), NULL))); } void PaladinCureStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h b/src/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h index b4bd6a6d..1a1c8939 100644 --- a/src/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h +++ b/src/strategy/paladin/GenericPaladinStrategyActionNodeFactory.h @@ -24,6 +24,7 @@ class GenericPaladinStrategyActionNodeFactory : public NamedObjectFactory& triggers) @@ -32,16 +33,42 @@ void HealPaladinStrategy::InitTriggers(std::vector& triggers) GenericPaladinStrategy::InitTriggers(triggers); triggers.push_back(new TriggerNode("concentration aura", NextAction::array(0, new NextAction("concentration aura", 90.0f), nullptr))); - triggers.push_back(new TriggerNode("seal", NextAction::array(0, new NextAction("seal of light", ACTION_HIGH), nullptr))); - triggers.push_back(new TriggerNode("enemy is close", NextAction::array(0, new NextAction("judgement of light", ACTION_HIGH + 10), nullptr))); - triggers.push_back(new TriggerNode("enemy is close", NextAction::array(0, new NextAction("judgement", ACTION_HIGH + 10), nullptr))); + triggers.push_back(new TriggerNode("seal", NextAction::array(0, new NextAction("seal of wisdom", ACTION_HIGH), nullptr))); triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("divine favor", ACTION_HIGH + 1), nullptr))); - triggers.push_back(new TriggerNode("almost full health", NextAction::array(0, new NextAction("flash of light", ACTION_LIGHT_HEAL + 2), nullptr))); - triggers.push_back(new TriggerNode("party member almost full health", NextAction::array(0, new NextAction("flash of light on party", ACTION_LIGHT_HEAL + 1), nullptr))); - triggers.push_back(new TriggerNode("medium health", NextAction::array(0, new NextAction("flash of light", ACTION_MEDIUM_HEAL + 2), nullptr))); - triggers.push_back(new TriggerNode("party member medium health", NextAction::array(0, new NextAction("flash of light on party", ACTION_MEDIUM_HEAL + 1), nullptr))); - triggers.push_back(new TriggerNode("low health", NextAction::array(0, new NextAction("divine favor", ACTION_MEDIUM_HEAL + 4), new NextAction("holy shock", ACTION_MEDIUM_HEAL + 3), new NextAction("holy light", ACTION_MEDIUM_HEAL + 2), nullptr))); - triggers.push_back(new TriggerNode("party member low health", NextAction::array(0, new NextAction("divine favor", ACTION_MEDIUM_HEAL + 7), new NextAction("holy shock on party", ACTION_MEDIUM_HEAL + 6), new NextAction("holy light on party", ACTION_MEDIUM_HEAL + 5), nullptr))); - triggers.push_back(new TriggerNode("blessing", NextAction::array(0, new NextAction("blessing of sanctuary", ACTION_HIGH + 9), nullptr))); + // triggers.push_back(new TriggerNode("blessing", NextAction::array(0, new NextAction("blessing of sanctuary", ACTION_HIGH + 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_EMERGENCY + 3), nullptr))); + + triggers.push_back(new TriggerNode( + "party member critical health", + NextAction::array(0, + new NextAction("holy shock on party", ACTION_CRITICAL_HEAL + 5), + new NextAction("holy light on party", ACTION_CRITICAL_HEAL + 4), + NULL))); + + triggers.push_back(new TriggerNode( + "party member low health", + NextAction::array(0, + new NextAction("holy light on party", ACTION_MEDIUM_HEAL + 5), + NULL))); + + triggers.push_back(new TriggerNode( + "party member medium health", + NextAction::array(0, + new NextAction("holy light on party", ACTION_LIGHT_HEAL + 9), + new NextAction("flash of light on party", ACTION_LIGHT_HEAL + 8), + NULL))); + + triggers.push_back(new TriggerNode( + "party member almost full health", + NextAction::array(0, + new NextAction("flash of light on party", ACTION_LIGHT_HEAL + 3), + NULL))); + + 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), NULL))); + + triggers.push_back(new TriggerNode( + "sacred shield on main tank", + NextAction::array(0, new NextAction("sacred shield on main tank", ACTION_CRITICAL_HEAL + 6), NULL))); } diff --git a/src/strategy/paladin/HealPaladinStrategy.h b/src/strategy/paladin/HealPaladinStrategy.h index c1ee0944..b15bf22f 100644 --- a/src/strategy/paladin/HealPaladinStrategy.h +++ b/src/strategy/paladin/HealPaladinStrategy.h @@ -17,7 +17,7 @@ class HealPaladinStrategy : public GenericPaladinStrategy void InitTriggers(std::vector& triggers) override; std::string const getName() override { return "heal"; } NextAction** getDefaultActions() override; - uint32 GetType() const override { return STRATEGY_TYPE_HEAL | STRATEGY_TYPE_MELEE; } + uint32 GetType() const override { return STRATEGY_TYPE_HEAL | STRATEGY_TYPE_RANGED; } }; #endif diff --git a/src/strategy/paladin/PaladinActions.cpp b/src/strategy/paladin/PaladinActions.cpp index 49d7f523..66f7315c 100644 --- a/src/strategy/paladin/PaladinActions.cpp +++ b/src/strategy/paladin/PaladinActions.cpp @@ -77,7 +77,16 @@ bool CastSealSpellAction::isUseful() return AI_VALUE2(bool, "combat", "self target"); } -Value* CastTurnUndeadAction:: GetTargetValue() +Value* CastTurnUndeadAction::GetTargetValue() { return context->GetValue("cc target", getName()); } + +Unit* CastRighteousDefenseAction::GetTarget() +{ + Unit* current_target = AI_VALUE(Unit*, "current target"); + if (!current_target) { + return NULL; + } + return current_target->GetVictim(); +} \ No newline at end of file diff --git a/src/strategy/paladin/PaladinActions.h b/src/strategy/paladin/PaladinActions.h index 5d78343d..00755499 100644 --- a/src/strategy/paladin/PaladinActions.h +++ b/src/strategy/paladin/PaladinActions.h @@ -259,6 +259,7 @@ class CastRighteousDefenseAction : public CastSpellAction { public: CastRighteousDefenseAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "righteous defense") { } + virtual Unit* GetTarget() override; }; class CastCleansePoisonAction : public CastCureSpellAction @@ -343,4 +344,27 @@ class CastTurnUndeadAction : public CastBuffSpellAction PROTECT_ACTION(CastBlessingOfProtectionProtectAction, "blessing of protection"); +class CastDivinePleaAction : public CastBuffSpellAction +{ +public: + CastDivinePleaAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "divine plea") {} +}; + +class ShieldOfRighteousnessAction : public CastMeleeSpellAction +{ +public: + ShieldOfRighteousnessAction(PlayerbotAI* ai) : CastMeleeSpellAction(ai, "shield of righteousness") {} +}; + +class CastBeaconOfLightOnMainTankAction : public BuffOnMainTankAction +{ +public: + CastBeaconOfLightOnMainTankAction(PlayerbotAI* ai) : BuffOnMainTankAction(ai, "beacon of light", true) {} +}; + +class CastSacredShieldOnMainTankAction : public BuffOnMainTankAction +{ +public: + CastSacredShieldOnMainTankAction(PlayerbotAI* ai) : BuffOnMainTankAction(ai, "sacred shield", false) {} +}; #endif diff --git a/src/strategy/paladin/PaladinAiObjectContext.cpp b/src/strategy/paladin/PaladinAiObjectContext.cpp index fcc30dcf..4285a6e7 100644 --- a/src/strategy/paladin/PaladinAiObjectContext.cpp +++ b/src/strategy/paladin/PaladinAiObjectContext.cpp @@ -126,6 +126,8 @@ class PaladinTriggerFactoryInternal : public NamedObjectContext creators["repentance on enemy healer"] = &PaladinTriggerFactoryInternal::repentance_on_enemy_healer; creators["repentance on snare target"] = &PaladinTriggerFactoryInternal::repentance_on_snare_target; creators["repentance interrupt"] = &PaladinTriggerFactoryInternal::repentance_interrupt; + creators["beacon of light on main tank"] = &PaladinTriggerFactoryInternal::beacon_of_light_on_main_tank; + creators["sacred shield on main tank"] = &PaladinTriggerFactoryInternal::sacred_shield_on_main_tank; } private: @@ -163,6 +165,8 @@ class PaladinTriggerFactoryInternal : public NamedObjectContext static Trigger* repentance_on_enemy_healer(PlayerbotAI* botAI) { return new RepentanceOnHealerTrigger(botAI); } static Trigger* repentance_on_snare_target(PlayerbotAI* botAI) { return new RepentanceSnareTrigger(botAI); } static Trigger* repentance_interrupt(PlayerbotAI* botAI) { return new RepentanceInterruptTrigger(botAI); } + static Trigger* beacon_of_light_on_main_tank(PlayerbotAI* ai) { return new BeaconOfLightOnMainTankTrigger(ai); } + static Trigger* sacred_shield_on_main_tank(PlayerbotAI* ai) { return new SacredShieldOnMainTankTrigger(ai); } }; class PaladinAiObjectContextInternal : public NamedObjectContext @@ -238,6 +242,10 @@ class PaladinAiObjectContextInternal : public NamedObjectContext creators["sanctity aura"] = &PaladinAiObjectContextInternal::sanctity_aura; creators["holy shock"] = &PaladinAiObjectContextInternal::holy_shock; creators["holy shock on party"] = &PaladinAiObjectContextInternal::holy_shock_on_party; + creators["divine plea"] = &PaladinAiObjectContextInternal::divine_plea; + creators["shield of righteousness"] = &PaladinAiObjectContextInternal::shield_of_righteousness; + creators["beacon of light on main tank"] = &PaladinAiObjectContextInternal::beacon_of_light_on_main_tank; + creators["sacred shield on main tank"] = &PaladinAiObjectContextInternal::sacred_shield_on_main_tank; } private: @@ -309,6 +317,10 @@ class PaladinAiObjectContextInternal : public NamedObjectContext static Action* sanctity_aura(PlayerbotAI* botAI) { return new CastSanctityAuraAction(botAI); } static Action* holy_shock(PlayerbotAI* botAI) { return new CastHolyShockAction(botAI); } static Action* holy_shock_on_party(PlayerbotAI* botAI) { return new CastHolyShockOnPartyAction(botAI); } + static Action* divine_plea(PlayerbotAI* ai) { return new CastDivinePleaAction(ai); } + static Action* shield_of_righteousness(PlayerbotAI* ai) { return new ShieldOfRighteousnessAction(ai); } + static Action* beacon_of_light_on_main_tank(PlayerbotAI* ai) { return new CastBeaconOfLightOnMainTankAction(ai); } + static Action* sacred_shield_on_main_tank(PlayerbotAI* ai) { return new CastSacredShieldOnMainTankAction(ai); } }; PaladinAiObjectContext::PaladinAiObjectContext(PlayerbotAI* botAI) : AiObjectContext(botAI) diff --git a/src/strategy/paladin/PaladinTriggers.h b/src/strategy/paladin/PaladinTriggers.h index 0997da06..df92ad74 100644 --- a/src/strategy/paladin/PaladinTriggers.h +++ b/src/strategy/paladin/PaladinTriggers.h @@ -160,4 +160,15 @@ class TurnUndeadTrigger : public HasCcTargetTrigger DEBUFF_TRIGGER(AvengerShieldTrigger, "avenger's shield"); +class BeaconOfLightOnMainTankTrigger : public BuffOnMainTankTrigger +{ +public: + BeaconOfLightOnMainTankTrigger(PlayerbotAI* ai) : BuffOnMainTankTrigger(ai, "beacon of light", true) {} +}; + +class SacredShieldOnMainTankTrigger : public BuffOnMainTankTrigger +{ +public: + SacredShieldOnMainTankTrigger(PlayerbotAI* ai) : BuffOnMainTankTrigger(ai, "sacred shield", false) {} +}; #endif diff --git a/src/strategy/paladin/TankPaladinStrategy.cpp b/src/strategy/paladin/TankPaladinStrategy.cpp index b35cf783..a24f5070 100644 --- a/src/strategy/paladin/TankPaladinStrategy.cpp +++ b/src/strategy/paladin/TankPaladinStrategy.cpp @@ -33,7 +33,14 @@ TankPaladinStrategy::TankPaladinStrategy(PlayerbotAI* botAI) : GenericPaladinStr NextAction** TankPaladinStrategy::getDefaultActions() { - return NextAction::array(0, new NextAction("melee", ACTION_NORMAL), nullptr); + return NextAction::array(0, + new NextAction("shield of righteousness", ACTION_NORMAL + 6), + new NextAction("hammer of the righteous", ACTION_NORMAL + 5), + new NextAction("judgement of wisdom", ACTION_NORMAL + 4), + // new NextAction("avenger's shield", ACTION_NORMAL + 3), + // new NextAction("consecration", ACTION_NORMAL + 2), + new NextAction("melee", ACTION_NORMAL), + NULL); } void TankPaladinStrategy::InitTriggers(std::vector& triggers) @@ -42,16 +49,26 @@ void TankPaladinStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("seal", NextAction::array(0, new NextAction("seal of vengeance", 90.0f), NULL))); triggers.push_back(new TriggerNode("low mana", NextAction::array(0, new NextAction("seal of wisdom", 91.0f), nullptr))); - triggers.push_back(new TriggerNode("judgement of light", NextAction::array(0, new NextAction("judgement of light", ACTION_HIGH + 6), nullptr))); - triggers.push_back(new TriggerNode("medium mana", NextAction::array(0, new NextAction("judgement of wisdom", ACTION_HIGH + 6), nullptr))); - triggers.push_back(new TriggerNode("judgement", NextAction::array(0, new NextAction("judgement", ACTION_HIGH + 6), nullptr))); - triggers.push_back(new TriggerNode("judgement", NextAction::array(0, new NextAction("exorcism", ACTION_HIGH + 6), nullptr))); - triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("hammer of the righteous", ACTION_HIGH + 8), new NextAction("avenger's shield", ACTION_HIGH + 7), nullptr))); + // triggers.push_back(new TriggerNode("judgement of light", NextAction::array(0, new NextAction("judgement of light", ACTION_HIGH + 6), nullptr))); + // triggers.push_back(new TriggerNode("medium mana", NextAction::array(0, new NextAction("judgement of wisdom", ACTION_HIGH + 6), nullptr))); + // triggers.push_back(new TriggerNode("judgement", NextAction::array(0, new NextAction("judgement", ACTION_HIGH + 6), nullptr))); + // triggers.push_back(new TriggerNode("judgement", NextAction::array(0, new NextAction("exorcism", ACTION_HIGH + 6), nullptr))); + // triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("hammer of the righteous", ACTION_HIGH + 8), new NextAction("avenger's shield", ACTION_HIGH + 7), nullptr))); + triggers.push_back(new TriggerNode( + "medium aoe", + NextAction::array(0, new NextAction("consecration", ACTION_HIGH + 1), new NextAction("avenger's shield", ACTION_HIGH + 3), NULL))); triggers.push_back(new TriggerNode("avenger's shield", NextAction::array(0, new NextAction("avenger's shield", ACTION_HIGH + 7), nullptr))); - triggers.push_back(new TriggerNode("enemy is close", NextAction::array(0, new NextAction("consecration", ACTION_INTERRUPT), nullptr))); triggers.push_back(new TriggerNode("lose aggro", NextAction::array(0, new NextAction("hand of reckoning", ACTION_HIGH + 7), nullptr))); - triggers.push_back(new TriggerNode("lose aggro", NextAction::array(0, new NextAction("exorcism", ACTION_HIGH + 8), nullptr))); triggers.push_back(new TriggerNode("holy shield", NextAction::array(0, new NextAction("holy shield", ACTION_HIGH + 7), nullptr))); triggers.push_back(new TriggerNode("blessing", NextAction::array(0, new NextAction("blessing of sanctuary", ACTION_HIGH + 9), nullptr))); triggers.push_back(new TriggerNode("target critical health", NextAction::array(0, new NextAction("hammer of wrath", ACTION_CRITICAL_HEAL), nullptr))); + triggers.push_back(new TriggerNode( + "righteous fury", + NextAction::array(0, new NextAction("righteous fury", ACTION_HIGH + 8), NULL))); + triggers.push_back(new TriggerNode( + "not facing target", + NextAction::array(0, new NextAction("set facing", ACTION_NORMAL + 7), NULL))); + triggers.push_back(new TriggerNode( + "enemy out of melee", + NextAction::array(0, new NextAction("reach melee", ACTION_NORMAL + 8), NULL))); } diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index 684151d9..44781524 100644 --- a/src/strategy/triggers/GenericTriggers.cpp +++ b/src/strategy/triggers/GenericTriggers.cpp @@ -22,15 +22,6 @@ bool MediumManaTrigger::IsActive() bool NoPetTrigger::IsActive() { - // Guardian* gp = bot->GetGuardianPet(); - // bot->getpet - // if (gp) { - // bot->Yell("Guardian name: " + gp->GetName(), LANG_UNIVERSAL); - // } - // Minion* minion = bot->GetFirstMinion(); - // if (minion) { - // bot->Yell("has minion: " + minion->GetName(), LANG_UNIVERSAL); - // } return (bot->GetMinionGUID().IsEmpty()) && (!AI_VALUE(Unit*, "pet target")) && (!bot->GetGuardianPet()) && @@ -351,6 +342,13 @@ bool HasAuraTrigger::IsActive() return botAI->HasAura(getName(), GetTarget(), false, false, -1, true); } +bool HasAuraStackTrigger::IsActive() +{ + Aura *aura = botAI->GetAura(getName(), GetTarget(), false, true, stack); + // sLog->outMessage("playerbot", LOG_LEVEL_DEBUG, "HasAuraStackTrigger::IsActive %s %d", getName(), aura ? aura->GetStackAmount() : -1); + return aura; +} + bool TimerTrigger::IsActive() { if (time(nullptr) != lastCheck) @@ -553,3 +551,8 @@ bool HasAreaDebuffTrigger::IsActive() { return AI_VALUE2(bool, "has area debuff", "self target"); } + +Value* BuffOnMainTankTrigger::GetTargetValue() +{ + return context->GetValue("main tank", spell); +} \ No newline at end of file diff --git a/src/strategy/triggers/GenericTriggers.h b/src/strategy/triggers/GenericTriggers.h index d1d3802a..df8b5c0d 100644 --- a/src/strategy/triggers/GenericTriggers.h +++ b/src/strategy/triggers/GenericTriggers.h @@ -457,6 +457,17 @@ class HasAuraTrigger : public Trigger }; +class HasAuraStackTrigger : public Trigger { + public: + HasAuraStackTrigger(PlayerbotAI* ai, std::string spell, int stack, int checkInterval = 1) : Trigger(ai, spell, checkInterval), + stack(stack) {} + + std::string const GetTargetName() { return "self target"; } + virtual bool IsActive(); + private: + int stack; +}; + class HasNoAuraTrigger : public Trigger { public: @@ -720,4 +731,11 @@ class HasAreaDebuffTrigger : public Trigger { bool IsActive() override; }; +class BuffOnMainTankTrigger : public BuffTrigger +{ +public: + BuffOnMainTankTrigger(PlayerbotAI* botAI, std::string spell, bool checkIsOwner = false) : BuffTrigger(botAI, spell, 1, checkIsOwner) {} +public: + virtual Value* GetTargetValue(); +}; #endif diff --git a/src/strategy/values/PartyMemberValue.cpp b/src/strategy/values/PartyMemberValue.cpp index a6bb9379..bc34f666 100644 --- a/src/strategy/values/PartyMemberValue.cpp +++ b/src/strategy/values/PartyMemberValue.cpp @@ -139,3 +139,27 @@ bool PartyMemberValue::IsTargetOfSpellCast(Player* target, SpellEntryPredicate & return false; } + +class FindMainTankPlayer : public FindPlayerPredicate +{ +public: + FindMainTankPlayer(PlayerbotAI* botAI) : botAI(botAI) {} + + virtual bool Check(Unit* unit) + { + Player* player = unit->ToPlayer(); + if (!player) { + return false; + } + return botAI->IsMainTank(player); + } + +private: + PlayerbotAI* botAI; +}; + +Unit* PartyMemberMainTankValue::Calculate() +{ + FindMainTankPlayer findMainTankPlayer(botAI); + return FindPartyMember(findMainTankPlayer); +} \ No newline at end of file diff --git a/src/strategy/values/PartyMemberValue.h b/src/strategy/values/PartyMemberValue.h index 75950344..d5ee2758 100644 --- a/src/strategy/values/PartyMemberValue.h +++ b/src/strategy/values/PartyMemberValue.h @@ -35,4 +35,11 @@ class PartyMemberValue : public UnitCalculatedValue virtual bool Check(Unit* player); }; +class PartyMemberMainTankValue : public PartyMemberValue +{ +public: + PartyMemberMainTankValue(PlayerbotAI* botAI) : PartyMemberValue(botAI) {} + virtual Unit* Calculate(); +}; + #endif diff --git a/src/strategy/values/ValueContext.h b/src/strategy/values/ValueContext.h index 7d0c9080..a8bcf4ba 100644 --- a/src/strategy/values/ValueContext.h +++ b/src/strategy/values/ValueContext.h @@ -285,6 +285,8 @@ class ValueContext : public NamedObjectContext creators["RTSC saved location"] = &ValueContext::RTSC_saved_location; creators["has area debuff"] = &ValueContext::has_area_debuff; + + creators["main tank"] = &ValueContext::main_tank; } private: @@ -475,6 +477,8 @@ class ValueContext : public NamedObjectContext static UntypedValue* RTSC_saved_location(PlayerbotAI* botAI) { return new RTSCSavedLocationValue(botAI); } static UntypedValue* has_area_debuff(PlayerbotAI* botAI) { return new HasAreaDebuffValue(botAI); } + + static UntypedValue* main_tank(PlayerbotAI* ai) { return new PartyMemberMainTankValue(ai); } }; #endif diff --git a/src/strategy/warlock/WarlockActions.h b/src/strategy/warlock/WarlockActions.h index 0527711e..58f329fa 100644 --- a/src/strategy/warlock/WarlockActions.h +++ b/src/strategy/warlock/WarlockActions.h @@ -240,6 +240,7 @@ class CastDemonicEmpowermentAction : public CastBuffSpellAction { public: CastDemonicEmpowermentAction(PlayerbotAI* ai) : CastBuffSpellAction(ai, "demonic empowerment") {} + std::string const GetTargetName() override { return "pet target"; } }; class CastMetamorphosisAction : public CastBuffSpellAction