36#include <boost/heap/fibonacci_heap.hpp>
40class ThreatManager::Heap :
public boost::heap::fibonacci_heap<ThreatReference const*, boost::heap::compare<CompareThreatLessThan>>
195 if (tWho->GetSummonerGUID().IsPlayer())
202 _sortedThreatList(
std::make_unique<
Heap>()), _currentVictimRef(nullptr), _fixateRef(nullptr)
251 if (!ref->IsOffline())
261 if (ref->IsAvailable())
271 return (includeOffline || it->second->IsAvailable());
280 return (includeOffline || it->second->IsAvailable()) ? it->second->GetThreat() : 0.0f;
294 if (ref->IsAvailable() && ref->GetVictim()->GetTypeId() ==
TYPEID_PLAYER)
308 return (itr++)->second;
329 std::vector<ThreatReference*> list;
341 if (pair.second->IsAvailable())
351 return (includeOffline || it->second->IsAvailable());
359 bool const shouldBeSuppressed = pair.second->ShouldBeSuppressed();
360 if (pair.second->IsOnline() && shouldBeSuppressed)
363 pair.second->HeapNotifyDecreased();
365 else if (canExpire && pair.second->IsSuppressed() && !shouldBeSuppressed)
368 pair.second->HeapNotifyIncreased();
387 AddThreat(vehicle, amount, spell, ignoreModifiers, ignoreRedirects);
398 AddThreat(privateObjectOwner, amount, spell, ignoreModifiers, ignoreRedirects);
418 if (!ignoreModifiers)
422 if (!ignoreRedirects && amount > 0.0f)
425 if (!redirInfo.empty())
427 float const origAmount = amount;
429 for (
size_t i = 0; i < redirInfo.size(); ++i)
431 auto const pair = redirInfo[i];
432 Unit* redirTarget =
nullptr;
435 redirTarget = it->second->_victim;
441 float amountRedirected =
CalculatePct(origAmount, pair.second);
442 AddThreat(redirTarget, amountRedirected, spell,
true,
true);
443 amount -= amountRedirected;
491 it->second->ScaleThreat(std::max<float>(factor,0.0f));
519 std::unordered_map<ObjectGuid, ThreatReference::TauntState> tauntStates;
521 for (
auto it = tauntEffects.begin(), end = tauntEffects.end(); it != end; ++it)
526 auto it = tauntStates.find(pair.first);
527 if (it != tauntStates.end())
528 pair.second->UpdateTauntState(it->second);
530 pair.second->UpdateTauntState();
540 pair.second->ScaleThreat(0.0f);
619 if (oldVictimRef && oldVictimRef->
IsOffline())
620 oldVictimRef =
nullptr;
627 if (!oldVictimRef || highest == oldVictimRef)
645 if (next == oldVictimRef)
657 ABORT_MSG(
"Current victim not found in sorted threat list even though it has a reference - manager desync!");
688 if (threatEntry->pctMod != 1.0f)
689 threat *= threatEntry->pctMod;
726 threat *= it->second;
745 std::vector<Creature*> canBeThreatened, cannotBeThreatened;
750 canBeThreatened.push_back(owner);
752 cannotBeThreatened.push_back(owner);
755 if (!canBeThreatened.empty())
757 float const perTarget = baseAmount / canBeThreatened.size();
758 for (
Creature* threatened : canBeThreatened)
762 for (
Creature* threatened : cannotBeThreatened)
763 threatened->GetThreatManager().AddThreat(assistant, 0.0f, spell,
true);
771 ref->_mgr.ClearThreat(
_owner);
779 mod += eff->GetAmount();
785 bool const isIncrease = (it->second->_tempModifier < mod);
788 it->second->_tempModifier = mod;
790 it->second->HeapNotifyIncreased();
792 it->second->HeapNotifyDecreased();
823 auto& victimMap = it->second;
824 auto it2 = victimMap.find(victim);
825 if (it2 == victimMap.end())
827 victimMap.erase(it2);
848 auto fillSharedPacketDataAndSend = [&](
auto& packet)
854 if (!ref->IsAvailable())
858 threatInfo.
UnitGUID = ref->GetVictim()->GetGUID();
860 packet.ThreatList.push_back(threatInfo);
869 fillSharedPacketDataAndSend(highestThreatUpdate);
874 fillSharedPacketDataAndSend(threatUpdate);
905 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());
921 for (
auto const& victimPair : pair.second)
923 uint32 thisPct = std::min<uint32>(100 - 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_ATTR3_NO_INITIAL_AGGRO
@ SPELL_AURA_MOD_TOTAL_THREAT
ThreatListClientUpdateFlags
@ UNIT_FLAG_IMMUNE_TO_NPC
@ UNIT_FLAG_PLAYER_CONTROLLED
T CalculatePct(T base, U pct)
bool SetInCombatWith(Unit *who, bool addSecondUnitSuppressed=false)
bool IsInCombatWith(ObjectGuid const &who) const
virtual void JustStartedThreateningMe(Unit *who)
bool _IsTargetAcceptable(Unit const *target) const
bool CanCreatureAttack(Unit const *victim, bool force=true) const
SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType=BASE_ATTACK, uint8=0) const override
constexpr bool HasFlag(T flag) const
std::string ToString() const
static Creature * ToCreature(Object *o)
PackedGuid const & GetPackGUID() const
static ObjectGuid GetGUID(Object const *o)
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
EnumFlag< ThreatListClientUpdateFlags > _updateFlags
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 ==
std::vector< std::pair< ObjectGuid, uint32 > > _redirectInfo
bool IsThreatenedBy(ObjectGuid const &who, bool includeOffline=false) const
void RemoveMeFromThreatLists()
void PutThreatListRef(ObjectGuid const &guid, ThreatReference *ref)
== MY THREAT LIST ==
bool IsThreateningTo(ObjectGuid const &who, bool includeOffline=false) const
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
std::unordered_map< uint32, std::unordered_map< ObjectGuid, uint32 > > _redirectRegistry
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)
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()
void RegisterRedirectThreat(uint32 spellId, ObjectGuid const &victim, uint32 pct)
== REDIRECT SYSTEM ==
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)
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()
Unit * GetVehicleBase() const
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
ObjectGuid GetPrivateObjectOwner() const
bool IsPrivateObject() const
bool CanSeeOrDetect(WorldObject const *obj, bool implicitDetect=false, bool distanceCheck=false, bool checkAlert=false) const
Player * GetSpellModOwner() const
ObjectGuid HighestThreatGUID
WorldPacket const * Write() override
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
auto MapGetValuePtr(M &map, typename M::key_type const &key)