Resto druids should always be in tree form (#2192)

# Pull Request

Resto druids would not go into tree of life form when in combat until
certain triggers were hit.
They should be in tree of life form all the time.
Move tree form actions from the various triggers to default actions
instead, with highest priority

## Feature Evaluation

Please answer the following:

- Describe the **minimum logic** required to achieve the intended
behavior?|
When healer druids enter combat their first priority should be entering
tree form.
- Describe the **cheapest implementation** that produces an acceptable
result?
Add tree form action to default healer druid actions instead of
triggers.
- Describe the **runtime cost** when this logic executes across many
bots?
nil
---

## How to Test the Changes

- Have a resto druid bot with tree of life form talented.
- Enter combat
- The druid should immediately enter tree of life 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**)

If this introduces more advanced or AI-heavy logic:
- - [x] Lightweight mode remains the default
- - [ ] More complex behavior is optional and thereby configurable
---

## AI Assistance

Was AI assistance (e.g. ChatGPT or similar tools) used while working on
this change?
- - [x] No
- - [ ] Yes (**explain below**)

If yes, please specify:

- AI tool or model used (e.g. ChatGPT, GPT-4, Claude, etc.)
- Purpose of usage (e.g. brainstorming, refactoring, documentation, code
generation)
- Which parts of the change were influenced or generated
- Whether the result was manually reviewed and adapted

AI assistance is allowed, but all submitted code must be fully
understood, reviewed, and owned by the contributor.
Any AI-influenced changes must be verified against existing CORE and PB
logic. We expect contributors to be honest
about what they do and do not understand.

---

## 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

---

## Notes for Reviewers

Anything that significantly improves realism at the cost of stability or
performance should be carefully discussed
before merging.
This commit is contained in:
dillyns 2026-03-27 13:38:39 -04:00 committed by GitHub
parent 91eac70ca2
commit b172e88010
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 21 additions and 4 deletions

View File

@ -112,6 +112,7 @@ public:
creators["mangle (cat)"] = &DruidTriggerFactoryInternal::mangle_cat; creators["mangle (cat)"] = &DruidTriggerFactoryInternal::mangle_cat;
creators["ferocious bite time"] = &DruidTriggerFactoryInternal::ferocious_bite_time; creators["ferocious bite time"] = &DruidTriggerFactoryInternal::ferocious_bite_time;
creators["hurricane channel check"] = &DruidTriggerFactoryInternal::hurricane_channel_check; creators["hurricane channel check"] = &DruidTriggerFactoryInternal::hurricane_channel_check;
creators["no healer dps strategy"] = &DruidTriggerFactoryInternal::no_healer_dps_strategy;
} }
private: private:
@ -149,6 +150,7 @@ private:
static Trigger* mangle_cat(PlayerbotAI* ai) { return new MangleCatTrigger(ai); } static Trigger* mangle_cat(PlayerbotAI* ai) { return new MangleCatTrigger(ai); }
static Trigger* ferocious_bite_time(PlayerbotAI* ai) { return new FerociousBiteTimeTrigger(ai); } static Trigger* ferocious_bite_time(PlayerbotAI* ai) { return new FerociousBiteTimeTrigger(ai); }
static Trigger* hurricane_channel_check(PlayerbotAI* ai) { return new HurricaneChannelCheckTrigger(ai); } static Trigger* hurricane_channel_check(PlayerbotAI* ai) { return new HurricaneChannelCheckTrigger(ai); }
static Trigger* no_healer_dps_strategy(PlayerbotAI* ai) { return new NoHealerDpsStrategyTrigger(ai); }
}; };
class DruidAiObjectContextInternal : public NamedObjectContext<Action> class DruidAiObjectContextInternal : public NamedObjectContext<Action>

View File

@ -149,10 +149,10 @@ void DruidHealerDpsStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
triggers.push_back( triggers.push_back(
new TriggerNode("healer should attack", new TriggerNode("healer should attack",
{ {
NextAction("cancel tree form", ACTION_DEFAULT + 0.3f), NextAction("cancel tree form", ACTION_DEFAULT + 0.4f),
NextAction("moonfire", ACTION_DEFAULT + 0.2f), NextAction("moonfire", ACTION_DEFAULT + 0.3f),
NextAction("wrath", ACTION_DEFAULT + 0.1f), NextAction("wrath", ACTION_DEFAULT + 0.2f),
NextAction("starfire", ACTION_DEFAULT), NextAction("starfire", ACTION_DEFAULT + 0.1f),
})); }));
} }

View File

@ -33,6 +33,10 @@ void HealDruidStrategy::InitTriggers(std::vector<TriggerNode*>& triggers)
{ {
GenericDruidStrategy::InitTriggers(triggers); GenericDruidStrategy::InitTriggers(triggers);
// no healer dps strategy
triggers.push_back(new TriggerNode("no healer dps strategy",
{ NextAction("tree form", ACTION_DEFAULT) }));
triggers.push_back(new TriggerNode( triggers.push_back(new TriggerNode(
"party member to heal out of spell range", "party member to heal out of spell range",
{ NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 9) })); { NextAction("reach party member to heal", ACTION_CRITICAL_HEAL + 9) }));

View File

@ -280,4 +280,15 @@ protected:
static const std::set<uint32> HURRICANE_SPELL_IDS; static const std::set<uint32> HURRICANE_SPELL_IDS;
}; };
class NoHealerDpsStrategyTrigger : public Trigger
{
public:
NoHealerDpsStrategyTrigger(PlayerbotAI* botAI) : Trigger(botAI, "no healer dps strategy") {}
bool IsActive() override
{
return !botAI->HasStrategy("healer dps", BOT_STATE_COMBAT);
}
};
#endif #endif