aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Combat/ThreatManager.h
diff options
context:
space:
mode:
authorTreeston <treeston.mmoc@gmail.com>2018-01-03 20:04:19 +0100
committerShauren <shauren.trinity@gmail.com>2021-05-16 21:56:01 +0200
commit34c7810fe507eca1b8b9389630db5d5d26d92e77 (patch)
treee05653a0adaf4c4f5c406649f1bfe6573cbb22ff /src/server/game/Combat/ThreatManager.h
parent5158136ee8a77046e37bafa192481b8b61d4a116 (diff)
Core: Combat/threat system rewrite (PR #19930)
- PvE combat is now always mutual. UNIT_FLAG_IN_COMBAT is backed by actual references to the units we're in combat with. - PvP combat is now also tracked, and almost always mutual; spells like Vanish and Feign Death can break this rule. That means we can easily determine a list of players we're fighting. - By extension, IsInCombatWith now has sensible behavior when invoked on nonplayers. - Threat and combat systems are no longer the same. - They still have an enforced relationship (threat implies combat - clearing combat clears threat)... - ...but we can have combat without threat. A creature (with threat list) isn't considered to be engaged until it has an entry on its threat list... - ...which means we can now faithfully replicate retail engage behavior. Combat on projectile launch - engagement start on projectile impact. Yay for progress! - AI method refactor, as already ported in 6113b9d - `JustEngagedWith`, `JustEnteredCombat` and `JustExitedCombat`. - Vehicle threat is now properly pooled on the main vehicle body (fixes #16542). - Various edge case bug fixes for threat redirects (Misdirection "cancelling" Vigilance and similar). - Target re-selection is now significantly faster. - Fixed a ton of other smaller edge case bugs, probably. Closes #7951 and #19998. (cherry picked from commit 532ab1c7f8653d1a2e48aa1f1f8a9ba1041d4bb7)
Diffstat (limited to 'src/server/game/Combat/ThreatManager.h')
-rw-r--r--src/server/game/Combat/ThreatManager.h517
1 files changed, 229 insertions, 288 deletions
diff --git a/src/server/game/Combat/ThreatManager.h b/src/server/game/Combat/ThreatManager.h
index 7066794e5b7..486db4d7e13 100644
--- a/src/server/game/Combat/ThreatManager.h
+++ b/src/server/game/Combat/ThreatManager.h
@@ -15,320 +15,261 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _THREATMANAGER
-#define _THREATMANAGER
+ #ifndef TRINITY_THREATMANAGER_H
+ #define TRINITY_THREATMANAGER_H
#include "Common.h"
-#include "SharedDefines.h"
-#include "LinkedReference/Reference.h"
-#include "UnitEvents.h"
-#include "ObjectGuid.h"
#include "IteratorPair.h"
-
-#include <list>
-
-//==============================================================
+#include "ObjectGuid.h"
+#include "SharedDefines.h"
+#include <boost/heap/fibonacci_heap.hpp>
+#include <unordered_map>
+#include <vector>
class Unit;
-class Creature;
-class ThreatManager;
class SpellInfo;
-#define THREAT_UPDATE_INTERVAL 1 * IN_MILLISECONDS // Server should send threat update to client periodically each second
-
-//==============================================================
-// Class to calculate the real threat based
-
-struct TC_GAME_API ThreatCalcHelper
+/********************************************************************************************************************************************************\
+ * DEV DOCUMENTATION: THREAT SYSTEM *
+ * (future devs: please keep this up-to-date if you change the system) *
+ * The threat system works based on dynamically allocated threat list entries. *
+ * *
+ * Each such entry is a ThreatReference object, which is always stored in exactly three places: *
+ * - The threatened unit's (from now: reference "owner") sorted and unsorted threat lists *
+ * - The threatening unit's (from now: reference "victim") threatened-by-me list *
+ * A ThreatReference object carries the following implicit guarantees: *
+ * - Both owner and victim are valid units, which are currently in the world. Neither can be nullptr. *
+ * - There is an active combat reference between owner and victim. *
+ * *
+ * ThreatManager also keeps track of whether its owner is engaged (a boolean flag). *
+ * - If a (non-offline) threat list entry is added to a not-yet-engaged ThreatManager, it calls JustEngagedWith on its owner's AI. *
+ * - The engaged state is cleared in ClearAllThreat (which is invoked on evade). *
+ * - This flag can be accessed through the IsEngaged method. For creatures that can have a threat list, this is equal to Unit::IsEngaged. *
+ * *
+ * Note that (threat => combat) is a strong guarantee provided in conjunction with CombatManager. Thus: *
+ * - Adding threat will also create a combat reference between the units if one doesn't exist yet (even if the owner can't have a threat list!) *
+ * - Ending combat between two units will also delete any threat references that may exist between them. *
+ * *
+ * To manage a creature's threat list, ThreatManager maintains a heap of threat reference const pointers. *
+ * This heap is kept well-structured in all methods that modify ThreatReference, and is used to select the next target. *
+ * *
+ * Selection uses the following properties on ThreatReference, in order: *
+ * - Online state (one of ONLINE, SUPPRESSED, OFFLINE): *
+ * - ONLINE: Normal threat state, target is valid and attackable *
+ * - SUPPRESSED: Target is attackable, but fully immuned. This is used for targets under HoP, Divine Shield, Ice Block etc. *
+ * Targets with SUPPRESSED threat can still be valid targets, but any target with ONLINE threat will be preferred. *
+ * - OFFLINE: The target is, for whatever reason, not valid at this time (for example, IMMUNE_TO_X flags or game master state). *
+ * These targets can never be selected by SelectVictim, which will return nullptr if all targets are OFFLINE (typically causing evade). *
+ * - Related methods: GetOnlineState, IsOnline, IsAvailable, IsOffline *
+ * - Taunt state (one of TAUNT, NONE, DETAUNT), the names speak for themselves *
+ * - Related methods: GetTauntState, IsTaunting, IsDetaunted *
+ * - Actual threat value (GetThreat) *
+ * *
+ * The current (= last selected) victim can be accessed using GetCurrentVictim. SelectVictim selects a (potentially new) victim. *
+ * Beyond that, ThreatManager has a variety of helpers and notifiers, which are documented inline below. *
+ * *
+ * SPECIAL NOTE: Please be aware that any heap iterator may be invalidated if you modify a ThreatReference. The heap holds const pointers for a reason. *
+ * If you need to modify multiple ThreatReference objects, then use GetModifiableThreatList(), which is safe to modify! *
+\********************************************************************************************************************************************************/
+
+class ThreatReference;
+struct CompareThreatLessThan
{
- static float calcThreat(Unit* hatedUnit, Unit* hatingUnit, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* threatSpell = nullptr);
- static bool isValidProcess(Unit* hatedUnit, Unit* hatingUnit, SpellInfo const* threatSpell = nullptr);
+ CompareThreatLessThan() {}
+ bool operator()(ThreatReference const* a, ThreatReference const* b) const;
};
-//==============================================================
-class TC_GAME_API HostileReference : public Reference<Unit, ThreatManager>
+// Please check Game/Combat/ThreatManager.h for documentation on how this class works!
+class TC_GAME_API ThreatManager
{
public:
- HostileReference(Unit* refUnit, ThreatManager* threatManager, float threat);
-
- // -- compatibility layer for combat rewrite (PR #19930)
- Unit* GetOwner() const;
- Unit* GetVictim() const { return getTarget(); }
- void AddThreat(float amt) { addThreat(amt); }
- void SetThreat(float amt) { setThreat(amt); }
- void ModifyThreatByPercent(int32 pct) { addThreatPercent(pct); }
- void ScaleThreat(float factor) { setThreat(iThreat*factor); }
- bool IsOnline() const { return iOnline; }
- bool IsAvailable() const { return iOnline; }
- bool IsOffline() const { return !iOnline; }
- float GetThreat() const { return getThreat(); }
- void ClearThreat() { removeReference(); }
-
- //=================================================
- void addThreat(float modThreat);
-
- void setThreat(float threat) { addThreat(threat - iThreat); }
-
- void addThreatPercent(int32 percent);
-
- float getThreat() const { return iThreat + iTempThreatModifier; }
-
- bool isOnline() const { return iOnline; }
-
- // The Unit might be in water and the creature can not enter the water, but has range attack
- // in this case online = true, but accessible = false
- bool isAccessible() const { return iAccessible; }
-
- // used for temporary setting a threat and reducing it later again.
- // the threat modification is stored
- void setTempThreat(float threat)
- {
- addTempThreat(threat - iTempThreatModifier);
- }
-
- void addTempThreat(float threat)
- {
- if (!threat)
- return;
-
- iTempThreatModifier += threat;
-
- ThreatRefStatusChangeEvent event(UEV_THREAT_REF_THREAT_CHANGE, this, threat);
- fireStatusChanged(event);
- }
-
- void resetTempThreat()
- {
- addTempThreat(-iTempThreatModifier);
- }
-
- float getTempThreatModifier() { return iTempThreatModifier; }
-
- //=================================================
- // check, if source can reach target and set the status
- void updateOnlineStatus();
-
- void setOnlineOfflineState(bool isOnline);
-
- void setAccessibleState(bool isAccessible);
- //=================================================
-
- bool operator==(HostileReference const& hostileRef) const { return hostileRef.getUnitGuid() == getUnitGuid(); }
-
- //=================================================
-
- ObjectGuid getUnitGuid() const { return iUnitGuid; }
-
- //=================================================
- // reference is not needed anymore. realy delete it !
-
- void removeReference();
-
- //=================================================
-
- HostileReference* next() { return static_cast<HostileReference*>(Reference<Unit, ThreatManager>::next()); }
-
- //=================================================
-
- // Tell our refTo (target) object that we have a link
- void targetObjectBuildLink() override;
-
- // Tell our refTo (taget) object, that the link is cut
- void targetObjectDestroyLink() override;
-
- // Tell our refFrom (source) object, that the link is cut (Target destroyed)
- void sourceObjectDestroyLink() override;
-
- private:
- // Inform the source, that the status of that reference was changed
- void fireStatusChanged(ThreatRefStatusChangeEvent& threatRefStatusChangeEvent);
+ typedef boost::heap::fibonacci_heap<ThreatReference const*, boost::heap::compare<CompareThreatLessThan>> threat_list_heap;
+ static const uint32 CLIENT_THREAT_UPDATE_INTERVAL = 1000u;
+
+ static bool CanHaveThreatList(Unit const* who);
+
+ ThreatManager(Unit* owner);
+ // called from ::Create methods just after construction (once all fields on owner have been populated)
+ // should not be called from anywhere else
+ void Initialize();
+ // called from Creature::Update (only creatures can have their own threat list)
+ // should not be called from anywhere else
+ void Update(uint32 tdiff);
+
+ // never nullptr
+ Unit* GetOwner() const { return _owner; }
+ // can our owner have a threat list?
+ // identical to ThreatManager::CanHaveThreatList(GetOwner())
+ bool CanHaveThreatList() const { return _ownerCanHaveThreatList; }
+ // returns the victim selected by the last SelectVictim call - this can be nullptr
+ Unit* GetCurrentVictim() const;
+ // returns an arbitrary non-offline victim from owner's threat list if one exists, nullptr otherwise
+ Unit* GetAnyTarget() const;
+ // selects a (potentially new) victim from the threat list and returns it - this can be nullptr
+ Unit* SelectVictim();
+
+ bool IsEngaged() const { return _ownerEngaged; }
+ // are there any entries in owner's threat list?
+ bool IsThreatListEmpty(bool includeOffline = false) const;
+ // is there a threat list entry on owner's threat list with victim == who?
+ bool IsThreatenedBy(ObjectGuid const& who, bool includeOffline = false) const;
+ // is there a threat list entry on owner's threat list with victim == who?
+ bool IsThreatenedBy(Unit const* who, bool includeOffline = false) const;
+ // returns ThreatReference amount if a ref exists, 0.0f otherwise
+ float GetThreat(Unit const* who, bool includeOffline = false) const;
+ size_t GetThreatListSize() const { return _sortedThreatList.size(); }
+ // fastest of the three threat list getters - gets the threat list in "arbitrary" order
+ Trinity::IteratorPair<threat_list_heap::const_iterator> GetUnsortedThreatList() const { return { _sortedThreatList.begin(), _sortedThreatList.end() }; }
+ // slightly slower than GetUnsorted, but, well...sorted - only use it if you need the sorted property, of course
+ // note: current tank is NOT guaranteed to be the first entry in this list - check GetCurrentVictim 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
+ std::vector<ThreatReference*> GetModifiableThreatList() const;
+
+ // does any unit have a threat list entry with victim == this.owner?
+ bool IsThreateningAnyone(bool includeOffline = false) const;
+ // is there a threat list entry on who's threat list for this.owner?
+ bool IsThreateningTo(ObjectGuid const& who, bool includeOffline = false) const;
+ // is there a threat list entry on who's threat list for this.owner?
+ bool IsThreateningTo(Unit const* who, bool includeOffline = false) const;
+ auto const& GetThreatenedByMeList() const { return _threatenedByMe; }
+
+ // Notify the ThreatManager that a condition changed that may impact refs' online state so it can re-evaluate
+ void UpdateOnlineStates(bool meThreateningOthers = true, bool othersThreateningMe = true);
+ ///== AFFECT MY THREAT LIST ==
+ void AddThreat(Unit* target, float amount, SpellInfo const* spell = nullptr, bool ignoreModifiers = false, bool ignoreRedirects = false);
+ void ScaleThreat(Unit* target, float factor);
+ // Modify target's threat by +percent%
+ void ModifyThreatByPercent(Unit* target, int32 percent) { if (percent) ScaleThreat(target, 0.01f*float(100 + percent)); }
+ // Resets the specified unit's threat to zero
+ void ResetThreat(Unit* target) { ScaleThreat(target, 0.0f); }
+ // Sets the specified unit's threat to be equal to the highest entry on the threat list
+ void MatchUnitThreatToHighestThreat(Unit* target);
+ // Notify the ThreatManager that we have a new taunt aura (or a taunt aura expired)
+ void TauntUpdate();
+ // Sets all threat refs in owner's threat list to have zero threat
+ void ResetAllThreat();
+ // Removes specified target from the threat list
+ void ClearThreat(Unit* target);
+ // Removes all targets from the threat list (will cause evade in UpdateVictim if called)
+ void ClearAllThreat();
- Unit* GetSourceUnit();
+ // sends SMSG_THREAT_UPDATE to all nearby clients (used by client to forward threat list info to addons)
+ void SendThreatListToClients() const;
+
+ ///== AFFECT OTHERS' THREAT LISTS ==
+ // what it says on the tin - call AddThreat on everything that's threatened by us with the specified params
+ void ForwardThreatForAssistingMe(Unit* assistant, float baseAmount, SpellInfo const* spell = nullptr, bool ignoreModifiers = false);
+ // delete all ThreatReferences with victim == owner
+ void RemoveMeFromThreatLists();
+ // re-calculates the temporary threat modifier from auras on myself
+ void UpdateMyTempModifiers();
+ // re-calculate SPELL_AURA_MOD_THREAT modifiers
+ void UpdateMySpellSchoolModifiers();
+
+ ///== REDIRECT SYSTEM ==
+ // Register a redirection effect that redirects pct% of threat generated by owner to victim
+ void RegisterRedirectThreat(uint32 spellId, ObjectGuid const& victim, uint32 pct);
+ // Unregister a redirection effort for all victims
+ void UnregisterRedirectThreat(uint32 spellId);
+ // Unregister a redirection effect for a specific victim
+ void UnregisterRedirectThreat(uint32 spellId, ObjectGuid const& victim);
private:
- float iThreat;
- float iTempThreatModifier; // used for SPELL_AURA_MOD_TOTAL_THREAT
-
- ObjectGuid iUnitGuid;
- bool iOnline;
- bool iAccessible;
-};
-
-//==============================================================
-class ThreatManager;
-
-class TC_GAME_API ThreatContainer
-{
- friend class ThreatManager;
+ Unit* const _owner;
+ bool _ownerCanHaveThreatList;
+ bool _ownerEngaged;
+
+ static const CompareThreatLessThan CompareThreat;
+ static bool CompareReferencesLT(ThreatReference const* a, ThreatReference const* b, float aWeight);
+ static float CalculateModifiedThreat(float threat, Unit const* victim, SpellInfo const* spell);
+
+ // send opcodes (all for my own threat list)
+ void SendClearAllThreatToClients() const;
+ void SendRemoveToClients(Unit const* victim) const;
+ void SendNewVictimToClients(ThreatReference const* victimRef) const;
+
+ ///== MY THREAT LIST ==
+ void PutThreatListRef(ObjectGuid const& guid, ThreatReference* ref);
+ void PurgeThreatListRef(ObjectGuid const& guid, bool sendRemove);
+
+ uint32 _updateClientTimer;
+ threat_list_heap _sortedThreatList;
+ std::unordered_map<ObjectGuid, ThreatReference*> _myThreatListEntries;
+ ThreatReference const* _currentVictimRef;
+ ThreatReference const* ReselectVictim();
+
+ ///== OTHERS' THREAT LISTS ==
+ void PutThreatenedByMeRef(ObjectGuid const& guid, ThreatReference* ref);
+ void PurgeThreatenedByMeRef(ObjectGuid const& guid);
+ std::unordered_map<ObjectGuid, ThreatReference*> _threatenedByMe; // these refs are entries for myself on other units' threat lists
+ float _singleSchoolModifiers[MAX_SPELL_SCHOOL]; // most spells are single school - we pre-calculate these and store them
+ mutable std::unordered_map<std::underlying_type<SpellSchoolMask>::type, float> _multiSchoolModifiers; // these are calculated on demand
+
+ // redirect system (is kind of dumb, but that's because none of the redirection spells actually have any aura effect associated with them, so spellscript needs to deal with it)
+ void UpdateRedirectInfo();
+ std::vector<std::pair<ObjectGuid, uint32>> _redirectInfo; // current redirection targets and percentages (updated from registry in ThreatManager::UpdateRedirectInfo)
+ std::unordered_map<uint32, std::unordered_map<ObjectGuid, uint32>> _redirectRegistry; // spellid -> (victim -> pct); all redirection effects on us (removal individually managed by spell scripts because blizzard is dumb)
public:
- typedef std::list<HostileReference*> StorageType;
+ ThreatManager(ThreatManager const&) = delete;
+ ThreatManager& operator=(ThreatManager const&) = delete;
- ThreatContainer(): iDirty(false) { }
-
- ~ThreatContainer() { clearReferences(); }
-
- HostileReference* addThreat(Unit* victim, float threat);
-
- void ModifyThreatByPercent(Unit* victim, int32 percent);
-
- HostileReference* selectNextVictim(Creature* attacker, HostileReference* currentVictim) const;
-
- void setDirty(bool isDirty) { iDirty = isDirty; }
-
- bool isDirty() const { return iDirty; }
-
- bool empty() const
- {
- return iThreatList.empty();
- }
-
- HostileReference* getMostHated() const
- {
- return iThreatList.empty() ? nullptr : iThreatList.front();
- }
-
- HostileReference* getReferenceByTarget(Unit const* victim) const;
-
- StorageType const & getThreatList() const { return iThreatList; }
-
- private:
- void remove(HostileReference* hostileRef)
- {
- iThreatList.remove(hostileRef);
- }
-
- void addReference(HostileReference* hostileRef)
- {
- iThreatList.push_back(hostileRef);
- }
-
- void clearReferences();
-
- // Sort the list if necessary
- void update();
-
- StorageType iThreatList;
- bool iDirty;
+ friend class ThreatReference;
+ friend struct CompareThreatLessThan;
};
-//=================================================
-
-typedef HostileReference ThreatReference;
-class TC_GAME_API ThreatManager
+// Please check Game/Combat/ThreatManager.h for documentation on how this class works!
+class TC_GAME_API ThreatReference
{
public:
- // -- compatibility layer for combat rewrite (PR #19930)
- Trinity::IteratorPair<std::list<ThreatReference*>::const_iterator> GetSortedThreatList() const { auto& list = iThreatContainer.getThreatList(); return { list.cbegin(), list.cend() }; }
- Trinity::IteratorPair<std::list<ThreatReference*>::const_iterator> GetUnsortedThreatList() const { return GetSortedThreatList(); }
- std::list<ThreatReference*> GetModifiableThreatList() const { return iThreatContainer.getThreatList(); }
- Unit* SelectVictim() { return getHostilTarget(); }
- Unit* GetCurrentVictim() const { if (ThreatReference* ref = getCurrentVictim()) return ref->GetVictim(); else return nullptr; }
- bool IsThreatListEmpty(bool includeOffline = false) const { return includeOffline ? areThreatListsEmpty() : isThreatListEmpty(); }
- bool IsThreatenedBy(Unit const* who, bool includeOffline = false) const { return (FindReference(who, includeOffline) != nullptr); }
- size_t GetThreatListSize() const { return iThreatContainer.iThreatList.size(); }
- void ForwardThreatForAssistingMe(Unit* victim, float amount, SpellInfo const* spell, bool ignoreModifiers = false, bool ignoreRedirection = false);
- Unit* GetAnyTarget() const { auto const& list = getThreatList(); if (!list.empty()) return list.front()->getTarget(); return nullptr; }
- void ResetThreat(Unit const* who) { if (auto* ref = FindReference(who, true)) ref->setThreat(0.0f); }
- void ResetAllThreat() { resetAllAggro(); }
- float GetThreat(Unit const* who, bool includeOffline = false) const { if (auto* ref = FindReference(who, includeOffline)) return ref->GetThreat(); return 0.0f; }
- void ClearThreat(Unit const* who) { if (auto* ref = FindReference(who, true)) ref->removeReference(); }
- void ClearAllThreat();
- void AddThreat(Unit* victim, float amount, SpellInfo const* spell = nullptr, bool ignoreModifiers = false, bool ignoreRedirection = false);
+ enum TauntState { TAUNT_STATE_DETAUNT = -1, TAUNT_STATE_NONE = 0, TAUNT_STATE_TAUNT = 1 };
+ enum OnlineState { ONLINE_STATE_ONLINE = 2, ONLINE_STATE_SUPPRESSED = 1, ONLINE_STATE_OFFLINE = 0 };
+
+ Unit* GetOwner() const { return _owner; }
+ Unit* GetVictim() const { return _victim; }
+ float GetThreat() const { return std::max<float>(_baseAmount + (float)_tempModifier, 0.0f); }
+ OnlineState GetOnlineState() const { return _online; }
+ bool IsOnline() const { return (_online >= ONLINE_STATE_ONLINE); }
+ bool IsAvailable() const { return (_online > ONLINE_STATE_OFFLINE); }
+ bool IsOffline() const { return (_online <= ONLINE_STATE_OFFLINE); }
+ TauntState GetTauntState() const { return _taunted; }
+ bool IsTaunting() const { return _taunted == TAUNT_STATE_TAUNT; }
+ bool IsDetaunted() const { return _taunted == TAUNT_STATE_DETAUNT; }
+
+ void SetThreat(float amount) { _baseAmount = amount; HeapNotifyChanged(); }
+ void AddThreat(float amount);
+ void ScaleThreat(float factor);
+ void ModifyThreatByPercent(int32 percent) { if (percent) ScaleThreat(0.01f*float(100 + percent)); }
+ void UpdateOnlineState();
+
+ void ClearThreat(bool sendRemove = true); // dealloc's this
+
private:
- HostileReference* FindReference(Unit const* who, bool includeOffline) const { if (auto* ref = iThreatContainer.getReferenceByTarget(who)) return ref; if (includeOffline) if (auto* ref = iThreatOfflineContainer.getReferenceByTarget(who)) return ref; return nullptr; }
+ ThreatReference(ThreatManager* mgr, Unit* victim, float amount) : _owner(mgr->_owner), _mgr(mgr), _victim(victim), _baseAmount(amount), _tempModifier(0), _online(SelectOnlineState()), _taunted(TAUNT_STATE_NONE) { }
+ static bool FlagsAllowFighting(Unit const* a, Unit const* b);
+ OnlineState SelectOnlineState();
+ void UpdateTauntState(bool victimIsTaunting);
+ Unit* const _owner;
+ ThreatManager* const _mgr;
+ void HeapNotifyIncreased() { _mgr->_sortedThreatList.increase(_handle); }
+ void HeapNotifyDecreased() { _mgr->_sortedThreatList.decrease(_handle); }
+ void HeapNotifyChanged() { _mgr->_sortedThreatList.update(_handle); }
+ Unit* const _victim;
+ float _baseAmount;
+ int32 _tempModifier; // Temporary effects (auras with SPELL_AURA_MOD_TOTAL_THREAT) - set from victim's threatmanager in ThreatManager::UpdateMyTempModifiers
+ OnlineState _online;
+ TauntState _taunted;
+ ThreatManager::threat_list_heap::handle_type _handle;
public:
+ ThreatReference(ThreatReference const&) = delete;
+ ThreatReference& operator=(ThreatReference const&) = delete;
- friend class HostileReference;
-
- explicit ThreatManager(Unit* owner);
-
- ~ThreatManager() { clearReferences(); }
-
- void clearReferences();
-
- void addThreat(Unit* victim, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellInfo const* threatSpell = nullptr);
-
- void doAddThreat(Unit* victim, float threat);
-
- void ModifyThreatByPercent(Unit* victim, int32 percent);
-
- float getThreat(Unit* victim, bool alsoSearchOfflineList = false);
-
- bool isThreatListEmpty() const { return iThreatContainer.empty(); }
- bool areThreatListsEmpty() const { return iThreatContainer.empty() && iThreatOfflineContainer.empty(); }
-
- void processThreatEvent(ThreatRefStatusChangeEvent* threatRefStatusChangeEvent);
-
- bool isNeedUpdateToClient(uint32 time);
-
- HostileReference* getCurrentVictim() const { return iCurrentVictim; }
-
- Unit* GetOwner() const { return iOwner; }
-
- Unit* getHostilTarget();
-
- void tauntApply(Unit* taunter);
- void tauntFadeOut(Unit* taunter);
-
- void setCurrentVictim(HostileReference* hostileRef);
-
- void setDirty(bool isDirty) { iThreatContainer.setDirty(isDirty); }
-
- // Reset all aggro without modifying the threadlist.
- void resetAllAggro();
-
- // Reset all aggro of unit in threadlist satisfying the predicate.
- template<class PREDICATE> void resetAggro(PREDICATE predicate)
- {
- ThreatContainer::StorageType &threatList = iThreatContainer.iThreatList;
- if (threatList.empty())
- return;
-
- for (ThreatContainer::StorageType::iterator itr = threatList.begin(); itr != threatList.end(); ++itr)
- {
- HostileReference* ref = (*itr);
-
- if (predicate(ref->getTarget()))
- {
- ref->setThreat(0);
- setDirty(true);
- }
- }
- }
-
- // methods to access the lists from the outside to do some dirty manipulation (scriping and such)
- // I hope they are used as little as possible.
- ThreatContainer::StorageType const & getThreatList() const { return iThreatContainer.getThreatList(); }
- ThreatContainer::StorageType const & getOfflineThreatList() const { return iThreatOfflineContainer.getThreatList(); }
- ThreatContainer& getOnlineContainer() { return iThreatContainer; }
- ThreatContainer& getOfflineContainer() { return iThreatOfflineContainer; }
- private:
- void _addThreat(Unit* victim, float threat);
-
- HostileReference* iCurrentVictim;
- Unit* iOwner;
- uint32 iUpdateTimer;
- ThreatContainer iThreatContainer;
- ThreatContainer iThreatOfflineContainer;
+ friend class ThreatManager;
+ friend struct CompareThreatLessThan;
};
-//=================================================
+inline bool CompareThreatLessThan::operator()(ThreatReference const* a, ThreatReference const* b) const { return ThreatManager::CompareReferencesLT(a, b, 1.0f); }
-namespace Trinity
-{
- // Binary predicate for sorting HostileReferences based on threat value
- class ThreatOrderPred
- {
- public:
- ThreatOrderPred(bool ascending = false) : m_ascending(ascending) { }
- bool operator() (HostileReference const* a, HostileReference const* b) const
- {
- return m_ascending ? a->getThreat() < b->getThreat() : a->getThreat() > b->getThreat();
- }
- private:
- const bool m_ascending;
- };
-}
-#endif
+ #endif