Core/AI: Finally move the "is creature engaged" flag to be a property of the creature AI, where it honestly always belonged.
Port From (https://github.com/TrinityCore/TrinityCore/commit/c13d83796f7b2111c5dcf8546bdd84eccd232ae3)
This commit is contained in:
@@ -29,6 +29,7 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
public class CreatureAI : UnitAI
|
public class CreatureAI : UnitAI
|
||||||
{
|
{
|
||||||
|
bool _isEngaged;
|
||||||
bool _moveInLOSLocked;
|
bool _moveInLOSLocked;
|
||||||
List<AreaBoundary> _boundary = new();
|
List<AreaBoundary> _boundary = new();
|
||||||
bool _negateBoundary;
|
bool _negateBoundary;
|
||||||
@@ -201,6 +202,12 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void JustEnteredCombat(Unit who)
|
||||||
|
{
|
||||||
|
if (!IsEngaged() && !me.CanHaveThreatList())
|
||||||
|
EngagementStart(who);
|
||||||
|
}
|
||||||
|
|
||||||
// Called for reaction at stopping attack at no attackers or targets
|
// Called for reaction at stopping attack at no attackers or targets
|
||||||
public virtual void EnterEvadeMode(EvadeReason why = EvadeReason.Other)
|
public virtual void EnterEvadeMode(EvadeReason why = EvadeReason.Other)
|
||||||
{
|
{
|
||||||
@@ -231,7 +238,7 @@ namespace Game.AI
|
|||||||
|
|
||||||
public bool UpdateVictim()
|
public bool UpdateVictim()
|
||||||
{
|
{
|
||||||
if (!me.IsEngaged())
|
if (!IsEngaged())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!me.HasReactState(ReactStates.Passive))
|
if (!me.HasReactState(ReactStates.Passive))
|
||||||
@@ -254,23 +261,53 @@ namespace Game.AI
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void EngagementStart(Unit who)
|
||||||
|
{
|
||||||
|
if (_isEngaged)
|
||||||
|
{
|
||||||
|
//Log.outError(LogFilter.ScriptsAi, $"CreatureAI::EngagementStart called even though creature is already engaged. Creature debug info:\n{me.GetDebugInfo()}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_isEngaged = true;
|
||||||
|
|
||||||
|
me.AtEngage(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EngagementOver()
|
||||||
|
{
|
||||||
|
if (!_isEngaged)
|
||||||
|
{
|
||||||
|
//Log.outError(LogFilter.ScriptsAi, $"CreatureAI::EngagementOver called even though creature is not currently engaged. Creature debug info:\n{me.GetDebugInfo()}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_isEngaged = false;
|
||||||
|
|
||||||
|
me.AtDisengage();
|
||||||
|
}
|
||||||
|
|
||||||
public bool _EnterEvadeMode(EvadeReason why = EvadeReason.Other)
|
public bool _EnterEvadeMode(EvadeReason why = EvadeReason.Other)
|
||||||
{
|
{
|
||||||
if (!me.IsAlive())
|
if (me.IsInEvadeMode())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!me.IsAlive())
|
||||||
|
{
|
||||||
|
EngagementOver();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
me.RemoveAurasOnEvade();
|
me.RemoveAurasOnEvade();
|
||||||
|
|
||||||
// sometimes bosses stuck in combat?
|
// sometimes bosses stuck in combat?
|
||||||
me.CombatStop(true);
|
me.CombatStop(true);
|
||||||
me.GetThreatManager().NotifyDisengaged();
|
|
||||||
me.SetLootRecipient(null);
|
me.SetLootRecipient(null);
|
||||||
me.ResetPlayerDamageReq();
|
me.ResetPlayerDamageReq();
|
||||||
me.SetLastDamagedTime(0);
|
me.SetLastDamagedTime(0);
|
||||||
me.SetCannotReachTarget(false);
|
me.SetCannotReachTarget(false);
|
||||||
me.DoNotReacquireTarget();
|
me.DoNotReacquireTarget();
|
||||||
|
EngagementOver();
|
||||||
|
|
||||||
return !me.IsInEvadeMode();
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CypherStrings VisualizeBoundary(int duration, Unit owner = null, bool fill = false)
|
public CypherStrings VisualizeBoundary(int duration, Unit owner = null, bool fill = false)
|
||||||
@@ -404,11 +441,22 @@ namespace Game.AI
|
|||||||
me.DoImmediateBoundaryCheck();
|
me.DoImmediateBoundaryCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called for reaction whenever a new non-offline unit is added to the threat list
|
||||||
|
public virtual void JustStartedThreateningMe(Unit who)
|
||||||
|
{
|
||||||
|
if (!IsEngaged())
|
||||||
|
EngagementStart(who);
|
||||||
|
}
|
||||||
|
|
||||||
// Called for reaction when initially engaged - this will always happen _after_ JustEnteredCombat
|
// Called for reaction when initially engaged - this will always happen _after_ JustEnteredCombat
|
||||||
public virtual void JustEngagedWith(Unit who) { }
|
public virtual void JustEngagedWith(Unit who) { }
|
||||||
|
|
||||||
// Called when the creature is killed
|
// Called when the creature is killed
|
||||||
public virtual void JustDied(Unit killer) { }
|
public virtual void JustDied(Unit killer)
|
||||||
|
{
|
||||||
|
if (IsEngaged())
|
||||||
|
EngagementOver();
|
||||||
|
}
|
||||||
|
|
||||||
// Called when the creature kills a unit
|
// Called when the creature kills a unit
|
||||||
public virtual void KilledUnit(Unit victim) { }
|
public virtual void KilledUnit(Unit victim) { }
|
||||||
@@ -521,6 +569,8 @@ namespace Game.AI
|
|||||||
public virtual bool IsEscortNPC(bool onlyIfActive) { return false; }
|
public virtual bool IsEscortNPC(bool onlyIfActive) { return false; }
|
||||||
|
|
||||||
public List<AreaBoundary> GetBoundary() { return _boundary; }
|
public List<AreaBoundary> GetBoundary() { return _boundary; }
|
||||||
|
|
||||||
|
public bool IsEngaged() { return _isEngaged; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AISpellInfoType
|
public class AISpellInfoType
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
me.GetMotionMaster().MoveIdle();
|
me.GetMotionMaster().MoveIdle();
|
||||||
me.CombatStop(true);
|
me.CombatStop(true);
|
||||||
me.GetThreatManager().NotifyDisengaged();
|
EngagementOver();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ namespace Game.AI
|
|||||||
|
|
||||||
me.RemoveAllAuras();
|
me.RemoveAllAuras();
|
||||||
me.CombatStop(true);
|
me.CombatStop(true);
|
||||||
me.GetThreatManager().NotifyDisengaged();
|
EngagementOver();
|
||||||
|
|
||||||
me.GetMotionMaster().MoveTargetedHome();
|
me.GetMotionMaster().MoveTargetedHome();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,21 @@ namespace Game.AI
|
|||||||
|
|
||||||
public override void MoveInLineOfSight(Unit who) { }
|
public override void MoveInLineOfSight(Unit who) { }
|
||||||
|
|
||||||
|
public override void JustEnteredCombat(Unit who)
|
||||||
|
{
|
||||||
|
EngagementStart(who);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void JustExitedCombat()
|
||||||
|
{
|
||||||
|
EngagementOver();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void JustStartedThreateningMe(Unit who)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public override void EnterEvadeMode(EvadeReason why) { }
|
public override void EnterEvadeMode(EvadeReason why) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +104,8 @@ namespace Game.AI
|
|||||||
|
|
||||||
public override void MoveInLineOfSight(Unit unit) { }
|
public override void MoveInLineOfSight(Unit unit) { }
|
||||||
public override void AttackStart(Unit unit) { }
|
public override void AttackStart(Unit unit) { }
|
||||||
|
public override void JustStartedThreateningMe(Unit unit) { }
|
||||||
|
public override void JustEnteredCombat(Unit who) { }
|
||||||
public override void UpdateAI(uint diff) { }
|
public override void UpdateAI(uint diff) { }
|
||||||
public override void JustAppeared() { }
|
public override void JustAppeared() { }
|
||||||
public override void EnterEvadeMode(EvadeReason why) { }
|
public override void EnterEvadeMode(EvadeReason why) { }
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ using Game.Maps;
|
|||||||
|
|
||||||
namespace Game.AI
|
namespace Game.AI
|
||||||
{
|
{
|
||||||
public class TotemAI : CreatureAI
|
public class TotemAI : NullCreatureAI
|
||||||
{
|
{
|
||||||
ObjectGuid _victimGuid;
|
ObjectGuid _victimGuid;
|
||||||
|
|
||||||
@@ -30,15 +30,6 @@ namespace Game.AI
|
|||||||
_victimGuid = ObjectGuid.Empty;
|
_victimGuid = ObjectGuid.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void MoveInLineOfSight(Unit who) { }
|
|
||||||
|
|
||||||
public override void JustAppeared() { }
|
|
||||||
|
|
||||||
public override void EnterEvadeMode(EvadeReason why)
|
|
||||||
{
|
|
||||||
me.CombatStop(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void UpdateAI(uint diff)
|
public override void UpdateAI(uint diff)
|
||||||
{
|
{
|
||||||
if (me.ToTotem().GetTotemType() != TotemType.Active)
|
if (me.ToTotem().GetTotemType() != TotemType.Active)
|
||||||
|
|||||||
@@ -536,7 +536,7 @@ namespace Game.AI
|
|||||||
_me = unit;
|
_me = unit;
|
||||||
_dist = dist;
|
_dist = dist;
|
||||||
_playerOnly = playerOnly;
|
_playerOnly = playerOnly;
|
||||||
_exception = !withTank ? _me.GetThreatManager().GetCurrentVictim() : null;
|
_exception = !withTank ? unit.GetThreatManager().GetLastVictim() : null;
|
||||||
_aura = aura;
|
_aura = aura;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -135,9 +135,10 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
me.RemoveAllAuras();
|
me.RemoveAllAuras();
|
||||||
me.CombatStop(true);
|
me.CombatStop(true);
|
||||||
me.GetThreatManager().NotifyDisengaged();
|
|
||||||
me.SetLootRecipient(null);
|
me.SetLootRecipient(null);
|
||||||
|
|
||||||
|
EngagementOver();
|
||||||
|
|
||||||
if (HasEscortState(EscortState.Escorting))
|
if (HasEscortState(EscortState.Escorting))
|
||||||
{
|
{
|
||||||
AddEscortState(EscortState.Returning);
|
AddEscortState(EscortState.Returning);
|
||||||
|
|||||||
@@ -123,15 +123,19 @@ namespace Game.AI
|
|||||||
public override void EnterEvadeMode(EvadeReason why)
|
public override void EnterEvadeMode(EvadeReason why)
|
||||||
{
|
{
|
||||||
if (!me.IsAlive())
|
if (!me.IsAlive())
|
||||||
|
{
|
||||||
|
EngagementOver();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
me.RemoveAllAuras();
|
me.RemoveAllAuras();
|
||||||
me.CombatStop(true);
|
me.CombatStop(true);
|
||||||
me.GetThreatManager().NotifyDisengaged();
|
|
||||||
me.SetLootRecipient(null);
|
me.SetLootRecipient(null);
|
||||||
me.SetCannotReachTarget(false);
|
me.SetCannotReachTarget(false);
|
||||||
me.DoNotReacquireTarget();
|
me.DoNotReacquireTarget();
|
||||||
|
|
||||||
|
EngagementOver();
|
||||||
|
|
||||||
if (HasFollowState(FollowState.Inprogress))
|
if (HasFollowState(FollowState.Inprogress))
|
||||||
{
|
{
|
||||||
Log.outDebug(LogFilter.Scripts, "FollowerAI left combat, returning to CombatStartPosition.");
|
Log.outDebug(LogFilter.Scripts, "FollowerAI left combat, returning to CombatStartPosition.");
|
||||||
|
|||||||
@@ -234,15 +234,9 @@ namespace Game.Combat
|
|||||||
|
|
||||||
public static void NotifyAICombat(Unit me, Unit other)
|
public static void NotifyAICombat(Unit me, Unit other)
|
||||||
{
|
{
|
||||||
if (!me.IsAIEnabled())
|
UnitAI ai = me.GetAI();
|
||||||
return;
|
if (ai != null)
|
||||||
|
ai.JustEnteredCombat(other);
|
||||||
me.GetAI().JustEnteredCombat(other);
|
|
||||||
|
|
||||||
Creature cMe = me.ToCreature();
|
|
||||||
if (cMe != null)
|
|
||||||
if (!cMe.CanHaveThreatList())
|
|
||||||
cMe.GetAI().JustEngagedWith(other);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PutReference(ObjectGuid guid, CombatReference refe)
|
void PutReference(ObjectGuid guid, CombatReference refe)
|
||||||
@@ -277,14 +271,14 @@ namespace Game.Combat
|
|||||||
{
|
{
|
||||||
_owner.AddUnitFlag(UnitFlags.InCombat);
|
_owner.AddUnitFlag(UnitFlags.InCombat);
|
||||||
_owner.AtEnterCombat();
|
_owner.AtEnterCombat();
|
||||||
if (!_owner.CanHaveThreatList() && !_owner.IsEngaged())
|
if (_owner.IsCreature())
|
||||||
_owner.AtEngage(GetAnyTarget());
|
_owner.AtEngage(GetAnyTarget());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_owner.RemoveUnitFlag(UnitFlags.InCombat);
|
_owner.RemoveUnitFlag(UnitFlags.InCombat);
|
||||||
_owner.AtExitCombat();
|
_owner.AtExitCombat();
|
||||||
if (_owner.IsEngaged() && !(_owner.IsCreature() && _owner.CanHaveThreatList() && _owner.ToCreature().IsAIEnabled()))
|
if (!_owner.IsCreature())
|
||||||
_owner.AtDisengage();
|
_owner.AtDisengage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ namespace Game.Combat
|
|||||||
uint _updateTimer;
|
uint _updateTimer;
|
||||||
List<ThreatReference> _sortedThreatList = new();
|
List<ThreatReference> _sortedThreatList = new();
|
||||||
Dictionary<ObjectGuid, ThreatReference> _myThreatListEntries = new();
|
Dictionary<ObjectGuid, ThreatReference> _myThreatListEntries = new();
|
||||||
|
List<ThreatReference> _needsAIUpdate = new();
|
||||||
ThreatReference _currentVictimRef;
|
ThreatReference _currentVictimRef;
|
||||||
ThreatReference _fixateRef;
|
ThreatReference _fixateRef;
|
||||||
|
|
||||||
@@ -98,6 +99,12 @@ namespace Game.Combat
|
|||||||
if (_currentVictimRef == null || _currentVictimRef.ShouldBeOffline())
|
if (_currentVictimRef == null || _currentVictimRef.ShouldBeOffline())
|
||||||
UpdateVictim();
|
UpdateVictim();
|
||||||
|
|
||||||
|
Cypher.Assert(_currentVictimRef == null || _currentVictimRef.IsAvailable());
|
||||||
|
return _currentVictimRef?.GetVictim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Unit GetLastVictim()
|
||||||
|
{
|
||||||
if (_currentVictimRef != null && !_currentVictimRef.ShouldBeOffline())
|
if (_currentVictimRef != null && !_currentVictimRef.ShouldBeOffline())
|
||||||
return _currentVictimRef.GetVictim();
|
return _currentVictimRef.GetVictim();
|
||||||
|
|
||||||
@@ -294,7 +301,7 @@ namespace Game.Combat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetRefe.IsOnline())
|
if (targetRefe.IsOnline())
|
||||||
targetRefe.AddThreat(amount);
|
targetRefe.AddThreat(amount);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -306,14 +313,13 @@ namespace Game.Combat
|
|||||||
|
|
||||||
// afterwards, we evaluate whether this is an online reference (it might not be an acceptable target, but we need to add it to our threat list before we check!)
|
// afterwards, we evaluate whether this is an online reference (it might not be an acceptable target, but we need to add it to our threat list before we check!)
|
||||||
newRefe.UpdateOffline();
|
newRefe.UpdateOffline();
|
||||||
if (newRefe.IsOnline()) // ...and if the ref is online it also gets the threat it should have
|
if (newRefe.IsOnline()) // we only add the threat if the ref is currently available
|
||||||
newRefe.AddThreat(amount);
|
newRefe.AddThreat(amount);
|
||||||
|
|
||||||
if (!_owner.IsEngaged())
|
if (_currentVictimRef == null)
|
||||||
{
|
|
||||||
_owner.AtEngage(target);
|
|
||||||
UpdateVictim();
|
UpdateVictim();
|
||||||
}
|
else
|
||||||
|
ProcessAIUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScaleThreat(Unit target, float factor)
|
void ScaleThreat(Unit target, float factor)
|
||||||
@@ -398,18 +404,6 @@ namespace Game.Combat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// THIS SHOULD ONLY BE CALLED FROM A CREATURE'S AI (typically in EnterEvadeMode)
|
|
||||||
/// notify the unit that the AI has disengaged
|
|
||||||
/// </summary>
|
|
||||||
public void NotifyDisengaged()
|
|
||||||
{
|
|
||||||
// note: i don't really like having this here
|
|
||||||
// (maybe engage flag should be in creature ai? it's inherently an AI property...)
|
|
||||||
if (_owner.IsEngaged())
|
|
||||||
_owner.AtDisengage();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FixateTarget(Unit target)
|
public void FixateTarget(Unit target)
|
||||||
{
|
{
|
||||||
if (target)
|
if (target)
|
||||||
@@ -446,6 +440,7 @@ namespace Game.Combat
|
|||||||
NeedClientUpdate = false;
|
NeedClientUpdate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ProcessAIUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreatReference ReselectVictim()
|
ThreatReference ReselectVictim()
|
||||||
@@ -454,7 +449,7 @@ namespace Game.Combat
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
foreach (var pair in _myThreatListEntries)
|
foreach (var pair in _myThreatListEntries)
|
||||||
pair.Value.UpdateOffline();
|
pair.Value.UpdateOffline(); // AI notifies are processed in ::UpdateVictim caller
|
||||||
|
|
||||||
// fixated target is always preferred
|
// fixated target is always preferred
|
||||||
if (_fixateRef != null && _fixateRef.IsAvailable())
|
if (_fixateRef != null && _fixateRef.IsAvailable())
|
||||||
@@ -509,6 +504,16 @@ namespace Game.Combat
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcessAIUpdates()
|
||||||
|
{
|
||||||
|
CreatureAI ai = _owner.ToCreature().GetAI();
|
||||||
|
List<ThreatReference> v = new(_needsAIUpdate); // _needClientUpdate is now empty in case this triggers a recursive call
|
||||||
|
if (ai == null)
|
||||||
|
return;
|
||||||
|
foreach (ThreatReference refe in v)
|
||||||
|
ai.JustStartedThreateningMe(refe.GetVictim());
|
||||||
|
}
|
||||||
|
|
||||||
// returns true if a is LOWER on the threat list than b
|
// returns true if a is LOWER on the threat list than b
|
||||||
public static bool CompareReferencesLT(ThreatReference a, ThreatReference b, float aWeight)
|
public static bool CompareReferencesLT(ThreatReference a, ThreatReference b, float aWeight)
|
||||||
{
|
{
|
||||||
@@ -563,17 +568,17 @@ namespace Game.Combat
|
|||||||
threat *= victimMgr._singleSchoolModifiers[(int)SpellSchools.Arcane];
|
threat *= victimMgr._singleSchoolModifiers[(int)SpellSchools.Arcane];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
{
|
||||||
|
if (victimMgr._multiSchoolModifiers.TryGetValue(mask, out float value))
|
||||||
{
|
{
|
||||||
if (victimMgr._multiSchoolModifiers.TryGetValue(mask, out float value))
|
threat *= value;
|
||||||
{
|
|
||||||
threat *= value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
float mod = victim.GetTotalAuraMultiplierByMiscMask(AuraType.ModThreat, (uint)mask);
|
|
||||||
victimMgr._multiSchoolModifiers[mask] = mod;
|
|
||||||
threat *= mod;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
float mod = victim.GetTotalAuraMultiplierByMiscMask(AuraType.ModThreat, (uint)mask);
|
||||||
|
victimMgr._multiSchoolModifiers[mask] = mod;
|
||||||
|
threat *= mod;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return threat;
|
return threat;
|
||||||
}
|
}
|
||||||
@@ -671,7 +676,7 @@ namespace Game.Combat
|
|||||||
threatClear.UnitGUID = _owner.GetGUID();
|
threatClear.UnitGUID = _owner.GetGUID();
|
||||||
_owner.SendMessageToSet(threatClear, false);
|
_owner.SendMessageToSet(threatClear, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendRemoveToClients(Unit victim)
|
public void SendRemoveToClients(Unit victim)
|
||||||
{
|
{
|
||||||
ThreatRemove threatRemove = new();
|
ThreatRemove threatRemove = new();
|
||||||
@@ -797,6 +802,8 @@ namespace Game.Combat
|
|||||||
|
|
||||||
// Resets the specified unit's threat to zero
|
// Resets the specified unit's threat to zero
|
||||||
public void ResetThreat(Unit target) { ScaleThreat(target, 0.0f); }
|
public void ResetThreat(Unit target) { ScaleThreat(target, 0.0f); }
|
||||||
|
|
||||||
|
public void RegisterForAIUpdate(ThreatReference refe) { _needsAIUpdate.Add(refe); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum TauntState
|
public enum TauntState
|
||||||
@@ -827,7 +834,7 @@ namespace Game.Combat
|
|||||||
_owner = mgr._owner as Creature;
|
_owner = mgr._owner as Creature;
|
||||||
_mgr = mgr;
|
_mgr = mgr;
|
||||||
_victim = victim;
|
_victim = victim;
|
||||||
Online = ShouldBeSuppressed() ? OnlineState.Suppressed : OnlineState.Online;
|
Online = OnlineState.Offline;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddThreat(float amount)
|
public void AddThreat(float amount)
|
||||||
@@ -866,6 +873,7 @@ namespace Game.Combat
|
|||||||
{
|
{
|
||||||
Online = ShouldBeSuppressed() ? OnlineState.Suppressed : OnlineState.Online;
|
Online = ShouldBeSuppressed() ? OnlineState.Suppressed : OnlineState.Online;
|
||||||
ListNotifyChanged();
|
ListNotifyChanged();
|
||||||
|
_mgr.RegisterForAIUpdate(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1047,6 +1047,14 @@ namespace Game.Entities
|
|||||||
&& !GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoXpAtKill);
|
&& !GetCreatureTemplate().FlagsExtra.HasAnyFlag(CreatureFlagsExtra.NoXpAtKill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool IsEngaged()
|
||||||
|
{
|
||||||
|
CreatureAI ai = GetAI();
|
||||||
|
if (ai != null)
|
||||||
|
return ai.IsEngaged();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public override void AtEngage(Unit target)
|
public override void AtEngage(Unit target)
|
||||||
{
|
{
|
||||||
base.AtEngage(target);
|
base.AtEngage(target);
|
||||||
@@ -1353,7 +1361,7 @@ namespace Game.Entities
|
|||||||
CreatureBaseStats stats = Global.ObjectMgr.GetCreatureBaseStats(level, cInfo.UnitClass);
|
CreatureBaseStats stats = Global.ObjectMgr.GetCreatureBaseStats(level, cInfo.UnitClass);
|
||||||
|
|
||||||
// health
|
// health
|
||||||
float healthmod = _GetHealthMod(rank);
|
float healthmod = GetHealthMod(rank);
|
||||||
|
|
||||||
uint basehp = (uint)GetMaxHealthByLevel(level);
|
uint basehp = (uint)GetMaxHealthByLevel(level);
|
||||||
uint health = (uint)(basehp * healthmod);
|
uint health = (uint)(basehp * healthmod);
|
||||||
@@ -1416,7 +1424,7 @@ namespace Game.Entities
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float _GetHealthMod(CreatureEliteType Rank)
|
public float GetHealthMod(CreatureEliteType Rank)
|
||||||
{
|
{
|
||||||
switch (Rank) // define rates for each elite rank
|
switch (Rank) // define rates for each elite rank
|
||||||
{
|
{
|
||||||
@@ -1567,7 +1575,7 @@ namespace Game.Entities
|
|||||||
curhealth = m_creatureData.curhealth;
|
curhealth = m_creatureData.curhealth;
|
||||||
if (curhealth != 0)
|
if (curhealth != 0)
|
||||||
{
|
{
|
||||||
curhealth = (uint)(curhealth * _GetHealthMod(GetCreatureTemplate().Rank));
|
curhealth = (uint)(curhealth * GetHealthMod(GetCreatureTemplate().Rank));
|
||||||
if (curhealth < 1)
|
if (curhealth < 1)
|
||||||
curhealth = 1;
|
curhealth = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,8 +57,9 @@ namespace Game.Entities
|
|||||||
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.LeavingCombat);
|
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags.LeavingCombat);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void AtEngage(Unit target) { m_isEngaged = true; }
|
public virtual void AtEngage(Unit target) { }
|
||||||
public virtual void AtDisengage() { m_isEngaged = false; }
|
|
||||||
|
public virtual void AtDisengage() { }
|
||||||
|
|
||||||
public void CombatStop(bool includingCast = false, bool mutualPvP = true)
|
public void CombatStop(bool includingCast = false, bool mutualPvP = true)
|
||||||
{
|
{
|
||||||
@@ -147,10 +148,10 @@ namespace Game.Entities
|
|||||||
|
|
||||||
public bool CanHaveThreatList() { return m_threatManager.CanHaveThreatList(); }
|
public bool CanHaveThreatList() { return m_threatManager.CanHaveThreatList(); }
|
||||||
|
|
||||||
// This value can be different from IsInCombat:
|
// This value can be different from IsInCombat, for example:
|
||||||
// - when a projectile spell is midair against a creature (combat on launch - threat+aggro on impact)
|
// - when a projectile spell is midair against a creature (combat on launch - threat+aggro on impact)
|
||||||
// - when the creature has no targets left, but the AI has not yet ceased engaged logic
|
// - when the creature has no targets left, but the AI has not yet ceased engaged logic
|
||||||
public bool IsEngaged() { return m_isEngaged; }
|
public virtual bool IsEngaged() { return IsInCombat(); }
|
||||||
|
|
||||||
public bool IsEngagedBy(Unit who) { return CanHaveThreatList() ? IsThreatenedBy(who) : IsInCombatWith(who); }
|
public bool IsEngagedBy(Unit who) { return CanHaveThreatList() ? IsThreatenedBy(who) : IsInCombatWith(who); }
|
||||||
|
|
||||||
@@ -230,7 +231,6 @@ namespace Game.Entities
|
|||||||
minion.StopAttackFaction(factionId);
|
minion.StopAttackFaction(factionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void HandleProcExtraAttackFor(Unit victim)
|
public void HandleProcExtraAttackFor(Unit victim)
|
||||||
{
|
{
|
||||||
while (ExtraAttacks != 0)
|
while (ExtraAttacks != 0)
|
||||||
|
|||||||
@@ -56,8 +56,6 @@ namespace Game.Entities
|
|||||||
protected uint[] m_attackTimer = new uint[(int)WeaponAttackType.Max];
|
protected uint[] m_attackTimer = new uint[(int)WeaponAttackType.Max];
|
||||||
|
|
||||||
// Threat+combat management
|
// Threat+combat management
|
||||||
bool m_isEngaged;
|
|
||||||
|
|
||||||
CombatManager m_combatManager;
|
CombatManager m_combatManager;
|
||||||
ThreatManager m_threatManager;
|
ThreatManager m_threatManager;
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace Scripts.Pets
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
me.CombatStop(true);
|
me.CombatStop(true);
|
||||||
me.GetThreatManager().NotifyDisengaged();
|
EngagementOver();
|
||||||
me.ResetPlayerDamageReq();
|
me.ResetPlayerDamageReq();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user