30#include <boost/heap/fibonacci_heap.hpp>
34class ThreatManager::Heap :
public boost::heap::fibonacci_heap<ThreatReference const*, boost::heap::compare<CompareThreatLessThan>>
186 if (tWho->GetSummonerGUID().IsPlayer())
196ThreatManager::ThreatManager(
Unit* owner) : _owner(owner), _ownerCanHaveThreatList(false), _needClientUpdate(false), _needThreatClearUpdate(false), _updateTimer(THREAT_UPDATE_INTERVAL),
197 _sortedThreatList(
std::make_unique<
Heap>()), _currentVictimRef(nullptr), _fixateRef(nullptr)
260 if (!ref->IsOffline())
270 if (ref->IsAvailable())
280 return (includeOffline || it->second->IsAvailable());
289 return (includeOffline || it->second->IsAvailable()) ? it->second->GetThreat() : 0.0f;
303 if (ref->IsAvailable() && ref->GetVictim()->GetTypeId() ==
TYPEID_PLAYER)
317 return (itr++)->second;
338 std::vector<ThreatReference*> list;
350 if (pair.second->IsAvailable())
360 return (includeOffline || it->second->IsAvailable());
368 bool const shouldBeSuppressed = pair.second->ShouldBeSuppressed();
369 if (pair.second->IsOnline() && shouldBeSuppressed)
372 pair.second->HeapNotifyDecreased();
374 else if (canExpire && pair.second->IsSuppressed() && !shouldBeSuppressed)
377 pair.second->HeapNotifyIncreased();
408 if (!ignoreModifiers)
412 if (!ignoreRedirects && amount > 0.0f)
415 if (!redirInfo.empty())
417 float const origAmount = amount;
419 for (
size_t i = 0; i < redirInfo.size(); ++i)
421 auto const pair = redirInfo[i];
422 Unit* redirTarget =
nullptr;
425 redirTarget = it->second->_victim;
431 float amountRedirected =
CalculatePct(origAmount, pair.second);
432 AddThreat(redirTarget, amountRedirected, spell,
true,
true);
433 amount -= amountRedirected;
481 it->second->ScaleThreat(std::max<float>(factor,0.0f));
509 std::unordered_map<ObjectGuid, uint32> tauntStates;
511 for (
AuraEffect const* tauntEffect : tauntEffects)
512 tauntStates[tauntEffect->GetCasterGUID()] = ++tauntPriority;
516 auto it = tauntStates.find(pair.first);
517 if (it != tauntStates.end())
520 pair.second->UpdateTauntState();
530 pair.second->ScaleThreat(0.0f);
609 if (oldVictimRef && oldVictimRef->
IsOffline())
610 oldVictimRef =
nullptr;
617 if (!oldVictimRef || highest == oldVictimRef)
635 if (next == oldVictimRef)
647 ABORT_MSG(
"Current victim not found in sorted threat list even though it has a reference - manager desync!");
683 if (threatEntry->pctMod != 1.0f)
684 threat *= threatEntry->pctMod;
721 threat *= it->second;
740 std::vector<Creature*> canBeThreatened, cannotBeThreatened;
745 canBeThreatened.push_back(owner);
747 cannotBeThreatened.push_back(owner);
750 if (!canBeThreatened.empty())
752 float const perTarget = baseAmount / canBeThreatened.size();
753 for (
Creature* threatened : canBeThreatened)
757 for (
Creature* threatened : cannotBeThreatened)
758 threatened->GetThreatManager().AddThreat(assistant, 0.0f, spell,
true);
763 std::vector<ThreatReference*> threatReferencesToRemove;
766 if (!unitFilter || unitFilter(ref->GetOwner()))
767 threatReferencesToRemove.push_back(ref);
770 ref->_mgr.ClearThreat(
_owner);
777 mod += eff->GetAmount();
783 bool const isIncrease = (it->second->_tempModifier < mod);
786 it->second->_tempModifier = mod;
788 it->second->HeapNotifyIncreased();
790 it->second->HeapNotifyDecreased();
821 auto& victimMap = it->second;
822 auto it2 = victimMap.find(victim);
823 if (it2 == victimMap.end())
825 victimMap.erase(it2);
855 auto fillSharedPacketDataAndSend = [&](
auto& packet)
861 if (!ref->IsAvailable())
865 threatInfo.
UnitGUID = ref->GetVictim()->GetGUID();
867 packet.ThreatList.push_back(threatInfo);
876 fillSharedPacketDataAndSend(highestThreatUpdate);
881 fillSharedPacketDataAndSend(threatUpdate);
912 ASSERT(!inMap,
"Duplicate threatened-by-me reference at %p being inserted on %s for %s - memory leak!", ref,
_owner->
GetGUID().
ToString().c_str(), guid.
ToString().c_str());
928 for (
auto const& victimPair : pair.second)
930 float thisPct = std::min(100.0f - totalPct, victimPair.second);
#define ASSERT_NOTNULL(pointer)
@ SPELL_SCHOOL_MASK_NORMAL
@ SPELL_SCHOOL_MASK_SHADOW
@ SPELL_SCHOOL_MASK_ARCANE
@ SPELL_SCHOOL_MASK_NATURE
@ SPELL_SCHOOL_MASK_FROST
@ SPELL_ATTR2_NO_INITIAL_THREAT
@ SPELL_ATTR4_NO_HELPFUL_THREAT
@ SPELL_AURA_MOD_TOTAL_THREAT
double SpellEffectValue
This is a double instead of float to be able to store full range of int32.
@ UNIT_FLAG_IMMUNE_TO_NPC
@ UNIT_FLAG_PLAYER_CONTROLLED
T CalculatePct(T base, U pct)
ObjectGuid const & GetGUID() const
bool SetInCombatWith(Unit *who, bool addSecondUnitSuppressed=false)
bool IsInCombatWith(ObjectGuid const &who) const
virtual void JustStartedThreateningMe(Unit *who)
bool _IsTargetAcceptable(Unit const *target) const
SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType=BASE_ATTACK) const override
bool CanCreatureAttack(Unit const *victim, bool force=true) const
std::string ToString() const
SpellSchoolMask GetSchoolMask() const
bool HasAttribute(SpellAttr0 attribute) const
std::unordered_map< ObjectGuid, ThreatReference * > _threatenedByMe
bool CanHaveThreatList() const
ThreatManager(Unit *owner)
static float CalculateModifiedThreat(float threat, Unit const *victim, SpellInfo const *spell)
void SendClearAllThreatToClients() const
void RegisterRedirectThreat(uint32 spellId, ObjectGuid const &victim, float pct)
== REDIRECT SYSTEM ==
void EvaluateSuppressed(bool canExpire=false)
void UnregisterRedirectThreat(uint32 spellId)
void ForwardThreatForAssistingMe(Unit *assistant, float baseAmount, SpellInfo const *spell=nullptr, bool ignoreModifiers=false)
== AFFECT OTHERS' THREAT LISTS ==
bool IsThreatenedBy(ObjectGuid const &who, bool includeOffline=false) const
void PutThreatListRef(ObjectGuid const &guid, ThreatReference *ref)
== MY THREAT LIST ==
bool IsThreateningTo(ObjectGuid const &who, bool includeOffline=false) const
void RemoveMeFromThreatLists(bool(*unitFilter)(Unit const *otherUnit))
Unit * GetCurrentVictim()
static const uint32 THREAT_UPDATE_INTERVAL
void PutThreatenedByMeRef(ObjectGuid const &guid, ThreatReference *ref)
== OTHERS' THREAT LISTS ==
void RegisterForAIUpdate(ObjectGuid const &guid)
void SendThreatListToClients(bool newHighest) const
void UpdateRedirectInfo()
std::array< float, MAX_SPELL_SCHOOL > _singleSchoolModifiers
void UpdateMySpellSchoolModifiers()
static bool CompareReferencesLT(ThreatReference const *a, ThreatReference const *b, float aWeight)
Trinity::IteratorPair< ThreatListIterator, std::nullptr_t > GetUnsortedThreatList() const
static const CompareThreatLessThan CompareThreat
std::unique_ptr< Heap > _sortedThreatList
void ScaleThreat(Unit *target, float factor)
void ClearThreat(Unit *target)
ThreatReference const * _currentVictimRef
Unit * GetAnyTarget() const
Unit * GetLastVictim() const
std::unordered_map< ObjectGuid, ThreatReference * > _myThreatListEntries
bool _ownerCanHaveThreatList
void FixateTarget(Unit *target)
bool IsThreatListEmpty(bool includeOffline=false) const
std::vector< ObjectGuid > _needsAIUpdate
void Update(uint32 tdiff)
std::unordered_map< uint32, std::unordered_map< ObjectGuid, float > > _redirectRegistry
void PurgeThreatListRef(ObjectGuid const &guid)
void AddThreat(Unit *target, float amount, SpellInfo const *spell=nullptr, bool ignoreModifiers=false, bool ignoreRedirects=false)
== AFFECT MY THREAT LIST ==
bool IsThreateningAnyone(bool includeOffline=false) const
ThreatReference const * _fixateRef
ThreatReference const * ReselectVictim()
void SendRemoveToClients(Unit const *victim) const
uint32 GetThreatListPlayerCount(bool includeOffline=false) const
Trinity::IteratorPair< ThreatListIterator, std::nullptr_t > GetSortedThreatList() const
std::vector< ThreatReference * > GetModifiableThreatList()
std::unordered_map< std::underlying_type< SpellSchoolMask >::type, float > _multiSchoolModifiers
Unit * GetFixateTarget() const
friend class ThreatReferenceImpl
void UpdateMyTempModifiers()
void PurgeThreatenedByMeRef(ObjectGuid const &guid)
float GetThreat(Unit const *who, bool includeOffline=false) const
void MatchUnitThreatToHighestThreat(Unit *target)
std::vector< std::pair< ObjectGuid, float > > _redirectInfo
bool _needThreatClearUpdate
size_t GetThreatListSize() const
ThreatManager::Heap::handle_type _handle
ThreatReferenceImpl(ThreatManager *mgr, Unit *victim)
static bool FlagsAllowFighting(Unit const *a, Unit const *b)
void HeapNotifyDecreased()
void ScaleThreat(float factor)
void HeapNotifyIncreased()
@ ONLINE_STATE_SUPPRESSED
bool ShouldBeSuppressed() const
OnlineState GetOnlineState() const
bool ShouldBeOffline() const
void UpdateTauntState(TauntState state=TAUNT_STATE_NONE)
void AddThreat(float amount)
Utility class to enable range for loop syntax for multimap.equal_range uses.
constexpr iterator begin() const
bool IsWithinMeleeRange(Unit const *obj) const
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
ThreatManager & GetThreatManager()
std::forward_list< AuraEffect * > AuraEffectList
bool HasUnitFlag(UnitFlags flags) const
TempSummon * ToTempSummon()
bool HasAuraType(AuraType auraType) const
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
float GetTotalAuraMultiplierByMiscMask(AuraType auraType, uint32 misc_mask) const
bool HasUnitState(const uint32 f) const
uint32 HasUnitTypeMask(uint32 mask) const
bool HasBreakableByDamageAuraType(AuraType type, uint32 excludeAura=0) const
CombatManager & GetCombatManager()
virtual bool IsEngaged() const
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
bool CanSeeOrDetect(WorldObject const *obj, CanSeeOrDetectExtraArgs const &args={ }) const
Player * GetSpellModOwner() const
ObjectGuid HighestThreatGUID
WorldPacket const * Write() override
WorldPacket const * Write() override
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
auto MapGetValuePtr(M &map, typename M::key_type const &key)