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

---
This commit is contained in:
kadeshar 2026-03-20 20:42:22 +01:00 committed by GitHub
parent f160420d70
commit 98395a1090
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 102 additions and 5 deletions

View File

@ -104,6 +104,13 @@ public:
creators["target"] = &ChatTriggerContext::target; creators["target"] = &ChatTriggerContext::target;
creators["formation"] = &ChatTriggerContext::formation; creators["formation"] = &ChatTriggerContext::formation;
creators["stance"] = &ChatTriggerContext::stance; 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["sendmail"] = &ChatTriggerContext::sendmail;
creators["mail"] = &ChatTriggerContext::mail; creators["mail"] = &ChatTriggerContext::mail;
creators["outfit"] = &ChatTriggerContext::outfit; creators["outfit"] = &ChatTriggerContext::outfit;
@ -159,6 +166,13 @@ private:
static Trigger* sendmail(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "sendmail"); } static Trigger* sendmail(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "sendmail"); }
static Trigger* formation(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "formation"); } static Trigger* formation(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "formation"); }
static Trigger* stance(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "stance"); } 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* attackers(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "attackers"); }
static Trigger* target(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "target"); } static Trigger* target(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "target"); }
static Trigger* max_dps(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "max dps"); } static Trigger* max_dps(PlayerbotAI* botAI) { return new ChatCommandTrigger(botAI, "max dps"); }

View File

@ -160,6 +160,13 @@ ChatCommandHandlerStrategy::ChatCommandHandlerStrategy(PlayerbotAI* botAI) : Pas
supported.push_back("save mana"); supported.push_back("save mana");
supported.push_back("formation"); supported.push_back("formation");
supported.push_back("stance"); 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("sendmail");
supported.push_back("mail"); supported.push_back("mail");
supported.push_back("outfit"); supported.push_back("outfit");

View File

@ -44,13 +44,13 @@ bool CastCasterFormAction::isUseful()
AI_VALUE2(uint8, "mana", "self target") > sPlayerbotAIConfig.mediumHealth; 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; return true;
} }
bool CastCancelTreeFormAction::isUseful() { return botAI->HasAura(33891, bot); } bool CastCancelDruidAction::isUseful() { return botAI->HasAura(auraId, bot); }
bool CastTreeFormAction::isUseful() bool CastTreeFormAction::isUseful()
{ {

View File

@ -71,14 +71,78 @@ public:
bool isPossible() override { return true; } bool isPossible() override { return true; }
}; };
class CastCancelTreeFormAction : public CastBuffSpellAction class CastCancelDruidAction : public CastBuffSpellAction
{ {
public: 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 Execute(Event event) override;
bool isUseful() override; bool isUseful() override;
bool isPossible() override { return true; } 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 #endif

View File

@ -170,6 +170,12 @@ public:
creators["aquatic form"] = &DruidAiObjectContextInternal::aquatic_form; creators["aquatic form"] = &DruidAiObjectContextInternal::aquatic_form;
creators["caster form"] = &DruidAiObjectContextInternal::caster_form; creators["caster form"] = &DruidAiObjectContextInternal::caster_form;
creators["cancel tree form"] = &DruidAiObjectContextInternal::cancel_tree_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["mangle (bear)"] = &DruidAiObjectContextInternal::mangle_bear;
creators["maul"] = &DruidAiObjectContextInternal::maul; creators["maul"] = &DruidAiObjectContextInternal::maul;
creators["bash"] = &DruidAiObjectContextInternal::bash; creators["bash"] = &DruidAiObjectContextInternal::bash;
@ -258,6 +264,12 @@ private:
static Action* aquatic_form(PlayerbotAI* botAI) { return new CastAquaticFormAction(botAI); } static Action* aquatic_form(PlayerbotAI* botAI) { return new CastAquaticFormAction(botAI); }
static Action* caster_form(PlayerbotAI* botAI) { return new CastCasterFormAction(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_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* mangle_bear(PlayerbotAI* botAI) { return new CastMangleBearAction(botAI); }
static Action* maul(PlayerbotAI* botAI) { return new CastMaulAction(botAI); } static Action* maul(PlayerbotAI* botAI) { return new CastMaulAction(botAI); }
static Action* bash(PlayerbotAI* botAI) { return new CastBashAction(botAI); } static Action* bash(PlayerbotAI* botAI) { return new CastBashAction(botAI); }