Core/Threat: Threat system adjustments
Port From (https://github.com/TrinityCore/TrinityCore/commit/392a644dc8562ea54b9c185a2776fceb1006e2cd)
This commit is contained in:
+163
-124
@@ -28,13 +28,13 @@ namespace Game.Combat
|
|||||||
{
|
{
|
||||||
public class ThreatManager
|
public class ThreatManager
|
||||||
{
|
{
|
||||||
public static uint CLIENT_THREAT_UPDATE_INTERVAL = 1000u;
|
public static uint THREAT_UPDATE_INTERVAL = 1000u;
|
||||||
|
|
||||||
public Unit _owner;
|
public Unit _owner;
|
||||||
bool _ownerCanHaveThreatList;
|
bool _ownerCanHaveThreatList;
|
||||||
bool _ownerEngaged;
|
bool _ownerEngaged;
|
||||||
|
|
||||||
uint _updateClientTimer;
|
uint _updateTimer;
|
||||||
List<ThreatReference> _sortedThreatList = new();
|
List<ThreatReference> _sortedThreatList = new();
|
||||||
Dictionary<ObjectGuid, ThreatReference> _myThreatListEntries = new();
|
Dictionary<ObjectGuid, ThreatReference> _myThreatListEntries = new();
|
||||||
ThreatReference _currentVictimRef;
|
ThreatReference _currentVictimRef;
|
||||||
@@ -68,7 +68,7 @@ namespace Game.Combat
|
|||||||
public ThreatManager(Unit owner)
|
public ThreatManager(Unit owner)
|
||||||
{
|
{
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
_updateClientTimer = CLIENT_THREAT_UPDATE_INTERVAL;
|
_updateTimer = THREAT_UPDATE_INTERVAL;
|
||||||
|
|
||||||
for (var i = 0; i < (int)SpellSchools.Max; ++i)
|
for (var i = 0; i < (int)SpellSchools.Max; ++i)
|
||||||
_singleSchoolModifiers[i] = 1.0f;
|
_singleSchoolModifiers[i] = 1.0f;
|
||||||
@@ -84,18 +84,21 @@ namespace Game.Combat
|
|||||||
if (!CanHaveThreatList() || !IsEngaged())
|
if (!CanHaveThreatList() || !IsEngaged())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_updateClientTimer <= tdiff)
|
if (_updateTimer <= tdiff)
|
||||||
{
|
{
|
||||||
_updateClientTimer = CLIENT_THREAT_UPDATE_INTERVAL;
|
UpdateVictim();
|
||||||
SendThreatListToClients();
|
_updateTimer = THREAT_UPDATE_INTERVAL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_updateClientTimer -= tdiff;
|
_updateTimer -= tdiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Unit GetCurrentVictim()
|
public Unit GetCurrentVictim()
|
||||||
{
|
{
|
||||||
if (_currentVictimRef != null)
|
if (_currentVictimRef != null || _currentVictimRef.ShouldBeOffline())
|
||||||
|
UpdateVictim();
|
||||||
|
|
||||||
|
if (_currentVictimRef != null && !_currentVictimRef.ShouldBeOffline())
|
||||||
return _currentVictimRef.GetVictim();
|
return _currentVictimRef.GetVictim();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -110,22 +113,6 @@ namespace Game.Combat
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Unit SelectVictim()
|
|
||||||
{
|
|
||||||
if (_sortedThreatList.Empty())
|
|
||||||
return null;
|
|
||||||
|
|
||||||
ThreatReference newVictimRef = ReselectVictim();
|
|
||||||
if (newVictimRef != _currentVictimRef)
|
|
||||||
{
|
|
||||||
if (newVictimRef != null)
|
|
||||||
SendNewVictimToClients(newVictimRef);
|
|
||||||
|
|
||||||
_currentVictimRef = newVictimRef;
|
|
||||||
}
|
|
||||||
return newVictimRef != null ? newVictimRef.GetVictim() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsThreatListEmpty(bool includeOffline = false)
|
public bool IsThreatListEmpty(bool includeOffline = false)
|
||||||
{
|
{
|
||||||
if (includeOffline)
|
if (includeOffline)
|
||||||
@@ -186,14 +173,11 @@ namespace Game.Combat
|
|||||||
|
|
||||||
public bool IsThreateningTo(Unit who, bool includeOffline = false) { return IsThreateningTo(who.GetGUID(), includeOffline); }
|
public bool IsThreateningTo(Unit who, bool includeOffline = false) { return IsThreateningTo(who.GetGUID(), includeOffline); }
|
||||||
|
|
||||||
public void UpdateOnlineStates(bool meThreateningOthers, bool othersThreateningMe)
|
public void EvaluateSuppressed()
|
||||||
{
|
{
|
||||||
if (othersThreateningMe)
|
foreach (var pair in _threatenedByMe)
|
||||||
foreach (var pair in _myThreatListEntries)
|
if (pair.Value.IsOnline() && pair.Value.ShouldBeSuppressed())
|
||||||
pair.Value.UpdateOnlineState();
|
pair.Value.Online = OnlineState.Suppressed;
|
||||||
if (meThreateningOthers)
|
|
||||||
foreach (var pair in _threatenedByMe)
|
|
||||||
pair.Value.UpdateOnlineState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SaveCreatureHomePositionIfNeed(Creature c)
|
static void SaveCreatureHomePositionIfNeed(Creature c)
|
||||||
@@ -296,7 +280,13 @@ namespace Game.Combat
|
|||||||
var targetRefe = _myThreatListEntries.LookupByKey(target.GetGUID());
|
var targetRefe = _myThreatListEntries.LookupByKey(target.GetGUID());
|
||||||
if (targetRefe != null)
|
if (targetRefe != null)
|
||||||
{
|
{
|
||||||
targetRefe.AddThreat(amount);
|
// causing threat causes SUPPRESSED threat states to stop being suppressed
|
||||||
|
if (targetRefe.GetOnlineState() == OnlineState.Suppressed)
|
||||||
|
if (!targetRefe.ShouldBeSuppressed())
|
||||||
|
targetRefe.Online = OnlineState.Online;
|
||||||
|
|
||||||
|
if (targetRefe.IsOnline())
|
||||||
|
targetRefe.AddThreat(amount);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,10 +297,10 @@ namespace Game.Combat
|
|||||||
|
|
||||||
if (!_ownerEngaged)
|
if (!_ownerEngaged)
|
||||||
{
|
{
|
||||||
|
Creature cOwner = _owner.ToCreature(); // if we got here the owner can have a threat list, and must be a creature!
|
||||||
_ownerEngaged = true;
|
_ownerEngaged = true;
|
||||||
|
|
||||||
Creature cOwner = _owner.ToCreature();
|
UpdateVictim();
|
||||||
Cypher.Assert(cOwner != null); // if we got here the owner can have a threat list, and must be a creature!
|
|
||||||
SaveCreatureHomePositionIfNeed(cOwner);
|
SaveCreatureHomePositionIfNeed(cOwner);
|
||||||
CreatureAI ownerAI = cOwner.GetAI();
|
CreatureAI ownerAI = cOwner.GetAI();
|
||||||
if (ownerAI != null)
|
if (ownerAI != null)
|
||||||
@@ -368,14 +358,22 @@ namespace Game.Combat
|
|||||||
public void ResetAllThreat()
|
public void ResetAllThreat()
|
||||||
{
|
{
|
||||||
foreach (var pair in _myThreatListEntries)
|
foreach (var pair in _myThreatListEntries)
|
||||||
pair.Value.SetThreat(0.0f);
|
pair.Value.ScaleThreat(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearThreat(Unit target)
|
public void ClearThreat(Unit target)
|
||||||
{
|
{
|
||||||
var refe = _myThreatListEntries.LookupByKey(target.GetGUID());
|
var refe = _myThreatListEntries.LookupByKey(target.GetGUID());
|
||||||
if (refe != null)
|
if (refe != null)
|
||||||
refe.ClearThreat();
|
ClearThreat(refe);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearThreat(ThreatReference refe)
|
||||||
|
{
|
||||||
|
SendRemoveToClients(refe.GetVictim());
|
||||||
|
refe.UnregisterAndFree();
|
||||||
|
if (_currentVictimRef == null)
|
||||||
|
UpdateVictim();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearAllThreat()
|
public void ClearAllThreat()
|
||||||
@@ -386,7 +384,7 @@ namespace Game.Combat
|
|||||||
|
|
||||||
SendClearAllThreatToClients();
|
SendClearAllThreatToClients();
|
||||||
do
|
do
|
||||||
_myThreatListEntries.First().Value.ClearThreat(false);
|
_myThreatListEntries.First().Value.UnregisterAndFree();
|
||||||
while (!_myThreatListEntries.Empty());
|
while (!_myThreatListEntries.Empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,8 +412,24 @@ namespace Game.Combat
|
|||||||
|
|
||||||
public void ClearFixate() { FixateTarget(null); }
|
public void ClearFixate() { FixateTarget(null); }
|
||||||
|
|
||||||
|
void UpdateVictim()
|
||||||
|
{
|
||||||
|
ThreatReference newVictim = ReselectVictim();
|
||||||
|
bool newHighest = (newVictim != _currentVictimRef);
|
||||||
|
|
||||||
|
_currentVictimRef = newVictim;
|
||||||
|
SendThreatListToClients(newVictim != null && newHighest);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ThreatReference ReselectVictim()
|
ThreatReference ReselectVictim()
|
||||||
{
|
{
|
||||||
|
if (_sortedThreatList.Empty())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
foreach (var pair in _myThreatListEntries)
|
||||||
|
pair.Value.UpdateOffline();
|
||||||
|
|
||||||
// fixated target is always preferred
|
// fixated target is always preferred
|
||||||
if (_fixateRef != null && _fixateRef.IsAvailable())
|
if (_fixateRef != null && _fixateRef.IsAvailable())
|
||||||
return _fixateRef;
|
return _fixateRef;
|
||||||
@@ -538,30 +552,6 @@ namespace Game.Combat
|
|||||||
return threat;
|
return threat;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendClearAllThreatToClients()
|
|
||||||
{
|
|
||||||
ThreatClear threatClear = new();
|
|
||||||
threatClear.UnitGUID = _owner.GetGUID();
|
|
||||||
_owner.SendMessageToSet(threatClear, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendThreatListToClients()
|
|
||||||
{
|
|
||||||
ThreatUpdate threatUpdate = new();
|
|
||||||
threatUpdate.UnitGUID = _owner.GetGUID();
|
|
||||||
foreach (ThreatReference refe in _sortedThreatList)
|
|
||||||
{
|
|
||||||
if (!refe.IsAvailable()) // @todo check if suppressed threat should get sent for bubble/iceblock/hop etc
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ThreatInfo threatInfo = new();
|
|
||||||
threatInfo.UnitGUID = refe.GetVictim().GetGUID();
|
|
||||||
threatInfo.Threat = (long)(refe.GetThreat() * 100);
|
|
||||||
threatUpdate.ThreatList.Add(threatInfo);
|
|
||||||
}
|
|
||||||
_owner.SendMessageToSet(threatUpdate, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ForwardThreatForAssistingMe(Unit assistant, float baseAmount, SpellInfo spell = null, bool ignoreModifiers = false)
|
public void ForwardThreatForAssistingMe(Unit assistant, float baseAmount, SpellInfo spell = null, bool ignoreModifiers = false)
|
||||||
{
|
{
|
||||||
if (spell != null && spell.HasAttribute(SpellAttr1.NoThreat)) // shortcut, none of the calls would do anything
|
if (spell != null && spell.HasAttribute(SpellAttr1.NoThreat)) // shortcut, none of the calls would do anything
|
||||||
@@ -570,16 +560,35 @@ namespace Game.Combat
|
|||||||
if (_threatenedByMe.Empty())
|
if (_threatenedByMe.Empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float perTarget = baseAmount / _threatenedByMe.Count; // Threat is divided evenly among all targets (LibThreat sourced)
|
List<Creature> canBeThreatened = new();
|
||||||
|
List<Creature> cannotBeThreatened = new();
|
||||||
foreach (var pair in _threatenedByMe)
|
foreach (var pair in _threatenedByMe)
|
||||||
pair.Value.GetOwner().GetThreatManager().AddThreat(assistant, perTarget, spell, ignoreModifiers);
|
{
|
||||||
|
Creature owner = pair.Value.GetOwner();
|
||||||
|
if (!owner.HasBreakableByDamageCrowdControlAura())
|
||||||
|
canBeThreatened.Add(owner);
|
||||||
|
else
|
||||||
|
cannotBeThreatened.Add(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canBeThreatened.Empty()) // targets under CC cannot gain assist threat - split evenly among the rest
|
||||||
|
{
|
||||||
|
float perTarget = baseAmount / canBeThreatened.Count;
|
||||||
|
foreach (Creature threatened in canBeThreatened)
|
||||||
|
threatened.GetThreatManager().AddThreat(assistant, perTarget, spell, ignoreModifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Creature threatened in cannotBeThreatened)
|
||||||
|
threatened.GetThreatManager().AddThreat(assistant, 0.0f, spell, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveMeFromThreatLists()
|
public void RemoveMeFromThreatLists()
|
||||||
{
|
{
|
||||||
while (!_threatenedByMe.Empty())
|
while (!_threatenedByMe.Empty())
|
||||||
_threatenedByMe.First().Value.ClearThreat();
|
{
|
||||||
|
var refe = _threatenedByMe.FirstOrDefault().Value;
|
||||||
|
refe._mgr.ClearThreat(_owner);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateMyTempModifiers()
|
public void UpdateMyTempModifiers()
|
||||||
@@ -588,9 +597,12 @@ namespace Game.Combat
|
|||||||
foreach (AuraEffect eff in _owner.GetAuraEffectsByType(AuraType.ModTotalThreat))
|
foreach (AuraEffect eff in _owner.GetAuraEffectsByType(AuraType.ModTotalThreat))
|
||||||
mod += eff.GetAmount();
|
mod += eff.GetAmount();
|
||||||
|
|
||||||
|
if (_threatenedByMe.Empty())
|
||||||
|
return;
|
||||||
|
|
||||||
foreach (var pair in _threatenedByMe)
|
foreach (var pair in _threatenedByMe)
|
||||||
{
|
{
|
||||||
pair.Value._tempModifier = mod;
|
pair.Value.TempModifier = mod;
|
||||||
pair.Value.ListNotifyChanged();
|
pair.Value.ListNotifyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -627,6 +639,13 @@ namespace Game.Combat
|
|||||||
UpdateRedirectInfo();
|
UpdateRedirectInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SendClearAllThreatToClients()
|
||||||
|
{
|
||||||
|
ThreatClear threatClear = new();
|
||||||
|
threatClear.UnitGUID = _owner.GetGUID();
|
||||||
|
_owner.SendMessageToSet(threatClear, false);
|
||||||
|
}
|
||||||
|
|
||||||
public void SendRemoveToClients(Unit victim)
|
public void SendRemoveToClients(Unit victim)
|
||||||
{
|
{
|
||||||
ThreatRemove threatRemove = new();
|
ThreatRemove threatRemove = new();
|
||||||
@@ -635,22 +654,37 @@ namespace Game.Combat
|
|||||||
_owner.SendMessageToSet(threatRemove, false);
|
_owner.SendMessageToSet(threatRemove, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendNewVictimToClients(ThreatReference victimRef)
|
void SendThreatListToClients(bool newHighest)
|
||||||
{
|
{
|
||||||
HighestThreatUpdate highestThreatUpdate = new();
|
void fillSharedPacketDataAndSend(dynamic packet)
|
||||||
highestThreatUpdate.UnitGUID = _owner.GetGUID();
|
|
||||||
highestThreatUpdate.HighestThreatGUID = victimRef.GetVictim().GetGUID();
|
|
||||||
foreach (ThreatReference refe in _sortedThreatList)
|
|
||||||
{
|
{
|
||||||
if (!refe.IsAvailable())
|
packet.UnitGUID = _owner.GetGUID();
|
||||||
continue;
|
packet.ThreatList.reserve(_sortedThreatList.Count);
|
||||||
|
|
||||||
ThreatInfo threatInfo = new();
|
foreach (ThreatReference refe in _sortedThreatList)
|
||||||
threatInfo.UnitGUID = refe.GetVictim().GetGUID();
|
{
|
||||||
threatInfo.Threat = (long)(refe.GetThreat() * 100);
|
if (!refe.IsAvailable())
|
||||||
highestThreatUpdate.ThreatList.Add(threatInfo);
|
continue;
|
||||||
|
|
||||||
|
ThreatInfo threatInfo = new();
|
||||||
|
threatInfo.UnitGUID = refe.GetVictim().GetGUID();
|
||||||
|
threatInfo.Threat = (long)(refe.GetThreat() * 100);
|
||||||
|
packet.ThreatList.Add(threatInfo);
|
||||||
|
}
|
||||||
|
_owner.SendMessageToSet(packet, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newHighest)
|
||||||
|
{
|
||||||
|
HighestThreatUpdate highestThreatUpdate = new();
|
||||||
|
highestThreatUpdate.HighestThreatGUID = _currentVictimRef.GetVictim().GetGUID();
|
||||||
|
fillSharedPacketDataAndSend(highestThreatUpdate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ThreatUpdate threatUpdate = new();
|
||||||
|
fillSharedPacketDataAndSend(threatUpdate);
|
||||||
}
|
}
|
||||||
_owner.SendMessageToSet(highestThreatUpdate, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PutThreatListRef(ObjectGuid guid, ThreatReference refe)
|
void PutThreatListRef(ObjectGuid guid, ThreatReference refe)
|
||||||
@@ -661,23 +695,20 @@ namespace Game.Combat
|
|||||||
_sortedThreatList.Sort();
|
_sortedThreatList.Sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PurgeThreatListRef(ObjectGuid guid, bool sendRemove)
|
public void PurgeThreatListRef(ObjectGuid guid)
|
||||||
{
|
{
|
||||||
var refe = _myThreatListEntries.LookupByKey(guid);
|
var refe = _myThreatListEntries.LookupByKey(guid);
|
||||||
if (refe == null)
|
if (refe == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_myThreatListEntries.Remove(guid);
|
_myThreatListEntries.Remove(guid);
|
||||||
|
_sortedThreatList.Remove(refe);
|
||||||
|
|
||||||
if (_currentVictimRef == refe)
|
|
||||||
_currentVictimRef = null;
|
|
||||||
if (_fixateRef == refe)
|
if (_fixateRef == refe)
|
||||||
_fixateRef = null;
|
_fixateRef = null;
|
||||||
|
|
||||||
_sortedThreatList.Remove(refe);
|
if (_currentVictimRef == refe)
|
||||||
_sortedThreatList.Sort();
|
_currentVictimRef = null;
|
||||||
if (sendRemove && refe.IsAvailable())
|
|
||||||
SendRemoveToClients(refe.GetVictim());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PutThreatenedByMeRef(ObjectGuid guid, ThreatReference refe)
|
void PutThreatenedByMeRef(ObjectGuid guid, ThreatReference refe)
|
||||||
@@ -759,21 +790,21 @@ namespace Game.Combat
|
|||||||
|
|
||||||
public class ThreatReference : IComparable<ThreatReference>
|
public class ThreatReference : IComparable<ThreatReference>
|
||||||
{
|
{
|
||||||
Unit _owner;
|
Creature _owner;
|
||||||
ThreatManager _mgr;
|
public ThreatManager _mgr;
|
||||||
Unit _victim;
|
Unit _victim;
|
||||||
|
public OnlineState Online;
|
||||||
float _baseAmount;
|
float _baseAmount;
|
||||||
public int _tempModifier; // Temporary effects (auras with SPELL_AURA_MOD_TOTAL_THREAT) - set from victim's threatmanager in ThreatManager::UpdateMyTempModifiers
|
public int TempModifier; // Temporary effects (auras with SPELL_AURA_MOD_TOTAL_THREAT) - set from victim's threatmanager in ThreatManager::UpdateMyTempModifiers
|
||||||
OnlineState _online;
|
|
||||||
TauntState _taunted;
|
TauntState _taunted;
|
||||||
|
|
||||||
public ThreatReference(ThreatManager mgr, Unit victim, float amount)
|
public ThreatReference(ThreatManager mgr, Unit victim, float amount)
|
||||||
{
|
{
|
||||||
_owner = mgr._owner;
|
_owner = mgr._owner as Creature;
|
||||||
_mgr = mgr;
|
_mgr = mgr;
|
||||||
_victim = victim;
|
_victim = victim;
|
||||||
_baseAmount = amount;
|
Online = ShouldBeOffline() ? OnlineState.Offline : ShouldBeSuppressed() ? OnlineState.Suppressed : OnlineState.Online;
|
||||||
_online = SelectOnlineState();
|
_baseAmount = IsOnline() ? amount : 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddThreat(float amount)
|
public void AddThreat(float amount)
|
||||||
@@ -794,17 +825,23 @@ namespace Game.Combat
|
|||||||
ListNotifyChanged();
|
ListNotifyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateOnlineState()
|
public void UpdateOffline()
|
||||||
{
|
{
|
||||||
OnlineState onlineState = SelectOnlineState();
|
bool shouldBeOffline = ShouldBeOffline();
|
||||||
if (onlineState == _online)
|
if (shouldBeOffline == IsOffline())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_online = onlineState;
|
if (shouldBeOffline)
|
||||||
ListNotifyChanged();
|
{
|
||||||
|
Online = OnlineState.Offline;
|
||||||
if (!IsAvailable())
|
ListNotifyChanged();
|
||||||
_owner.GetThreatManager().SendRemoveToClients(_victim);
|
_mgr.SendRemoveToClients(_victim);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Online = ShouldBeSuppressed() ? OnlineState.Suppressed : OnlineState.Online;
|
||||||
|
ListNotifyChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool FlagsAllowFighting(Unit a, Unit b)
|
public static bool FlagsAllowFighting(Unit a, Unit b)
|
||||||
@@ -825,31 +862,28 @@ namespace Game.Combat
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnlineState SelectOnlineState()
|
public bool ShouldBeOffline()
|
||||||
{
|
{
|
||||||
// first, check all offline conditions
|
if (!_owner.CanSeeOrDetect(_victim))
|
||||||
if (!_owner.CanSeeOrDetect(_victim)) // not in map/phase, or stealth/invis
|
return true;
|
||||||
return OnlineState.Offline;
|
|
||||||
|
|
||||||
if (_victim.HasUnitState(UnitState.Died)) // feign death
|
if (!_owner._IsTargetAcceptable(_victim) || !_owner.CanCreatureAttack(_victim))
|
||||||
return OnlineState.Offline;
|
return true;
|
||||||
|
|
||||||
if (!FlagsAllowFighting(_owner, _victim) || !FlagsAllowFighting(_victim, _owner))
|
if (!FlagsAllowFighting(_owner, _victim) || !FlagsAllowFighting(_victim, _owner))
|
||||||
return OnlineState.Offline;
|
return true;
|
||||||
|
|
||||||
if (_owner.IsAIEnabled() && !_owner.GetAI().CanAIAttack(_victim))
|
return false;
|
||||||
return OnlineState.Offline;
|
}
|
||||||
|
|
||||||
// next, check suppression (immunity to chosen melee attack school)
|
public bool ShouldBeSuppressed()
|
||||||
|
{
|
||||||
if (_victim.IsImmunedToDamage(_owner.GetMeleeDamageSchoolMask()))
|
if (_victim.IsImmunedToDamage(_owner.GetMeleeDamageSchoolMask()))
|
||||||
return OnlineState.Suppressed;
|
return true;
|
||||||
|
|
||||||
// or any form of CC that will break on damage - disorient, polymorph, blind etc
|
|
||||||
if (_victim.HasBreakableByDamageCrowdControlAura())
|
if (_victim.HasBreakableByDamageCrowdControlAura())
|
||||||
return OnlineState.Suppressed;
|
return true;
|
||||||
|
|
||||||
// no suppression - we're online
|
return false;
|
||||||
return OnlineState.Online;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateTauntState(TauntState state = TauntState.None)
|
public void UpdateTauntState(TauntState state = TauntState.None)
|
||||||
@@ -866,19 +900,24 @@ namespace Game.Combat
|
|||||||
ListNotifyChanged();
|
ListNotifyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearThreat(bool sendRemove = true)
|
public void ClearThreat()
|
||||||
{
|
{
|
||||||
_owner.GetThreatManager().PurgeThreatListRef(_victim.GetGUID(), sendRemove);
|
_mgr.ClearThreat(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnregisterAndFree()
|
||||||
|
{
|
||||||
|
_owner.GetThreatManager().PurgeThreatListRef(_victim.GetGUID());
|
||||||
_victim.GetThreatManager().PurgeThreatenedByMeRef(_owner.GetGUID());
|
_victim.GetThreatManager().PurgeThreatenedByMeRef(_owner.GetGUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Unit GetOwner() { return _owner; }
|
public Creature GetOwner() { return _owner; }
|
||||||
public Unit GetVictim() { return _victim; }
|
public Unit GetVictim() { return _victim; }
|
||||||
public float GetThreat() { return Math.Max(_baseAmount + (float)_tempModifier, 0.0f); }
|
public float GetThreat() { return Math.Max(_baseAmount + (float)TempModifier, 0.0f); }
|
||||||
public OnlineState GetOnlineState() { return _online; }
|
public OnlineState GetOnlineState() { return Online; }
|
||||||
public bool IsOnline() { return (_online >= OnlineState.Online); }
|
public bool IsOnline() { return Online >= OnlineState.Online; }
|
||||||
public bool IsAvailable() { return (_online > OnlineState.Offline); }
|
public bool IsAvailable() { return Online > OnlineState.Offline; }
|
||||||
public bool IsOffline() { return (_online <= OnlineState.Offline); }
|
public bool IsOffline() { return Online <= OnlineState.Offline; }
|
||||||
public TauntState GetTauntState() { return IsTaunting() ? TauntState.Taunt : _taunted; }
|
public TauntState GetTauntState() { return IsTaunting() ? TauntState.Taunt : _taunted; }
|
||||||
public bool IsTaunting() { return _taunted >= TauntState.Taunt; }
|
public bool IsTaunting() { return _taunted >= TauntState.Taunt; }
|
||||||
public bool IsDetaunted() { return _taunted == TauntState.Detaunt; }
|
public bool IsDetaunted() { return _taunted == TauntState.Detaunt; }
|
||||||
|
|||||||
@@ -417,7 +417,7 @@ namespace Game.Entities
|
|||||||
LoadCreaturesAddon();
|
LoadCreaturesAddon();
|
||||||
LoadTemplateImmunities();
|
LoadTemplateImmunities();
|
||||||
|
|
||||||
GetThreatManager().UpdateOnlineStates(true, true);
|
GetThreatManager().EvaluateSuppressed();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -541,7 +541,6 @@ namespace Game.Entities
|
|||||||
if (diff >= m_boundaryCheckTime)
|
if (diff >= m_boundaryCheckTime)
|
||||||
{
|
{
|
||||||
GetAI().CheckInRoom();
|
GetAI().CheckInRoom();
|
||||||
GetThreatManager().UpdateOnlineStates(false, true);
|
|
||||||
m_boundaryCheckTime = 2500;
|
m_boundaryCheckTime = 2500;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -898,7 +897,7 @@ namespace Game.Entities
|
|||||||
Unit target;
|
Unit target;
|
||||||
|
|
||||||
if (CanHaveThreatList())
|
if (CanHaveThreatList())
|
||||||
target = GetThreatManager().SelectVictim();
|
target = GetThreatManager().GetCurrentVictim();
|
||||||
else if (!HasReactState(ReactStates.Passive))
|
else if (!HasReactState(ReactStates.Passive))
|
||||||
{
|
{
|
||||||
// We're a player pet, probably
|
// We're a player pet, probably
|
||||||
|
|||||||
@@ -152,8 +152,6 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public bool CanHaveThreatList() { return m_threatManager.CanHaveThreatList(); }
|
public bool CanHaveThreatList() { return m_threatManager.CanHaveThreatList(); }
|
||||||
|
|
||||||
void SendThreatListUpdate() { m_threatManager.SendThreatListToClients(); }
|
|
||||||
|
|
||||||
// For NPCs with threat list: Whether there are any enemies on our threat list
|
// For NPCs with threat list: Whether there are any enemies on our threat list
|
||||||
// For other units: Whether we're in combat
|
// For other units: Whether we're in combat
|
||||||
// This value is different from IsInCombat when a projectile spell is midair (combat on launch - threat+aggro on impact)
|
// This value is different from IsInCombat when a projectile spell is midair (combat on launch - threat+aggro on impact)
|
||||||
|
|||||||
@@ -419,7 +419,6 @@ namespace Game.Entities
|
|||||||
AddToNotify(NotifyFlags.VisibilityChanged);
|
AddToNotify(NotifyFlags.VisibilityChanged);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_threatManager.UpdateOnlineStates(true, true);
|
|
||||||
base.UpdateObjectVisibility(true);
|
base.UpdateObjectVisibility(true);
|
||||||
// call MoveInLineOfSight for nearby creatures
|
// call MoveInLineOfSight for nearby creatures
|
||||||
AIRelocationNotifier notifier = new(this);
|
AIRelocationNotifier notifier = new(this);
|
||||||
@@ -2882,16 +2881,11 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
AddUnitFlag(UnitFlags.ImmuneToPc | UnitFlags.ImmuneToNpc);
|
AddUnitFlag(UnitFlags.ImmuneToPc | UnitFlags.ImmuneToNpc);
|
||||||
ValidateAttackersAndOwnTarget();
|
ValidateAttackersAndOwnTarget();
|
||||||
if (keepCombat)
|
if (!keepCombat)
|
||||||
m_threatManager.UpdateOnlineStates(true, true);
|
|
||||||
else
|
|
||||||
m_combatManager.EndAllCombat();
|
m_combatManager.EndAllCombat();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
RemoveUnitFlag(UnitFlags.ImmuneToPc | UnitFlags.ImmuneToNpc);
|
RemoveUnitFlag(UnitFlags.ImmuneToPc | UnitFlags.ImmuneToNpc);
|
||||||
m_threatManager.UpdateOnlineStates(true, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void SetImmuneToAll(bool apply) { SetImmuneToAll(apply, false); }
|
public virtual void SetImmuneToAll(bool apply) { SetImmuneToAll(apply, false); }
|
||||||
@@ -2904,9 +2898,7 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
AddUnitFlag(UnitFlags.ImmuneToPc);
|
AddUnitFlag(UnitFlags.ImmuneToPc);
|
||||||
ValidateAttackersAndOwnTarget();
|
ValidateAttackersAndOwnTarget();
|
||||||
if (keepCombat)
|
if (!keepCombat)
|
||||||
m_threatManager.UpdateOnlineStates(true, true);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
List<CombatReference> toEnd = new();
|
List<CombatReference> toEnd = new();
|
||||||
foreach (var pair in m_combatManager.GetPvECombatRefs())
|
foreach (var pair in m_combatManager.GetPvECombatRefs())
|
||||||
@@ -2922,10 +2914,7 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
RemoveUnitFlag(UnitFlags.ImmuneToPc);
|
RemoveUnitFlag(UnitFlags.ImmuneToPc);
|
||||||
m_threatManager.UpdateOnlineStates(true, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void SetImmuneToPC(bool apply) { SetImmuneToPC(apply, false); }
|
public virtual void SetImmuneToPC(bool apply) { SetImmuneToPC(apply, false); }
|
||||||
@@ -2938,9 +2927,7 @@ namespace Game.Entities
|
|||||||
{
|
{
|
||||||
AddUnitFlag(UnitFlags.ImmuneToNpc);
|
AddUnitFlag(UnitFlags.ImmuneToNpc);
|
||||||
ValidateAttackersAndOwnTarget();
|
ValidateAttackersAndOwnTarget();
|
||||||
if (keepCombat)
|
if (!keepCombat)
|
||||||
m_threatManager.UpdateOnlineStates(true, true);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
List<CombatReference> toEnd = new();
|
List<CombatReference> toEnd = new();
|
||||||
foreach (var pair in m_combatManager.GetPvECombatRefs())
|
foreach (var pair in m_combatManager.GetPvECombatRefs())
|
||||||
@@ -2956,10 +2943,7 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
RemoveUnitFlag(UnitFlags.ImmuneToNpc);
|
RemoveUnitFlag(UnitFlags.ImmuneToNpc);
|
||||||
m_threatManager.UpdateOnlineStates(true, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void SetImmuneToNPC(bool apply) { SetImmuneToNPC(apply, false); }
|
public virtual void SetImmuneToNPC(bool apply) { SetImmuneToNPC(apply, false); }
|
||||||
|
|||||||
@@ -1581,7 +1581,7 @@ namespace Game.Spells
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
target.GetThreatManager().UpdateOnlineStates(true, false);
|
target.GetThreatManager().EvaluateSuppressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
[AuraEffectHandler(AuraType.ModScale)]
|
[AuraEffectHandler(AuraType.ModScale)]
|
||||||
@@ -1696,8 +1696,6 @@ namespace Game.Spells
|
|||||||
if (creature != null)
|
if (creature != null)
|
||||||
creature.InitializeReactState();
|
creature.InitializeReactState();
|
||||||
}
|
}
|
||||||
|
|
||||||
target.GetThreatManager().UpdateOnlineStates(true, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[AuraEffectHandler(AuraType.ModUnattackable)]
|
[AuraEffectHandler(AuraType.ModUnattackable)]
|
||||||
@@ -2383,7 +2381,7 @@ namespace Game.Spells
|
|||||||
Unit target = aurApp.GetTarget();
|
Unit target = aurApp.GetTarget();
|
||||||
|
|
||||||
target.SetControlled(apply, UnitState.Confused);
|
target.SetControlled(apply, UnitState.Confused);
|
||||||
target.GetThreatManager().UpdateOnlineStates(true, false);
|
target.GetThreatManager().EvaluateSuppressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
[AuraEffectHandler(AuraType.ModFear)]
|
[AuraEffectHandler(AuraType.ModFear)]
|
||||||
@@ -2395,7 +2393,7 @@ namespace Game.Spells
|
|||||||
Unit target = aurApp.GetTarget();
|
Unit target = aurApp.GetTarget();
|
||||||
|
|
||||||
target.SetControlled(apply, UnitState.Fleeing);
|
target.SetControlled(apply, UnitState.Fleeing);
|
||||||
target.GetThreatManager().UpdateOnlineStates(true, false);
|
target.GetThreatManager().EvaluateSuppressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
[AuraEffectHandler(AuraType.ModStun)]
|
[AuraEffectHandler(AuraType.ModStun)]
|
||||||
@@ -2407,7 +2405,7 @@ namespace Game.Spells
|
|||||||
Unit target = aurApp.GetTarget();
|
Unit target = aurApp.GetTarget();
|
||||||
|
|
||||||
target.SetControlled(apply, UnitState.Stunned);
|
target.SetControlled(apply, UnitState.Stunned);
|
||||||
target.GetThreatManager().UpdateOnlineStates(true, false);
|
target.GetThreatManager().EvaluateSuppressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
[AuraEffectHandler(AuraType.ModRoot)]
|
[AuraEffectHandler(AuraType.ModRoot)]
|
||||||
@@ -2420,7 +2418,7 @@ namespace Game.Spells
|
|||||||
Unit target = aurApp.GetTarget();
|
Unit target = aurApp.GetTarget();
|
||||||
|
|
||||||
target.SetControlled(apply, UnitState.Root);
|
target.SetControlled(apply, UnitState.Root);
|
||||||
target.GetThreatManager().UpdateOnlineStates(true, false);
|
target.GetThreatManager().EvaluateSuppressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
[AuraEffectHandler(AuraType.PreventsFleeing)]
|
[AuraEffectHandler(AuraType.PreventsFleeing)]
|
||||||
@@ -2817,7 +2815,7 @@ namespace Game.Spells
|
|||||||
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis);
|
target.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.StealthOrInvis);
|
||||||
}
|
}
|
||||||
|
|
||||||
target.GetThreatManager().UpdateOnlineStates(true, false);
|
target.GetThreatManager().EvaluateSuppressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
[AuraEffectHandler(AuraType.DamageImmunity)]
|
[AuraEffectHandler(AuraType.DamageImmunity)]
|
||||||
@@ -2829,7 +2827,7 @@ namespace Game.Spells
|
|||||||
Unit target = aurApp.GetTarget();
|
Unit target = aurApp.GetTarget();
|
||||||
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
|
m_spellInfo.ApplyAllSpellImmunitiesTo(target, GetSpellEffectInfo(), apply);
|
||||||
|
|
||||||
target.GetThreatManager().UpdateOnlineStates(true, false);
|
target.GetThreatManager().EvaluateSuppressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
[AuraEffectHandler(AuraType.DispelImmunity)]
|
[AuraEffectHandler(AuraType.DispelImmunity)]
|
||||||
|
|||||||
@@ -3217,7 +3217,7 @@ namespace Game.Spells
|
|||||||
{
|
{
|
||||||
// in dungeons (or for nonplayers), reset this unit on all enemies' threat lists
|
// in dungeons (or for nonplayers), reset this unit on all enemies' threat lists
|
||||||
foreach (var pair in unitTarget.GetThreatManager().GetThreatenedByMeList())
|
foreach (var pair in unitTarget.GetThreatManager().GetThreatenedByMeList())
|
||||||
pair.Value.SetThreat(0.0f);
|
pair.Value.ScaleThreat(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// makes spells cast before this time fizzle
|
// makes spells cast before this time fizzle
|
||||||
|
|||||||
Reference in New Issue
Block a user