From 8e03371147807b885eb578ada558642fa0cbf8bc Mon Sep 17 00:00:00 2001 From: Gonzalo Date: Wed, 19 Nov 2025 17:00:59 -0300 Subject: [PATCH] Balance-Druid-improve-Starfall-usage-and-add-CC-safety (#1713) - Move Starfall from default actions to AOE strategy only - Require 2+ enemies for Starfall usage (prevents single-target casting) - Add CC safety: avoid casting Starfall near current CC targets - Prioritize Starfall over Hurricane in medium AOE situations - Remove Starfall from pull/opener rotation to prevent early single-target usage This prevents Balance druids from wasting Starfall on single targets and breaking crowd control effects in group content. --- src/strategy/druid/DruidActions.cpp | 29 +++++++++++++++++++++++++++++ src/strategy/druid/DruidActions.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/src/strategy/druid/DruidActions.cpp b/src/strategy/druid/DruidActions.cpp index b5a493db..217db825 100644 --- a/src/strategy/druid/DruidActions.cpp +++ b/src/strategy/druid/DruidActions.cpp @@ -7,6 +7,9 @@ #include "Event.h" #include "Playerbots.h" +#include "ServerFacade.h" +#include "AoeValues.h" +#include "TargetValue.h" NextAction** CastAbolishPoisonAction::getAlternatives() { @@ -30,6 +33,32 @@ bool CastEntanglingRootsCcAction::Execute(Event event) { return botAI->CastSpell Value* CastHibernateCcAction::GetTargetValue() { return context->GetValue("cc target", "hibernate"); } bool CastHibernateCcAction::Execute(Event event) { return botAI->CastSpell("hibernate", GetTarget()); } +bool CastStarfallAction::isUseful() +{ + if (!CastSpellAction::isUseful()) + return false; + + // Avoid breaking CC + WorldLocation aoePos = *context->GetValue("aoe position"); + Unit* ccTarget = context->GetValue("current cc target")->Get(); + if (ccTarget && ccTarget->IsAlive()) + { + float dist2d = sServerFacade->GetDistance2d(ccTarget, aoePos.GetPositionX(), aoePos.GetPositionY()); + if (sServerFacade->IsDistanceLessOrEqualThan(dist2d, sPlayerbotAIConfig->aoeRadius)) + return false; + } + + // Avoid single-target usage on initial pull + uint8 aoeCount = *context->GetValue("aoe count"); + if (aoeCount < 2) + { + Unit* target = context->GetValue("current target")->Get(); + if (!target || (!botAI->HasAura("moonfire", target) && !botAI->HasAura("insect swarm", target))) + return false; + } + + return true; +} NextAction** CastReviveAction::getPrerequisites() { diff --git a/src/strategy/druid/DruidActions.h b/src/strategy/druid/DruidActions.h index 402073d2..d0af6e5a 100644 --- a/src/strategy/druid/DruidActions.h +++ b/src/strategy/druid/DruidActions.h @@ -144,6 +144,8 @@ class CastStarfallAction : public CastSpellAction { public: CastStarfallAction(PlayerbotAI* botAI) : CastSpellAction(botAI, "starfall") {} + + bool isUseful() override; }; class CastHurricaneAction : public CastSpellAction