From e30d823f03230de23baf08960f0fb3ad2be32b38 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Sun, 21 Jul 2024 05:10:56 +1000 Subject: [PATCH 01/12] Frost mage AI --- src/strategy/mage/FrostMageStrategy.cpp | 72 +++++++++++++++++++++-- src/strategy/mage/GenericMageStrategy.cpp | 29 ++++++++- src/strategy/mage/MageActions.h | 47 +++++++++++++-- src/strategy/mage/MageAiObjectContext.cpp | 24 ++++++++ src/strategy/mage/MageTriggers.h | 33 ++++++++++- 5 files changed, 195 insertions(+), 10 deletions(-) diff --git a/src/strategy/mage/FrostMageStrategy.cpp b/src/strategy/mage/FrostMageStrategy.cpp index 39822aa12..fcafcee38 100644 --- a/src/strategy/mage/FrostMageStrategy.cpp +++ b/src/strategy/mage/FrostMageStrategy.cpp @@ -5,15 +5,68 @@ #include "FrostMageStrategy.h" #include "Playerbots.h" +class FrostMageStrategyActionNodeFactory : public NamedObjectFactory +{ +public: + FrostMageStrategyActionNodeFactory() + { + creators["deep freeze"] = &deep_freeze; + creators["frostbolt and deep freeze"] = &frostbolt_and_deep_freeze; + } +private: + static ActionNode* cold_snap([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode ("cold snap", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ nullptr); + } + + static ActionNode* ice_barrier([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode ("ice_barrier", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ nullptr); + } + + static ActionNode* summon_water_elemental([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode ("summon water elemental", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ nullptr); + } + + static ActionNode* deep_freeze([[maybe_unused]] PlayerbotAI* botAI) + { + return new ActionNode ("deep freeze", + /*P*/ nullptr, + /*A*/ NextAction::array(0, new NextAction("ice lance"), nullptr), + /*C*/ nullptr); + } + + static ActionNode* frostbolt_and_deep_freeze([[maybe_unused]] PlayerbotAI* botAI) + // Combo cast the last charge of fingers of frost for double crits. + // Should only do this on the final charge of FoF. + { + return new ActionNode ("frostbolt", + /*P*/ nullptr, + /*A*/ nullptr, + /*C*/ NextAction::array(0, new NextAction("deep freeze"), NULL)); + } +}; + FrostMageStrategy::FrostMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI) { + actionNodeFactories.Add(new FrostMageStrategyActionNodeFactory()); } NextAction** FrostMageStrategy::getDefaultActions() { return NextAction::array(0, - new NextAction("frostbolt", ACTION_DEFAULT + 0.1f), - new NextAction("shoot", ACTION_DEFAULT), + new NextAction("frostbolt", ACTION_DEFAULT + 0.1f), + new NextAction("shoot", ACTION_DEFAULT), nullptr); } @@ -21,11 +74,22 @@ NextAction** FrostMageStrategy::getDefaultActions() void FrostMageStrategy::InitTriggers(std::vector& triggers) { GenericMageStrategy::InitTriggers(triggers); - triggers.push_back(new TriggerNode("icy veins", NextAction::array(0, new NextAction("icy veins", 50.0f), nullptr))); + // No logic currently for cold snap usage.. possibly use right after icy veins drops off? + // triggers.push_back(new TriggerNode("cold snap", NextAction::array(0, new NextAction("cold snap", 50.0f), nullptr))); + + triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon water elemental", 70.0f), nullptr))); + triggers.push_back(new TriggerNode("ice barrier", NextAction::array(0, new NextAction("ice barrier", 30.0f), nullptr))); + + triggers.push_back(new TriggerNode("brain freeze", NextAction::array(0, new NextAction("frostfire bolt", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("fingers of frost single", NextAction::array(0, new NextAction("frostbolt and deep freeze", 20.0f), nullptr))); + // May not need this, frostbolt is the default action so probably don't need to specify. + // Maybe uncomment if you find the mage is prioritising auxillary spells while this buff is up, and wasting the proc. + // triggers.push_back(new TriggerNode("fingers of frost double", NextAction::array(0, new NextAction("frostbolt", 10.0f), nullptr))); } void FrostMageAoeStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("blizzard", 40.0f), nullptr))); + triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("blizzard", 40.0f), nullptr))); + triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("cone of cold", 45.0f), nullptr))); } diff --git a/src/strategy/mage/GenericMageStrategy.cpp b/src/strategy/mage/GenericMageStrategy.cpp index e6bff447d..682ddfb4c 100644 --- a/src/strategy/mage/GenericMageStrategy.cpp +++ b/src/strategy/mage/GenericMageStrategy.cpp @@ -12,9 +12,12 @@ class GenericMageStrategyActionNodeFactory : public NamedObjectFactory* GetTargetValue() override; }; @@ -223,7 +263,6 @@ class CastEvocationAction : public CastSpellAction { public: CastEvocationAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "evocation") { } - std::string const GetTargetName() override { return "self target"; } }; diff --git a/src/strategy/mage/MageAiObjectContext.cpp b/src/strategy/mage/MageAiObjectContext.cpp index 671ea97eb..894c0231e 100644 --- a/src/strategy/mage/MageAiObjectContext.cpp +++ b/src/strategy/mage/MageAiObjectContext.cpp @@ -79,7 +79,12 @@ class MageTriggerFactoryInternal : public NamedObjectContext creators["fireball"] = &MageTriggerFactoryInternal::fireball; creators["pyroblast"] = &MageTriggerFactoryInternal::pyroblast; creators["combustion"] = &MageTriggerFactoryInternal::combustion; + creators["fingers of frost single"] = &MageTriggerFactoryInternal::fingers_of_frost_single; + creators["fingers of frost double"] = &MageTriggerFactoryInternal::fingers_of_frost_double; + creators["brain freeze"] = &MageTriggerFactoryInternal::brain_freeze; creators["icy veins"] = &MageTriggerFactoryInternal::icy_veins; + creators["cold snap"] = &MageTriggerFactoryInternal::cold_snap; + creators["ice barrier"] = &MageTriggerFactoryInternal::ice_barrier; creators["arcane intellect"] = &MageTriggerFactoryInternal::arcane_intellect; creators["arcane intellect on party"] = &MageTriggerFactoryInternal::arcane_intellect_on_party; creators["mage armor"] = &MageTriggerFactoryInternal::mage_armor; @@ -110,7 +115,12 @@ class MageTriggerFactoryInternal : public NamedObjectContext static Trigger* fireball(PlayerbotAI* botAI) { return new FireballTrigger(botAI); } static Trigger* pyroblast(PlayerbotAI* botAI) { return new PyroblastTrigger(botAI); } static Trigger* combustion(PlayerbotAI* botAI) { return new CombustionTrigger(botAI); } + static Trigger* fingers_of_frost_single(PlayerbotAI* botAI) { return new FingersOfFrostSingleTrigger(botAI); } + static Trigger* fingers_of_frost_double(PlayerbotAI* botAI) { return new FingersOfFrostDoubleTrigger(botAI); } + static Trigger* brain_freeze(PlayerbotAI* botAI) { return new BrainFreezeTrigger(botAI); } static Trigger* icy_veins(PlayerbotAI* botAI) { return new IcyVeinsTrigger(botAI); } + static Trigger* cold_snap(PlayerbotAI* botAI) { return new ColdSnapTrigger(botAI); } + static Trigger* ice_barrier(PlayerbotAI* botAI) { return new IceBarrierTrigger(botAI); } static Trigger* arcane_intellect(PlayerbotAI* botAI) { return new ArcaneIntellectTrigger(botAI); } static Trigger* arcane_intellect_on_party(PlayerbotAI* botAI) { return new ArcaneIntellectOnPartyTrigger(botAI); } static Trigger* mage_armor(PlayerbotAI* botAI) { return new MageArmorTrigger(botAI); } @@ -135,7 +145,11 @@ class MageAiObjectContextInternal : public NamedObjectContext creators["arcane power"] = &MageAiObjectContextInternal::arcane_power; creators["presence of mind"] = &MageAiObjectContextInternal::presence_of_mind; creators["frostbolt"] = &MageAiObjectContextInternal::frostbolt; + creators["frostfire bolt"] = &MageAiObjectContextInternal::frostfire_bolt; + creators["ice lance"] = &MageAiObjectContextInternal::ice_lance; + creators["deep freeze"] = &MageAiObjectContextInternal::deep_freeze; creators["blizzard"] = &MageAiObjectContextInternal::blizzard; + creators["cone of cold"] = &MageAiObjectContextInternal::cone_of_cold; creators["frost nova"] = &MageAiObjectContextInternal::frost_nova; creators["arcane intellect"] = &MageAiObjectContextInternal::arcane_intellect; creators["arcane intellect on party"] = &MageAiObjectContextInternal::arcane_intellect_on_party; @@ -156,6 +170,9 @@ class MageAiObjectContextInternal : public NamedObjectContext creators["remove lesser curse"] = &MageAiObjectContextInternal::remove_lesser_curse; creators["remove lesser curse on party"] = &MageAiObjectContextInternal::remove_lesser_curse_on_party; creators["icy veins"] = &MageAiObjectContextInternal::icy_veins; + creators["cold snap"] = &MageAiObjectContextInternal::cold_snap; + creators["ice barrier"] = &MageAiObjectContextInternal::ice_barrier; + creators["summon_water_elemental"] = &MageAiObjectContextInternal::summon_water_elemental; creators["combustion"] = &MageAiObjectContextInternal::combustion; creators["ice block"] = &MageAiObjectContextInternal::ice_block; creators["polymorph"] = &MageAiObjectContextInternal::polymorph; @@ -183,7 +200,11 @@ class MageAiObjectContextInternal : public NamedObjectContext static Action* arcane_barrage(PlayerbotAI* botAI) { return new CastArcaneBarrageAction(botAI); } static Action* arcane_blast(PlayerbotAI* botAI) { return new CastArcaneBlastAction(botAI); } static Action* frostbolt(PlayerbotAI* botAI) { return new CastFrostboltAction(botAI); } + static Action* frostfire_bolt(PlayerbotAI* botAI) { return new CastFrostfireBoltAction(botAI); } + static Action* ice_lance(PlayerbotAI* botAI) { return new CastIceLanceAction(botAI); } + static Action* deep_freeze(PlayerbotAI* botAI) { return new CastDeepFreezeAction(botAI); } static Action* blizzard(PlayerbotAI* botAI) { return new CastBlizzardAction(botAI); } + static Action* cone_of_cold(PlayerbotAI* botAI) { return new CastConeOfColdAction(botAI); } static Action* frost_nova(PlayerbotAI* botAI) { return new CastFrostNovaAction(botAI); } static Action* arcane_intellect(PlayerbotAI* botAI) { return new CastArcaneIntellectAction(botAI); } static Action* arcane_intellect_on_party(PlayerbotAI* botAI) { return new CastArcaneIntellectOnPartyAction(botAI); } @@ -204,6 +225,9 @@ class MageAiObjectContextInternal : public NamedObjectContext static Action* remove_lesser_curse(PlayerbotAI* botAI) { return new CastRemoveLesserCurseAction(botAI); } static Action* remove_lesser_curse_on_party(PlayerbotAI* botAI) { return new CastRemoveLesserCurseOnPartyAction(botAI); } static Action* icy_veins(PlayerbotAI* botAI) { return new CastIcyVeinsAction(botAI); } + static Action* cold_snap(PlayerbotAI* botAI) { return new CastColdSnapAction(botAI); } + static Action* ice_barrier(PlayerbotAI* botAI) { return new CastIceBarrierAction(botAI); } + static Action* summon_water_elemental(PlayerbotAI* botAI) { return new CastSummonWaterElementalAction(botAI); } static Action* combustion(PlayerbotAI* botAI) { return new CastCombustionAction(botAI); } static Action* ice_block(PlayerbotAI* botAI) { return new CastIceBlockAction(botAI); } static Action* polymorph(PlayerbotAI* botAI) { return new CastPolymorphAction(botAI); } diff --git a/src/strategy/mage/MageTriggers.h b/src/strategy/mage/MageTriggers.h index 7bd776d95..e33a5f222 100644 --- a/src/strategy/mage/MageTriggers.h +++ b/src/strategy/mage/MageTriggers.h @@ -74,6 +74,24 @@ class ArcaneBlastTrigger : public BuffTrigger ArcaneBlastTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "arcane blast") { } }; +class FingersOfFrostSingleTrigger : public HasAuraStackTrigger +{ +public: + FingersOfFrostSingleTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "fingers of frost", 1, 1) {} +}; + +class FingersOfFrostDoubleTrigger : public HasAuraStackTrigger +{ +public: + FingersOfFrostDoubleTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "fingers of frost", 2, 1) {} +}; + +class BrainFreezeTrigger : public HasAuraTrigger +{ + public: + BrainFreezeTrigger(PlayerbotAI* botAI) : HasAuraTrigger(botAI, "fireball!") { } +}; + class CounterspellInterruptSpellTrigger : public InterruptSpellTrigger { public: @@ -92,6 +110,18 @@ class IcyVeinsTrigger : public BoostTrigger IcyVeinsTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "icy veins") { } }; +class ColdSnapTrigger : public BoostTrigger +{ + public: + ColdSnapTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "cold snap") { } +}; + +class IceBarrierTrigger : public BuffTrigger +{ + public: + IceBarrierTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "ice barrier") { } +}; + class PolymorphTrigger : public HasCcTargetTrigger { public: @@ -134,7 +164,8 @@ class PresenceOfMindTrigger : public BuffTrigger PresenceOfMindTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "presence of mind") { } }; -class ArcaneBlastStackTrigger : public HasAuraStackTrigger { +class ArcaneBlastStackTrigger : public HasAuraStackTrigger +{ public: ArcaneBlastStackTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "arcane blast", 3, 1) {} }; From b36521a353448595a5523a02096cd6bd2610950b Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Sun, 21 Jul 2024 05:12:53 +1000 Subject: [PATCH 02/12] Frost mage AI --- src/strategy/mage/FrostMageStrategy.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/strategy/mage/FrostMageStrategy.cpp b/src/strategy/mage/FrostMageStrategy.cpp index fcafcee38..6f2d717b2 100644 --- a/src/strategy/mage/FrostMageStrategy.cpp +++ b/src/strategy/mage/FrostMageStrategy.cpp @@ -10,6 +10,9 @@ class FrostMageStrategyActionNodeFactory : public NamedObjectFactory public: FrostMageStrategyActionNodeFactory() { + creators["cold snap"] = &cold_snap; + creators["ice barrier"] = &ice_barrier; + creators["summon water elemental"] = &summon_water_elemental; creators["deep freeze"] = &deep_freeze; creators["frostbolt and deep freeze"] = &frostbolt_and_deep_freeze; } From ba4751fb014ee7c9e4620320dadddf968bbcb9b9 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Sun, 21 Jul 2024 05:14:27 +1000 Subject: [PATCH 03/12] Frost mage AI --- src/strategy/mage/FrostMageStrategy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/mage/FrostMageStrategy.cpp b/src/strategy/mage/FrostMageStrategy.cpp index 6f2d717b2..2accab2b8 100644 --- a/src/strategy/mage/FrostMageStrategy.cpp +++ b/src/strategy/mage/FrostMageStrategy.cpp @@ -56,7 +56,7 @@ class FrostMageStrategyActionNodeFactory : public NamedObjectFactory return new ActionNode ("frostbolt", /*P*/ nullptr, /*A*/ nullptr, - /*C*/ NextAction::array(0, new NextAction("deep freeze"), NULL)); + /*C*/ NextAction::array(0, new NextAction("deep freeze"), nullptr)); } }; From e29cf4f195b596b826646a309222ed768d048e77 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Sun, 21 Jul 2024 05:45:38 +1000 Subject: [PATCH 04/12] Ice barrier typo --- src/strategy/mage/FrostMageStrategy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/mage/FrostMageStrategy.cpp b/src/strategy/mage/FrostMageStrategy.cpp index 2accab2b8..4e283d199 100644 --- a/src/strategy/mage/FrostMageStrategy.cpp +++ b/src/strategy/mage/FrostMageStrategy.cpp @@ -27,7 +27,7 @@ class FrostMageStrategyActionNodeFactory : public NamedObjectFactory static ActionNode* ice_barrier([[maybe_unused]] PlayerbotAI* botAI) { - return new ActionNode ("ice_barrier", + return new ActionNode ("ice barrier", /*P*/ nullptr, /*A*/ nullptr, /*C*/ nullptr); From af4ea8de2f6c798a4f8f22f60e1f7c63b1a484c4 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Sun, 21 Jul 2024 06:43:00 +1000 Subject: [PATCH 05/12] Water ele typo --- src/strategy/mage/MageAiObjectContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategy/mage/MageAiObjectContext.cpp b/src/strategy/mage/MageAiObjectContext.cpp index 894c0231e..c92e463be 100644 --- a/src/strategy/mage/MageAiObjectContext.cpp +++ b/src/strategy/mage/MageAiObjectContext.cpp @@ -172,7 +172,7 @@ class MageAiObjectContextInternal : public NamedObjectContext creators["icy veins"] = &MageAiObjectContextInternal::icy_veins; creators["cold snap"] = &MageAiObjectContextInternal::cold_snap; creators["ice barrier"] = &MageAiObjectContextInternal::ice_barrier; - creators["summon_water_elemental"] = &MageAiObjectContextInternal::summon_water_elemental; + creators["summon water elemental"] = &MageAiObjectContextInternal::summon_water_elemental; creators["combustion"] = &MageAiObjectContextInternal::combustion; creators["ice block"] = &MageAiObjectContextInternal::ice_block; creators["polymorph"] = &MageAiObjectContextInternal::polymorph; From adf1411a01ea9bd0af73d9a09695766bc8fd1b23 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Sun, 21 Jul 2024 06:59:57 +1000 Subject: [PATCH 06/12] Water ele waterbolt --- src/strategy/mage/FrostMageStrategy.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/strategy/mage/FrostMageStrategy.cpp b/src/strategy/mage/FrostMageStrategy.cpp index 4e283d199..d7fb89414 100644 --- a/src/strategy/mage/FrostMageStrategy.cpp +++ b/src/strategy/mage/FrostMageStrategy.cpp @@ -81,7 +81,8 @@ void FrostMageStrategy::InitTriggers(std::vector& triggers) // No logic currently for cold snap usage.. possibly use right after icy veins drops off? // triggers.push_back(new TriggerNode("cold snap", NextAction::array(0, new NextAction("cold snap", 50.0f), nullptr))); - triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon water elemental", 70.0f), nullptr))); + triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon water elemental", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", 60.0f), nullptr))); triggers.push_back(new TriggerNode("ice barrier", NextAction::array(0, new NextAction("ice barrier", 30.0f), nullptr))); triggers.push_back(new TriggerNode("brain freeze", NextAction::array(0, new NextAction("frostfire bolt", 60.0f), nullptr))); From 5635b90bbe1c1012dc04fccc7e236748e5a9648c Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Mon, 22 Jul 2024 21:53:02 +1000 Subject: [PATCH 07/12] Proper FoF combo, non-arbitrary weightings --- src/strategy/mage/FrostMageStrategy.cpp | 26 ++++++++++--------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/strategy/mage/FrostMageStrategy.cpp b/src/strategy/mage/FrostMageStrategy.cpp index d7fb89414..f396e272c 100644 --- a/src/strategy/mage/FrostMageStrategy.cpp +++ b/src/strategy/mage/FrostMageStrategy.cpp @@ -14,7 +14,6 @@ class FrostMageStrategyActionNodeFactory : public NamedObjectFactory creators["ice barrier"] = &ice_barrier; creators["summon water elemental"] = &summon_water_elemental; creators["deep freeze"] = &deep_freeze; - creators["frostbolt and deep freeze"] = &frostbolt_and_deep_freeze; } private: static ActionNode* cold_snap([[maybe_unused]] PlayerbotAI* botAI) @@ -48,16 +47,6 @@ class FrostMageStrategyActionNodeFactory : public NamedObjectFactory /*A*/ NextAction::array(0, new NextAction("ice lance"), nullptr), /*C*/ nullptr); } - - static ActionNode* frostbolt_and_deep_freeze([[maybe_unused]] PlayerbotAI* botAI) - // Combo cast the last charge of fingers of frost for double crits. - // Should only do this on the final charge of FoF. - { - return new ActionNode ("frostbolt", - /*P*/ nullptr, - /*A*/ nullptr, - /*C*/ NextAction::array(0, new NextAction("deep freeze"), nullptr)); - } }; FrostMageStrategy::FrostMageStrategy(PlayerbotAI* botAI) : GenericMageStrategy(botAI) @@ -81,15 +70,20 @@ void FrostMageStrategy::InitTriggers(std::vector& triggers) // No logic currently for cold snap usage.. possibly use right after icy veins drops off? // triggers.push_back(new TriggerNode("cold snap", NextAction::array(0, new NextAction("cold snap", 50.0f), nullptr))); - triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon water elemental", 60.0f), nullptr))); - triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", 60.0f), nullptr))); - triggers.push_back(new TriggerNode("ice barrier", NextAction::array(0, new NextAction("ice barrier", 30.0f), nullptr))); + triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon water elemental", ACTION_HIGH), nullptr))); + triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", ACTION_HIGH + 1), nullptr))); + triggers.push_back(new TriggerNode("ice barrier", NextAction::array(0, new NextAction("ice barrier", ACTION_HIGH), nullptr))); triggers.push_back(new TriggerNode("brain freeze", NextAction::array(0, new NextAction("frostfire bolt", 60.0f), nullptr))); - triggers.push_back(new TriggerNode("fingers of frost single", NextAction::array(0, new NextAction("frostbolt and deep freeze", 20.0f), nullptr))); + // Combo cast the last charge of fingers of frost for double crits. + // Should only do this on the final charge of FoF. + triggers.push_back(new TriggerNode("fingers of frost single", NextAction::array(0, + new NextAction("frostbolt", ACTION_NORMAL + 2), + new NextAction("deep freeze", ACTION_NORMAL + 1), + nullptr))); // May not need this, frostbolt is the default action so probably don't need to specify. // Maybe uncomment if you find the mage is prioritising auxillary spells while this buff is up, and wasting the proc. - // triggers.push_back(new TriggerNode("fingers of frost double", NextAction::array(0, new NextAction("frostbolt", 10.0f), nullptr))); + // triggers.push_back(new TriggerNode("fingers of frost double", NextAction::array(0, new NextAction("frostbolt", ACTION_NORMAL), nullptr))); } void FrostMageAoeStrategy::InitTriggers(std::vector& triggers) From 9fd500503087593a8edccb1703522790882ec000 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Tue, 23 Jul 2024 01:58:09 +1000 Subject: [PATCH 08/12] Proper FoF stack handling --- src/strategy/mage/MageTriggers.cpp | 8 ++++++++ src/strategy/mage/MageTriggers.h | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/strategy/mage/MageTriggers.cpp b/src/strategy/mage/MageTriggers.cpp index b8023a514..8856bd291 100644 --- a/src/strategy/mage/MageTriggers.cpp +++ b/src/strategy/mage/MageTriggers.cpp @@ -21,3 +21,11 @@ bool MageArmorTrigger::IsActive() Unit* target = GetTarget(); return !botAI->HasAura("ice armor", target) && !botAI->HasAura("frost armor", target) && !botAI->HasAura("molten armor", target) && !botAI->HasAura("mage armor", target); } + +bool FingersOfFrostSingleTrigger::IsActive() +{ + // Fingers of Frost "stack" count is always 1. + // The value is instead stored in the charges. + Aura *aura = botAI->GetAura(getName(), GetTarget(), false, true, -1); + return (aura && aura->GetCharges() == 1); +} diff --git a/src/strategy/mage/MageTriggers.h b/src/strategy/mage/MageTriggers.h index e33a5f222..e67dba9d0 100644 --- a/src/strategy/mage/MageTriggers.h +++ b/src/strategy/mage/MageTriggers.h @@ -26,7 +26,6 @@ class ArcaneIntellectTrigger : public BuffTrigger { public: ArcaneIntellectTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "arcane intellect", 2 * 2000) { } - bool IsActive() override; }; @@ -34,7 +33,6 @@ class MageArmorTrigger : public BuffTrigger { public: MageArmorTrigger(PlayerbotAI* botAI) : BuffTrigger(botAI, "mage armor", 5 * 2000) { } - bool IsActive() override; }; @@ -78,12 +76,14 @@ class FingersOfFrostSingleTrigger : public HasAuraStackTrigger { public: FingersOfFrostSingleTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "fingers of frost", 1, 1) {} + bool IsActive() override; }; class FingersOfFrostDoubleTrigger : public HasAuraStackTrigger { public: FingersOfFrostDoubleTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "fingers of frost", 2, 1) {} + // bool IsActive() override; }; class BrainFreezeTrigger : public HasAuraTrigger From 71bb45ec7c14dc0da0a68e797c959efe7441e129 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Tue, 23 Jul 2024 18:09:55 +1000 Subject: [PATCH 09/12] Cone of Cold isUseful check --- src/strategy/mage/MageActions.cpp | 7 +++++++ src/strategy/mage/MageActions.h | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/strategy/mage/MageActions.cpp b/src/strategy/mage/MageActions.cpp index fcbc5b836..455bad573 100644 --- a/src/strategy/mage/MageActions.cpp +++ b/src/strategy/mage/MageActions.cpp @@ -15,3 +15,10 @@ bool CastFrostNovaAction::isUseful() { return sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f); } + +bool CastConeOfColdAction::isUseful() +{ + bool facingTarget = AI_VALUE2(bool, "facing", "current target"); + bool targetClose = sServerFacade->IsDistanceLessOrEqualThan(AI_VALUE2(float, "distance", GetTargetName()), 10.f); + return facingTarget && targetClose; +} diff --git a/src/strategy/mage/MageActions.h b/src/strategy/mage/MageActions.h index 3b159db05..a9ae6ff9d 100644 --- a/src/strategy/mage/MageActions.h +++ b/src/strategy/mage/MageActions.h @@ -106,7 +106,7 @@ class CastConeOfColdAction : public CastSpellAction public: CastConeOfColdAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "cone of cold") { } ActionThreatType getThreatType() override { return ActionThreatType::Aoe; } - // bool isUseful() override; + bool isUseful() override; }; class CastArcaneIntellectAction : public CastBuffSpellAction From 4043edfba3ae5c36eee41914116ffc73b5cbaee7 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Tue, 23 Jul 2024 20:00:05 +1000 Subject: [PATCH 10/12] Freeze snare testing --- src/strategy/mage/FrostMageStrategy.cpp | 10 +++++++++- src/strategy/mage/MageAiObjectContext.cpp | 4 ++++ src/strategy/mage/MageTriggers.h | 18 +++++++++++++++--- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/strategy/mage/FrostMageStrategy.cpp b/src/strategy/mage/FrostMageStrategy.cpp index f396e272c..beaae78da 100644 --- a/src/strategy/mage/FrostMageStrategy.cpp +++ b/src/strategy/mage/FrostMageStrategy.cpp @@ -74,7 +74,7 @@ void FrostMageStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", ACTION_HIGH + 1), nullptr))); triggers.push_back(new TriggerNode("ice barrier", NextAction::array(0, new NextAction("ice barrier", ACTION_HIGH), nullptr))); - triggers.push_back(new TriggerNode("brain freeze", NextAction::array(0, new NextAction("frostfire bolt", 60.0f), nullptr))); + triggers.push_back(new TriggerNode("brain freeze", NextAction::array(0, new NextAction("frostfire bolt", ACTION_NORMAL + 3), nullptr))); // Combo cast the last charge of fingers of frost for double crits. // Should only do this on the final charge of FoF. triggers.push_back(new TriggerNode("fingers of frost single", NextAction::array(0, @@ -84,6 +84,14 @@ void FrostMageStrategy::InitTriggers(std::vector& triggers) // May not need this, frostbolt is the default action so probably don't need to specify. // Maybe uncomment if you find the mage is prioritising auxillary spells while this buff is up, and wasting the proc. // triggers.push_back(new TriggerNode("fingers of frost double", NextAction::array(0, new NextAction("frostbolt", ACTION_NORMAL), nullptr))); + triggers.push_back(new TriggerNode("frost nova on target", NextAction::array(0, + new NextAction("fireball", ACTION_NORMAL + 2), + new NextAction("scorch", ACTION_NORMAL + 1), + nullptr))); + triggers.push_back(new TriggerNode("frostbite on target", NextAction::array(0, + new NextAction("arcane missiles", ACTION_NORMAL + 2), + new NextAction("arcane explosion", ACTION_NORMAL + 1), + nullptr))); } void FrostMageAoeStrategy::InitTriggers(std::vector& triggers) diff --git a/src/strategy/mage/MageAiObjectContext.cpp b/src/strategy/mage/MageAiObjectContext.cpp index c92e463be..ebfeb4063 100644 --- a/src/strategy/mage/MageAiObjectContext.cpp +++ b/src/strategy/mage/MageAiObjectContext.cpp @@ -104,6 +104,8 @@ class MageTriggerFactoryInternal : public NamedObjectContext creators["frost ward"] = &MageTriggerFactoryInternal::frost_ward; creators["arcane blast stack"] = &MageTriggerFactoryInternal::arcane_blast_stack; creators["mirror image"] = &MageTriggerFactoryInternal::mirror_image; + creators["frost nova on target"] = &MageTriggerFactoryInternal::mirror_image; + creators["frostbite on target"] = &MageTriggerFactoryInternal::mirror_image; } private: @@ -135,6 +137,8 @@ class MageTriggerFactoryInternal : public NamedObjectContext static Trigger* counterspell_enemy_healer(PlayerbotAI* botAI) { return new CounterspellEnemyHealerTrigger(botAI); } static Trigger* arcane_blast_stack(PlayerbotAI* botAI) { return new ArcaneBlastStackTrigger(botAI); } static Trigger* mirror_image(PlayerbotAI* botAI) { return new MirrorImageTrigger(botAI); } + static Trigger* frost_nova_on_target(PlayerbotAI* botAI) { return new FrostNovaOnTargetTrigger(botAI); } + static Trigger* frostbite_on_target(PlayerbotAI* botAI) { return new FrostbiteOnTargetTrigger(botAI); } }; class MageAiObjectContextInternal : public NamedObjectContext diff --git a/src/strategy/mage/MageTriggers.h b/src/strategy/mage/MageTriggers.h index e67dba9d0..77ca40c62 100644 --- a/src/strategy/mage/MageTriggers.h +++ b/src/strategy/mage/MageTriggers.h @@ -167,13 +167,25 @@ class PresenceOfMindTrigger : public BuffTrigger class ArcaneBlastStackTrigger : public HasAuraStackTrigger { public: - ArcaneBlastStackTrigger(PlayerbotAI* ai) : HasAuraStackTrigger(ai, "arcane blast", 3, 1) {} + ArcaneBlastStackTrigger(PlayerbotAI* botAI) : HasAuraStackTrigger(botAI, "arcane blast", 3, 1) {} }; -class MirrorImageTrigger : public BoostTrigger +class MirrorImageTrigger : public BoostTrigger { public: - MirrorImageTrigger(PlayerbotAI* ai) : BoostTrigger(ai, "mirror image") {} + MirrorImageTrigger(PlayerbotAI* botAI) : BoostTrigger(botAI, "mirror image") {} +}; + +class FrostNovaOnTargetTrigger : public DebuffTrigger +{ + public: + FrostNovaOnTargetTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frost nova", 1, false, 2.0f) {} +}; + +class FrostbiteOnTargetTrigger : public DebuffTrigger +{ + public: + FrostbiteOnTargetTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frostbite", 1, false, 2.0f) {} }; #endif From 79c7dcf4a1d3a46fdb21e4412823128171be7acd Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Tue, 23 Jul 2024 20:35:09 +1000 Subject: [PATCH 11/12] Frost mage test triggers --- src/strategy/mage/MageTriggers.cpp | 24 ++++++++++++++++++++++++ src/strategy/mage/MageTriggers.h | 6 ++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/strategy/mage/MageTriggers.cpp b/src/strategy/mage/MageTriggers.cpp index 8856bd291..8f21bbbcd 100644 --- a/src/strategy/mage/MageTriggers.cpp +++ b/src/strategy/mage/MageTriggers.cpp @@ -29,3 +29,27 @@ bool FingersOfFrostSingleTrigger::IsActive() Aura *aura = botAI->GetAura(getName(), GetTarget(), false, true, -1); return (aura && aura->GetCharges() == 1); } + +bool FrostNovaOnTargetTrigger::IsActive() +{ + Unit* target = GetTarget(); + if (!target || !target->IsAlive() || !target->IsInWorld()) { + return false; + } + bool aura = botAI->HasAura("frostbite", target); + if (aura) + LOG_DEBUG("playerbots", ":: FROST NOVA ACTIVE"); + return !botAI->HasAura("frost nova", target); +} + +bool FrostbiteOnTargetTrigger::IsActive() +{ + Unit* target = GetTarget(); + if (!target || !target->IsAlive() || !target->IsInWorld()) { + return false; + } + bool aura = botAI->HasAura("frostbite", target); + if (aura) + LOG_DEBUG("playerbots", ":: FROSTBITE ACTIVE"); + return botAI->HasAura("frostbite", target); +} diff --git a/src/strategy/mage/MageTriggers.h b/src/strategy/mage/MageTriggers.h index 77ca40c62..111ba341d 100644 --- a/src/strategy/mage/MageTriggers.h +++ b/src/strategy/mage/MageTriggers.h @@ -179,13 +179,15 @@ class MirrorImageTrigger : public BoostTrigger class FrostNovaOnTargetTrigger : public DebuffTrigger { public: - FrostNovaOnTargetTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frost nova", 1, false, 2.0f) {} + FrostNovaOnTargetTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frost nova", 1, false) {} + bool IsActive() override; }; class FrostbiteOnTargetTrigger : public DebuffTrigger { public: - FrostbiteOnTargetTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frostbite", 1, false, 2.0f) {} + FrostbiteOnTargetTrigger(PlayerbotAI* botAI) : DebuffTrigger(botAI, "frostbite", 1, false) {} + bool IsActive() override; }; #endif From b1ffbf2d996aa40d39d1bb5602b0cec63f10dc98 Mon Sep 17 00:00:00 2001 From: Bobblybook Date: Tue, 23 Jul 2024 21:38:40 +1000 Subject: [PATCH 12/12] Frost mage freeze procs complete --- src/strategy/mage/FrostMageStrategy.cpp | 16 +++++++++------- src/strategy/mage/MageAiObjectContext.cpp | 4 ++-- src/strategy/mage/MageTriggers.cpp | 10 ++-------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/strategy/mage/FrostMageStrategy.cpp b/src/strategy/mage/FrostMageStrategy.cpp index beaae78da..4898b1ad2 100644 --- a/src/strategy/mage/FrostMageStrategy.cpp +++ b/src/strategy/mage/FrostMageStrategy.cpp @@ -72,7 +72,7 @@ void FrostMageStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("no pet", NextAction::array(0, new NextAction("summon water elemental", ACTION_HIGH), nullptr))); triggers.push_back(new TriggerNode("has pet", NextAction::array(0, new NextAction("toggle pet spell", ACTION_HIGH + 1), nullptr))); - triggers.push_back(new TriggerNode("ice barrier", NextAction::array(0, new NextAction("ice barrier", ACTION_HIGH), nullptr))); + triggers.push_back(new TriggerNode("ice barrier", NextAction::array(0, new NextAction("ice barrier", ACTION_NORMAL), nullptr))); triggers.push_back(new TriggerNode("brain freeze", NextAction::array(0, new NextAction("frostfire bolt", ACTION_NORMAL + 3), nullptr))); // Combo cast the last charge of fingers of frost for double crits. @@ -84,18 +84,20 @@ void FrostMageStrategy::InitTriggers(std::vector& triggers) // May not need this, frostbolt is the default action so probably don't need to specify. // Maybe uncomment if you find the mage is prioritising auxillary spells while this buff is up, and wasting the proc. // triggers.push_back(new TriggerNode("fingers of frost double", NextAction::array(0, new NextAction("frostbolt", ACTION_NORMAL), nullptr))); + + // Same 2-spell combo for various freeze procs triggers.push_back(new TriggerNode("frost nova on target", NextAction::array(0, - new NextAction("fireball", ACTION_NORMAL + 2), - new NextAction("scorch", ACTION_NORMAL + 1), + new NextAction("frostbolt", ACTION_NORMAL + 2), + new NextAction("deep freeze", ACTION_NORMAL + 1), nullptr))); triggers.push_back(new TriggerNode("frostbite on target", NextAction::array(0, - new NextAction("arcane missiles", ACTION_NORMAL + 2), - new NextAction("arcane explosion", ACTION_NORMAL + 1), + new NextAction("frostbolt", ACTION_NORMAL + 2), + new NextAction("deep freeze", ACTION_NORMAL + 1), nullptr))); } void FrostMageAoeStrategy::InitTriggers(std::vector& triggers) { - triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("blizzard", 40.0f), nullptr))); - triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("cone of cold", 45.0f), nullptr))); + triggers.push_back(new TriggerNode("medium aoe", NextAction::array(0, new NextAction("blizzard", ACTION_HIGH), nullptr))); + triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("cone of cold", ACTION_HIGH + 1), nullptr))); } diff --git a/src/strategy/mage/MageAiObjectContext.cpp b/src/strategy/mage/MageAiObjectContext.cpp index ebfeb4063..8e8af0b11 100644 --- a/src/strategy/mage/MageAiObjectContext.cpp +++ b/src/strategy/mage/MageAiObjectContext.cpp @@ -104,8 +104,8 @@ class MageTriggerFactoryInternal : public NamedObjectContext creators["frost ward"] = &MageTriggerFactoryInternal::frost_ward; creators["arcane blast stack"] = &MageTriggerFactoryInternal::arcane_blast_stack; creators["mirror image"] = &MageTriggerFactoryInternal::mirror_image; - creators["frost nova on target"] = &MageTriggerFactoryInternal::mirror_image; - creators["frostbite on target"] = &MageTriggerFactoryInternal::mirror_image; + creators["frost nova on target"] = &MageTriggerFactoryInternal::frost_nova_on_target; + creators["frostbite on target"] = &MageTriggerFactoryInternal::frostbite_on_target; } private: diff --git a/src/strategy/mage/MageTriggers.cpp b/src/strategy/mage/MageTriggers.cpp index 8f21bbbcd..72bea2070 100644 --- a/src/strategy/mage/MageTriggers.cpp +++ b/src/strategy/mage/MageTriggers.cpp @@ -36,10 +36,7 @@ bool FrostNovaOnTargetTrigger::IsActive() if (!target || !target->IsAlive() || !target->IsInWorld()) { return false; } - bool aura = botAI->HasAura("frostbite", target); - if (aura) - LOG_DEBUG("playerbots", ":: FROST NOVA ACTIVE"); - return !botAI->HasAura("frost nova", target); + return botAI->HasAura(spell, target); } bool FrostbiteOnTargetTrigger::IsActive() @@ -48,8 +45,5 @@ bool FrostbiteOnTargetTrigger::IsActive() if (!target || !target->IsAlive() || !target->IsInWorld()) { return false; } - bool aura = botAI->HasAura("frostbite", target); - if (aura) - LOG_DEBUG("playerbots", ":: FROSTBITE ACTIVE"); - return botAI->HasAura("frostbite", target); + return botAI->HasAura(spell, target); }