Core/AI: Finally move the "is creature engaged" flag to be a property of the creature AI, where it honestly always belonged. Fixes #17981 and #23602 for real this time.
(cherry picked from commit 0e7c66cb4c7ff7d44e232d0b50703a48605ffd24)
This commit is contained in:
@@ -52,7 +52,7 @@ void GuardAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ void GuardAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
|
||||
@@ -39,6 +39,9 @@ class TC_GAME_API PossessedAI : public CreatureAI
|
||||
|
||||
void MoveInLineOfSight(Unit*) override { }
|
||||
void AttackStart(Unit* target) override;
|
||||
void JustEnteredCombat(Unit* who) override { EngagementStart(who); }
|
||||
void JustExitedCombat() override { EngagementOver(); }
|
||||
void JustStartedThreateningMe(Unit*) override { }
|
||||
void UpdateAI(uint32) override;
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override { }
|
||||
|
||||
@@ -55,6 +58,8 @@ class TC_GAME_API NullCreatureAI : public CreatureAI
|
||||
|
||||
void MoveInLineOfSight(Unit*) override { }
|
||||
void AttackStart(Unit*) override { }
|
||||
void JustStartedThreateningMe(Unit*) override { }
|
||||
void JustEnteredCombat(Unit*) override { }
|
||||
void UpdateAI(uint32) override { }
|
||||
void JustAppeared() override { }
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override { }
|
||||
|
||||
@@ -33,16 +33,9 @@ int32 TotemAI::Permissible(Creature const* creature)
|
||||
return PERMIT_BASE_NO;
|
||||
}
|
||||
|
||||
TotemAI::TotemAI(Creature* creature, uint32 scriptId) : CreatureAI(creature, scriptId), _victimGUID()
|
||||
TotemAI::TotemAI(Creature* creature, uint32 scriptId) : NullCreatureAI(creature, scriptId), _victimGUID()
|
||||
{
|
||||
ASSERT(creature->IsTotem(), "TotemAI: AI assigned to a no-totem creature (%s)!", creature->GetGUID().ToString().c_str());
|
||||
}
|
||||
|
||||
void TotemAI::MoveInLineOfSight(Unit* /*who*/) { }
|
||||
|
||||
void TotemAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
me->CombatStop(true);
|
||||
ASSERT(creature->IsTotem(), "TotemAI: AI assigned to a non-totem creature (%s)!", creature->GetGUID().ToString().c_str());
|
||||
}
|
||||
|
||||
void TotemAI::UpdateAI(uint32 /*diff*/)
|
||||
|
||||
@@ -19,20 +19,18 @@
|
||||
#define TRINITY_TOTEMAI_H
|
||||
|
||||
#include "CreatureAI.h"
|
||||
#include "PassiveAI.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class Creature;
|
||||
class Totem;
|
||||
|
||||
class TC_GAME_API TotemAI : public CreatureAI
|
||||
class TC_GAME_API TotemAI : public NullCreatureAI
|
||||
{
|
||||
public:
|
||||
explicit TotemAI(Creature* creature, uint32 scriptId = {});
|
||||
|
||||
void MoveInLineOfSight(Unit* who) override;
|
||||
void AttackStart(Unit* victim) override;
|
||||
void JustAppeared() override { }
|
||||
void EnterEvadeMode(EvadeReason /*why*/) override;
|
||||
|
||||
void UpdateAI(uint32 diff) override;
|
||||
static int32 Permissible(Creature const* creature);
|
||||
|
||||
@@ -318,7 +318,7 @@ std::string UnitAI::GetDebugInfo() const
|
||||
}
|
||||
|
||||
DefaultTargetSelector::DefaultTargetSelector(Unit const* unit, float dist, bool playerOnly, bool withTank, int32 aura)
|
||||
: _me(unit), _dist(dist), _playerOnly(playerOnly), _exception(!withTank ? _me->GetThreatManager().GetCurrentVictim() : nullptr), _aura(aura)
|
||||
: _me(unit), _dist(dist), _playerOnly(playerOnly), _exception(!withTank ? unit->GetThreatManager().GetLastVictim() : nullptr), _aura(aura)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ AISpellInfoType* GetAISpellInfo(uint32 spellId, Difficulty difficulty)
|
||||
|
||||
CreatureAI::CreatureAI(Creature* creature, uint32 scriptId)
|
||||
: UnitAI(creature), me(creature), _boundary(nullptr),
|
||||
_negateBoundary(false), _scriptId(scriptId ? scriptId : creature->GetScriptId()), _moveInLOSLocked(false)
|
||||
_negateBoundary(false), _scriptId(scriptId ? scriptId : creature->GetScriptId()), _isEngaged(false), _moveInLOSLocked(false)
|
||||
{
|
||||
ASSERT(_scriptId, "A CreatureAI was initialized with an invalid scriptId!");
|
||||
}
|
||||
@@ -207,6 +207,12 @@ void CreatureAI::JustAppeared()
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureAI::JustEnteredCombat(Unit* who)
|
||||
{
|
||||
if (!IsEngaged() && !me->CanHaveThreatList())
|
||||
EngagementStart(who);
|
||||
}
|
||||
|
||||
void CreatureAI::EnterEvadeMode(EvadeReason why)
|
||||
{
|
||||
if (!_EnterEvadeMode(why))
|
||||
@@ -235,7 +241,7 @@ void CreatureAI::EnterEvadeMode(EvadeReason why)
|
||||
|
||||
bool CreatureAI::UpdateVictim()
|
||||
{
|
||||
if (!me->IsEngaged())
|
||||
if (!IsEngaged())
|
||||
return false;
|
||||
|
||||
if (!me->HasReactState(REACT_PASSIVE))
|
||||
@@ -257,22 +263,52 @@ bool CreatureAI::UpdateVictim()
|
||||
return true;
|
||||
}
|
||||
|
||||
void CreatureAI::EngagementStart(Unit* who)
|
||||
{
|
||||
if (_isEngaged)
|
||||
{
|
||||
TC_LOG_ERROR("scripts.ai", "CreatureAI::EngagementStart called even though creature is already engaged. Creature debug info:\n%s", me->GetDebugInfo().c_str());
|
||||
return;
|
||||
}
|
||||
_isEngaged = true;
|
||||
|
||||
me->AtEngage(who);
|
||||
}
|
||||
|
||||
void CreatureAI::EngagementOver()
|
||||
{
|
||||
if (!_isEngaged)
|
||||
{
|
||||
TC_LOG_ERROR("scripts.ai", "CreatureAI::EngagementOver called even though creature is not currently engaged. Creature debug info:\n%s", me->GetDebugInfo().c_str());
|
||||
return;
|
||||
}
|
||||
_isEngaged = false;
|
||||
|
||||
me->AtDisengage();
|
||||
}
|
||||
|
||||
bool CreatureAI::_EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
if (me->IsInEvadeMode())
|
||||
return false;
|
||||
|
||||
if (!me->IsAlive())
|
||||
{
|
||||
EngagementOver();
|
||||
return false;
|
||||
}
|
||||
|
||||
me->RemoveAurasOnEvade();
|
||||
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
me->SetLootRecipient(nullptr);
|
||||
me->ResetPlayerDamageReq();
|
||||
me->SetLastDamagedTime(0);
|
||||
me->SetCannotReachTarget(false);
|
||||
me->DoNotReacquireTarget();
|
||||
EngagementOver();
|
||||
|
||||
return !me->IsInEvadeMode();
|
||||
return true;
|
||||
}
|
||||
|
||||
Optional<QuestGiverStatus> CreatureAI::GetDialogStatus(Player* /*player*/)
|
||||
|
||||
@@ -84,6 +84,8 @@ class TC_GAME_API CreatureAI : public UnitAI
|
||||
// Gets the id of the AI (script id)
|
||||
uint32 GetId() const { return _scriptId; }
|
||||
|
||||
bool IsEngaged() const { return _isEngaged; }
|
||||
|
||||
void Talk(uint8 id, WorldObject const* whisperTarget = nullptr);
|
||||
|
||||
/// == Reactions At =================================
|
||||
@@ -97,11 +99,17 @@ class TC_GAME_API CreatureAI : public UnitAI
|
||||
// Called for reaction at stopping attack at no attackers or targets
|
||||
virtual void EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER);
|
||||
|
||||
// Called for reaction whenever we start being in combat (overridden from base UnitAI)
|
||||
void JustEnteredCombat(Unit* /*who*/) override;
|
||||
|
||||
// Called for reaction whenever a new non-offline unit is added to the threat list
|
||||
virtual void JustStartedThreateningMe(Unit* who) { if (!IsEngaged()) EngagementStart(who); }
|
||||
|
||||
// Called for reaction when initially engaged - this will always happen _after_ JustEnteredCombat
|
||||
virtual void JustEngagedWith(Unit* /*who*/) { }
|
||||
|
||||
// Called when the creature is killed
|
||||
virtual void JustDied(Unit* /*killer*/) { }
|
||||
virtual void JustDied(Unit* /*killer*/) { if (IsEngaged()) EngagementOver(); }
|
||||
|
||||
// Called when the creature kills a unit
|
||||
virtual void KilledUnit(Unit* /*victim*/) { }
|
||||
@@ -227,6 +235,8 @@ class TC_GAME_API CreatureAI : public UnitAI
|
||||
|
||||
// intended for encounter design/debugging. do not use for other purposes. expensive.
|
||||
int32 VisualizeBoundary(uint32 duration, Unit* owner = nullptr, bool fill = false) const;
|
||||
|
||||
// boundary system methods
|
||||
virtual bool CheckInRoom();
|
||||
CreatureBoundary const* GetBoundary() const { return _boundary; }
|
||||
void SetBoundary(CreatureBoundary const* boundary, bool negativeBoundaries = false);
|
||||
@@ -235,6 +245,8 @@ class TC_GAME_API CreatureAI : public UnitAI
|
||||
bool IsInBoundary(Position const* who = nullptr) const;
|
||||
|
||||
protected:
|
||||
void EngagementStart(Unit* who);
|
||||
void EngagementOver();
|
||||
virtual void MoveInLineOfSight(Unit* /*who*/);
|
||||
|
||||
bool _EnterEvadeMode(EvadeReason why = EVADE_REASON_OTHER);
|
||||
@@ -246,6 +258,7 @@ class TC_GAME_API CreatureAI : public UnitAI
|
||||
void OnOwnerCombatInteraction(Unit* target);
|
||||
|
||||
uint32 const _scriptId;
|
||||
bool _isEngaged;
|
||||
bool _moveInLOSLocked;
|
||||
};
|
||||
|
||||
|
||||
@@ -94,8 +94,9 @@ void EscortAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
me->SetLootRecipient(nullptr);
|
||||
|
||||
EngagementOver();
|
||||
|
||||
if (HasEscortState(STATE_ESCORT_ESCORTING))
|
||||
{
|
||||
|
||||
@@ -103,14 +103,18 @@ void FollowerAI::JustAppeared()
|
||||
void FollowerAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
{
|
||||
if (!me->IsAlive())
|
||||
{
|
||||
EngagementOver();
|
||||
return;
|
||||
}
|
||||
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
me->SetLootRecipient(nullptr);
|
||||
me->SetCannotReachTarget(false);
|
||||
me->DoNotReacquireTarget();
|
||||
|
||||
EngagementOver();
|
||||
|
||||
if (HasFollowState(STATE_FOLLOW_INPROGRESS))
|
||||
{
|
||||
|
||||
@@ -293,13 +293,8 @@ void CombatManager::EndAllPvPCombat()
|
||||
|
||||
/*static*/ void CombatManager::NotifyAICombat(Unit* me, Unit* other)
|
||||
{
|
||||
if (!me->IsAIEnabled())
|
||||
return;
|
||||
me->GetAI()->JustEnteredCombat(other);
|
||||
|
||||
if (Creature* cMe = me->ToCreature())
|
||||
if (!cMe->CanHaveThreatList())
|
||||
cMe->AI()->JustEngagedWith(other);
|
||||
if (UnitAI* ai = me->GetAI())
|
||||
ai->JustEnteredCombat(other);
|
||||
}
|
||||
|
||||
void CombatManager::PutReference(ObjectGuid const& guid, CombatReference* ref)
|
||||
@@ -336,14 +331,14 @@ bool CombatManager::UpdateOwnerCombatState() const
|
||||
{
|
||||
_owner->AddUnitFlag(UNIT_FLAG_IN_COMBAT);
|
||||
_owner->AtEnterCombat();
|
||||
if (!_owner->CanHaveThreatList() && !_owner->IsEngaged())
|
||||
if (_owner->GetTypeId() == TYPEID_UNIT)
|
||||
_owner->AtEngage(GetAnyTarget());
|
||||
}
|
||||
else
|
||||
{
|
||||
_owner->RemoveUnitFlag(UNIT_FLAG_IN_COMBAT);
|
||||
_owner->AtExitCombat();
|
||||
if (_owner->IsEngaged() && !(_owner->ToCreature() && _owner->CanHaveThreatList() && _owner->ToCreature()->IsAIEnabled()))
|
||||
if (_owner->GetTypeId() != TYPEID_UNIT)
|
||||
_owner->AtDisengage();
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ void ThreatReference::UpdateOffline()
|
||||
{
|
||||
_online = ShouldBeSuppressed() ? ONLINE_STATE_SUPPRESSED : ONLINE_STATE_ONLINE;
|
||||
HeapNotifyIncreased();
|
||||
_mgr.RegisterForAIUpdate(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,10 +200,11 @@ Unit* ThreatManager::GetCurrentVictim()
|
||||
{
|
||||
if (!_currentVictimRef || _currentVictimRef->ShouldBeOffline())
|
||||
UpdateVictim();
|
||||
return const_cast<ThreatManager const*>(this)->GetCurrentVictim();
|
||||
ASSERT(!_currentVictimRef || _currentVictimRef->IsAvailable());
|
||||
return _currentVictimRef ? _currentVictimRef->GetVictim() : nullptr;
|
||||
}
|
||||
|
||||
Unit* ThreatManager::GetCurrentVictim() const
|
||||
Unit* ThreatManager::GetLastVictim() const
|
||||
{
|
||||
if (_currentVictimRef && !_currentVictimRef->ShouldBeOffline())
|
||||
return _currentVictimRef->GetVictim();
|
||||
@@ -244,7 +246,7 @@ float ThreatManager::GetThreat(Unit const* who, bool includeOffline) const
|
||||
return (includeOffline || it->second->IsAvailable()) ? it->second->GetThreat() : 0.0f;
|
||||
}
|
||||
|
||||
std::vector<ThreatReference*> ThreatManager::GetModifiableThreatList() const
|
||||
std::vector<ThreatReference*> ThreatManager::GetModifiableThreatList()
|
||||
{
|
||||
std::vector<ThreatReference*> list;
|
||||
list.reserve(_myThreatListEntries.size());
|
||||
@@ -394,16 +396,14 @@ void ThreatManager::AddThreat(Unit* target, float amount, SpellInfo const* spell
|
||||
PutThreatListRef(target->GetGUID(), ref);
|
||||
target->GetThreatManager().PutThreatenedByMeRef(_owner->GetGUID(), ref);
|
||||
|
||||
// afterwards, we evaluate whether this is an online reference (it might not be an acceptable target, but we need to add it to our threat list before we check!)
|
||||
ref->UpdateOffline();
|
||||
if (ref->IsOnline()) // ...and if the ref is online it also gets the threat it should have
|
||||
if (ref->IsOnline()) // we only add the threat if the ref is currently available
|
||||
ref->AddThreat(amount);
|
||||
|
||||
if (!_owner->IsEngaged())
|
||||
{
|
||||
_owner->AtEngage(target);
|
||||
if (!_currentVictimRef)
|
||||
UpdateVictim();
|
||||
}
|
||||
else
|
||||
ProcessAIUpdates();
|
||||
}
|
||||
|
||||
void ThreatManager::ScaleThreat(Unit* target, float factor)
|
||||
@@ -488,14 +488,6 @@ void ThreatManager::ClearAllThreat()
|
||||
}
|
||||
}
|
||||
|
||||
void ThreatManager::NotifyDisengaged()
|
||||
{
|
||||
// note: i don't really like having this here
|
||||
// (maybe engage flag should be in creature ai? it's inherently an AI property...)
|
||||
if (_owner->IsEngaged())
|
||||
_owner->AtDisengage();
|
||||
}
|
||||
|
||||
void ThreatManager::FixateTarget(Unit* target)
|
||||
{
|
||||
if (target)
|
||||
@@ -530,6 +522,7 @@ void ThreatManager::UpdateVictim()
|
||||
_needClientUpdate = false;
|
||||
}
|
||||
|
||||
ProcessAIUpdates();
|
||||
}
|
||||
|
||||
ThreatReference const* ThreatManager::ReselectVictim()
|
||||
@@ -538,7 +531,7 @@ ThreatReference const* ThreatManager::ReselectVictim()
|
||||
return nullptr;
|
||||
|
||||
for (auto const& pair : _myThreatListEntries)
|
||||
pair.second->UpdateOffline();
|
||||
pair.second->UpdateOffline(); // AI notifies are processed in ::UpdateVictim caller
|
||||
|
||||
// fixated target is always preferred
|
||||
if (_fixateRef && _fixateRef->IsAvailable())
|
||||
@@ -587,6 +580,16 @@ ThreatReference const* ThreatManager::ReselectVictim()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ThreatManager::ProcessAIUpdates()
|
||||
{
|
||||
CreatureAI* ai = ASSERT_NOTNULL(_owner->ToCreature())->AI();
|
||||
std::vector<ThreatReference const*> v(std::move(_needsAIUpdate)); // _needClientUpdate is now empty in case this triggers a recursive call
|
||||
if (!ai)
|
||||
return;
|
||||
for (ThreatReference const* ref : v)
|
||||
ai->JustStartedThreateningMe(ref->GetVictim());
|
||||
}
|
||||
|
||||
// returns true if a is LOWER on the threat list than b
|
||||
/*static*/ bool ThreatManager::CompareReferencesLT(ThreatReference const* a, ThreatReference const* b, float aWeight)
|
||||
{
|
||||
|
||||
@@ -103,7 +103,7 @@ class TC_GAME_API ThreatManager
|
||||
bool CanHaveThreatList() const { return _ownerCanHaveThreatList; }
|
||||
// returns the current victim - this can be nullptr if owner's threat list is empty, or has only offline targets
|
||||
Unit* GetCurrentVictim();
|
||||
Unit* GetCurrentVictim() const;
|
||||
Unit* GetLastVictim() const;
|
||||
// returns an arbitrary non-offline victim from owner's threat list if one exists, nullptr otherwise
|
||||
Unit* GetAnyTarget() const;
|
||||
|
||||
@@ -121,10 +121,10 @@ class TC_GAME_API ThreatManager
|
||||
Trinity::IteratorPair<ThreatListIterator> GetUnsortedThreatList() const { return { _myThreatListEntries.begin(), _myThreatListEntries.end() }; }
|
||||
// slightly slower than GetUnsorted, but, well...sorted - only use it if you need the sorted property, of course
|
||||
// this iterator pair will invalidate on any modification (even indirect) of the threat list; spell casts and similar can all induce this!
|
||||
// note: current tank is NOT guaranteed to be the first entry in this list - check GetCurrentVictim separately if you want that!
|
||||
// note: current tank is NOT guaranteed to be the first entry in this list - check GetLastVictim separately if you want that!
|
||||
Trinity::IteratorPair<threat_list_heap::ordered_iterator> GetSortedThreatList() const { return { _sortedThreatList.ordered_begin(), _sortedThreatList.ordered_end() }; }
|
||||
// slowest of the three threat list getters (by far), but lets you modify the threat references - this is also sorted
|
||||
std::vector<ThreatReference*> GetModifiableThreatList() const;
|
||||
std::vector<ThreatReference*> GetModifiableThreatList();
|
||||
|
||||
// does any unit have a threat list entry with victim == this.owner?
|
||||
bool IsThreateningAnyone(bool includeOffline = false) const;
|
||||
@@ -154,9 +154,6 @@ class TC_GAME_API ThreatManager
|
||||
void ClearThreat(ThreatReference* ref);
|
||||
// Removes all targets from the threat list (will cause evade in UpdateVictim if called)
|
||||
void ClearAllThreat();
|
||||
// THIS SHOULD ONLY BE CALLED FROM A CREATURE'S AI (typically in EnterEvadeMode)
|
||||
// notify the unit that the AI has disengaged
|
||||
void NotifyDisengaged();
|
||||
|
||||
// Fixate on the passed target; this target will always be selected until the fixate is cleared
|
||||
// (if the target is not in the threat list, does nothing)
|
||||
@@ -204,6 +201,12 @@ class TC_GAME_API ThreatManager
|
||||
threat_list_heap _sortedThreatList;
|
||||
std::unordered_map<ObjectGuid, ThreatReference*> _myThreatListEntries;
|
||||
|
||||
// AI notifies are delayed to ensure we are in a consistent state before we call out to arbitrary logic
|
||||
// threat references might register themselves here when ::UpdateOffline() is called - MAKE SURE THIS IS PROCESSED JUST BEFORE YOU EXIT THREATMANAGER LOGIC
|
||||
void ProcessAIUpdates();
|
||||
void RegisterForAIUpdate(ThreatReference const* ref) { _needsAIUpdate.push_back(ref); }
|
||||
std::vector<ThreatReference const*> _needsAIUpdate;
|
||||
|
||||
// picks a new victim - called from ::Update periodically
|
||||
void UpdateVictim();
|
||||
ThreatReference const* ReselectVictim();
|
||||
@@ -278,7 +281,7 @@ class TC_GAME_API ThreatReference
|
||||
_owner(reinterpret_cast<Creature*>(mgr->_owner)), _mgr(*mgr), _victim(victim),
|
||||
_baseAmount(0.0f), _tempModifier(0), _taunted(TAUNT_STATE_NONE)
|
||||
{
|
||||
_online = ShouldBeSuppressed() ? ONLINE_STATE_SUPPRESSED : ONLINE_STATE_ONLINE;
|
||||
_online = ONLINE_STATE_OFFLINE;
|
||||
}
|
||||
|
||||
void UnregisterAndFree();
|
||||
|
||||
@@ -3397,6 +3397,13 @@ bool Creature::CanGiveExperience() const
|
||||
&& !(GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL);
|
||||
}
|
||||
|
||||
bool Creature::IsEngaged() const
|
||||
{
|
||||
if (CreatureAI const* ai = AI())
|
||||
return ai->IsEngaged();
|
||||
return false;
|
||||
}
|
||||
|
||||
void Creature::AtEngage(Unit* target)
|
||||
{
|
||||
Unit::AtEngage(target);
|
||||
|
||||
@@ -367,6 +367,7 @@ class TC_GAME_API Creature : public Unit, public GridObject<Creature>, public Ma
|
||||
|
||||
bool CanGiveExperience() const;
|
||||
|
||||
bool IsEngaged() const override;
|
||||
void AtEngage(Unit* target) override;
|
||||
void AtDisengage() override;
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ Unit::Unit(bool isWorldObject) :
|
||||
m_removedAurasCount(0), m_interruptMask(SpellAuraInterruptFlags::None), m_interruptMask2(SpellAuraInterruptFlags2::None),
|
||||
m_unitMovedByMe(nullptr), m_playerMovingMe(nullptr), m_charmer(nullptr), m_charmed(nullptr),
|
||||
i_motionMaster(new MotionMaster(this)), m_regenTimer(0), m_vehicle(nullptr),
|
||||
m_vehicleKit(nullptr), m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_isEngaged(false), m_combatManager(this),
|
||||
m_vehicleKit(nullptr), m_unitTypeMask(UNIT_MASK_NONE), m_Diminishing(), m_combatManager(this),
|
||||
m_threatManager(this), m_aiLocked(false), _playHoverAnim(false), _aiAnimKitId(0), _movementAnimKitId(0), _meleeAnimKitId(0),
|
||||
_spellHistory(new SpellHistory(this))
|
||||
{
|
||||
|
||||
@@ -1099,10 +1099,10 @@ class TC_GAME_API Unit : public WorldObject
|
||||
|
||||
/// ====================== THREAT & COMBAT ====================
|
||||
bool CanHaveThreatList() const { return m_threatManager.CanHaveThreatList(); }
|
||||
// This value can be different from IsInCombat:
|
||||
// This value can be different from IsInCombat, for example:
|
||||
// - when a projectile spell is midair against a creature (combat on launch - threat+aggro on impact)
|
||||
// - when the creature has no targets left, but the AI has not yet ceased engaged logic
|
||||
bool IsEngaged() const { return m_isEngaged; }
|
||||
virtual bool IsEngaged() const { return IsInCombat(); }
|
||||
bool IsEngagedBy(Unit const* who) const { return CanHaveThreatList() ? IsThreatenedBy(who) : IsInCombatWith(who); }
|
||||
void EngageWithTarget(Unit* who); // Adds target to threat list if applicable, otherwise just sets combat state
|
||||
// Combat handling
|
||||
@@ -1938,11 +1938,12 @@ class TC_GAME_API Unit : public WorldObject
|
||||
virtual void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional<LiquidData> const& liquidData);
|
||||
virtual void SetInWater(bool inWater);
|
||||
|
||||
// notifiers
|
||||
virtual void AtEnterCombat();
|
||||
virtual void AtExitCombat();
|
||||
|
||||
virtual void AtEngage(Unit* /*target*/) { m_isEngaged = true; }
|
||||
virtual void AtDisengage() { m_isEngaged = false; }
|
||||
virtual void AtEngage(Unit* /*target*/) {}
|
||||
virtual void AtDisengage() {}
|
||||
|
||||
private:
|
||||
|
||||
@@ -1971,7 +1972,6 @@ class TC_GAME_API Unit : public WorldObject
|
||||
Diminishing m_Diminishing;
|
||||
|
||||
// Threat+combat management
|
||||
bool m_isEngaged;
|
||||
friend class CombatManager;
|
||||
CombatManager m_combatManager;
|
||||
friend class ThreatManager;
|
||||
|
||||
@@ -872,7 +872,7 @@ public:
|
||||
ThreatManager& mgr = target->GetThreatManager();
|
||||
if (!target->IsAlive())
|
||||
{
|
||||
handler->PSendSysMessage("%s (%s) is not alive.", target->GetName().c_str(), target->GetGUID().ToString().c_str());
|
||||
handler->PSendSysMessage("%s (%s) is not alive.%s", target->GetName().c_str(), target->GetGUID().ToString().c_str(), target->IsEngaged() ? " (It is, however, engaged. Huh?)" : "");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+2
-9
@@ -372,16 +372,9 @@ public:
|
||||
if (Creature* boss = instance->GetCreature(TombBossGUIDs[i]))
|
||||
{
|
||||
if (!boss->IsAlive())
|
||||
{//do not call EnterEvadeMode(), it will create infinit loops
|
||||
boss->Respawn();
|
||||
boss->RemoveAllAuras();
|
||||
boss->CombatStop(true);
|
||||
boss->GetThreatManager().NotifyDisengaged();
|
||||
boss->LoadCreaturesAddon();
|
||||
boss->GetMotionMaster()->MoveTargetedHome();
|
||||
boss->SetLootRecipient(nullptr);
|
||||
}
|
||||
boss->SetFaction(FACTION_FRIENDLY);
|
||||
else
|
||||
boss->SetFaction(FACTION_FRIENDLY);
|
||||
}
|
||||
}
|
||||
GhostKillCount = 0;
|
||||
|
||||
@@ -1257,7 +1257,6 @@ public:
|
||||
Julianne->GetMotionMaster()->Clear();
|
||||
Julianne->setDeathState(JUST_DIED);
|
||||
Julianne->CombatStop(true);
|
||||
Julianne->GetThreatManager().NotifyDisengaged();
|
||||
Julianne->SetDynamicFlags(UNIT_DYNFLAG_LOOTABLE);
|
||||
}
|
||||
return;
|
||||
@@ -1527,7 +1526,6 @@ void boss_julianne::boss_julianneAI::DamageTaken(Unit* /*done_by*/, uint32 &dama
|
||||
Romulo->GetMotionMaster()->Clear();
|
||||
Romulo->setDeathState(JUST_DIED);
|
||||
Romulo->CombatStop(true);
|
||||
Romulo->GetThreatManager().NotifyDisengaged();
|
||||
Romulo->SetDynamicFlags(UNIT_DYNFLAG_LOOTABLE);
|
||||
}
|
||||
|
||||
|
||||
@@ -1388,9 +1388,10 @@ public:
|
||||
me->RemoveAurasDueToSpell(SPELL_THE_MIGHT_OF_MOGRAINE);
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
me->InterruptNonMeleeSpells(false);
|
||||
me->SetWalk(false);
|
||||
|
||||
EngagementOver();
|
||||
|
||||
for (uint8 i = 0; i < ENCOUNTER_DEFENDER_NUMBER; ++i)
|
||||
DespawnNPC(uiDefenderGUID[i]);
|
||||
@@ -1407,9 +1408,9 @@ public:
|
||||
|
||||
if (Creature* temp = ObjectAccessor::GetCreature(*me, uiKorfaxGUID))
|
||||
{
|
||||
temp->AI()->EnterEvadeMode();
|
||||
temp->RemoveAllAuras();
|
||||
temp->CombatStop(true);
|
||||
temp->GetThreatManager().NotifyDisengaged();
|
||||
temp->AttackStop();
|
||||
temp->SetFaction(me->GetFaction());
|
||||
temp->SetWalk(false);
|
||||
@@ -1428,9 +1429,9 @@ public:
|
||||
|
||||
if (Creature* temp = ObjectAccessor::GetCreature(*me, uiEligorGUID))
|
||||
{
|
||||
temp->AI()->EnterEvadeMode();
|
||||
temp->RemoveAllAuras();
|
||||
temp->CombatStop(true);
|
||||
temp->GetThreatManager().NotifyDisengaged();
|
||||
temp->AttackStop();
|
||||
temp->SetFaction(me->GetFaction());
|
||||
temp->SetWalk(false);
|
||||
@@ -1440,9 +1441,9 @@ public:
|
||||
|
||||
if (Creature* temp = ObjectAccessor::GetCreature(*me, uiKoltiraGUID))
|
||||
{
|
||||
temp->AI()->EnterEvadeMode();
|
||||
temp->RemoveAllAuras();
|
||||
temp->CombatStop(true);
|
||||
temp->GetThreatManager().NotifyDisengaged();
|
||||
temp->AttackStop();
|
||||
temp->SetFaction(me->GetFaction());
|
||||
temp->SetWalk(false);
|
||||
@@ -1455,9 +1456,9 @@ public:
|
||||
|
||||
if (Creature* temp = ObjectAccessor::GetCreature(*me, uiThassarianGUID))
|
||||
{
|
||||
temp->AI()->EnterEvadeMode();
|
||||
temp->RemoveAllAuras();
|
||||
temp->CombatStop(true);
|
||||
temp->GetThreatManager().NotifyDisengaged();
|
||||
temp->AttackStop();
|
||||
temp->SetFaction(me->GetFaction());
|
||||
temp->SetWalk(false);
|
||||
|
||||
@@ -423,9 +423,10 @@ void hyjalAI::EnterEvadeMode(EvadeReason /*why*/)
|
||||
if (me->GetEntry() != JAINA)
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
|
||||
EngagementOver();
|
||||
|
||||
me->LoadCreaturesAddon();
|
||||
|
||||
if (me->IsAlive())
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
|
||||
|
||||
@@ -86,9 +86,11 @@ public:
|
||||
|
||||
me->UpdateEntry(NPC_TAMED_KODO);
|
||||
me->CombatStop();
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
me->SetFaction(FACTION_FRIENDLY);
|
||||
me->SetSpeedRate(MOVE_RUN, 0.6f);
|
||||
|
||||
EngagementOver();
|
||||
|
||||
me->GetMotionMaster()->MoveFollow(caster, PET_FOLLOW_DIST, me->GetFollowAngle());
|
||||
me->setActive(true);
|
||||
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
|
||||
|
||||
@@ -215,11 +215,11 @@ public:
|
||||
{
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
|
||||
me->StopMoving();
|
||||
|
||||
EngagementOver();
|
||||
|
||||
me->GetMotionMaster()->MoveIdle();
|
||||
|
||||
me->SetFaction(FACTION_FRIENDLY_F);
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_SALUTE);
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ class npc_sc_millhouse_manastorm : public CreatureScript
|
||||
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
|
||||
switch (pointId)
|
||||
{
|
||||
|
||||
@@ -580,7 +580,7 @@ struct gunship_npc_AI : public ScriptedAI
|
||||
return;
|
||||
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
}
|
||||
|
||||
@@ -725,7 +725,6 @@ class npc_gunship : public CreatureScript
|
||||
Creature* stalker = *itr;
|
||||
stalker->RemoveAllAuras();
|
||||
stalker->CombatStop(true);
|
||||
stalker->GetThreatManager().NotifyDisengaged();
|
||||
}
|
||||
|
||||
uint32 explosionSpell = isVictory ? SPELL_EXPLOSION_VICTORY : SPELL_EXPLOSION_WIPE;
|
||||
@@ -878,7 +877,7 @@ class npc_high_overlord_saurfang_igb : public CreatureScript
|
||||
return;
|
||||
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
|
||||
Reset();
|
||||
@@ -1142,7 +1141,7 @@ class npc_muradin_bronzebeard_igb : public CreatureScript
|
||||
return;
|
||||
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
me->GetMotionMaster()->MoveTargetedHome();
|
||||
|
||||
Reset();
|
||||
|
||||
@@ -1778,7 +1778,7 @@ class npc_terenas_menethil : public CreatureScript
|
||||
return;
|
||||
|
||||
me->CombatStop(false);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
|
||||
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
ThreatReference* secondThreat = nullptr;
|
||||
ThreatReference* thirdThreat = nullptr;
|
||||
|
||||
ThreatManager const& mgr = me->GetThreatManager();
|
||||
ThreatManager& mgr = me->GetThreatManager();
|
||||
Unit* currentVictim = mgr.GetCurrentVictim();
|
||||
auto list = mgr.GetModifiableThreatList();
|
||||
auto it = list.begin(), end = list.end();
|
||||
|
||||
@@ -293,7 +293,7 @@ class boss_urom : public CreatureScript
|
||||
{
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop(false);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
}
|
||||
|
||||
void SpellHit(Unit* /*caster*/, SpellInfo const* spellInfo) override
|
||||
|
||||
@@ -634,7 +634,7 @@ class boss_freya : public CreatureScript
|
||||
Elder->RemoveAllAuras();
|
||||
Elder->AttackStop();
|
||||
Elder->CombatStop(true);
|
||||
Elder->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
Elder->AI()->DoAction(ACTION_ELDER_FREYA_KILLED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -751,7 +751,6 @@ public:
|
||||
Creature* owner = GetOwner()->ToCreature();
|
||||
owner->RemoveAllAurasExceptType(SPELL_AURA_DUMMY);
|
||||
owner->CombatStop(true);
|
||||
owner->GetThreatManager().NotifyDisengaged();
|
||||
owner->GetMotionMaster()->Clear();
|
||||
owner->GetMotionMaster()->MoveFollow(GetCaster(), 4.0f, 0.0f);
|
||||
owner->CastSpell(owner, SPELL_SUBDUED, true);
|
||||
|
||||
+1
-1
@@ -524,7 +524,7 @@ public:
|
||||
{
|
||||
ThreatManager const& mgr = me->GetThreatManager();
|
||||
std::list<Unit*> TargetList;
|
||||
Unit* currentVictim = mgr.GetCurrentVictim();
|
||||
Unit* currentVictim = mgr.GetLastVictim();
|
||||
for (ThreatReference const* ref : mgr.GetSortedThreatList())
|
||||
{
|
||||
if (Player* tempTarget = ref->GetVictim()->ToPlayer())
|
||||
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
me->AddNpcFlag(UNIT_NPC_FLAG_QUESTGIVER);
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
Talk(SAY_FREE);
|
||||
return;
|
||||
}
|
||||
@@ -973,7 +973,7 @@ public:
|
||||
me->RestoreFaction();
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
me->AddNpcFlag(UNIT_NPC_FLAG_QUESTGIVER);
|
||||
me->SetImmuneToPC(true);
|
||||
Talk(SAY_DEFEATED);
|
||||
|
||||
@@ -91,7 +91,7 @@ public:
|
||||
me->SetStandState(UNIT_STAND_STATE_SIT);
|
||||
me->RemoveAllAuras();
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
UnkorUnfriendly_Timer = 60000;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class npc_pet_pri_lightwell : public CreatureScript
|
||||
return;
|
||||
|
||||
me->CombatStop(true);
|
||||
me->GetThreatManager().NotifyDisengaged();
|
||||
EngagementOver();
|
||||
me->ResetPlayerDamageReq();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user