From 98395a1090fb1ec6df6b976a1dd7ff4cc78de5ca Mon Sep 17 00:00:00 2001 From: kadeshar Date: Fri, 20 Mar 2026 20:42:22 +0100 Subject: [PATCH] Added cancellation druid form actions (#2194) # Pull Request Added new (for now manual) actions to cancel druid forms. Resolve: https://github.com/mod-playerbots/mod-playerbots/issues/1788 --- ## Feature Evaluation Please answer the following: - order bot enter some form like `do travel form` - order bot cancel form like `do cancel travel form` --- ## How to Test the Changes - order bot enter some form like `do travel form` - order bot cancel form like `do cancel travel form` ## Complexity & Impact Does this change add new decision branches? - - [x] No - - [ ] Yes (**explain below**) Does this change increase per-bot or per-tick processing? - - [x] No - - [ ] Yes (**describe and justify impact**) Could this logic scale poorly under load? - - [x] No - - [ ] Yes (**explain why**) --- ## Defaults & Configuration Does this change modify default bot behavior? - - [x] No - - [ ] Yes (**explain why**) - --- ## AI Assistance Was AI assistance (e.g. ChatGPT or similar tools) used while working on this change? - - [x] No - - [ ] Yes (**explain below**) --- ## Final Checklist - - [x] Stability is not compromised - - [x] Performance impact is understood, tested, and acceptable - - [x] Added logic complexity is justified and explained - - [x] Documentation updated if needed --- --- src/Ai/Base/ChatTriggerContext.h | 14 ++++ .../Strategy/ChatCommandHandlerStrategy.cpp | 7 ++ .../Druid/Action/DruidShapeshiftActions.cpp | 6 +- .../Druid/Action/DruidShapeshiftActions.h | 68 ++++++++++++++++++- src/Ai/Class/Druid/DruidAiObjectContext.cpp | 12 ++++ 5 files changed, 102 insertions(+), 5 deletions(-) diff --git a/src/Ai/Base/ChatTriggerContext.h b/src/Ai/Base/ChatTriggerContext.h index 54ae236b4..b305b19ea 100644 --- a/src/Ai/Base/ChatTriggerContext.h +++ b/src/Ai/Base/ChatTriggerContext.h @@ -104,6 +104,13 @@ public: creators["target"] = &ChatTriggerContext::target; creators["formation"] = &ChatTriggerContext::formation; creators["stance"] = &ChatTriggerContext::stance; + creators["cancel tree form"] = &ChatTriggerContext::cancel_tree_form; + creators["cancel travel form"] = &ChatTriggerContext::cancel_travel_form; + creators["cancel bear form"] = &ChatTriggerContext::cancel_bear_form; + creators["cancel dire bear form"] = &ChatTriggerContext::cancel_dire_bear_form; + creators["cancel cat form"] = &ChatTriggerContext::cancel_cat_form; + creators["cancel moonkin form"] = &ChatTriggerContext::cancel_moonkin_form; + creators["cancel aquatic form"] = &ChatTriggerContext::cancel_aquatic_form; creators["sendmail"] = &ChatTriggerContext::sendmail; creators["mail"] = &ChatTriggerContext::mail; creators["outfit"] = &ChatTriggerContext::outfit; @@ -159,6 +166,13 @@ private: static Trigger* sendmail(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "sendmail"); } static Trigger* formation(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "formation"); } static Trigger* stance(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "stance"); } + static Trigger* cancel_tree_form(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "cancel tree form"); } + static Trigger* cancel_travel_form(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "cancel travel form"); } + static Trigger* cancel_bear_form(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "cancel bear form"); } + static Trigger* cancel_dire_bear_form(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "cancel dire bear form"); } + static Trigger* cancel_cat_form(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "cancel cat form"); } + static Trigger* cancel_moonkin_form(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "cancel moonkin form"); } + static Trigger* cancel_aquatic_form(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "cancel aquatic form"); } static Trigger* attackers(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "attackers"); } static Trigger* target(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "target"); } static Trigger* max_dps(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "max dps"); } diff --git a/src/Ai/Base/Strategy/ChatCommandHandlerStrategy.cpp b/src/Ai/Base/Strategy/ChatCommandHandlerStrategy.cpp index 7bc1d5395..64334b799 100644 --- a/src/Ai/Base/Strategy/ChatCommandHandlerStrategy.cpp +++ b/src/Ai/Base/Strategy/ChatCommandHandlerStrategy.cpp @@ -160,6 +160,13 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas supported.push_back("save mana"); supported.push_back("formation"); supported.push_back("stance"); + supported.push_back("cancel tree form"); + supported.push_back("cancel travel form"); + supported.push_back("cancel bear form"); + supported.push_back("cancel dire bear form"); + supported.push_back("cancel cat form"); + supported.push_back("cancel moonkin form"); + supported.push_back("cancel aquatic form"); supported.push_back("sendmail"); supported.push_back("mail"); supported.push_back("outfit"); diff --git a/src/Ai/Class/Druid/Action/DruidShapeshiftActions.cpp b/src/Ai/Class/Druid/Action/DruidShapeshiftActions.cpp index a87f22a3b..f30d4ec03 100644 --- a/src/Ai/Class/Druid/Action/DruidShapeshiftActions.cpp +++ b/src/Ai/Class/Druid/Action/DruidShapeshiftActions.cpp @@ -44,13 +44,13 @@ bool CastCasterFormAction::isUseful() AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.mediumHealth; } -bool CastCancelTreeFormAction::Execute(Event /*event*/) +bool CastCancelDruidAction::Execute(Event /*event*/) { - botAI->RemoveAura("tree of life"); + botAI->RemoveAura(auraName); return true; } -bool CastCancelTreeFormAction::isUseful() { return botAI->HasAura(33891, bot); } +bool CastCancelDruidAction::isUseful() { return botAI->HasAura(auraId, bot); } bool CastTreeFormAction::isUseful() { diff --git a/src/Ai/Class/Druid/Action/DruidShapeshiftActions.h b/src/Ai/Class/Druid/Action/DruidShapeshiftActions.h index 9d75f2682..d485171d2 100644 --- a/src/Ai/Class/Druid/Action/DruidShapeshiftActions.h +++ b/src/Ai/Class/Druid/Action/DruidShapeshiftActions.h @@ -71,14 +71,78 @@ public: bool isPossible() override { return true; } }; -class CastCancelTreeFormAction : public CastBuffSpellAction +class CastCancelDruidAction : public CastBuffSpellAction { public: - CastCancelTreeFormAction(PlayerbotAI* botAI) : CastBuffSpellAction(botAI, "cancel tree form") {} + CastCancelDruidAction(PlayerbotAI* botAI, std::string const& actionName, std::string const& auraName, uint32 auraId) + : CastBuffSpellAction(botAI, actionName), auraName(auraName), auraId(auraId) + { + } bool Execute(Event event) override; bool isUseful() override; bool isPossible() override { return true; } + +private: + std::string auraName; + uint32 auraId; +}; + +class CastCancelTreeFormAction : public CastCancelDruidAction +{ +public: + CastCancelTreeFormAction(PlayerbotAI* botAI) + : CastCancelDruidAction(botAI, "cancel tree form", "tree of life", 33891) + { + } +}; + +class CastCancelTravelFormAction : public CastCancelDruidAction +{ +public: + CastCancelTravelFormAction(PlayerbotAI* botAI) + : CastCancelDruidAction(botAI, "cancel travel form", "travel form", 783) + { + } +}; + +class CastCancelBearFormAction : public CastCancelDruidAction +{ +public: + CastCancelBearFormAction(PlayerbotAI* botAI) : CastCancelDruidAction(botAI, "cancel bear form", "bear form", 5487) {} +}; + +class CastCancelDireBearFormAction : public CastCancelDruidAction +{ +public: + CastCancelDireBearFormAction(PlayerbotAI* botAI) + : CastCancelDruidAction(botAI, "cancel dire bear form", "dire bear form", 9634) + { + } +}; + +class CastCancelCatFormAction : public CastCancelDruidAction +{ +public: + CastCancelCatFormAction(PlayerbotAI* botAI) : CastCancelDruidAction(botAI, "cancel cat form", "cat form", 768) {} +}; + +class CastCancelMoonkinFormAction : public CastCancelDruidAction +{ +public: + CastCancelMoonkinFormAction(PlayerbotAI* botAI) + : CastCancelDruidAction(botAI, "cancel moonkin form", "moonkin form", 24858) + { + } +}; + +class CastCancelAquaticFormAction : public CastCancelDruidAction +{ +public: + CastCancelAquaticFormAction(PlayerbotAI* botAI) + : CastCancelDruidAction(botAI, "cancel aquatic form", "aquatic form", 1066) + { + } }; #endif diff --git a/src/Ai/Class/Druid/DruidAiObjectContext.cpp b/src/Ai/Class/Druid/DruidAiObjectContext.cpp index 29d9d4fdc..cc12f009f 100644 --- a/src/Ai/Class/Druid/DruidAiObjectContext.cpp +++ b/src/Ai/Class/Druid/DruidAiObjectContext.cpp @@ -170,6 +170,12 @@ public: creators["aquatic form"] = &DruidAiObjectContextInternal::aquatic_form; creators["caster form"] = &DruidAiObjectContextInternal::caster_form; creators["cancel tree form"] = &DruidAiObjectContextInternal::cancel_tree_form; + creators["cancel travel form"] = &DruidAiObjectContextInternal::cancel_travel_form; + creators["cancel bear form"] = &DruidAiObjectContextInternal::cancel_bear_form; + creators["cancel dire bear form"] = &DruidAiObjectContextInternal::cancel_dire_bear_form; + creators["cancel cat form"] = &DruidAiObjectContextInternal::cancel_cat_form; + creators["cancel moonkin form"] = &DruidAiObjectContextInternal::cancel_moonkin_form; + creators["cancel aquatic form"] = &DruidAiObjectContextInternal::cancel_aquatic_form; creators["mangle (bear)"] = &DruidAiObjectContextInternal::mangle_bear; creators["maul"] = &DruidAiObjectContextInternal::maul; creators["bash"] = &DruidAiObjectContextInternal::bash; @@ -258,6 +264,12 @@ private: static Action* aquatic_form(PlayerbotAI* botAI) { return new CastAquaticFormAction(botAI); } static Action* caster_form(PlayerbotAI* botAI) { return new CastCasterFormAction(botAI); } static Action* cancel_tree_form(PlayerbotAI* botAI) { return new CastCancelTreeFormAction(botAI); } + static Action* cancel_travel_form(PlayerbotAI* botAI) { return new CastCancelTravelFormAction(botAI); } + static Action* cancel_bear_form(PlayerbotAI* botAI) { return new CastCancelBearFormAction(botAI); } + static Action* cancel_dire_bear_form(PlayerbotAI* botAI) { return new CastCancelDireBearFormAction(botAI); } + static Action* cancel_cat_form(PlayerbotAI* botAI) { return new CastCancelCatFormAction(botAI); } + static Action* cancel_moonkin_form(PlayerbotAI* botAI) { return new CastCancelMoonkinFormAction(botAI); } + static Action* cancel_aquatic_form(PlayerbotAI* botAI) { return new CastCancelAquaticFormAction(botAI); } static Action* mangle_bear(PlayerbotAI* botAI) { return new CastMangleBearAction(botAI); } static Action* maul(PlayerbotAI* botAI) { return new CastMaulAction(botAI); } static Action* bash(PlayerbotAI* botAI) { return new CastBashAction(botAI); }