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;
306 return (itr++)->second;
327 std::vector<ThreatReference*> list;
339 if (pair.second->IsAvailable())
349 return (includeOffline || it->second->IsAvailable());
357 bool const shouldBeSuppressed = pair.second->ShouldBeSuppressed();
358 if (pair.second->IsOnline() && shouldBeSuppressed)
361 pair.second->HeapNotifyDecreased();
363 else if (canExpire && pair.second->IsSuppressed() && !shouldBeSuppressed)
366 pair.second->HeapNotifyIncreased();
397 if (!ignoreModifiers)
401 if (!ignoreRedirects && amount > 0.0f)
404 if (!redirInfo.empty())
406 float const origAmount = amount;
408 for (
size_t i = 0; i < redirInfo.size(); ++i)
410 auto const pair = redirInfo[i];
411 Unit* redirTarget =
nullptr;
414 redirTarget = it->second->_victim;
420 float amountRedirected =
CalculatePct(origAmount, pair.second);
421 AddThreat(redirTarget, amountRedirected, spell,
true,
true);
422 amount -= amountRedirected;
470 it->second->ScaleThreat(std::max<float>(factor,0.0f));
498 std::unordered_map<ObjectGuid, uint32> tauntStates;
500 for (
AuraEffect const* tauntEffect : tauntEffects)
501 tauntStates[tauntEffect->GetCasterGUID()] = ++tauntPriority;
505 auto it = tauntStates.find(pair.first);
506 if (it != tauntStates.end())
509 pair.second->UpdateTauntState();
519 pair.second->ScaleThreat(0.0f);
598 if (oldVictimRef && oldVictimRef->
IsOffline())
599 oldVictimRef =
nullptr;
606 if (!oldVictimRef || highest == oldVictimRef)
624 if (next == oldVictimRef)
636 ABORT_MSG(
"Current victim not found in sorted threat list even though it has a reference - manager desync!");
672 if (threatEntry->pctMod != 1.0f)
673 threat *= threatEntry->pctMod;
710 threat *= it->second;
729 std::vector<Creature*> canBeThreatened, cannotBeThreatened;
734 canBeThreatened.push_back(owner);
736 cannotBeThreatened.push_back(owner);
739 if (!canBeThreatened.empty())
741 float const perTarget = baseAmount / canBeThreatened.size();
742 for (
Creature* threatened : canBeThreatened)
746 for (
Creature* threatened : cannotBeThreatened)
747 threatened->GetThreatManager().AddThreat(assistant, 0.0f, spell,
true);
752 std::vector<ThreatReference*> threatReferencesToRemove;
755 if (!unitFilter || unitFilter(ref->GetOwner()))
756 threatReferencesToRemove.push_back(ref);
759 ref->_mgr.ClearThreat(
_owner);
766 mod += eff->GetAmount();
772 bool const isIncrease = (it->second->_tempModifier < mod);
775 it->second->_tempModifier = mod;
777 it->second->HeapNotifyIncreased();
779 it->second->HeapNotifyDecreased();
810 auto& victimMap = it->second;
811 auto it2 = victimMap.find(victim);
812 if (it2 == victimMap.end())
814 victimMap.erase(it2);
844 auto fillSharedPacketDataAndSend = [&](
auto& packet)
850 if (!ref->IsAvailable())
854 threatInfo.
UnitGUID = ref->GetVictim()->GetGUID();
856 packet.ThreatList.push_back(threatInfo);
865 fillSharedPacketDataAndSend(highestThreatUpdate);
870 fillSharedPacketDataAndSend(threatUpdate);
901 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());
917 for (
auto const& victimPair : pair.second)
919 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
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)