fix(Core/Combat): Fix guardians not attacking after threat system port (#25157)

Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>
This commit is contained in:
blinkysc 2026-03-21 11:05:57 -05:00 committed by GitHub
parent a361a10a01
commit bf4c181b59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 41 additions and 11 deletions

View file

@ -239,14 +239,16 @@ void CreatureAI::EnterEvadeMode(EvadeReason why)
{
if (Unit* owner = me->GetCharmerOrOwner())
{
// Owned creatures (pets/guardians) follow their owner — clear evade state
// so they can re-enter combat immediately via CanBeginCombat
me->ClearUnitState(UNIT_STATE_EVADE);
me->GetMotionMaster()->Clear(false);
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE);
}
else
{
// Required to prevent attacking creatures that are evading and cause them to reenter combat
// Does not apply to MoveFollow
me->AddUnitState(UNIT_STATE_EVADE);
// Does not apply to MoveFollow — UNIT_STATE_EVADE is already set from _EnterEvadeMode
me->GetMotionMaster()->MoveTargetedHome();
}
}
@ -381,8 +383,11 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)
return false;
}
// Set evade state early to prevent recursion when CombatStop triggers JustExitedCombat
// This will be cleared in MoveTargetedHome for pets/guardians following their owner
// Set evade state early to prevent recursion: CombatStop below purges combat
// refs, which triggers JustExitedCombat -> EnterEvadeMode -> _EnterEvadeMode.
// The IsInEvadeMode() check above will catch it.
// EnterEvadeMode will clear this for owned creatures (pets/guardians) that
// use MoveFollow instead of MoveTargetedHome.
me->AddUnitState(UNIT_STATE_EVADE);
// don't remove vehicle auras, passengers aren't supposed to drop off the vehicle

View file

@ -7333,19 +7333,22 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
// set position before any AI calls/assistance
//if (IsCreature())
// ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
if (creature && !IsControlledByPlayer())
if (creature)
{
EngageWithTarget(victim);
creature->SendAIReaction(AI_REACTION_HOSTILE);
if (!IsControlledByPlayer())
{
creature->SendAIReaction(AI_REACTION_HOSTILE);
/// @todo: Implement aggro range, detection range and assistance range templates
if (!(creature->HasFlagsExtra(CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE)))
creature->CallAssistance();
/// @todo: Implement aggro range, detection range and assistance range templates
if (!(creature->HasFlagsExtra(CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE)))
creature->CallAssistance();
creature->SetAssistanceTimer(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_PERIOD));
creature->SetAssistanceTimer(sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_PERIOD));
SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
}
}
// delay offhand weapon attack by 50% of the base attack time

View file

@ -306,6 +306,8 @@ struct npc_pet_dk_army_of_the_dead : public AggressorAI
{
npc_pet_dk_army_of_the_dead(Creature* creature) : AggressorAI(creature) { }
// Restrict MoveInLineOfSight aggro to targets already fighting our owner,
// so ghouls don't pull extra packs on their own.
bool CanAIAttack(Unit const* target) const override
{
if (!target)
@ -315,6 +317,26 @@ struct npc_pet_dk_army_of_the_dead : public AggressorAI
return false;
return AggressorAI::CanAIAttack(target);
}
// Owner started attacking a target — engage immediately.
// We bypass OnOwnerCombatInteraction because CanStartAttack -> CanAIAttack
// may reject the target before combat refs are established.
void OwnerAttacked(Unit* target) override
{
if (!target || !me->IsAlive() || me->HasReactState(REACT_PASSIVE))
return;
if (me->IsValidAttackTarget(target))
AttackStart(target);
}
// Owner was attacked — help defend.
void OwnerAttackedBy(Unit* attacker) override
{
if (!attacker || !me->IsAlive() || me->HasReactState(REACT_PASSIVE))
return;
if (me->IsValidAttackTarget(attacker))
AttackStart(attacker);
}
};
struct npc_pet_dk_dancing_rune_weapon : public NullCreatureAI