Combat/Threat rewrite - prep & refactor

Port From (https://github.com/TrinityCore/TrinityCore/commit/8be23fcbbdf26e8169defd761e61765f301bebe0)
This commit is contained in:
hondacrx
2020-08-22 11:58:19 -04:00
parent 67bacbb731
commit 193ad3a48d
42 changed files with 533 additions and 421 deletions
+14 -23
View File
@@ -102,16 +102,8 @@ namespace Game.AI
{ {
creature.SetInCombatWith(player); creature.SetInCombatWith(player);
player.SetInCombatWith(creature); player.SetInCombatWith(creature);
creature.AddThreat(player, 0.0f); creature.GetThreatManager().AddThreat(player, 0.0f, null, true, true);
} }
/* Causes certain things to never leave the threat list (Priest Lightwell, etc):
foreach (var unit in player.m_Controlled)
{
me.SetInCombatWith(unit);
unit.SetInCombatWith(me);
me.AddThreat(unit, 0.0f);
}*/
} }
} }
@@ -119,6 +111,7 @@ namespace Game.AI
{ {
if (MoveInLineOfSight_locked) if (MoveInLineOfSight_locked)
return; return;
MoveInLineOfSight_locked = true; MoveInLineOfSight_locked = true;
MoveInLineOfSight(who); MoveInLineOfSight(who);
MoveInLineOfSight_locked = false; MoveInLineOfSight_locked = false;
@@ -126,11 +119,11 @@ namespace Game.AI
public virtual void MoveInLineOfSight(Unit who) public virtual void MoveInLineOfSight(Unit who)
{ {
if (me.GetVictim() != null) if (me.IsEngaged())
return; return;
if (me.HasReactState(ReactStates.Aggressive) && me.CanStartAttack(who, false)) if (me.HasReactState(ReactStates.Aggressive) && me.CanStartAttack(who, false))
AttackStart(who); me.EngageWithTarget(who);
} }
void _OnOwnerCombatInteraction(Unit target) void _OnOwnerCombatInteraction(Unit target)
@@ -139,12 +132,7 @@ namespace Game.AI
return; return;
if (!me.HasReactState(ReactStates.Passive) && me.CanStartAttack(target, true)) if (!me.HasReactState(ReactStates.Passive) && me.CanStartAttack(target, true))
{ me.EngageWithTarget(target);
if (me.IsInCombat())
me.AddThreat(target, 0.0f);
else
AttackStart(target);
}
} }
// Distract creature, if player gets too close while stealthed/prowling // Distract creature, if player gets too close while stealthed/prowling
@@ -154,8 +142,8 @@ namespace Game.AI
if (!who || !who.IsTypeId(TypeId.Player)) if (!who || !who.IsTypeId(TypeId.Player))
return; return;
// If this unit isn't an NPC, is already distracted, is in combat, is confused, stunned or fleeing, do nothing // If this unit isn't an NPC, is already distracted, is fighting, is confused, stunned or fleeing, do nothing
if (!me.IsTypeId(TypeId.Unit) || me.IsInCombat() || me.HasUnitState(UnitState.Confused | UnitState.Stunned | UnitState.Fleeing | UnitState.Distracted)) if (!me.IsTypeId(TypeId.Unit) || me.IsEngaged() || me.HasUnitState(UnitState.Confused | UnitState.Stunned | UnitState.Fleeing | UnitState.Distracted))
return; return;
// Only alert for hostiles! // Only alert for hostiles!
@@ -214,7 +202,7 @@ namespace Game.AI
public bool UpdateVictimWithGaze() public bool UpdateVictimWithGaze()
{ {
if (!me.IsInCombat()) if (!me.IsEngaged())
return false; return false;
if (me.HasReactState(ReactStates.Passive)) if (me.HasReactState(ReactStates.Passive))
@@ -237,7 +225,7 @@ namespace Game.AI
public bool UpdateVictim() public bool UpdateVictim()
{ {
if (!me.IsInCombat()) if (!me.IsEngaged())
return false; return false;
if (!me.HasReactState(ReactStates.Passive)) if (!me.HasReactState(ReactStates.Passive))
@@ -266,7 +254,7 @@ namespace Game.AI
me.RemoveAurasOnEvade(); me.RemoveAurasOnEvade();
// sometimes bosses stuck in combat? // sometimes bosses stuck in combat?
me.DeleteThreatList(); me.GetThreatManager().ClearAllThreat();
me.CombatStop(true); me.CombatStop(true);
me.SetLootRecipient(null); me.SetLootRecipient(null);
me.ResetPlayerDamageReq(); me.ResetPlayerDamageReq();
@@ -410,7 +398,10 @@ namespace Game.AI
me.DoImmediateBoundaryCheck(); me.DoImmediateBoundaryCheck();
} }
// Called for reaction at enter to combat if not in combat yet (enemy can be NULL) /// <summary>
/// Called for reaction when initially engaged
/// </summary>
/// <param name="victim"></param>
public virtual void EnterCombat(Unit victim) { } public virtual void EnterCombat(Unit victim) { }
// Called when the creature is killed // Called when the creature is killed
+5 -8
View File
@@ -34,12 +34,9 @@ namespace Game.AI
public override bool CanSeeAlways(WorldObject obj) public override bool CanSeeAlways(WorldObject obj)
{ {
if (!obj.IsTypeMask(TypeMask.Unit)) Unit unit = obj.ToUnit();
return false; if (unit != null)
if (unit.IsControlledByPlayer() && me.IsEngagedBy(unit))
var threatList = me.GetThreatManager().GetThreatList();
foreach (var refe in threatList)
if (refe.GetUnitGuid() == obj.GetGUID())
return true; return true;
return false; return false;
@@ -51,14 +48,14 @@ namespace Game.AI
{ {
me.GetMotionMaster().MoveIdle(); me.GetMotionMaster().MoveIdle();
me.CombatStop(true); me.CombatStop(true);
me.DeleteThreatList(); me.GetThreatManager().ClearAllThreat();
return; return;
} }
Log.outDebug(LogFilter.Unit, "Guard entry: {0} enters evade mode.", me.GetEntry()); Log.outDebug(LogFilter.Unit, "Guard entry: {0} enters evade mode.", me.GetEntry());
me.RemoveAllAuras(); me.RemoveAllAuras();
me.DeleteThreatList(); me.GetThreatManager().ClearAllThreat();
me.CombatStop(true); me.CombatStop(true);
// Remove ChaseMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead // Remove ChaseMovementGenerator from MotionMaster stack list, and add HomeMovementGenerator instead
+163 -71
View File
@@ -57,9 +57,9 @@ namespace Game.AI
return me.GetThreatManager(); return me.GetThreatManager();
} }
void SortByDistanceTo(Unit reference, List<Unit> targets) void SortByDistance(List<Unit> targets, bool ascending)
{ {
targets.Sort(new ObjectDistanceOrderPred(reference)); targets.Sort(new ObjectDistanceOrderPred(me, true));
} }
public void DoMeleeAttackIfReady() public void DoMeleeAttackIfReady()
@@ -113,100 +113,187 @@ namespace Game.AI
return false; return false;
} }
public Unit SelectTarget(SelectAggroTarget targetType, uint position = 0, float dist = 0.0f, bool playerOnly = false, int aura = 0) /// <summary>
/// Select the best target (in <targetType> order) from the threat list that fulfill the following:
/// - Not among the first <offset> entries in <targetType> order (or MAXTHREAT order, if <targetType> is RANDOM).
/// - Within at most <dist> yards (if dist > 0.0f)
/// - At least -<dist> yards away (if dist < 0.0f)
/// - Is a player (if playerOnly = true)
/// - Not the current tank (if withTank = false)
/// - Has aura with ID <aura> (if aura > 0)
/// - Does not have aura with ID -<aura> (if aura < 0)
/// </summary>
public Unit SelectTarget(SelectAggroTarget targetType, uint offset = 0, float dist = 0.0f, bool playerOnly = false, bool withTank = true, int aura = 0)
{ {
return SelectTarget(targetType, position, new DefaultTargetSelector(me, dist, playerOnly, aura)); return SelectTarget(targetType, offset, new DefaultTargetSelector(me, dist, playerOnly, withTank, aura));
} }
// Select the targets satifying the predicate. /// <summary>
public Unit SelectTarget(SelectAggroTarget targetType, uint position, ISelector selector) /// Select the best target (in <targetType> order) satisfying <predicate> from the threat list.
/// If <offset> is nonzero, the first <offset> entries in <targetType> order (or MAXTHREAT order, if <targetType> is RANDOM) are skipped.
/// </summary>
public Unit SelectTarget(SelectAggroTarget targetType, uint offset, ISelector selector)
{ {
var threatlist = GetThreatManager().GetThreatList(); ThreatManager mgr = GetThreatManager();
if (position >= threatlist.Count) // shortcut: if we ignore the first <offset> elements, and there are at most <offset> elements, then we ignore ALL elements
if (mgr.GetThreatListSize() <= offset)
return null; return null;
List<Unit> targetList = new List<Unit>(); List<Unit> targetList = new List<Unit>();
Unit currentVictim = null; if (targetType == SelectAggroTarget.MaxDistance || targetType == SelectAggroTarget.MinDistance)
var currentVictimReference = GetThreatManager().GetCurrentVictim();
if (currentVictimReference != null)
{ {
currentVictim = currentVictimReference.GetTarget(); foreach (HostileReference refe in mgr.GetThreatList())
{
if (!refe.IsOnline())
continue;
// Current victim always goes first targetList.Add(refe.GetTarget());
if (currentVictim && selector.Check(currentVictim)) }
}
else
{
Unit currentVictim = mgr.GetCurrentVictim();
if (currentVictim)
targetList.Add(currentVictim); targetList.Add(currentVictim);
foreach (HostileReference refe in mgr.GetThreatList())
{
if (!refe.IsOnline())
continue;
Unit thisTarget = refe.GetTarget();
if (thisTarget != currentVictim)
targetList.Add(thisTarget);
}
} }
foreach (var hostileRef in threatlist) // filter by predicate
{ targetList.RemoveAll(target => { return !selector.Check(target); });
if (currentVictim != null && hostileRef.GetTarget() != currentVictim && selector.Check(hostileRef.GetTarget())) // shortcut: the list certainly isn't gonna get any larger after this point
targetList.Add(hostileRef.GetTarget()); if (targetList.Count <= offset)
else if (currentVictim == null && selector.Check(hostileRef.GetTarget()))
targetList.Add(hostileRef.GetTarget());
}
if (position >= targetList.Count)
return null; return null;
if (targetType == SelectAggroTarget.Nearest || targetType == SelectAggroTarget.Farthest) // right now, list is unsorted for DISTANCE types - re-sort by MAXDISTANCE
SortByDistanceTo(me, targetList); if (targetType == SelectAggroTarget.MaxDistance || targetType == SelectAggroTarget.MinDistance)
SortByDistance(targetList, targetType == SelectAggroTarget.MinDistance);
// then reverse the sorting for MIN sortings
if (targetType == SelectAggroTarget.MinThreat)
targetList.Reverse();
// now pop the first <offset> elements
while (offset != 0)
{
targetList.RemoveAt(0);
--offset;
}
// maybe nothing fulfills the predicate
if (targetList.Empty())
return null;
switch (targetType) switch (targetType)
{ {
case SelectAggroTarget.Nearest: case SelectAggroTarget.MaxThreat:
case SelectAggroTarget.TopAggro: case SelectAggroTarget.MinThreat:
{ case SelectAggroTarget.MaxDistance:
return targetList.First(); case SelectAggroTarget.MinDistance:
} return targetList[0];
case SelectAggroTarget.Farthest:
case SelectAggroTarget.BottomAggro:
{
return targetList.Last();
}
case SelectAggroTarget.Random: case SelectAggroTarget.Random:
{
return targetList.SelectRandom(); return targetList.SelectRandom();
}
default: default:
break; return null;
} }
return null;
} }
public List<Unit> SelectTargetList(uint num, SelectAggroTarget targetType, float dist, bool playerOnly, int aura = 0) /// <summary>
/// Select the best (up to) <num> targets (in <targetType> order) from the threat list that fulfill the following:
/// - Not among the first <offset> entries in <targetType> order (or MAXTHREAT order, if <targetType> is RANDOM).
/// - Within at most <dist> yards (if dist > 0.0f)
/// - At least -<dist> yards away (if dist < 0.0f)
/// - Is a player (if playerOnly = true)
/// - Not the current tank (if withTank = false)
/// - Has aura with ID <aura> (if aura > 0)
/// - Does not have aura with ID -<aura> (if aura < 0)
/// The resulting targets are stored in <targetList> (which is cleared first).
/// </summary>
public List<Unit> SelectTargetList(uint num, SelectAggroTarget targetType, uint offset, float dist, bool playerOnly, bool withTank, int aura = 0)
{ {
return SelectTargetList(new DefaultTargetSelector(me, dist, playerOnly, aura), num, targetType); return SelectTargetList(num, targetType, offset, new DefaultTargetSelector(me, dist, playerOnly, withTank, aura));
} }
// Select the targets satifying the predicate. /// <summary>
// predicate shall extend std.unary_function<Unit*, bool> /// Select the best (up to) <num> targets (in <targetType> order) satisfying <predicate> from the threat list and stores them in <targetList> (which is cleared first).
public List<Unit> SelectTargetList(ISelector selector, uint maxTargets, SelectAggroTarget targetType) /// If <offset> is nonzero, the first <offset> entries in <targetType> order (or MAXTHREAT order, if <targetType> is RANDOM) are skipped.
/// </summary>
public List<Unit> SelectTargetList(uint num, SelectAggroTarget targetType, uint offset, ISelector selector)
{ {
var targetList = new List<Unit>(); var targetList = new List<Unit>();
var threatlist = GetThreatManager().GetThreatList(); ThreatManager mgr = GetThreatManager();
if (threatlist.Empty()) // shortcut: we're gonna ignore the first <offset> elements, and there's at most <offset> elements, so we ignore them all - nothing to do here
if (mgr.GetThreatListSize() <= offset)
return targetList; return targetList;
foreach (var hostileRef in threatlist) if (targetType == SelectAggroTarget.MaxDistance || targetType == SelectAggroTarget.MinDistance)
if (selector.Check(hostileRef.GetTarget())) {
targetList.Add(hostileRef.GetTarget()); foreach (HostileReference refe in mgr.GetThreatList())
{
if (!refe.IsOnline())
continue;
if (targetList.Count < maxTargets) targetList.Add(refe.GetTarget());
}
}
else
{
Unit currentVictim = mgr.GetCurrentVictim();
if (currentVictim != null)
targetList.Add(currentVictim);
foreach (HostileReference refe in mgr.GetThreatList())
{
if (!refe.IsOnline())
continue;
Unit thisTarget = refe.GetTarget();
if (thisTarget != currentVictim)
targetList.Add(thisTarget);
}
}
// filter by predicate
targetList.RemoveAll(target => { return !selector.Check(target); });
// shortcut: the list isn't gonna get any larger
if (targetList.Count <= offset)
{
targetList.Clear();
return targetList; return targetList;
}
if (targetType == SelectAggroTarget.Nearest || targetType == SelectAggroTarget.Farthest) // right now, list is unsorted for DISTANCE types - re-sort by MAXDISTANCE
SortByDistanceTo(me, targetList); if (targetType == SelectAggroTarget.MaxDistance || targetType == SelectAggroTarget.MinDistance)
SortByDistance(targetList, targetType == SelectAggroTarget.MinDistance);
if (targetType == SelectAggroTarget.Farthest || targetType == SelectAggroTarget.BottomAggro) // now the list is MAX sorted, reverse for MIN types
if (targetType == SelectAggroTarget.MinThreat)
targetList.Reverse(); targetList.Reverse();
// ignore the first <offset> elements
while (offset != 0)
{
targetList.RemoveAt(0);
--offset;
}
if (targetList.Count <= num)
return targetList;
if (targetType == SelectAggroTarget.Random) if (targetType == SelectAggroTarget.Random)
targetList = targetList.SelectRandom(maxTargets).ToList(); targetList = targetList.SelectRandom(num).ToList();
else else
targetList.Resize(maxTargets); targetList.Resize(num);
return targetList; return targetList;
} }
@@ -247,7 +334,7 @@ namespace Game.AI
bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyTargetPlayers); bool playerOnly = spellInfo.HasAttribute(SpellAttr3.OnlyTargetPlayers);
float range = spellInfo.GetMaxRange(false); float range = spellInfo.GetMaxRange(false);
DefaultTargetSelector targetSelector = new DefaultTargetSelector(me, range, playerOnly, -(int)spellId); DefaultTargetSelector targetSelector = new DefaultTargetSelector(me, range, playerOnly, true, -(int)spellId);
if (!spellInfo.HasAuraInterruptFlag(SpellAuraInterruptFlags.NotVictim) if (!spellInfo.HasAuraInterruptFlag(SpellAuraInterruptFlags.NotVictim)
&& targetSelector.Check(me.GetVictim())) && targetSelector.Check(me.GetVictim()))
target = me.GetVictim(); target = me.GetVictim();
@@ -498,11 +585,11 @@ namespace Game.AI
public enum SelectAggroTarget public enum SelectAggroTarget
{ {
Random = 0, //Just selects a random target Random = 0, // just pick a random target
TopAggro, //Selects targes from top aggro to bottom MaxThreat, // prefer targets higher in the threat list
BottomAggro, //Selects targets from bottom aggro to top MinThreat, // prefer targets lower in the threat list
Nearest, MaxDistance, // prefer targets further from us
Farthest MinDistance // prefer targets closer to us
} }
public interface ISelector public interface ISelector
@@ -516,29 +603,34 @@ namespace Game.AI
Unit me; Unit me;
float m_dist; float m_dist;
bool m_playerOnly; bool m_playerOnly;
Unit except;
int m_aura; int m_aura;
// unit: the reference unit /// <param name="unit">the reference unit</param>
// dist: if 0: ignored, if > 0: maximum distance to the reference unit, if < 0: minimum distance to the reference unit /// <param name="dist">if 0: ignored, if > 0: maximum distance to the reference unit, if < 0: minimum distance to the reference unit</param>
// playerOnly: self explaining /// <param name="playerOnly">self explaining</param>
// aura: if 0: ignored, if > 0: the target shall have the aura, if < 0, the target shall NOT have the aura /// <param name="withMainTank">allow current tank to be selected</param>
public DefaultTargetSelector(Unit unit, float dist, bool playerOnly, int aura) /// <param name="aura">if 0: ignored, if > 0: the target shall have the aura, if < 0, the target shall NOT have the aura</param>
public DefaultTargetSelector(Unit unit, float dist, bool playerOnly, bool withMainTank, int aura)
{ {
me = unit; me = unit;
m_dist = dist; m_dist = dist;
m_playerOnly = playerOnly; m_playerOnly = playerOnly;
except = withMainTank ? me.GetThreatManager().GetCurrentVictim() : null;
m_aura = aura; m_aura = aura;
} }
public bool Check(Unit target) public bool Check(Unit target)
{ {
if (me == null) if (me == null)
return false; return false;
if (target == null) if (target == null)
return false; return false;
if (target == except)
return false;
if (m_playerOnly && !target.IsTypeId(TypeId.Player)) if (m_playerOnly && !target.IsTypeId(TypeId.Player))
return false; return false;
@@ -665,9 +757,9 @@ namespace Game.AI
if (_playerOnly && !target.IsTypeId(TypeId.Player)) if (_playerOnly && !target.IsTypeId(TypeId.Player))
return false; return false;
HostileReference currentVictim = _source.GetThreatManager().GetCurrentVictim(); Unit currentVictim = _source.GetThreatManager().GetCurrentVictim();
if (currentVictim != null) if (currentVictim != null)
return target.GetGUID() != currentVictim.GetUnitGuid(); return target != currentVictim;
return target != _source.GetVictim(); return target != _source.GetVictim();
} }
+1 -1
View File
@@ -1243,7 +1243,7 @@ namespace Game.AI
} }
} }
if (charmer.IsInCombat()) if (charmer.IsEngaged())
{ {
Unit target = me.GetVictim(); Unit target = me.GetVictim();
if (!target || !charmer.IsValidAttackTarget(target) || target.HasBreakableByDamageCrowdControlAura()) if (!target || !charmer.IsValidAttackTarget(target) || target.HasBreakableByDamageCrowdControlAura())
+80 -34
View File
@@ -111,6 +111,85 @@ namespace Game.AI
source.PlayDirectSound(soundId); source.PlayDirectSound(soundId);
} }
/// <summary>
/// Add specified amount of threat directly to victim (ignores redirection effects) - also puts victim in combat and engages them if necessary
/// </summary>
/// <param name="victim"></param>
/// <param name="amount"></param>
/// <param name="who"></param>
public void AddThreat(Unit victim, float amount, Unit who = null)
{
if (!victim)
return;
if (!who)
who = me;
who.GetThreatManager().AddThreat(victim, amount, null, true, true);
}
/// <summary>
/// Adds/removes the specified percentage from the specified victim's threat (to who, or me if not specified)
/// </summary>
/// <param name="victim"></param>
/// <param name="pct"></param>
/// <param name="who"></param>
public void ModifyThreatByPercent(Unit victim, int pct, Unit who = null)
{
if (!victim)
return;
if (!who)
who = me;
who.GetThreatManager().ModifyThreatByPercent(victim, pct);
}
/// <summary>
/// Resets the victim's threat level to who (or me if not specified) to zero
/// </summary>
/// <param name="victim"></param>
/// <param name="who"></param>
void ResetThreat(Unit victim, Unit who)
{
if (!victim)
return;
if (!who)
who = me;
who.GetThreatManager().ResetThreat(victim);
}
/// <summary>
/// Resets the specified unit's threat list (me if not specified) - does not delete entries, just sets their threat to zero
/// </summary>
/// <param name="who"></param>
public void ResetThreatList(Unit who = null)
{
if (!who)
who = me;
who.GetThreatManager().ResetAllThreat();
}
/// <summary>
/// Returns the threat level of victim towards who (or me if not specified)
/// </summary>
/// <param name="victim"></param>
/// <param name="who"></param>
/// <returns></returns>
public float GetThreat(Unit victim, Unit who = null)
{
if (!victim)
return 0.0f;
if (!who)
who = me;
return who.GetThreatManager().GetThreat(victim);
}
//Spawns a creature relative to me //Spawns a creature relative to me
public Creature DoSpawnCreature(uint entry, float offsetX, float offsetY, float offsetZ, float angle, TempSummonType type, uint despawntime) public Creature DoSpawnCreature(uint entry, float offsetX, float offsetY, float offsetZ, float angle, TempSummonType type, uint despawntime)
{ {
@@ -182,39 +261,6 @@ namespace Game.AI
return apSpell[RandomHelper.IRand(0, (int)(spellCount - 1))]; return apSpell[RandomHelper.IRand(0, (int)(spellCount - 1))];
} }
//Drops all threat to 0%. Does not remove players from the threat list
public void DoResetThreat()
{
if (!me.CanHaveThreatList() || me.GetThreatManager().IsThreatListEmpty())
{
Log.outError(LogFilter.Scripts, "DoResetThreat called for creature that either cannot have threat list or has empty threat list (me entry = {0})", me.GetEntry());
return;
}
var threatlist = me.GetThreatManager().GetThreatList();
foreach (var refe in threatlist)
{
Unit unit = Global.ObjAccessor.GetUnit(me, refe.GetUnitGuid());
if (unit != null && DoGetThreat(unit) != 0)
DoModifyThreatPercent(unit, -100);
}
}
public float DoGetThreat(Unit unit)
{
if (unit == null)
return 0.0f;
return me.GetThreatManager().GetThreat(unit);
}
public void DoModifyThreatPercent(Unit unit, int pct)
{
if (unit == null)
return;
me.GetThreatManager().ModifyThreatPercent(unit, pct);
}
void DoTeleportTo(float x, float y, float z, uint time = 0) void DoTeleportTo(float x, float y, float z, uint time = 0)
{ {
me.Relocate(x, y, z); me.Relocate(x, y, z);
@@ -499,7 +545,7 @@ namespace Game.AI
public override void JustSummoned(Creature summon) public override void JustSummoned(Creature summon)
{ {
summons.Summon(summon); summons.Summon(summon);
if (me.IsInCombat()) if (me.IsEngaged())
DoZoneInCombat(summon); DoZoneInCombat(summon);
} }
+3 -21
View File
@@ -88,8 +88,7 @@ namespace Game.AI
} }
else else
{ {
who.SetInCombatWith(me); me.EngageWithTarget(who);
me.AddThreat(who, 0.0f);
return true; return true;
} }
} }
@@ -111,24 +110,7 @@ namespace Game.AI
{ {
float fAttackRadius = me.GetAttackDistance(who); float fAttackRadius = me.GetAttackDistance(who);
if (me.IsWithinDistInMap(who, fAttackRadius) && me.IsWithinLOSInMap(who)) if (me.IsWithinDistInMap(who, fAttackRadius) && me.IsWithinLOSInMap(who))
{ me.EngageWithTarget(who);
if (!me.GetVictim())
{
// Clear distracted state on combat
if (me.HasUnitState(UnitState.Distracted))
{
me.ClearUnitState(UnitState.Distracted);
me.GetMotionMaster().Clear();
}
AttackStart(who);
}
else if (me.GetMap().IsDungeon())
{
who.SetInCombatWith(me);
me.AddThreat(who, 0.0f);
}
}
} }
} }
} }
@@ -181,7 +163,7 @@ namespace Game.AI
public override void EnterEvadeMode(EvadeReason why = EvadeReason.Other) public override void EnterEvadeMode(EvadeReason why = EvadeReason.Other)
{ {
me.RemoveAllAuras(); me.RemoveAllAuras();
me.DeleteThreatList(); me.GetThreatManager().ClearAllThreat();
me.CombatStop(true); me.CombatStop(true);
me.SetLootRecipient(null); me.SetLootRecipient(null);
@@ -49,9 +49,7 @@ namespace Game.AI
if (me.Attack(who, true)) if (me.Attack(who, true))
{ {
me.AddThreat(who, 0.0f); me.EngageWithTarget(who); // in case it doesn't have threat+combat yet
me.SetInCombatWith(who);
who.SetInCombatWith(me);
if (me.HasUnitState(UnitState.Follow)) if (me.HasUnitState(UnitState.Follow))
me.ClearUnitState(UnitState.Follow); me.ClearUnitState(UnitState.Follow);
@@ -84,18 +82,8 @@ namespace Game.AI
//too far away and no free sight? //too far away and no free sight?
if (me.IsWithinDistInMap(who, 100.0f) && me.IsWithinLOSInMap(who)) if (me.IsWithinDistInMap(who, 100.0f) && me.IsWithinLOSInMap(who))
{ {
//already fighting someone? me.EngageWithTarget(who);
if (!me.GetVictim()) return true;
{
AttackStart(who);
return true;
}
else
{
who.SetInCombatWith(me);
me.AddThreat(who, 0.0f);
return true;
}
} }
return false; return false;
@@ -128,10 +116,7 @@ namespace Game.AI
AttackStart(who); AttackStart(who);
} }
else if (me.GetMap().IsDungeon()) else if (me.GetMap().IsDungeon())
{ me.EngageWithTarget(who);
who.SetInCombatWith(me);
me.AddThreat(who, 0.0f);
}
} }
} }
} }
@@ -178,7 +163,7 @@ namespace Game.AI
public override void EnterEvadeMode(EvadeReason why) public override void EnterEvadeMode(EvadeReason why)
{ {
me.RemoveAllAuras(); me.RemoveAllAuras();
me.DeleteThreatList(); me.GetThreatManager().ClearAllThreat();
me.CombatStop(true); me.CombatStop(true);
me.SetLootRecipient(null); me.SetLootRecipient(null);
+2 -12
View File
@@ -544,18 +544,8 @@ namespace Game.AI
//too far away and no free sight? //too far away and no free sight?
if (me.IsWithinDistInMap(who, SMART_MAX_AID_DIST) && me.IsWithinLOSInMap(who)) if (me.IsWithinDistInMap(who, SMART_MAX_AID_DIST) && me.IsWithinLOSInMap(who))
{ {
//already fighting someone? me.EngageWithTarget(who);
if (me.GetVictim() == null) return true;
{
AttackStart(who);
return true;
}
else
{
who.SetInCombatWith(me);
me.AddThreat(who, 0.0f);
return true;
}
} }
return false; return false;
+31 -47
View File
@@ -334,16 +334,10 @@ namespace Game.AI
if (me == null) if (me == null)
break; break;
var threatList = me.GetThreatManager().GetThreatList(); foreach (var refe in me.GetThreatManager().GetThreatList())
foreach (var refe in threatList)
{ {
Unit target = Global.ObjAccessor.GetUnit(me, refe.GetUnitGuid()); refe.AddThreatPercent(Math.Max(-100, (int)(e.Action.threatPCT.threatINC - e.Action.threatPCT.threatDEC)));
if (target != null) Log.outDebug(LogFilter.ScriptsAi, $"SmartScript.ProcessAction: SMART_ACTION_THREAT_ALL_PCT: Creature {me.GetGUID()} modify threat for {refe.GetTarget().GetGUID()}, value {e.Action.threatPCT.threatINC - e.Action.threatPCT.threatDEC}");
{
me.GetThreatManager().ModifyThreatPercent(target, e.Action.threatPCT.threatINC != 0 ? (int)e.Action.threatPCT.threatINC : -(int)e.Action.threatPCT.threatDEC);
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction. SMART_ACTION_THREAT_ALL_PCT: Creature guidLow {0} modify threat for unit {1}, value {2}",
me.GetGUID().ToString(), target.GetGUID().ToString(), e.Action.threatPCT.threatINC != 0 ? (int)e.Action.threatPCT.threatINC : -(int)e.Action.threatPCT.threatDEC);
}
} }
break; break;
} }
@@ -356,9 +350,8 @@ namespace Game.AI
{ {
if (IsUnit(target)) if (IsUnit(target))
{ {
me.GetThreatManager().ModifyThreatPercent(target.ToUnit(), e.Action.threatPCT.threatINC != 0 ? (int)e.Action.threatPCT.threatINC : -(int)e.Action.threatPCT.threatDEC); me.GetThreatManager().ModifyThreatByPercent(target.ToUnit(), Math.Max(-100, (int)(e.Action.threatPCT.threatINC - e.Action.threatPCT.threatDEC)));
Log.outDebug(LogFilter.ScriptsAi, "SmartScript.ProcessAction. SMART_ACTION_THREAT_SINGLE_PCT: Creature guidLow {0} modify threat for unit {1}, value {2}", Log.outDebug(LogFilter.ScriptsAi, $"SmartScript.ProcessAction: SMART_ACTION_THREAT_SINGLE_PCT: Creature {me.GetGUID()} modify threat for {target.GetGUID()}, value {e.Action.threatPCT.threatINC - e.Action.threatPCT.threatDEC}");
me.GetGUID().ToString(), target.GetGUID().ToString(), e.Action.threatPCT.threatINC != 0 ? (int)e.Action.threatPCT.threatINC : -(int)e.Action.threatPCT.threatDEC);
} }
} }
break; break;
@@ -2094,7 +2087,7 @@ namespace Game.AI
{ {
foreach (var target in targets) foreach (var target in targets)
if (IsUnit(target)) if (IsUnit(target))
me.AddThreat(target.ToUnit(), (float)e.Action.threatPCT.threatINC - (float)e.Action.threatPCT.threatDEC); me.GetThreatManager().AddThreat(target.ToUnit(), (float)(e.Action.threatPCT.threatINC - (float)e.Action.threatPCT.threatDEC), null, true, true);
break; break;
} }
@@ -2377,13 +2370,13 @@ namespace Game.AI
{ {
if (e.Target.hostilRandom.powerType != 0) if (e.Target.hostilRandom.powerType != 0)
{ {
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.TopAggro, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0)); Unit u = me.GetAI().SelectTarget(SelectAggroTarget.MaxThreat, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0));
if (u != null) if (u != null)
targets.Add(u); targets.Add(u);
} }
else else
{ {
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.TopAggro, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0); Unit u = me.GetAI().SelectTarget(SelectAggroTarget.MaxThreat, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0);
if (u != null) if (u != null)
targets.Add(u); targets.Add(u);
} }
@@ -2394,13 +2387,13 @@ namespace Game.AI
{ {
if (e.Target.hostilRandom.powerType != 0) if (e.Target.hostilRandom.powerType != 0)
{ {
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.BottomAggro, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0)); Unit u = me.GetAI().SelectTarget(SelectAggroTarget.MinThreat, 1, new PowerUsersSelector(me, (PowerType)(e.Target.hostilRandom.powerType - 1), (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0));
if (u != null) if (u != null)
targets.Add(u); targets.Add(u);
} }
else else
{ {
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.BottomAggro, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0); Unit u = me.GetAI().SelectTarget(SelectAggroTarget.MinThreat, 1, (float)e.Target.hostilRandom.maxDist, e.Target.hostilRandom.playerOnly != 0);
if (u != null) if (u != null)
targets.Add(u); targets.Add(u);
} }
@@ -2443,7 +2436,7 @@ namespace Game.AI
case SmartTargets.Farthest: case SmartTargets.Farthest:
if (me) if (me)
{ {
Unit u = me.GetAI().SelectTarget(SelectAggroTarget.Farthest, 0, new FarthestTargetSelector(me, (float)e.Target.farthest.maxDist, e.Target.farthest.playerOnly != 0, e.Target.farthest.isInLos != 0)); Unit u = me.GetAI().SelectTarget(SelectAggroTarget.MaxDistance, 0, new FarthestTargetSelector(me, (float)e.Target.farthest.maxDist, e.Target.farthest.playerOnly != 0, e.Target.farthest.isInLos != 0));
if (u != null) if (u != null)
targets.Add(u); targets.Add(u);
} }
@@ -2674,16 +2667,12 @@ namespace Game.AI
} }
case SmartTargets.ThreatList: case SmartTargets.ThreatList:
{ {
if (me != null) if (me != null && me.CanHaveThreatList())
{ {
var threatList = me.GetThreatManager().GetThreatList(); var threatList = me.GetThreatManager().GetThreatList();
foreach (var refe in threatList) foreach (var refe in me.GetThreatManager().GetThreatList())
{ if (e.Target.hostilRandom.maxDist == 0 || me.IsWithinCombatRange(refe.GetTarget(), e.Target.hostilRandom.maxDist))
Unit temp = Global.ObjAccessor.GetUnit(me, refe.GetUnitGuid()); targets.Add(refe.GetTarget());
if (temp != null)
if (e.Target.hostilRandom.maxDist == 0 || me.IsWithinCombatRange(temp, (float)e.Target.hostilRandom.maxDist))
targets.Add(temp);
}
} }
break; break;
} }
@@ -2790,18 +2779,18 @@ namespace Game.AI
ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax); ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax);
break; break;
case SmartEvents.UpdateOoc: case SmartEvents.UpdateOoc:
if (me != null && me.IsInCombat()) if (me != null && me.IsEngaged())
return; return;
ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax); ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax);
break; break;
case SmartEvents.UpdateIc: case SmartEvents.UpdateIc:
if (me == null || !me.IsInCombat()) if (me == null || !me.IsEngaged())
return; return;
ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax); ProcessTimedAction(e, e.Event.minMaxRepeat.repeatMin, e.Event.minMaxRepeat.repeatMax);
break; break;
case SmartEvents.HealthPct: case SmartEvents.HealthPct:
{ {
if (me == null || !me.IsInCombat() || me.GetMaxHealth() == 0) if (me == null || !me.IsEngaged() || me.GetMaxHealth() == 0)
return; return;
uint perc = (uint)me.GetHealthPct(); uint perc = (uint)me.GetHealthPct();
if (perc > e.Event.minMaxRepeat.max || perc < e.Event.minMaxRepeat.min) if (perc > e.Event.minMaxRepeat.max || perc < e.Event.minMaxRepeat.min)
@@ -2811,7 +2800,7 @@ namespace Game.AI
} }
case SmartEvents.TargetHealthPct: case SmartEvents.TargetHealthPct:
{ {
if (me == null || !me.IsInCombat() || me.GetVictim() == null || me.GetVictim().GetMaxHealth() == 0) if (me == null || !me.IsEngaged() || me.GetVictim() == null || me.GetVictim().GetMaxHealth() == 0)
return; return;
uint perc = (uint)me.GetVictim().GetHealthPct(); uint perc = (uint)me.GetVictim().GetHealthPct();
if (perc > e.Event.minMaxRepeat.max || perc < e.Event.minMaxRepeat.min) if (perc > e.Event.minMaxRepeat.max || perc < e.Event.minMaxRepeat.min)
@@ -2821,7 +2810,7 @@ namespace Game.AI
} }
case SmartEvents.ManaPct: case SmartEvents.ManaPct:
{ {
if (me == null || !me.IsInCombat() || me.GetMaxPower(PowerType.Mana) == 0) if (me == null || !me.IsEngaged() || me.GetMaxPower(PowerType.Mana) == 0)
return; return;
uint perc = (uint)me.GetPowerPct(PowerType.Mana); uint perc = (uint)me.GetPowerPct(PowerType.Mana);
if (perc > e.Event.minMaxRepeat.max || perc < e.Event.minMaxRepeat.min) if (perc > e.Event.minMaxRepeat.max || perc < e.Event.minMaxRepeat.min)
@@ -2831,7 +2820,7 @@ namespace Game.AI
} }
case SmartEvents.TargetManaPct: case SmartEvents.TargetManaPct:
{ {
if (me == null || !me.IsInCombat() || me.GetVictim() == null || me.GetVictim().GetMaxPower(PowerType.Mana) == 0) if (me == null || !me.IsEngaged() || me.GetVictim() == null || me.GetVictim().GetMaxPower(PowerType.Mana) == 0)
return; return;
uint perc = (uint)me.GetVictim().GetPowerPct(PowerType.Mana); uint perc = (uint)me.GetVictim().GetPowerPct(PowerType.Mana);
if (perc > e.Event.minMaxRepeat.max || perc < e.Event.minMaxRepeat.min) if (perc > e.Event.minMaxRepeat.max || perc < e.Event.minMaxRepeat.min)
@@ -2841,7 +2830,7 @@ namespace Game.AI
} }
case SmartEvents.Range: case SmartEvents.Range:
{ {
if (me == null || !me.IsInCombat() || me.GetVictim() == null) if (me == null || !me.IsEngaged() || me.GetVictim() == null)
return; return;
if (me.IsInRange(me.GetVictim(), e.Event.minMaxRepeat.min, e.Event.minMaxRepeat.max)) if (me.IsInRange(me.GetVictim(), e.Event.minMaxRepeat.min, e.Event.minMaxRepeat.max))
@@ -2852,7 +2841,7 @@ namespace Game.AI
} }
case SmartEvents.VictimCasting: case SmartEvents.VictimCasting:
{ {
if (me == null || !me.IsInCombat()) if (me == null || !me.IsEngaged())
return; return;
Unit victim = me.GetVictim(); Unit victim = me.GetVictim();
@@ -2873,7 +2862,7 @@ namespace Game.AI
} }
case SmartEvents.FriendlyHealth: case SmartEvents.FriendlyHealth:
{ {
if (me == null || !me.IsInCombat()) if (me == null || !me.IsEngaged())
return; return;
Unit target = DoSelectLowestHpFriendly(e.Event.friendlyHealth.radius, e.Event.friendlyHealth.hpDeficit); Unit target = DoSelectLowestHpFriendly(e.Event.friendlyHealth.radius, e.Event.friendlyHealth.hpDeficit);
@@ -2889,7 +2878,7 @@ namespace Game.AI
} }
case SmartEvents.FriendlyIsCc: case SmartEvents.FriendlyIsCc:
{ {
if (me == null || !me.IsInCombat()) if (me == null || !me.IsEngaged())
return; return;
List<Creature> creatures = new List<Creature>(); List<Creature> creatures = new List<Creature>();
@@ -3016,7 +3005,7 @@ namespace Game.AI
} }
case SmartEvents.OocLos: case SmartEvents.OocLos:
{ {
if (me == null || me.IsInCombat()) if (me == null || me.IsEngaged())
return; return;
//can trigger if closer than fMaxAllowedRange //can trigger if closer than fMaxAllowedRange
float range = e.Event.los.maxDist; float range = e.Event.los.maxDist;
@@ -3036,7 +3025,7 @@ namespace Game.AI
} }
case SmartEvents.IcLos: case SmartEvents.IcLos:
{ {
if (me == null || !me.IsInCombat()) if (me == null || !me.IsEngaged())
return; return;
//can trigger if closer than fMaxAllowedRange //can trigger if closer than fMaxAllowedRange
float range = e.Event.los.maxDist; float range = e.Event.los.maxDist;
@@ -3226,7 +3215,7 @@ namespace Game.AI
} }
case SmartEvents.FriendlyHealthPCT: case SmartEvents.FriendlyHealthPCT:
{ {
if (me == null || !me.IsInCombat()) if (me == null || !me.IsEngaged())
return; return;
List<WorldObject> targets; List<WorldObject> targets;
@@ -3401,10 +3390,10 @@ namespace Game.AI
if (e.Event.event_phase_mask != 0 && !IsInPhase(e.Event.event_phase_mask)) if (e.Event.event_phase_mask != 0 && !IsInPhase(e.Event.event_phase_mask))
return; return;
if (e.GetEventType() == SmartEvents.UpdateIc && (me == null || !me.IsInCombat())) if (e.GetEventType() == SmartEvents.UpdateIc && (me == null || !me.IsEngaged()))
return; return;
if (e.GetEventType() == SmartEvents.UpdateOoc && (me != null && me.IsInCombat()))//can be used with me=NULL (go script) if (e.GetEventType() == SmartEvents.UpdateOoc && (me != null && me.IsEngaged()))//can be used with me=NULL (go script)
return; return;
if (e.timer < diff) if (e.timer < diff)
@@ -3741,15 +3730,10 @@ namespace Game.AI
public void OnMoveInLineOfSight(Unit who) public void OnMoveInLineOfSight(Unit who)
{ {
ProcessEventsFor(SmartEvents.OocLos, who);
if (me == null) if (me == null)
return; return;
if (me.GetVictim() != null) ProcessEventsFor(me.IsEngaged() ? SmartEvents.IcLos : SmartEvents.OocLos, who);
return;
ProcessEventsFor(SmartEvents.IcLos, who);
} }
Unit DoSelectLowestHpFriendly(float range, uint MinHPDiff) Unit DoSelectLowestHpFriendly(float range, uint MinHPDiff)
+2
View File
@@ -209,10 +209,12 @@ namespace Game.Combat
{ {
GetTarget().AddHatedBy(this); GetTarget().AddHatedBy(this);
} }
public override void TargetObjectDestroyLink() public override void TargetObjectDestroyLink()
{ {
GetTarget().RemoveHatedBy(this); GetTarget().RemoveHatedBy(this);
} }
public override void SourceObjectDestroyLink() public override void SourceObjectDestroyLink()
{ {
SetOnlineOfflineState(false); SetOnlineOfflineState(false);
+82 -19
View File
@@ -36,6 +36,28 @@ namespace Game.Combat
const int ThreatUpdateInternal = 1 * Time.InMilliseconds; const int ThreatUpdateInternal = 1 * Time.InMilliseconds;
public void ForwardThreatForAssistingMe(Unit victim, float amount, SpellInfo spell, bool ignoreModifiers = false, bool ignoreRedirection = false)
{
GetOwner().GetHostileRefManager().ThreatAssist(victim, amount, spell);
}
public void AddThreat(Unit victim, float amount, SpellInfo spell, bool ignoreModifiers = false, bool ignoreRedirection = false)
{
if (!Owner.CanHaveThreatList() || Owner.HasUnitState(UnitState.Evade))
return;
Owner.SetInCombatWith(victim);
victim.SetInCombatWith(Owner);
AddThreat(victim, amount, spell != null ? spell.GetSchoolMask() : victim.GetMeleeDamageSchoolMask(), spell);
}
public void ClearAllThreat()
{
if (Owner.CanHaveThreatList(true) && !IsThreatListEmpty())
Owner.SendClearThreatList();
ClearReferences();
}
public void ClearReferences() public void ClearReferences()
{ {
threatContainer.ClearReferences(); threatContainer.ClearReferences();
@@ -111,17 +133,17 @@ namespace Game.Combat
} }
} }
public void ModifyThreatPercent(Unit victim, int percent) public void ModifyThreatByPercent(Unit victim, int percent)
{ {
threatContainer.ModifyThreatPercent(victim, percent); threatContainer.ModifyThreatByPercent(victim, percent);
} }
public Unit GetHostilTarget() public Unit GetHostilTarget()
{ {
threatContainer.Update(); threatContainer.Update();
HostileReference nextVictim = threatContainer.SelectNextVictim(GetOwner().ToCreature(), GetCurrentVictim()); HostileReference nextVictim = threatContainer.SelectNextVictim(GetOwner().ToCreature(), getCurrentVictim());
SetCurrentVictim(nextVictim); SetCurrentVictim(nextVictim);
return GetCurrentVictim() != null ? GetCurrentVictim().GetTarget() : null; return GetCurrentVictim() != null ? GetCurrentVictim() : null;
} }
public float GetThreat(Unit victim, bool alsoSearchOfflineList = false) public float GetThreat(Unit victim, bool alsoSearchOfflineList = false)
@@ -138,10 +160,10 @@ namespace Game.Combat
void TauntApply(Unit taunter) void TauntApply(Unit taunter)
{ {
HostileReference refe = threatContainer.GetReferenceByTarget(taunter); HostileReference refe = threatContainer.GetReferenceByTarget(taunter);
if (GetCurrentVictim() != null && refe != null && (refe.GetThreat() < GetCurrentVictim().GetThreat())) if (GetCurrentVictim() != null && refe != null && (refe.GetThreat() < getCurrentVictim().GetThreat()))
{ {
if (refe.GetTempThreatModifier() == 0.0f) // Ok, temp threat is unused if (refe.GetTempThreatModifier() == 0.0f) // Ok, temp threat is unused
refe.SetTempThreat(GetCurrentVictim().GetThreat()); refe.SetTempThreat(getCurrentVictim().GetThreat());
} }
} }
@@ -170,14 +192,14 @@ namespace Game.Combat
switch (threatRefStatusChangeEvent.GetEventType()) switch (threatRefStatusChangeEvent.GetEventType())
{ {
case UnitEventTypes.ThreatRefThreatChange: case UnitEventTypes.ThreatRefThreatChange:
if ((GetCurrentVictim() == hostilRef && threatRefStatusChangeEvent.GetFValue() < 0.0f) || if ((getCurrentVictim() == hostilRef && threatRefStatusChangeEvent.GetFValue() < 0.0f) ||
(GetCurrentVictim() != hostilRef && threatRefStatusChangeEvent.GetFValue() > 0.0f)) (getCurrentVictim() != hostilRef && threatRefStatusChangeEvent.GetFValue() > 0.0f))
SetDirty(true); // the order in the threat list might have changed SetDirty(true); // the order in the threat list might have changed
break; break;
case UnitEventTypes.ThreatRefOnlineStatus: case UnitEventTypes.ThreatRefOnlineStatus:
if (!hostilRef.IsOnline()) if (!hostilRef.IsOnline())
{ {
if (hostilRef == GetCurrentVictim()) if (hostilRef == getCurrentVictim())
{ {
SetCurrentVictim(null); SetCurrentVictim(null);
SetDirty(true); SetDirty(true);
@@ -188,14 +210,14 @@ namespace Game.Combat
} }
else else
{ {
if (GetCurrentVictim() != null && hostilRef.GetThreat() > (1.1f * GetCurrentVictim().GetThreat())) if (GetCurrentVictim() != null && hostilRef.GetThreat() > (1.1f * getCurrentVictim().GetThreat()))
SetDirty(true); SetDirty(true);
threatContainer.AddReference(hostilRef); threatContainer.AddReference(hostilRef);
threatOfflineContainer.Remove(hostilRef); threatOfflineContainer.Remove(hostilRef);
} }
break; break;
case UnitEventTypes.ThreatRefRemoveFromList: case UnitEventTypes.ThreatRefRemoveFromList:
if (hostilRef == GetCurrentVictim()) if (hostilRef == getCurrentVictim())
{ {
SetCurrentVictim(null); SetCurrentVictim(null);
SetDirty(true); SetDirty(true);
@@ -209,7 +231,6 @@ namespace Game.Combat
} }
} }
public bool IsNeedUpdateToClient(uint time) public bool IsNeedUpdateToClient(uint time)
{ {
if (IsThreatListEmpty()) if (IsThreatListEmpty())
@@ -245,10 +266,7 @@ namespace Game.Combat
return threatContainer.Empty() && threatOfflineContainer.Empty(); return threatContainer.Empty() && threatOfflineContainer.Empty();
} }
public HostileReference GetCurrentVictim() public HostileReference getCurrentVictim() { return currentVictim; }
{
return currentVictim;
}
public Unit GetOwner() public Unit GetOwner()
{ {
@@ -264,8 +282,53 @@ namespace Game.Combat
public List<HostileReference> GetOfflineThreatList() { return threatOfflineContainer.GetThreatList(); } public List<HostileReference> GetOfflineThreatList() { return threatOfflineContainer.GetThreatList(); }
public ThreatContainer GetOnlineContainer() { return threatContainer; } public ThreatContainer GetOnlineContainer() { return threatContainer; }
// The hatingUnit is not used yet public Unit SelectVictim() { return GetHostilTarget(); }
public static float CalcThreat(Unit hatedUnit, Unit hatingUnit, float threat, SpellSchoolMask schoolMask = SpellSchoolMask.Normal, SpellInfo threatSpell = null) public Unit GetCurrentVictim()
{
var refe = getCurrentVictim();
if (refe != null)
return refe.GetTarget();
else
return null;
}
public bool IsThreatListEmpty(bool includeOffline = false) { return includeOffline ? IsThreatListsEmpty() : IsThreatListEmpty(); }
public bool IsThreatenedBy(Unit who, bool includeOffline = false) { return FindReference(who, includeOffline) != null; }
public int GetThreatListSize() { return threatContainer.threatList.Count; }
public Unit GetAnyTarget()
{
var list = GetThreatList();
if (!list.Empty())
return list[0].GetTarget();
return null;
}
public void ResetThreat(Unit who)
{
var refe = FindReference(who, true);
if (refe != null)
refe.SetThreat(0.0f);
}
public void ResetAllThreat() { ResetAllAggro(); }
HostileReference FindReference(Unit who, bool includeOffline)
{
var refe = threatContainer.GetReferenceByTarget(who);
if (refe != null)
return refe;
if (includeOffline)
{
var offlineRefe = threatOfflineContainer.GetReferenceByTarget(who);
if (offlineRefe != null)
return offlineRefe;
}
return null;
}
// The hatingUnit is not used yet
public static float CalcThreat(Unit hatedUnit, Unit hatingUnit, float threat, SpellSchoolMask schoolMask = SpellSchoolMask.Normal, SpellInfo threatSpell = null)
{ {
if (threatSpell != null) if (threatSpell != null)
{ {
@@ -370,7 +433,7 @@ namespace Game.Combat
return reff; return reff;
} }
public void ModifyThreatPercent(Unit victim, int percent) public void ModifyThreatByPercent(Unit victim, int percent)
{ {
HostileReference refe = GetReferenceByTarget(victim); HostileReference refe = GetReferenceByTarget(victim);
if (refe != null) if (refe != null)
+8 -21
View File
@@ -475,7 +475,7 @@ namespace Game.Entities
} }
// periodic check to see if the creature has passed an evade boundary // periodic check to see if the creature has passed an evade boundary
if (IsAIEnabled && !IsInEvadeMode() && IsInCombat()) if (IsAIEnabled && !IsInEvadeMode() && IsEngaged())
{ {
if (diff >= m_boundaryCheckTime) if (diff >= m_boundaryCheckTime)
{ {
@@ -487,7 +487,7 @@ namespace Game.Entities
} }
// if periodic combat pulse is enabled and we are both in combat and in a dungeon, do this now // if periodic combat pulse is enabled and we are both in combat and in a dungeon, do this now
if (m_combatPulseDelay > 0 && IsInCombat() && GetMap().IsDungeon()) if (m_combatPulseDelay > 0 && IsEngaged() && GetMap().IsDungeon())
{ {
if (diff > m_combatPulseTime) if (diff > m_combatPulseTime)
m_combatPulseTime = 0; m_combatPulseTime = 0;
@@ -503,12 +503,7 @@ namespace Game.Entities
continue; continue;
if (player.IsAlive() && IsHostileTo(player)) if (player.IsAlive() && IsHostileTo(player))
{ EngageWithTarget(player);
if (CanHaveThreatList())
AddThreat(player, 0.0f);
SetInCombatWith(player);
player.SetInCombatWith(this);
}
} }
m_combatPulseTime = m_combatPulseDelay * Time.InMilliseconds; m_combatPulseTime = m_combatPulseDelay * Time.InMilliseconds;
} }
@@ -1484,7 +1479,7 @@ namespace Game.Entities
if (!_IsTargetAcceptable(who)) if (!_IsTargetAcceptable(who))
return false; return false;
if (who.IsInCombat() && IsWithinDist(who, SharedConst.AttackDistance)) if (who.IsEngaged() && IsWithinDist(who, SharedConst.AttackDistance))
{ {
Unit victim = who.GetAttackerForHelper(); Unit victim = who.GetAttackerForHelper();
if (victim != null) if (victim != null)
@@ -2022,7 +2017,7 @@ namespace Game.Entities
return false; return false;
// skip fighting creature // skip fighting creature
if (IsInCombat()) if (IsEngaged())
return false; return false;
// only free creature // only free creature
@@ -2067,7 +2062,7 @@ namespace Game.Entities
Unit targetVictim = target.GetAttackerForHelper(); Unit targetVictim = target.GetAttackerForHelper();
// if I'm already fighting target, or I'm hostile towards the target, the target is acceptable // if I'm already fighting target, or I'm hostile towards the target, the target is acceptable
if (IsInCombatWith(target) || IsHostileTo(target)) if (IsEngagedBy(target) || IsHostileTo(target))
return true; return true;
// if the target's victim is friendly, and the target is neutral, the target is acceptable // if the target's victim is friendly, and the target is neutral, the target is acceptable
@@ -2256,7 +2251,6 @@ namespace Game.Entities
} }
var PlList = map.GetPlayers(); var PlList = map.GetPlayers();
if (PlList.Empty()) if (PlList.Empty())
return; return;
@@ -2266,12 +2260,7 @@ namespace Game.Entities
continue; continue;
if (player.IsAlive()) if (player.IsAlive())
{ EngageWithTarget(player);
SetInCombatWith(player);
player.SetInCombatWith(this);
AddThreat(player, 0.0f);
}
} }
} }
@@ -3270,9 +3259,7 @@ namespace Game.Entities
if (assistant != null && assistant.CanAssistTo(m_owner, victim)) if (assistant != null && assistant.CanAssistTo(m_owner, victim))
{ {
assistant.SetNoCallAssistance(true); assistant.SetNoCallAssistance(true);
assistant.CombatStart(victim); assistant.EngageWithTarget(victim);
if (assistant.IsAIEnabled)
assistant.GetAI().AttackStart(victim);
} }
} }
} }
@@ -170,7 +170,7 @@ namespace Game.Entities
member.SetFormation(null); member.SetFormation(null);
} }
public void MemberAttackStart(Creature member, Unit target) public void MemberEngagingTarget(Creature member, Unit target)
{ {
GroupAIFlags groupAI = (GroupAIFlags)FormationMgr.CreatureGroupMap[member.GetSpawnId()].groupAI; GroupAIFlags groupAI = (GroupAIFlags)FormationMgr.CreatureGroupMap[member.GetSpawnId()].groupAI;
if (groupAI == 0) if (groupAI == 0)
@@ -186,9 +186,6 @@ namespace Game.Entities
foreach (var pair in m_members) foreach (var pair in m_members)
{ {
if (m_leader) // avoid crash if leader was killed and reset.
Log.outDebug(LogFilter.Unit, "GROUP ATTACK: group instance id {0} calls member instid {1}", m_leader.GetInstanceId(), member.GetInstanceId());
Creature other = pair.Key; Creature other = pair.Key;
// Skip self // Skip self
@@ -198,11 +195,8 @@ namespace Game.Entities
if (!other.IsAlive()) if (!other.IsAlive())
continue; continue;
if (other.GetVictim())
continue;
if (((other != m_leader && groupAI.HasAnyFlag(GroupAIFlags.MembersAssistLeader)) || (other == m_leader && groupAI.HasAnyFlag(GroupAIFlags.LeaderAssistsMember))) && other.IsValidAttackTarget(target)) if (((other != m_leader && groupAI.HasAnyFlag(GroupAIFlags.MembersAssistLeader)) || (other == m_leader && groupAI.HasAnyFlag(GroupAIFlags.LeaderAssistsMember))) && other.IsValidAttackTarget(target))
other.GetAI().AttackStart(target); other.EngageWithTarget(target);
} }
} }
+1 -4
View File
@@ -1738,9 +1738,7 @@ namespace Game.Entities
public void AddToNotify(NotifyFlags f) { m_notifyflags |= f; } public void AddToNotify(NotifyFlags f) { m_notifyflags |= f; }
public bool IsNeedNotify(NotifyFlags f) { return Convert.ToBoolean(m_notifyflags & f); } public bool IsNeedNotify(NotifyFlags f) { return Convert.ToBoolean(m_notifyflags & f); }
NotifyFlags GetNotifyFlags() { return m_notifyflags; } NotifyFlags GetNotifyFlags() { return m_notifyflags; }
bool NotifyExecuted(NotifyFlags f) { return Convert.ToBoolean(m_executed_notifies & f); } public void ResetAllNotifies() { m_notifyflags = 0; }
void SetNotified(NotifyFlags f) { m_executed_notifies |= f; }
public void ResetAllNotifies() { m_notifyflags = 0; m_executed_notifies = 0; }
public bool IsActiveObject() { return m_isActive; } public bool IsActiveObject() { return m_isActive; }
public bool IsPermanentWorldObject() { return m_isWorldObject; } public bool IsPermanentWorldObject() { return m_isWorldObject; }
@@ -2363,7 +2361,6 @@ namespace Game.Entities
public bool IsInWorld { get; set; } public bool IsInWorld { get; set; }
NotifyFlags m_notifyflags; NotifyFlags m_notifyflags;
NotifyFlags m_executed_notifies;
public FlaggedArray<StealthType> m_stealth = new FlaggedArray<StealthType>(2); public FlaggedArray<StealthType> m_stealth = new FlaggedArray<StealthType>(2);
public FlaggedArray<StealthType> m_stealthDetect = new FlaggedArray<StealthType>(2); public FlaggedArray<StealthType> m_stealthDetect = new FlaggedArray<StealthType>(2);
+26 -2
View File
@@ -22,6 +22,7 @@ using Game.Networking.Packets;
using Game.Spells; using Game.Spells;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Game.Maps;
namespace Game.Entities namespace Game.Entities
{ {
@@ -485,15 +486,38 @@ namespace Game.Entities
} }
} }
public void SetContestedPvP(Player attackedPlayer = null)
{
if (attackedPlayer != null && (attackedPlayer == this || (duel != null && duel.opponent == attackedPlayer)))
return;
SetContestedPvPTimer(30000);
if (!HasUnitState(UnitState.AttackPlayer))
{
AddUnitState(UnitState.AttackPlayer);
AddPlayerFlag(PlayerFlags.ContestedPVP);
// call MoveInLineOfSight for nearby contested guards
AIRelocationNotifier notifier = new AIRelocationNotifier(this);
Cell.VisitWorldObjects(this, notifier, GetVisibilityRange());
}
foreach (Unit unit in m_Controlled)
{
if (!unit.HasUnitState(UnitState.AttackPlayer))
{
unit.AddUnitState(UnitState.AttackPlayer);
AIRelocationNotifier notifier = new AIRelocationNotifier(unit);
Cell.VisitWorldObjects(this, notifier, GetVisibilityRange());
}
}
}
public void UpdateContestedPvP(uint diff) public void UpdateContestedPvP(uint diff)
{ {
if (m_contestedPvPTimer == 0 || IsInCombat()) if (m_contestedPvPTimer == 0 || IsInCombat())
return; return;
if (m_contestedPvPTimer <= diff) if (m_contestedPvPTimer <= diff)
{
ResetContestedPvP(); ResetContestedPvP();
}
else else
m_contestedPvPTimer -= diff; m_contestedPvPTimer -= diff;
} }
+24 -45
View File
@@ -125,7 +125,7 @@ namespace Game.Entities
public virtual void SetCanDualWield(bool value) { m_canDualWield = value; } public virtual void SetCanDualWield(bool value) { m_canDualWield = value; }
void SendClearThreatList() public void SendClearThreatList()
{ {
ThreatClear packet = new ThreatClear(); ThreatClear packet = new ThreatClear();
packet.UnitGUID = GetGUID(); packet.UnitGUID = GetGUID();
@@ -158,13 +158,6 @@ namespace Game.Entities
} }
} }
public void DeleteThreatList()
{
if (CanHaveThreatList(true) && !threatManager.IsThreatListEmpty())
SendClearThreatList();
threatManager.ClearReferences();
}
public void TauntApply(Unit taunter) public void TauntApply(Unit taunter)
{ {
Cypher.Assert(IsTypeId(TypeId.Unit)); Cypher.Assert(IsTypeId(TypeId.Unit));
@@ -325,12 +318,6 @@ namespace Game.Entities
} }
public void RemoveHatedBy(HostileReference pHostileReference) { } //nothing to do yet public void RemoveHatedBy(HostileReference pHostileReference) { } //nothing to do yet
public void AddThreat(Unit victim, float fThreat, SpellSchoolMask schoolMask = SpellSchoolMask.Normal, SpellInfo threatSpell = null)
{
// Only mobs can manage threat lists
if (CanHaveThreatList() && !HasUnitState(UnitState.Evade))
threatManager.AddThreat(victim, fThreat, schoolMask, threatSpell);
}
public float ApplyTotalThreatModifier(float fThreat, SpellSchoolMask schoolMask = SpellSchoolMask.Normal) public float ApplyTotalThreatModifier(float fThreat, SpellSchoolMask schoolMask = SpellSchoolMask.Normal)
{ {
if (!HasAuraType(AuraType.ModThreat) || fThreat < 0) if (!HasAuraType(AuraType.ModThreat) || fThreat < 0)
@@ -360,6 +347,17 @@ namespace Game.Entities
return m_deathState; return m_deathState;
} }
public bool IsEngaged() { return IsInCombat(); }
public bool IsEngagedBy(Unit who) { return IsInCombatWith(who); }
public void EngageWithTarget(Unit who)
{
SetInCombatWith(who);
who.SetInCombatWith(this);
GetThreatManager().AddThreat(who, 0.0f);
}
public bool IsThreatened() { return CanHaveThreatList() && !GetThreatManager().IsThreatListEmpty(); }
public bool IsThreatenedBy(Unit who) { return who != null && CanHaveThreatList() && GetThreatManager().IsThreatenedBy(who); }
public bool IsInCombat() { return HasUnitFlag(UnitFlags.InCombat); } public bool IsInCombat() { return HasUnitFlag(UnitFlags.InCombat); }
public bool IsPetInCombat() { return HasUnitFlag(UnitFlags.PetInCombat); } public bool IsPetInCombat() { return HasUnitFlag(UnitFlags.PetInCombat); }
@@ -444,7 +442,7 @@ namespace Game.Entities
if (creature != null && !IsPet()) if (creature != null && !IsPet())
{ {
// should not let player enter combat by right clicking target - doesn't helps // should not let player enter combat by right clicking target - doesn't helps
AddThreat(victim, 0.0f); GetThreatManager().AddThreat(victim, 0.0f);
SetInCombatWith(victim); SetInCombatWith(victim);
if (victim.IsTypeId(TypeId.Player)) if (victim.IsTypeId(TypeId.Player))
@@ -453,7 +451,7 @@ namespace Game.Entities
Unit owner = victim.GetOwner(); Unit owner = victim.GetOwner();
if (owner != null) if (owner != null)
{ {
AddThreat(owner, 0.0f); GetThreatManager().AddThreat(owner, 0.0f);
SetInCombatWith(owner); SetInCombatWith(owner);
if (owner.GetTypeId() == TypeId.Player) if (owner.GetTypeId() == TypeId.Player)
owner.SetInCombatWith(this); owner.SetInCombatWith(this);
@@ -553,6 +551,9 @@ namespace Game.Entities
} }
public Unit GetAttackerForHelper() public Unit GetAttackerForHelper()
{ {
if (!IsEngaged())
return null;
Unit victim = GetVictim(); Unit victim = GetVictim();
if (victim != null) if (victim != null)
if ((!IsPet() && GetPlayerMovingMe() == null) || IsInCombatWith(victim) || victim.IsInCombatWith(this)) if ((!IsPet() && GetPlayerMovingMe() == null) || IsInCombatWith(victim) || victim.IsInCombatWith(this))
@@ -1143,7 +1144,7 @@ namespace Game.Entities
if (damagetype != DamageEffectType.DOT && damage > 0 && !victim.GetOwnerGUID().IsPlayer() && (spellProto == null || !spellProto.HasAura(AuraType.DamageShield))) if (damagetype != DamageEffectType.DOT && damage > 0 && !victim.GetOwnerGUID().IsPlayer() && (spellProto == null || !spellProto.HasAura(AuraType.DamageShield)))
victim.ToCreature().SetLastDamagedTime(GameTime.GetGameTime() + SharedConst.MaxAggroResetTime); victim.ToCreature().SetLastDamagedTime(GameTime.GetGameTime() + SharedConst.MaxAggroResetTime);
victim.AddThreat(this, damage, damageSchoolMask, spellProto); victim.GetThreatManager().AddThreat(this, damage, spellProto);
} }
else // victim is a player else // victim is a player
{ {
@@ -1338,11 +1339,12 @@ namespace Game.Entities
SetInCombatWith(target); SetInCombatWith(target);
target.SetInCombatWith(this); target.SetInCombatWith(this);
} }
Unit who = target.GetCharmerOrOwnerOrSelf();
if (who.IsTypeId(TypeId.Player))
SetContestedPvP(who.ToPlayer());
Player me = GetCharmerOrOwnerPlayerOrPlayerItself(); Player me = GetCharmerOrOwnerPlayerOrPlayerItself();
Unit who = target.GetCharmerOrOwnerOrSelf();
if (me != null && who.IsTypeId(TypeId.Player))
me.SetContestedPvP(who.ToPlayer());
if (me != null && who.IsPvP() && (!who.IsTypeId(TypeId.Player) || me.duel == null || me.duel.opponent != who)) if (me != null && who.IsPvP() && (!who.IsTypeId(TypeId.Player) || me.duel == null || me.duel.opponent != who))
{ {
me.UpdatePvP(true); me.UpdatePvP(true);
@@ -1403,7 +1405,7 @@ namespace Game.Entities
creature.GetAI().EnterCombat(enemy); creature.GetAI().EnterCombat(enemy);
if (creature.GetFormation() != null) if (creature.GetFormation() != null)
creature.GetFormation().MemberAttackStart(creature, enemy); creature.GetFormation().MemberEngagingTarget(creature, enemy);
} }
if (IsPet()) if (IsPet())
@@ -1595,7 +1597,7 @@ namespace Game.Entities
if (!creature.IsPet()) if (!creature.IsPet())
{ {
creature.DeleteThreatList(); creature.GetThreatManager().ClearAllThreat();
// must be after setDeathState which resets dynamic flags // must be after setDeathState which resets dynamic flags
if (!creature.loot.IsLooted()) if (!creature.loot.IsLooted())
@@ -1709,29 +1711,6 @@ namespace Game.Entities
public virtual uint GetBlockPercent() { return 30; } public virtual uint GetBlockPercent() { return 30; }
public void SetContestedPvP(Player attackedPlayer = null)
{
Player player = GetCharmerOrOwnerPlayerOrPlayerItself();
if (player == null || (attackedPlayer != null && (attackedPlayer == player || (player.duel != null && player.duel.opponent == attackedPlayer))))
return;
player.SetContestedPvPTimer(30000);
if (!player.HasUnitState(UnitState.AttackPlayer))
{
player.AddUnitState(UnitState.AttackPlayer);
player.AddPlayerFlag(PlayerFlags.ContestedPVP);
// call MoveInLineOfSight for nearby contested guards
UpdateObjectVisibility();
}
if (!HasUnitState(UnitState.AttackPlayer))
{
AddUnitState(UnitState.AttackPlayer);
// call MoveInLineOfSight for nearby contested guards
UpdateObjectVisibility();
}
}
void UpdateReactives(uint p_time) void UpdateReactives(uint p_time)
{ {
for (ReactiveType reactive = 0; reactive < ReactiveType.Max; ++reactive) for (ReactiveType reactive = 0; reactive < ReactiveType.Max; ++reactive)
+2 -2
View File
@@ -313,7 +313,7 @@ namespace Game.Entities
CastStop(); CastStop();
CombatStop(); // @todo CombatStop(true) may cause crash (interrupt spells) CombatStop(); // @todo CombatStop(true) may cause crash (interrupt spells)
DeleteThreatList(); GetThreatManager().ClearAllThreat();
Player playerCharmer = charmer.ToPlayer(); Player playerCharmer = charmer.ToPlayer();
@@ -456,7 +456,7 @@ namespace Game.Entities
CastStop(); CastStop();
CombatStop(); // @todo CombatStop(true) may cause crash (interrupt spells) CombatStop(); // @todo CombatStop(true) may cause crash (interrupt spells)
GetHostileRefManager().DeleteReferences(); GetHostileRefManager().DeleteReferences();
DeleteThreatList(); GetThreatManager().ClearAllThreat();
if (_oldFactionId != 0) if (_oldFactionId != 0)
{ {
+9 -4
View File
@@ -1508,14 +1508,19 @@ namespace Game.Entities
} }
public void EnergizeBySpell(Unit victim, uint spellId, int damage, PowerType powerType) public void EnergizeBySpell(Unit victim, uint spellId, int damage, PowerType powerType)
{
SpellInfo info = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID());
if (info != null)
EnergizeBySpell(victim, info, damage, powerType);
}
void EnergizeBySpell(Unit victim, SpellInfo spellInfo, int damage, PowerType powerType)
{ {
int gain = victim.ModifyPower(powerType, damage); int gain = victim.ModifyPower(powerType, damage);
int overEnergize = damage - gain; int overEnergize = damage - gain;
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); victim.GetThreatManager().ForwardThreatForAssistingMe(this, damage / 2, spellInfo, true);
victim.GetHostileRefManager().ThreatAssist(this, damage * 0.5f, spellInfo); SendEnergizeSpellLog(victim, spellInfo.Id, damage, overEnergize, powerType);
SendEnergizeSpellLog(victim, spellId, damage, overEnergize, powerType);
} }
public void ApplySpellImmune(uint spellId, SpellImmunity op, SpellSchoolMask type, bool apply) public void ApplySpellImmune(uint spellId, SpellImmunity op, SpellSchoolMask type, bool apply)
+2 -2
View File
@@ -491,7 +491,7 @@ namespace Game.Entities
m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map.RemoveAllObjectsInRemoveList m_Events.KillAllEvents(false); // non-delatable (currently casted spells) will not deleted now but it will deleted at call in Map.RemoveAllObjectsInRemoveList
CombatStop(); CombatStop();
DeleteThreatList(); GetThreatManager().ClearAllThreat();
GetHostileRefManager().DeleteReferences(); GetHostileRefManager().DeleteReferences();
} }
public override void CleanupsBeforeDelete(bool finalCleanup = true) public override void CleanupsBeforeDelete(bool finalCleanup = true)
@@ -1609,7 +1609,7 @@ namespace Game.Entities
if (s != DeathState.Alive && s != DeathState.JustRespawned) if (s != DeathState.Alive && s != DeathState.JustRespawned)
{ {
CombatStop(); CombatStop();
DeleteThreatList(); GetThreatManager().ClearAllThreat();
GetHostileRefManager().DeleteReferences(); GetHostileRefManager().DeleteReferences();
if (IsNonMeleeSpellCast(false)) if (IsNonMeleeSpellCast(false))
+1 -1
View File
@@ -168,7 +168,7 @@ namespace Game.Maps
if (creature.IsInCombat() || !creature.GetThreatManager().IsThreatListsEmpty()) if (creature.IsInCombat() || !creature.GetThreatManager().IsThreatListsEmpty())
{ {
creature.CombatStop(); creature.CombatStop();
creature.DeleteThreatList(); creature.GetThreatManager().ClearAllThreat();
if (creature.IsAIEnabled) if (creature.IsAIEnabled)
creature.GetAI().EnterEvadeMode(); creature.GetAI().EnterEvadeMode();
} }
+7 -6
View File
@@ -4239,7 +4239,7 @@ namespace Game.Spells
case 1515: // Tame beast case 1515: // Tame beast
// FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness // FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness
if (caster != null && target.CanHaveThreatList()) if (caster != null && target.CanHaveThreatList())
target.AddThreat(caster, 10.0f); target.GetThreatManager().AddThreat(caster, 10.0f);
break; break;
case 13139: // net-o-matic case 13139: // net-o-matic
// root to self part of (root_target.charge.root_self sequence // root to self part of (root_target.charge.root_self sequence
@@ -5597,7 +5597,7 @@ namespace Game.Spells
HealInfo healInfo = new HealInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo().GetSchoolMask()); HealInfo healInfo = new HealInfo(caster, caster, heal, GetSpellInfo(), GetSpellInfo().GetSchoolMask());
caster.HealBySpell(healInfo); caster.HealBySpell(healInfo);
caster.GetHostileRefManager().ThreatAssist(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo()); caster.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
caster.ProcSkillsAndAuras(caster, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.None, hitMask, null, null, healInfo); caster.ProcSkillsAndAuras(caster, ProcFlags.DonePeriodic, ProcFlags.TakenPeriodic, ProcFlagsSpellType.Heal, ProcFlagsSpellPhase.None, hitMask, null, null, healInfo);
} }
@@ -5707,7 +5707,7 @@ namespace Game.Spells
SpellPeriodicAuraLogInfo pInfo = new SpellPeriodicAuraLogInfo(this, heal, (uint)damage, heal - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit); SpellPeriodicAuraLogInfo pInfo = new SpellPeriodicAuraLogInfo(this, heal, (uint)damage, heal - healInfo.GetEffectiveHeal(), healInfo.GetAbsorb(), 0, 0.0f, crit);
target.SendPeriodicAuraLog(pInfo); target.SendPeriodicAuraLog(pInfo);
target.GetHostileRefManager().ThreatAssist(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo()); target.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, GetSpellInfo());
// %-based heal - does not proc auras // %-based heal - does not proc auras
if (GetAuraType() == AuraType.ObsModHealth) if (GetAuraType() == AuraType.ObsModHealth)
@@ -5751,7 +5751,8 @@ namespace Game.Spells
if (gainAmount != 0) if (gainAmount != 0)
{ {
gainedAmount = caster.ModifyPower(powerType, gainAmount); gainedAmount = caster.ModifyPower(powerType, gainAmount);
target.AddThreat(caster, gainedAmount * 0.5f, GetSpellInfo().GetSchoolMask(), GetSpellInfo()); // energize is not modified by threat modifiers
target.GetThreatManager().AddThreat(caster, gainedAmount * 0.5f, GetSpellInfo(), true);
} }
// Drain Mana // Drain Mana
@@ -5801,7 +5802,7 @@ namespace Game.Spells
int gain = target.ModifyPower(powerType, amount); int gain = target.ModifyPower(powerType, amount);
if (caster != null) if (caster != null)
target.GetHostileRefManager().ThreatAssist(caster, gain * 0.5f, GetSpellInfo()); target.GetThreatManager().ForwardThreatForAssistingMe(caster, gain * 0.5f, GetSpellInfo(), true);
target.SendPeriodicAuraLog(pInfo); target.SendPeriodicAuraLog(pInfo);
} }
@@ -5829,7 +5830,7 @@ namespace Game.Spells
int gain = target.ModifyPower(powerType, amount); int gain = target.ModifyPower(powerType, amount);
if (caster != null) if (caster != null)
target.GetHostileRefManager().ThreatAssist(caster, gain * 0.5f, GetSpellInfo()); target.GetThreatManager().ForwardThreatForAssistingMe(caster, gain * 0.5f, GetSpellInfo(), true);
target.SendPeriodicAuraLog(pInfo); target.SendPeriodicAuraLog(pInfo);
} }
+11 -9
View File
@@ -1938,7 +1938,7 @@ namespace Game.Spells
HealInfo healInfo = new HealInfo(caster, unitTarget, addhealth, m_spellInfo, m_spellInfo.GetSchoolMask()); HealInfo healInfo = new HealInfo(caster, unitTarget, addhealth, m_spellInfo, m_spellInfo.GetSchoolMask());
caster.HealBySpell(healInfo, crit); caster.HealBySpell(healInfo, crit);
unitTarget.GetHostileRefManager().ThreatAssist(caster, healInfo.GetEffectiveHeal() * 0.5f, m_spellInfo); unitTarget.GetThreatManager().ForwardThreatForAssistingMe(caster, healInfo.GetEffectiveHeal() * 0.5f, m_spellInfo);
m_healing = (int)healInfo.GetEffectiveHeal(); m_healing = (int)healInfo.GetEffectiveHeal();
// Do triggers for unit // Do triggers for unit
@@ -2007,8 +2007,7 @@ namespace Game.Spells
if (missInfo == SpellMissInfo.Resist && m_spellInfo.HasAttribute(SpellCustomAttributes.PickPocket) && unitTarget.IsTypeId(TypeId.Unit)) if (missInfo == SpellMissInfo.Resist && m_spellInfo.HasAttribute(SpellCustomAttributes.PickPocket) && unitTarget.IsTypeId(TypeId.Unit))
{ {
m_caster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Talk); m_caster.RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.Talk);
if (unitTarget.ToCreature().IsAIEnabled) unitTarget.ToCreature().EngageWithTarget(m_caster);
unitTarget.ToCreature().GetAI().AttackStart(m_caster);
} }
} }
@@ -2108,14 +2107,17 @@ namespace Game.Spells
// assisting case, healing and resurrection // assisting case, healing and resurrection
if (unit.HasUnitState(UnitState.AttackPlayer)) if (unit.HasUnitState(UnitState.AttackPlayer))
{ {
m_caster.SetContestedPvP(); Player playerOwner = m_caster.GetCharmerOrOwnerPlayerOrPlayerItself();
if (m_caster.IsTypeId(TypeId.Player)) if (playerOwner != null)
m_caster.ToPlayer().UpdatePvP(true); {
playerOwner.SetContestedPvP();
playerOwner.UpdatePvP(true);
}
} }
if (unit.IsInCombat() && m_spellInfo.HasInitialAggro()) if (unit.IsInCombat() && m_spellInfo.HasInitialAggro())
{ {
m_caster.SetInCombatState(unit.GetCombatTimer() > 0, unit); m_caster.SetInCombatState(unit.GetCombatTimer() > 0, unit);
unit.GetHostileRefManager().ThreatAssist(m_caster, 0.0f); unit.GetThreatManager().ForwardThreatForAssistingMe(m_caster, 0.0f, null, true);
} }
} }
} }
@@ -4377,14 +4379,14 @@ namespace Game.Spells
// positive spells distribute threat among all units that are in combat with target, like healing // positive spells distribute threat among all units that are in combat with target, like healing
if (m_spellInfo.IsPositive()) if (m_spellInfo.IsPositive())
target.GetHostileRefManager().ThreatAssist(m_caster, threatToAdd, m_spellInfo); target.GetThreatManager().ForwardThreatForAssistingMe(m_caster, threatToAdd, m_spellInfo);
// for negative spells threat gets distributed among affected targets // for negative spells threat gets distributed among affected targets
else else
{ {
if (!target.CanHaveThreatList()) if (!target.CanHaveThreatList())
continue; continue;
target.AddThreat(m_caster, threatToAdd, m_spellInfo.GetSchoolMask(), m_spellInfo); target.GetThreatManager().AddThreat(m_caster, threatToAdd, m_spellInfo, true);
} }
} }
Log.outDebug(LogFilter.Spells, "Spell {0}, added an additional {1} threat for {2} {3} target(s)", m_spellInfo.Id, threat, m_spellInfo.IsPositive() ? "assisting" : "harming", m_UniqueTargetInfo.Count); Log.outDebug(LogFilter.Spells, "Spell {0}, added an additional {1} threat for {2} {3} target(s)", m_spellInfo.Id, threat, m_spellInfo.IsPositive() ? "assisting" : "harming", m_UniqueTargetInfo.Count);
+3 -3
View File
@@ -1942,7 +1942,7 @@ namespace Game.Spells
return; return;
// Check for possible target // Check for possible target
if (unitTarget == null || unitTarget.IsInCombat()) if (unitTarget == null || unitTarget.IsEngaged())
return; return;
// target must be OK to do this // target must be OK to do this
@@ -2701,7 +2701,7 @@ namespace Game.Spells
if (!unitTarget.CanHaveThreatList()) if (!unitTarget.CanHaveThreatList())
return; return;
unitTarget.AddThreat(m_caster, damage); unitTarget.GetThreatManager().AddThreat(m_caster, damage);
} }
[SpellEffectHandler(SpellEffectName.HealMaxHealth)] [SpellEffectHandler(SpellEffectName.HealMaxHealth)]
@@ -4408,7 +4408,7 @@ namespace Game.Spells
if (unitTarget == null) if (unitTarget == null)
return; return;
unitTarget.GetThreatManager().ModifyThreatPercent(m_caster, damage); unitTarget.GetThreatManager().ModifyThreatByPercent(m_caster, damage);
} }
[SpellEffectHandler(SpellEffectName.TransDoor)] [SpellEffectHandler(SpellEffectName.TransDoor)]
@@ -102,7 +102,7 @@ namespace Scripts.EasternKingdoms.Karazhan.Curator
switch (eventId) switch (eventId)
{ {
case EventIds.HatefulBolt: case EventIds.HatefulBolt:
Unit target = SelectTarget(SelectAggroTarget.TopAggro, 1); Unit target = SelectTarget(SelectAggroTarget.MaxThreat, 1);
if (target != null) if (target != null)
DoCast(target, SpellIds.HatefulBolt); DoCast(target, SpellIds.HatefulBolt);
_events.Repeat(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(15)); _events.Repeat(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(15));
@@ -278,16 +278,9 @@ namespace Scripts.EasternKingdoms.Karazhan.Moroes
if (Blind_Timer <= diff) if (Blind_Timer <= diff)
{ {
List<Unit> targets = SelectTargetList(5, SelectAggroTarget.Random, me.GetCombatReach() * 5, true); Unit target = SelectTarget(SelectAggroTarget.MinDistance, 0, 0.0f, true, false);
foreach (var i in targets) if (target != null)
{ DoCast(target, SpellIds.Blind);
if (!me.IsWithinMeleeRange(i))
{
DoCast(i, SpellIds.Blind);
break;
}
}
Blind_Timer = 40000; Blind_Timer = 40000;
} }
else else
@@ -765,11 +765,11 @@ namespace Scripts.EasternKingdoms.Karazhan.OperaEvent
{ {
Talk(RedRidingHood.SayWolfHood); Talk(RedRidingHood.SayWolfHood);
DoCast(target, RedRidingHood.SpellLittleRedRidingHood, true); DoCast(target, RedRidingHood.SpellLittleRedRidingHood, true);
TempThreat = DoGetThreat(target); TempThreat = GetThreat(target);
if (TempThreat != 0.0f) if (TempThreat != 0.0f)
DoModifyThreatPercent(target, -100); ModifyThreatByPercent(target, -100);
HoodGUID = target.GetGUID(); HoodGUID = target.GetGUID();
me.AddThreat(target, 1000000.0f); AddThreat(target, 1000000.0f);
ChaseTimer = 20000; ChaseTimer = 20000;
IsChasing = true; IsChasing = true;
} }
@@ -781,9 +781,9 @@ namespace Scripts.EasternKingdoms.Karazhan.OperaEvent
if (target) if (target)
{ {
HoodGUID.Clear(); HoodGUID.Clear();
if (DoGetThreat(target) != 0f) if (GetThreat(target) != 0f)
DoModifyThreatPercent(target, -100); ModifyThreatByPercent(target, -100);
me.AddThreat(target, TempThreat); AddThreat(target, TempThreat);
TempThreat = 0; TempThreat = 0;
} }
@@ -1023,7 +1023,7 @@ namespace Scripts.EasternKingdoms.Karazhan.OperaEvent
Romulo.GetMotionMaster().Clear(); Romulo.GetMotionMaster().Clear();
Romulo.SetDeathState(DeathState.JustDied); Romulo.SetDeathState(DeathState.JustDied);
Romulo.CombatStop(true); Romulo.CombatStop(true);
Romulo.DeleteThreatList(); Romulo.GetThreatManager().ClearAllThreat();
Romulo.SetDynamicFlags(UnitDynFlags.Lootable); Romulo.SetDynamicFlags(UnitDynFlags.Lootable);
} }
@@ -1261,7 +1261,7 @@ namespace Scripts.EasternKingdoms.Karazhan.OperaEvent
Julianne.GetMotionMaster().Clear(); Julianne.GetMotionMaster().Clear();
Julianne.SetDeathState(DeathState.JustDied); Julianne.SetDeathState(DeathState.JustDied);
Julianne.CombatStop(true); Julianne.CombatStop(true);
Julianne.DeleteThreatList(); Julianne.GetThreatManager().ClearAllThreat();
Julianne.SetDynamicFlags(UnitDynFlags.Lootable); Julianne.SetDynamicFlags(UnitDynFlags.Lootable);
} }
return; return;
@@ -1290,7 +1290,7 @@ namespace Scripts.EasternKingdoms.Karazhan.OperaEvent
Creature Julianne = (ObjectAccessor.GetCreature(me, JulianneGUID)); Creature Julianne = (ObjectAccessor.GetCreature(me, JulianneGUID));
if (Julianne && Julianne.GetVictim()) if (Julianne && Julianne.GetVictim())
{ {
me.AddThreat(Julianne.GetVictim(), 1.0f); AddThreat(Julianne.GetVictim(), 1.0f);
AttackStart(Julianne.GetVictim()); AttackStart(Julianne.GetVictim());
} }
} }
@@ -170,7 +170,7 @@ namespace Scripts.Northrend.AzjolNerub.Ahnkahet.JedogaShadowseeker
else else
{ {
who.SetInCombatWith(me); who.SetInCombatWith(me);
me.AddThreat(who, 0.0f); AddThreat(who, 0.0f);
} }
} }
} }
@@ -175,8 +175,8 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheChampion
{ {
if (player && !player.IsGameMaster() && me.IsInRange(player, 8.0f, 25.0f, false)) if (player && !player.IsGameMaster() && me.IsInRange(player, 8.0f, 25.0f, false))
{ {
DoResetThreat(); ResetThreatList();
me.AddThreat(player, 1.0f); me.GetThreatManager().AddThreat(player, 1.0f);
DoCast(player, TrialOfChampionSpells.CHARGE); DoCast(player, TrialOfChampionSpells.CHARGE);
break; break;
} }
@@ -324,7 +324,7 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheChampion
temp.SetReactState(ReactStates.Aggressive); temp.SetReactState(ReactStates.Aggressive);
temp.SetInCombatWith(player); temp.SetInCombatWith(player);
player.SetInCombatWith(temp); player.SetInCombatWith(temp);
temp.AddThreat(player, 0.0f); temp.GetThreatManager().AddThreat(player, 0.0f);
} }
} }
} }
@@ -386,8 +386,8 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheChampion
{ {
if (player && !player.IsGameMaster() && me.IsInRange(player, 8.0f, 25.0f, false)) if (player && !player.IsGameMaster() && me.IsInRange(player, 8.0f, 25.0f, false))
{ {
DoResetThreat(); ResetThreatList();
me.AddThreat(player, 5.0f); me.GetThreatManager().AddThreat(player, 5.0f);
DoCast(player, TrialOfChampionSpells.INTERCEPT); DoCast(player, TrialOfChampionSpells.INTERCEPT);
break; break;
} }
@@ -549,7 +549,7 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheChampion
_scheduler.Schedule(TimeSpan.FromSeconds(12), task => _scheduler.Schedule(TimeSpan.FromSeconds(12), task =>
{ {
ObjectGuid uiTargetGUID = ObjectGuid.Empty; ObjectGuid uiTargetGUID = ObjectGuid.Empty;
Unit target = SelectTarget(SelectAggroTarget.Farthest, 0, 30.0f); Unit target = SelectTarget(SelectAggroTarget.MaxDistance, 0, 30.0f);
if (target) if (target)
{ {
uiTargetGUID = target.GetGUID(); uiTargetGUID = target.GetGUID();
@@ -448,7 +448,7 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheChampion
temp.SetReactState(ReactStates.Aggressive); temp.SetReactState(ReactStates.Aggressive);
temp.SetInCombatWith(player); temp.SetInCombatWith(player);
player.SetInCombatWith(temp); player.SetInCombatWith(temp);
temp.AddThreat(player, 0.0f); AddThreat(player, 0.0f, temp);
} }
} }
} }
@@ -155,7 +155,7 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheCrusader
return; return;
case Jaraxxus.EventFelLightning: case Jaraxxus.EventFelLightning:
{ {
Unit target = SelectTarget(SelectAggroTarget.Random, 0, 0.0f, true, -Jaraxxus.SpellLordHittin); Unit target = SelectTarget(SelectAggroTarget.Random, 0, 0.0f, true, true, -Jaraxxus.SpellLordHittin);
if (target) if (target)
DoCast(target, Jaraxxus.SpellFelLighting); DoCast(target, Jaraxxus.SpellFelLighting);
_events.ScheduleEvent(Jaraxxus.EventFelLightning, RandomHelper.URand(10 * Time.InMilliseconds, 15 * Time.InMilliseconds)); _events.ScheduleEvent(Jaraxxus.EventFelLightning, RandomHelper.URand(10 * Time.InMilliseconds, 15 * Time.InMilliseconds));
@@ -163,7 +163,7 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheCrusader
} }
case Jaraxxus.EventIncinerateFlesh: case Jaraxxus.EventIncinerateFlesh:
{ {
Unit target = SelectTarget(SelectAggroTarget.Random, 1, 0.0f, true, -Jaraxxus.SpellLordHittin); Unit target = SelectTarget(SelectAggroTarget.Random, 1, 0.0f, true, true, -Jaraxxus.SpellLordHittin);
if (target) if (target)
{ {
Talk(Jaraxxus.EmoteIncinerate, target); Talk(Jaraxxus.EmoteIncinerate, target);
@@ -179,7 +179,7 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheCrusader
return; return;
case Jaraxxus.EventLegionFlame: case Jaraxxus.EventLegionFlame:
{ {
Unit target = SelectTarget(SelectAggroTarget.Random, 1, 0.0f, true, -Jaraxxus.SpellLordHittin); Unit target = SelectTarget(SelectAggroTarget.Random, 1, 0.0f, true, true, -Jaraxxus.SpellLordHittin);
if (target) if (target)
{ {
Talk(Jaraxxus.EmoteLegionFlame, target); Talk(Jaraxxus.EmoteLegionFlame, target);
@@ -1174,8 +1174,7 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheCrusader
{ {
//1-shot Fizzlebang //1-shot Fizzlebang
temp.CastSpell(me, 67888, false); temp.CastSpell(me, 67888, false);
me.SetInCombatWith(temp); AddThreat(me, 1000.0f, temp);
temp.AddThreat(me, 1000.0f);
temp.GetAI().AttackStart(me); temp.GetAI().AttackStart(me);
} }
_instance.SetData(DataTypes.Event, 1160); _instance.SetData(DataTypes.Event, 1160);
@@ -174,8 +174,8 @@ namespace Scripts.Northrend.FrozenHalls.PitOfSaron.BossKrickAndIck
public void _ResetThreat(Unit target) public void _ResetThreat(Unit target)
{ {
DoModifyThreatPercent(target, -100); ModifyThreatByPercent(target, -100);
me.AddThreat(target, _tempThreat); AddThreat(target, _tempThreat);
} }
public override void UpdateAI(uint diff) public override void UpdateAI(uint diff)
@@ -617,8 +617,8 @@ namespace Scripts.Northrend.FrozenHalls.PitOfSaron.BossKrickAndIck
ick.GetAI().Talk(TextIds.SayIckChase1, target); ick.GetAI().Talk(TextIds.SayIckChase1, target);
ick.AddAura(GetSpellInfo().Id, target); ick.AddAura(GetSpellInfo().Id, target);
ick.GetAI<boss_ick>().SetTempThreat(ick.GetThreatManager().GetThreat(target)); ick.GetAI<boss_ick>().SetTempThreat(ick.GetThreatManager().GetThreat(target));
ick.AddThreat(target, GetEffectValue()); ick.GetThreatManager().AddThreat(target, GetEffectValue(), GetSpellInfo(), true, true);
target.AddThreat(ick, GetEffectValue()); target.GetThreatManager().AddThreat(ick, GetEffectValue(), GetSpellInfo(), true, true);
} }
} }
} }
@@ -587,7 +587,7 @@ namespace Scripts.Northrend.IcecrownCitadel
if (!me.IsAlive() || !me.IsInCombat()) if (!me.IsAlive() || !me.IsInCombat())
return; return;
me.DeleteThreatList(); me.GetThreatManager().ClearAllThreat();
me.CombatStop(true); me.CombatStop(true);
me.GetMotionMaster().MoveTargetedHome(); me.GetMotionMaster().MoveTargetedHome();
} }
@@ -733,11 +733,10 @@ namespace Scripts.Northrend.IcecrownCitadel
foreach (var stalker in creatures) foreach (var stalker in creatures)
{ {
stalker.RemoveAllAuras(); stalker.RemoveAllAuras();
stalker.DeleteThreatList(); stalker.GetThreatManager().ClearAllThreat();
stalker.CombatStop(true); stalker.CombatStop(true);
} }
uint explosionSpell = isVictory ? GunshipSpells.ExplosionVictory : GunshipSpells.ExplosionWipe; uint explosionSpell = isVictory ? GunshipSpells.ExplosionVictory : GunshipSpells.ExplosionWipe;
creatures.Clear(); creatures.Clear();
me.GetCreatureListWithEntryInGrid(creatures, CreatureIds.GunshipHull, 200.0f); me.GetCreatureListWithEntryInGrid(creatures, CreatureIds.GunshipHull, 200.0f);
@@ -872,7 +871,7 @@ namespace Scripts.Northrend.IcecrownCitadel
if (!me.IsAlive()) if (!me.IsAlive())
return; return;
me.DeleteThreatList(); me.GetThreatManager().ClearAllThreat();
me.CombatStop(true); me.CombatStop(true);
me.GetMotionMaster().MoveTargetedHome(); me.GetMotionMaster().MoveTargetedHome();
@@ -1132,7 +1131,7 @@ namespace Scripts.Northrend.IcecrownCitadel
if (!me.IsAlive()) if (!me.IsAlive())
return; return;
me.DeleteThreatList(); me.GetThreatManager().ClearAllThreat();
me.CombatStop(true); me.CombatStop(true);
me.GetMotionMaster().MoveTargetedHome(); me.GetMotionMaster().MoveTargetedHome();
@@ -1442,7 +1441,7 @@ namespace Scripts.Northrend.IcecrownCitadel
{ {
players.Sort(new ObjectDistanceOrderPred(me)); players.Sort(new ObjectDistanceOrderPred(me));
foreach (var pl in players) foreach (var pl in players)
me.AddThreat(pl, 1.0f); AddThreat(pl, 1.0f);
AttackStart(players.First()); AttackStart(players.First());
} }
@@ -646,7 +646,7 @@ namespace Scripts.Northrend.IcecrownCitadel
Talk(Texts.SaySvalnaAggro); Talk(Texts.SaySvalnaAggro);
break; break;
case EventTypes.ImpalingSpear: case EventTypes.ImpalingSpear:
Unit target = SelectTarget(SelectAggroTarget.Random, 1, 0.0f, true, -(int)InstanceSpells.ImpalingSpear); Unit target = SelectTarget(SelectAggroTarget.Random, 1, 0.0f, true, true, -(int)InstanceSpells.ImpalingSpear);
if (target) if (target)
{ {
DoCast(me, InstanceSpells.AetherShield); DoCast(me, InstanceSpells.AetherShield);
@@ -1509,7 +1509,7 @@ namespace Scripts.Northrend.IcecrownCitadel
if (warden) if (warden)
{ {
terenas.GetAI().AttackStart(warden); terenas.GetAI().AttackStart(warden);
warden.AddThreat(terenas, 300000.0f); warden.GetThreatManager().AddThreat(terenas, 300000.0f);
} }
} }
break; break;
@@ -313,7 +313,7 @@ namespace Scripts.Northrend.IcecrownCitadel
Talk(TextIds.SayDominateMind); Talk(TextIds.SayDominateMind);
for (byte i = 0; i < _dominateMindCount; i++) for (byte i = 0; i < _dominateMindCount; i++)
{ {
Unit target = SelectTarget(SelectAggroTarget.Random, 1, 0.0f, true, -(int)SpellIds.DominateMind); Unit target = SelectTarget(SelectAggroTarget.Random, 1, 0.0f, true, false, -(int)SpellIds.DominateMind);
if (target != null) if (target != null)
DoCast(target, SpellIds.DominateMind); DoCast(target, SpellIds.DominateMind);
} }
@@ -423,7 +423,7 @@ namespace Scripts.Northrend.IcecrownCitadel
Talk(TextIds.SayPhase2); Talk(TextIds.SayPhase2);
Talk(TextIds.EmotePhase2); Talk(TextIds.EmotePhase2);
DoStartMovement(me.GetVictim()); DoStartMovement(me.GetVictim());
DoResetThreat(); ResetThreatList();
damage -= (uint)me.GetPower(PowerType.Mana); damage -= (uint)me.GetPower(PowerType.Mana);
me.SetPower(PowerType.Mana, 0); me.SetPower(PowerType.Mana, 0);
@@ -470,8 +470,8 @@ namespace Scripts.Northrend.IcecrownCitadel
void SelectTarget(List<WorldObject> targets) void SelectTarget(List<WorldObject> targets)
{ {
targets.Clear(); targets.Clear();
// select any unit but not the tank (by owners threatlist) // select any unit but not the tank
Unit target = GetCaster().GetAI().SelectTarget(SelectAggroTarget.Random, 1, -GetCaster().GetCombatReach(), true, -(int)Spells.Impaled); Unit target = GetCaster().GetAI().SelectTarget(SelectAggroTarget.Random, 1, -GetCaster().GetCombatReach(), true, false, -(int)Spells.Impaled);
if (!target) if (!target)
target = GetCaster().GetAI().SelectTarget(SelectAggroTarget.Random, 0, 0.0f, true); // or the tank if its solo target = GetCaster().GetAI().SelectTarget(SelectAggroTarget.Random, 0, 0.0f, true); // or the tank if its solo
if (!target) if (!target)
@@ -565,7 +565,7 @@ namespace Scripts.Northrend.IcecrownCitadel
CreatureAI marrowgarAI = marrowgar.GetAI(); CreatureAI marrowgarAI = marrowgar.GetAI();
byte boneSpikeCount = (byte)(Convert.ToBoolean((int)GetCaster().GetMap().GetDifficultyID() & 1) ? 3 : 1); byte boneSpikeCount = (byte)(Convert.ToBoolean((int)GetCaster().GetMap().GetDifficultyID() & 1) ? 3 : 1);
List<Unit> targets = marrowgarAI.SelectTargetList(new BoneSpikeTargetSelector(marrowgarAI), boneSpikeCount, SelectAggroTarget.Random); List<Unit> targets = marrowgarAI.SelectTargetList(boneSpikeCount, SelectAggroTarget.Random, 1, new BoneSpikeTargetSelector(marrowgarAI));
if (targets.Empty()) if (targets.Empty())
return; return;
+2 -2
View File
@@ -1352,10 +1352,10 @@ namespace Scripts.Northrend.Ulduar
if (me.HasUnitState(UnitState.Root)) if (me.HasUnitState(UnitState.Root))
{ {
Unit newTarget = SelectTarget(SelectAggroTarget.Nearest, 0, 30.0f, true); Unit newTarget = SelectTarget(SelectAggroTarget.MinDistance, 0, 30.0f, true);
if (newTarget) if (newTarget)
{ {
me.DeleteThreatList(); me.GetThreatManager().ClearAllThreat();
AttackStart(newTarget); AttackStart(newTarget);
} }
} }
+1 -1
View File
@@ -73,7 +73,7 @@ namespace Scripts.Outlands
me.SetFaction(Aeranas.FactionFriendly); me.SetFaction(Aeranas.FactionFriendly);
me.AddNpcFlag(NPCFlags.QuestGiver); me.AddNpcFlag(NPCFlags.QuestGiver);
me.RemoveAllAuras(); me.RemoveAllAuras();
me.DeleteThreatList(); me.GetThreatManager().ClearAllThreat();
me.CombatStop(true); me.CombatStop(true);
Talk(Aeranas.SayFree); Talk(Aeranas.SayFree);
return; return;
+1 -1
View File
@@ -42,7 +42,7 @@ namespace Scripts.Pets.Priest
if (!me.IsAlive()) if (!me.IsAlive())
return; return;
me.DeleteThreatList(); me.GetThreatManager().ClearAllThreat();
me.CombatStop(true); me.CombatStop(true);
me.ResetPlayerDamageReq(); me.ResetPlayerDamageReq();
} }
+1 -1
View File
@@ -146,7 +146,7 @@ namespace Scripts.World.BossEmeraldDragons
_scheduler.Update(diff); _scheduler.Update(diff);
Unit target = SelectTarget(SelectAggroTarget.TopAggro, 0, -50.0f, true); Unit target = SelectTarget(SelectAggroTarget.MaxThreat, 0, -50.0f, true);
if (target) if (target)
DoCast(target, Spells.SummonPlayer); DoCast(target, Spells.SummonPlayer);
+1 -1
View File
@@ -1559,7 +1559,7 @@ namespace Scripts.World.NpcSpecial
public override void DamageTaken(Unit doneBy, ref uint damage) public override void DamageTaken(Unit doneBy, ref uint damage)
{ {
me.AddThreat(doneBy, damage); // just to create threat reference AddThreat(doneBy, damage); // just to create threat reference
_damageTimes[doneBy.GetGUID()] = Time.UnixTime; _damageTimes[doneBy.GetGUID()] = Time.UnixTime;
damage = 0; damage = 0;
} }