diff --git a/Source/Game/AI/SmartScripts/SmartAIManager.cs b/Source/Game/AI/SmartScripts/SmartAIManager.cs index f2f6da4c0..440bc32ae 100644 --- a/Source/Game/AI/SmartScripts/SmartAIManager.cs +++ b/Source/Game/AI/SmartScripts/SmartAIManager.cs @@ -1907,8 +1907,10 @@ namespace Game.AI }; } - public class SmartScriptHolder + public class SmartScriptHolder : IComparer { + public const uint DefaultPriority = uint.MaxValue; + public int EntryOrGuid; public SmartScriptType SourceType; public uint EventId; @@ -1917,6 +1919,7 @@ namespace Game.AI public SmartAction Action; public SmartTarget Target; public uint Timer; + public uint Priority; public bool Active; public bool RunOnce; public bool EnableTimed; @@ -1946,6 +1949,21 @@ namespace Game.AI { return $"Entry {EntryOrGuid} SourceType {GetScriptType()} Event {EventId} Action {GetActionType()}"; } + + public int Compare(SmartScriptHolder left, SmartScriptHolder right) + { + int result = left.Priority.CompareTo(right.Priority); + if (result == 0) + result = left.EntryOrGuid.CompareTo(right.EntryOrGuid); + if (result == 0) + result = left.SourceType.CompareTo(right.SourceType); + if (result == 0) + result = left.EventId.CompareTo(right.EventId); + if (result == 0) + result = left.Link.CompareTo(right.Link); + + return result; + } } [StructLayout(LayoutKind.Explicit)] diff --git a/Source/Game/AI/SmartScripts/SmartScript.cs b/Source/Game/AI/SmartScripts/SmartScript.cs index 198009757..1ef1da5e4 100644 --- a/Source/Game/AI/SmartScripts/SmartScript.cs +++ b/Source/Game/AI/SmartScripts/SmartScript.cs @@ -61,6 +61,8 @@ namespace Game.AI ObjectGuid _textGUID; uint _talkerEntry; bool _useTextTimer; + uint _currentPriority; + bool _eventSortingRequired; Dictionary _storedTargets = new(); @@ -95,9 +97,16 @@ namespace Game.AI InitTimer(holder); holder.RunOnce = false; } + + if (holder.Priority != SmartScriptHolder.DefaultPriority) + { + holder.Priority = SmartScriptHolder.DefaultPriority; + _eventSortingRequired = true; + } } + ProcessEventsFor(SmartEvents.Reset); - LastInvoker = ObjectGuid.Empty; + LastInvoker.Clear(); } public void ProcessEventsFor(SmartEvents e, Unit unit = null, uint var0 = 0, uint var1 = 0, bool bvar = false, SpellInfo spell = null, GameObject gob = null, string varString = "") @@ -427,6 +436,9 @@ namespace Game.AI if (e.Action.cast.targetsLimit > 0 && targets.Count > e.Action.cast.targetsLimit) targets.RandomResize(e.Action.cast.targetsLimit); + bool failedSpellCast = false; + bool successfulSpellCast = false; + foreach (var target in targets) { if (_go != null) @@ -458,7 +470,9 @@ namespace Game.AI ((SmartAI)_me.GetAI()).SetCombatMove(spellCastFailed, true); if (spellCastFailed) - RecalcTimer(e, 500, 500); + failedSpellCast = true; + else + successfulSpellCast = true; } else if (_go) _go.CastSpell(target.ToUnit(), e.Action.cast.spell, new CastSpellExtraArgs(triggerFlag)); @@ -467,6 +481,11 @@ namespace Game.AI Log.outDebug(LogFilter.ScriptsAi, "Spell {0} not casted because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (Guid: {1} Entry: {2} Type: {3}) already has the aura", e.Action.cast.spell, target.GetGUID(), target.GetEntry(), target.GetTypeId()); } + + // If there is at least 1 failed cast and no successful casts at all, retry again on next loop + if (failedSpellCast && !successfulSpellCast) + RaisePriority(e); + break; } case SmartActions.SelfCast: @@ -3779,7 +3798,7 @@ namespace Game.AI { if (_me != null && _me.HasUnitState(UnitState.Casting)) { - e.Timer = 1; + RaisePriority(e); return; } } @@ -3839,6 +3858,18 @@ namespace Game.AI break; } } + + if (e.Priority != SmartScriptHolder.DefaultPriority) + { + // Reset priority to default one only if the event hasn't been rescheduled again to next loop + if (e.Timer > 1) + { + // Re-sort events if this was moved to the top of the queue + _eventSortingRequired = true; + // Reset priority to default one + e.Priority = SmartScriptHolder.DefaultPriority; + } + } } else { @@ -3879,6 +3910,12 @@ namespace Game.AI InstallEvents();//before UpdateTimers + if (_eventSortingRequired) + { + SortEvents(_events); + _eventSortingRequired = false; + } + foreach (var holder in _events) UpdateTimer(holder, diff); @@ -3926,6 +3963,22 @@ namespace Game.AI } } + void SortEvents(List events) + { + events.Sort(); + } + + void RaisePriority(SmartScriptHolder e) + { + e.Timer = 1; + // Change priority only if it's set to default, otherwise keep the current order of events + if (e.Priority == SmartScriptHolder.DefaultPriority) + { + e.Priority = _currentPriority++; + _eventSortingRequired = true; + } + } + void FillScript(List e, WorldObject obj, AreaTriggerRecord at, SceneTemplate scene, Quest quest) { if (e.Empty())