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
3 changed files with 41 additions and 11 deletions
+9 -4
View File
@@ -239,14 +239,16 @@ void CreatureAI::EnterEvadeMode(EvadeReason why)
{ {
if (Unit* owner = me->GetCharmerOrOwner()) 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()->Clear(false);
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE);
} }
else else
{ {
// Required to prevent attacking creatures that are evading and cause them to reenter combat // Required to prevent attacking creatures that are evading and cause them to reenter combat
// Does not apply to MoveFollow // Does not apply to MoveFollow — UNIT_STATE_EVADE is already set from _EnterEvadeMode
me->AddUnitState(UNIT_STATE_EVADE);
me->GetMotionMaster()->MoveTargetedHome(); me->GetMotionMaster()->MoveTargetedHome();
} }
} }
@@ -381,8 +383,11 @@ bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)
return false; return false;
} }
// Set evade state early to prevent recursion when CombatStop triggers JustExitedCombat // Set evade state early to prevent recursion: CombatStop below purges combat
// This will be cleared in MoveTargetedHome for pets/guardians following their owner // 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); me->AddUnitState(UNIT_STATE_EVADE);
// don't remove vehicle auras, passengers aren't supposed to drop off the vehicle // don't remove vehicle auras, passengers aren't supposed to drop off the vehicle
+10 -7
View File
@@ -7333,19 +7333,22 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
// set position before any AI calls/assistance // set position before any AI calls/assistance
//if (IsCreature()) //if (IsCreature())
// ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ()); // ToCreature()->SetCombatStartPosition(GetPositionX(), GetPositionY(), GetPositionZ());
if (creature && !IsControlledByPlayer()) if (creature)
{ {
EngageWithTarget(victim); EngageWithTarget(victim);
creature->SendAIReaction(AI_REACTION_HOSTILE); if (!IsControlledByPlayer())
{
creature->SendAIReaction(AI_REACTION_HOSTILE);
/// @todo: Implement aggro range, detection range and assistance range templates /// @todo: Implement aggro range, detection range and assistance range templates
if (!(creature->HasFlagsExtra(CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE))) if (!(creature->HasFlagsExtra(CREATURE_FLAG_EXTRA_DONT_CALL_ASSISTANCE)))
creature->CallAssistance(); 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 // delay offhand weapon attack by 50% of the base attack time
+22
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) { } 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 bool CanAIAttack(Unit const* target) const override
{ {
if (!target) if (!target)
@@ -315,6 +317,26 @@ struct npc_pet_dk_army_of_the_dead : public AggressorAI
return false; return false;
return AggressorAI::CanAIAttack(target); 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 struct npc_pet_dk_dancing_rune_weapon : public NullCreatureAI