diff options
author | Treeston <treeston.mmoc@gmail.com> | 2018-01-03 20:04:19 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-05-16 21:56:01 +0200 |
commit | 34c7810fe507eca1b8b9389630db5d5d26d92e77 (patch) | |
tree | e05653a0adaf4c4f5c406649f1bfe6573cbb22ff /src/server/game/Combat/ThreatManager.h | |
parent | 5158136ee8a77046e37bafa192481b8b61d4a116 (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.h | 517 |
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 |