Core/SAI: Spell casts that cannot be executed because the unit is currently casting another spell will be retried asap with priority over other events
Port From (https://github.com/TrinityCore/TrinityCore/commit/f2ee365da43f851181c8a486e10325a95b75c55d)
This commit is contained in:
@@ -1907,8 +1907,10 @@ namespace Game.AI
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SmartScriptHolder
|
public class SmartScriptHolder : IComparer<SmartScriptHolder>
|
||||||
{
|
{
|
||||||
|
public const uint DefaultPriority = uint.MaxValue;
|
||||||
|
|
||||||
public int EntryOrGuid;
|
public int EntryOrGuid;
|
||||||
public SmartScriptType SourceType;
|
public SmartScriptType SourceType;
|
||||||
public uint EventId;
|
public uint EventId;
|
||||||
@@ -1917,6 +1919,7 @@ namespace Game.AI
|
|||||||
public SmartAction Action;
|
public SmartAction Action;
|
||||||
public SmartTarget Target;
|
public SmartTarget Target;
|
||||||
public uint Timer;
|
public uint Timer;
|
||||||
|
public uint Priority;
|
||||||
public bool Active;
|
public bool Active;
|
||||||
public bool RunOnce;
|
public bool RunOnce;
|
||||||
public bool EnableTimed;
|
public bool EnableTimed;
|
||||||
@@ -1946,6 +1949,21 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
return $"Entry {EntryOrGuid} SourceType {GetScriptType()} Event {EventId} Action {GetActionType()}";
|
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)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ namespace Game.AI
|
|||||||
ObjectGuid _textGUID;
|
ObjectGuid _textGUID;
|
||||||
uint _talkerEntry;
|
uint _talkerEntry;
|
||||||
bool _useTextTimer;
|
bool _useTextTimer;
|
||||||
|
uint _currentPriority;
|
||||||
|
bool _eventSortingRequired;
|
||||||
|
|
||||||
Dictionary<uint, ObjectGuidList> _storedTargets = new();
|
Dictionary<uint, ObjectGuidList> _storedTargets = new();
|
||||||
|
|
||||||
@@ -95,9 +97,16 @@ namespace Game.AI
|
|||||||
InitTimer(holder);
|
InitTimer(holder);
|
||||||
holder.RunOnce = false;
|
holder.RunOnce = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (holder.Priority != SmartScriptHolder.DefaultPriority)
|
||||||
|
{
|
||||||
|
holder.Priority = SmartScriptHolder.DefaultPriority;
|
||||||
|
_eventSortingRequired = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessEventsFor(SmartEvents.Reset);
|
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 = "")
|
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)
|
if (e.Action.cast.targetsLimit > 0 && targets.Count > e.Action.cast.targetsLimit)
|
||||||
targets.RandomResize(e.Action.cast.targetsLimit);
|
targets.RandomResize(e.Action.cast.targetsLimit);
|
||||||
|
|
||||||
|
bool failedSpellCast = false;
|
||||||
|
bool successfulSpellCast = false;
|
||||||
|
|
||||||
foreach (var target in targets)
|
foreach (var target in targets)
|
||||||
{
|
{
|
||||||
if (_go != null)
|
if (_go != null)
|
||||||
@@ -458,7 +470,9 @@ namespace Game.AI
|
|||||||
((SmartAI)_me.GetAI()).SetCombatMove(spellCastFailed, true);
|
((SmartAI)_me.GetAI()).SetCombatMove(spellCastFailed, true);
|
||||||
|
|
||||||
if (spellCastFailed)
|
if (spellCastFailed)
|
||||||
RecalcTimer(e, 500, 500);
|
failedSpellCast = true;
|
||||||
|
else
|
||||||
|
successfulSpellCast = true;
|
||||||
}
|
}
|
||||||
else if (_go)
|
else if (_go)
|
||||||
_go.CastSpell(target.ToUnit(), e.Action.cast.spell, new CastSpellExtraArgs(triggerFlag));
|
_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",
|
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());
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case SmartActions.SelfCast:
|
case SmartActions.SelfCast:
|
||||||
@@ -3779,7 +3798,7 @@ namespace Game.AI
|
|||||||
{
|
{
|
||||||
if (_me != null && _me.HasUnitState(UnitState.Casting))
|
if (_me != null && _me.HasUnitState(UnitState.Casting))
|
||||||
{
|
{
|
||||||
e.Timer = 1;
|
RaisePriority(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3839,6 +3858,18 @@ namespace Game.AI
|
|||||||
break;
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -3879,6 +3910,12 @@ namespace Game.AI
|
|||||||
|
|
||||||
InstallEvents();//before UpdateTimers
|
InstallEvents();//before UpdateTimers
|
||||||
|
|
||||||
|
if (_eventSortingRequired)
|
||||||
|
{
|
||||||
|
SortEvents(_events);
|
||||||
|
_eventSortingRequired = false;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var holder in _events)
|
foreach (var holder in _events)
|
||||||
UpdateTimer(holder, diff);
|
UpdateTimer(holder, diff);
|
||||||
|
|
||||||
@@ -3926,6 +3963,22 @@ namespace Game.AI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SortEvents(List<SmartScriptHolder> 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<SmartScriptHolder> e, WorldObject obj, AreaTriggerRecord at, SceneTemplate scene, Quest quest)
|
void FillScript(List<SmartScriptHolder> e, WorldObject obj, AreaTriggerRecord at, SceneTemplate scene, Quest quest)
|
||||||
{
|
{
|
||||||
if (e.Empty())
|
if (e.Empty())
|
||||||
|
|||||||
Reference in New Issue
Block a user