From aeeb37da7829e7725b1c86c9914037310d08cfe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E4=BD=A9=E8=8C=B9?= Date: Tue, 21 Mar 2023 12:25:25 -0600 Subject: [PATCH] Trigger fixes and Warrior AI tweaks --- src/AiFactory.cpp | 4 +-- src/strategy/AiObject.h | 9 +++++- src/strategy/triggers/GenericTriggers.cpp | 32 ++++++++++++++++++- src/strategy/triggers/GenericTriggers.h | 25 +++++++++++++++ src/strategy/warrior/ArmsWarriorStrategy.cpp | 9 ++++-- src/strategy/warrior/FuryWarriorStrategy.cpp | 2 +- .../warrior/GenericWarriorStrategy.cpp | 3 +- src/strategy/warrior/TankWarriorStrategy.cpp | 7 +++- src/strategy/warrior/TankWarriorStrategy.h | 1 + .../warrior/WarriorAiObjectContext.cpp | 11 +++++++ src/strategy/warrior/WarriorTriggers.h | 1 + 11 files changed, 94 insertions(+), 10 deletions(-) diff --git a/src/AiFactory.cpp b/src/AiFactory.cpp index 93e829b9..15ce83ce 100644 --- a/src/AiFactory.cpp +++ b/src/AiFactory.cpp @@ -310,9 +310,9 @@ void AiFactory::AddDefaultCombatStrategies(Player* player, PlayerbotAI* const fa if (tab == 2) engine->addStrategies("tank", "tank assist", "aoe", "close", "mark rti", nullptr); else if (player->getLevel() < 30 || tab == 0) - engine->addStrategies("arms", "aoe", "dps assist", "threat", "close", nullptr); + engine->addStrategies("arms", "aoe", "dps assist", "threat", "close", "behind", nullptr); else - engine->addStrategies("fury", "aoe", "dps assist", "threat", "close", nullptr); + engine->addStrategies("fury", "aoe", "dps assist", "threat", "close", "behind", nullptr); break; case CLASS_SHAMAN: if (tab == 0) diff --git a/src/strategy/AiObject.h b/src/strategy/AiObject.h index 16e09796..c066456b 100644 --- a/src/strategy/AiObject.h +++ b/src/strategy/AiObject.h @@ -143,6 +143,13 @@ class clazz : public SpellCanBeCastTrigger \ bool IsActive() override; \ } +#define CD_TRIGGER(clazz, spell) \ +class clazz : public SpellNoCooldownTrigger \ +{ \ + public: \ + clazz(PlayerbotAI* botAI) : SpellNoCooldownTrigger(botAI, spell) {} \ +} + #define INTERRUPT_TRIGGER(clazz, spell) \ class clazz : public InterruptSpellTrigger \ { \ @@ -491,7 +498,7 @@ static ActionNode* name(PlayerbotAI* botAI) \ return new ActionNode(spell, \ /*P*/ nullptr, \ /*A*/ nullptr, \ - /*C*/ NextAction::array(0, new NextAction(con), nullptr); \ + /*C*/ NextAction::array(0, new NextAction(con), nullptr)); \ } #endif diff --git a/src/strategy/triggers/GenericTriggers.cpp b/src/strategy/triggers/GenericTriggers.cpp index 0329caa1..72a6c01a 100644 --- a/src/strategy/triggers/GenericTriggers.cpp +++ b/src/strategy/triggers/GenericTriggers.cpp @@ -184,6 +184,15 @@ bool SpellCanBeCastTrigger::IsActive() return target && botAI->CanCastSpell(spell, target); } +bool SpellNoCooldownTrigger::IsActive() +{ + uint32 spellId = AI_VALUE2(uint32, "spell id", name); + if (!spellId) + return false; + + return !bot->HasSpellCooldown(spellId); +} + RandomTrigger::RandomTrigger(PlayerbotAI* botAI, std::string const name, int32 probability) : Trigger(botAI, name), probability(probability), lastCheck(time(nullptr)) { } @@ -202,7 +211,7 @@ bool RandomTrigger::IsActive() bool AndTrigger::IsActive() { - return ls->IsActive() && rs->IsActive(); + return ls && rs && ls->IsActive() && rs->IsActive(); } std::string const AndTrigger::getName() @@ -213,6 +222,27 @@ std::string const AndTrigger::getName() return name; } +bool TwoTriggers::IsActive() +{ + if (name1.empty() || name2.empty()) + return false; + + Trigger* trigger1 = botAI->GetAiObjectContext()->GetTrigger(name1); + Trigger* trigger2 = botAI->GetAiObjectContext()->GetTrigger(name2); + + if (!trigger1 || !trigger2) + return false; + + return trigger1->IsActive() && trigger2->IsActive(); +} + +std::string const TwoTriggers::getName() +{ + std::string name; + name = name1 + " and " + name2; + return name; +} + bool BoostTrigger::IsActive() { return BuffTrigger::IsActive() && AI_VALUE(uint8, "balance") <= balance; diff --git a/src/strategy/triggers/GenericTriggers.h b/src/strategy/triggers/GenericTriggers.h index 47a653ba..94dffaec 100644 --- a/src/strategy/triggers/GenericTriggers.h +++ b/src/strategy/triggers/GenericTriggers.h @@ -5,6 +5,8 @@ #ifndef _PLAYERBOT_GENERICTRIGGERS_H #define _PLAYERBOT_GENERICTRIGGERS_H +#include + #include "RangeTriggers.h" #include "HealthTriggers.h" @@ -133,6 +135,14 @@ class SpellCanBeCastTrigger : public SpellTrigger bool IsActive() override; }; +class SpellNoCooldownTrigger : public SpellTrigger +{ + public: + SpellNoCooldownTrigger(PlayerbotAI* botAI, std::string const spell) : SpellTrigger(botAI, spell) {} + + bool IsActive() override; +}; + // TODO: check other targets class InterruptSpellTrigger : public SpellTrigger { @@ -349,6 +359,21 @@ class AndTrigger : public Trigger Trigger* rs; }; +class TwoTriggers : public Trigger +{ + public: + explicit TwoTriggers(PlayerbotAI* botAI, std::string name1 = "", std::string name2 = "") : Trigger(botAI) + { + this->name1 = std::move(name1); + this->name2 = std::move(name2); + } + bool IsActive() override; + std::string const getName() override; + protected: + std::string name1; + std::string name2; +}; + class SnareTargetTrigger : public DebuffTrigger { public: diff --git a/src/strategy/warrior/ArmsWarriorStrategy.cpp b/src/strategy/warrior/ArmsWarriorStrategy.cpp index 83ce3547..ab321df6 100644 --- a/src/strategy/warrior/ArmsWarriorStrategy.cpp +++ b/src/strategy/warrior/ArmsWarriorStrategy.cpp @@ -14,6 +14,7 @@ class ArmsWarriorStrategyActionNodeFactory : public NamedObjectFactory& triggers) @@ -47,9 +49,10 @@ void ArmsWarriorStrategy::InitTriggers(std::vector& triggers) triggers.push_back(new TriggerNode("overpower", NextAction::array(0, new NextAction("overpower", ACTION_HIGH + 3), nullptr))); triggers.push_back(new TriggerNode("taste for blood", NextAction::array(0, new NextAction("overpower", ACTION_HIGH + 3), nullptr))); triggers.push_back(new TriggerNode("victory rush", NextAction::array(0, new NextAction("victory rush", ACTION_INTERRUPT), nullptr))); - triggers.push_back(new TriggerNode("high rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH), nullptr))); + triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 10), nullptr))); + /*triggers.push_back(new TriggerNode("high rage available", NextAction::array(0, new NextAction("slam", ACTION_HIGH + 1), nullptr)));*/ triggers.push_back(new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 2), nullptr))); triggers.push_back(new TriggerNode("death wish", NextAction::array(0, new NextAction("death wish", ACTION_HIGH + 2), nullptr))); - triggers.push_back(new TriggerNode("rend", NextAction::array(0, new NextAction("rend", ACTION_NORMAL + 1), nullptr))); + triggers.push_back(new TriggerNode("rend", NextAction::array(0, new NextAction("rend", ACTION_HIGH + 5), nullptr))); triggers.push_back(new TriggerNode("critical health", NextAction::array(0, new NextAction("intimidating shout", ACTION_EMERGENCY), nullptr))); } diff --git a/src/strategy/warrior/FuryWarriorStrategy.cpp b/src/strategy/warrior/FuryWarriorStrategy.cpp index 31c488e8..974143b9 100644 --- a/src/strategy/warrior/FuryWarriorStrategy.cpp +++ b/src/strategy/warrior/FuryWarriorStrategy.cpp @@ -53,7 +53,7 @@ void FuryWarriorStrategy::InitTriggers(std::vector &triggers) triggers.push_back(new TriggerNode("intercept on snare target", NextAction::array(0, new NextAction("intercept on snare target", ACTION_HIGH), nullptr))); triggers.push_back(new TriggerNode("bloodthirst", NextAction::array(0, new NextAction("bloodthirst", ACTION_HIGH + 2), nullptr))); triggers.push_back(new TriggerNode("instant slam", NextAction::array(0, new NextAction("slam", ACTION_HIGH + 1), nullptr))); - triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH), nullptr))); + triggers.push_back(new TriggerNode("medium rage available", NextAction::array(0, new NextAction("heroic strike", ACTION_HIGH + 10), nullptr))); triggers.push_back(new TriggerNode("berserker rage", NextAction::array(0, new NextAction("berserker rage", ACTION_HIGH + 2), nullptr))); triggers.push_back(new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 2), nullptr))); triggers.push_back(new TriggerNode("death wish", NextAction::array(0, new NextAction("death wish", ACTION_HIGH + 2), nullptr))); diff --git a/src/strategy/warrior/GenericWarriorStrategy.cpp b/src/strategy/warrior/GenericWarriorStrategy.cpp index 8435c9de..3174441a 100644 --- a/src/strategy/warrior/GenericWarriorStrategy.cpp +++ b/src/strategy/warrior/GenericWarriorStrategy.cpp @@ -40,11 +40,12 @@ WarrirorAoeStrategy::WarrirorAoeStrategy(PlayerbotAI* botAI) : CombatStrategy(bo void WarrirorAoeStrategy::InitTriggers(std::vector& triggers) { triggers.push_back(new TriggerNode("thunder clap on snare target", NextAction::array(0, new NextAction("thunder clap on snare target", ACTION_HIGH + 3), nullptr))); - triggers.push_back(new TriggerNode("thunder clap", NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 2), nullptr))); + triggers.push_back(new TriggerNode("thunder clap", NextAction::array(0, new NextAction("thunder clap", ACTION_HIGH + 10), nullptr))); triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("demoralizing shout", ACTION_HIGH + 1), nullptr))); triggers.push_back(new TriggerNode("shockwave on snare target", NextAction::array(0, new NextAction("shockwave on snare target", ACTION_HIGH + 5), nullptr))); triggers.push_back(new TriggerNode("shockwave", NextAction::array(0, new NextAction("shockwave", ACTION_HIGH + 4), nullptr))); triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("sweeping strikes", ACTION_HIGH + 3), nullptr))); triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("bladestorm", ACTION_HIGH + 3), nullptr))); triggers.push_back(new TriggerNode("light aoe", NextAction::array(0, new NextAction("whirlwind", ACTION_HIGH + 2), nullptr))); + triggers.push_back(new TriggerNode("high rage available", NextAction::array(0, new NextAction("whirlwind", ACTION_HIGH + 10), nullptr))); } diff --git a/src/strategy/warrior/TankWarriorStrategy.cpp b/src/strategy/warrior/TankWarriorStrategy.cpp index 5bff955e..236da888 100644 --- a/src/strategy/warrior/TankWarriorStrategy.cpp +++ b/src/strategy/warrior/TankWarriorStrategy.cpp @@ -22,6 +22,7 @@ class TankWarriorStrategyActionNodeFactory : public NamedObjectFactory& triggers) { GenericWarriorStrategy::InitTriggers(triggers); - triggers.push_back(new TriggerNode("enemy out of melee", NextAction::array(0, new NextAction("heroic throw", ACTION_MOVE + 10), new NextAction("charge", ACTION_MOVE + 9), nullptr))); + triggers.push_back(new TriggerNode("enemy out of melee", NextAction::array(0, new NextAction("heroic throw", ACTION_MOVE + 11), new NextAction("charge", ACTION_MOVE + 10), nullptr))); + triggers.push_back(new TriggerNode("intercept and rage", NextAction::array(0, new NextAction("berserker stance", ACTION_MOVE + 14), nullptr))); + triggers.push_back(new TriggerNode("intercept and rage", NextAction::array(0, new NextAction("intercept", ACTION_MOVE + 13), nullptr))); + triggers.push_back(new TriggerNode("thunder clap and rage", NextAction::array(0, new NextAction("battle stance", ACTION_MOVE + 12), nullptr))); + triggers.push_back(new TriggerNode("thunder clap and rage", NextAction::array(0, new NextAction("thunder clap", ACTION_MOVE + 11), nullptr))); triggers.push_back(new TriggerNode("defensive stance", NextAction::array(0, new NextAction("defensive stance", ACTION_HIGH + 9), nullptr))); triggers.push_back(new TriggerNode("commanding shout", NextAction::array(0, new NextAction("commanding shout", ACTION_HIGH + 8), nullptr))); triggers.push_back(new TriggerNode("bloodrage", NextAction::array(0, new NextAction("bloodrage", ACTION_HIGH + 2), nullptr))); diff --git a/src/strategy/warrior/TankWarriorStrategy.h b/src/strategy/warrior/TankWarriorStrategy.h index 161ecf3d..dcc18ae8 100644 --- a/src/strategy/warrior/TankWarriorStrategy.h +++ b/src/strategy/warrior/TankWarriorStrategy.h @@ -6,6 +6,7 @@ #define _PLAYERBOT_TANKWARRIORSTRATEGY_H #include "GenericWarriorStrategy.h" +#include "WarriorTriggers.h" class PlayerbotAI; diff --git a/src/strategy/warrior/WarriorAiObjectContext.cpp b/src/strategy/warrior/WarriorAiObjectContext.cpp index b0f246eb..69a88707 100644 --- a/src/strategy/warrior/WarriorAiObjectContext.cpp +++ b/src/strategy/warrior/WarriorAiObjectContext.cpp @@ -89,6 +89,11 @@ class WarriorTriggerFactoryInternal : public NamedObjectContext creators["shockwave"] = &WarriorTriggerFactoryInternal::shockwave; creators["shockwave on snare target"] = &WarriorTriggerFactoryInternal::shockwave_on_snare_target; creators["taste for blood"] = &WarriorTriggerFactoryInternal::taste_for_blood; + + creators["thunder clap and rage"] = &WarriorTriggerFactoryInternal::thunderclap_and_rage; + creators["intercept can cast"] = &WarriorTriggerFactoryInternal::intercept_can_cast; + creators["intercept and far enemy"] = &WarriorTriggerFactoryInternal::intercept_and_far_enemy; + creators["intercept and rage"] = &WarriorTriggerFactoryInternal::intercept_and_rage; } private: @@ -108,6 +113,12 @@ class WarriorTriggerFactoryInternal : public NamedObjectContext static Trigger* concussion_blow(PlayerbotAI* botAI) { return new ConcussionBlowTrigger(botAI); } static Trigger* SwordAndBoard(PlayerbotAI* botAI) { return new SwordAndBoardTrigger(botAI); } static Trigger* shield_bash_on_enemy_healer(PlayerbotAI* botAI) { return new ShieldBashInterruptEnemyHealerSpellTrigger(botAI); } + + static Trigger* thunderclap_and_rage(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "thunderclap", "light rage available"); } + static Trigger* intercept_can_cast(PlayerbotAI* botAI) { return new InterceptCanCastTrigger(botAI); } + static Trigger* intercept_and_far_enemy(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "enemy is out of melee", "intercept can cast"); } + static Trigger* intercept_and_rage(PlayerbotAI* botAI) { return new TwoTriggers(botAI, "intercept and far enemy", "light rage available"); } + static Trigger* intercept_on_snare_target(PlayerbotAI* botAI) { return new InterceptSnareTrigger(botAI); } static Trigger* spell_reflection(PlayerbotAI* botAI) { return new SpellReflectionTrigger(botAI); } static Trigger* taste_for_blood(PlayerbotAI* botAI) { return new TasteForBloodTrigger(botAI); } diff --git a/src/strategy/warrior/WarriorTriggers.h b/src/strategy/warrior/WarriorTriggers.h index 12afa7fd..71654813 100644 --- a/src/strategy/warrior/WarriorTriggers.h +++ b/src/strategy/warrior/WarriorTriggers.h @@ -32,6 +32,7 @@ SNARE_TRIGGER(ThunderClapSnareTrigger, "thunder clap"); DEBUFF_TRIGGER(ThunderClapTrigger, "thunder clap"); SNARE_TRIGGER(TauntSnareTrigger, "taunt"); SNARE_TRIGGER(InterceptSnareTrigger, "intercept"); +CD_TRIGGER(InterceptCanCastTrigger, "intercept"); SNARE_TRIGGER(ShockwaveSnareTrigger, "shockwave"); DEBUFF_TRIGGER(ShockwaveTrigger, "shockwave"); BOOST_TRIGGER(DeathWishTrigger, "death wish");