@@ -34,7 +34,7 @@ namespace
3434
3535CompanionAI::CompanionAI (Creature* creature) : CreatureAI(creature), _checkTimer(0 )
3636{
37- creature->SetReactState (REACT_PASSIVE );
37+ creature->SetReactState (REACT_DEFENSIVE );
3838}
3939
4040void CompanionAI::JustAppeared ()
@@ -68,6 +68,7 @@ void CompanionAI::StartFollowing(Player* player)
6868
6969void CompanionAI::StopFollowing ()
7070{
71+ me->SetReactState (REACT_DEFENSIVE ); // reset posture for the next recruiter
7172 NotifyDismissed ();
7273 me->GetMotionMaster ()->Clear ();
7374 me->GetMotionMaster ()->MoveTargetedHome ();
@@ -78,15 +79,8 @@ void CompanionAI::UpdateAI(uint32 diff)
7879 if (!IsRecruited ())
7980 return ;
8081
81- if (_checkTimer > diff)
82- {
83- _checkTimer -= diff;
84- return ;
85- }
86- _checkTimer = COMPANION_CHECK_INTERVAL ;
87-
88- // Map-local lookup: fails when the owner logged out or changed map,
89- // in which case the companion dismisses itself and walks home.
82+ // Resolved every tick now (cheap map-local lookup, same as PetAI does for real pets)
83+ // so combat below is responsive and owner-gone detection isn't up to 1s late.
9084 Player* owner = ObjectAccessor::GetPlayer (*me, _ownerGuid);
9185 if (!owner)
9286 {
@@ -97,13 +91,55 @@ void CompanionAI::UpdateAI(uint32 diff)
9791 if (!me->IsAlive ())
9892 return ;
9993
94+ if (me->IsEngaged ())
95+ {
96+ if (UpdateVictim ())
97+ DoMeleeAttackIfReady ();
98+ }
99+ else if (!me->HasReactState (REACT_PASSIVE ) && owner->IsAlive ())
100+ {
101+ if (Unit* target = SelectAssistTarget (owner))
102+ AttackStart (target);
103+ }
104+
105+ if (_checkTimer > diff)
106+ {
107+ _checkTimer -= diff;
108+ return ;
109+ }
110+ _checkTimer = COMPANION_CHECK_INTERVAL ;
111+
100112 if (!me->IsWithinDist (owner, COMPANION_TELEPORT_DIST ))
101113 me->NearTeleportTo (owner->GetPositionX (), owner->GetPositionY (), owner->GetPositionZ (), owner->GetOrientation ());
102114
103- if (me->GetMotionMaster ()->GetCurrentMovementGeneratorType () != FOLLOW_MOTION_TYPE )
115+ me->SetHomePosition (owner->GetPosition ());
116+
117+ if (!me->IsEngaged () && me->GetMotionMaster ()->GetCurrentMovementGeneratorType () != FOLLOW_MOTION_TYPE )
104118 StartFollowing (owner);
105119}
106120
121+ void CompanionAI::EnterEvadeMode (EvadeReason why)
122+ {
123+ if (!_EnterEvadeMode (why))
124+ return ;
125+
126+ if (Player* owner = ObjectAccessor::GetPlayer (*me, _ownerGuid))
127+ StartFollowing (owner);
128+ else
129+ me->GetMotionMaster ()->MoveTargetedHome ();
130+
131+ Reset ();
132+ }
133+
134+ Unit* CompanionAI::SelectAssistTarget (Player* owner) const
135+ {
136+ Unit* target = owner->getAttackerForHelper ();
137+ if (!target)
138+ target = owner->GetVictim ();
139+
140+ return me->CanCreatureAttack (target) ? target : nullptr ;
141+ }
142+
107143bool CompanionAI::OnGossipHello (Player* player)
108144{
109145 if (!sCompanionMgr ->IsCompanion (me->GetEntry ()))
0 commit comments