diff options
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.cpp | 55 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScript.h | 5 | ||||
-rw-r--r-- | src/server/game/AI/SmartScripts/SmartScriptMgr.h | 10 |
3 files changed, 67 insertions, 3 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 4df56079d1f..bf38219d4e7 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -57,6 +57,8 @@ SmartScript::SmartScript() mTemplate = SMARTAI_TEMPLATE_BASIC; mScriptType = SMART_SCRIPT_TYPE_CREATURE; isProcessingTimedActionList = false; + mCurrentPriority = 0; + mEventSortingRequired = false; } SmartScript::~SmartScript() @@ -174,6 +176,12 @@ void SmartScript::OnReset() InitTimer(event); event.runOnce = false; } + + if (event.priority != SmartScriptHolder::DEFAULT_PRIORITY) + { + event.priority = SmartScriptHolder::DEFAULT_PRIORITY; + mEventSortingRequired = true; + } } ProcessEventsFor(SMART_EVENT_RESET); mLastInvoker.Clear(); @@ -527,6 +535,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (e.action.cast.targetsLimit > 0 && targets.size() > e.action.cast.targetsLimit) Trinity::Containers::RandomResize(targets, e.action.cast.targetsLimit); + bool failedSpellCast = false, successfulSpellCast = false; + for (WorldObject* target : targets) { // may be nullptr @@ -562,7 +572,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } if (spellCastFailed) - RecalcTimer(e, 500, 500); + failedSpellCast = true; + else + successfulSpellCast = true; } else if (go) go->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlag); @@ -573,6 +585,10 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u else TC_LOG_DEBUG("scripts.ai", "Spell %u not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target (%s) already has the aura", e.action.cast.spell, target->GetGUID().ToString().c_str()); } + + // 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 SMART_ACTION_SELF_CAST: @@ -3474,7 +3490,7 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff) { if (me && me->HasUnitState(UNIT_STATE_CASTING)) { - e.timer = 1; + RaisePriority(e); return; } } @@ -3491,6 +3507,7 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff) } e.active = true;//activate events with cooldown + switch (e.GetEventType())//process ONLY timed events { case SMART_EVENT_UPDATE: @@ -3534,6 +3551,18 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff) break; } } + + if (e.priority != SmartScriptHolder::DEFAULT_PRIORITY) + { + // 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 + mEventSortingRequired = true; + // Reset priority to default one + e.priority = SmartScriptHolder::DEFAULT_PRIORITY; + } + } } else e.timer -= diff; @@ -3626,6 +3655,12 @@ void SmartScript::OnUpdate(uint32 const diff) InstallEvents();//before UpdateTimers + if (mEventSortingRequired) + { + SortEvents(mEvents); + mEventSortingRequired = false; + } + for (SmartScriptHolder& mEvent : mEvents) UpdateTimer(mEvent, diff); @@ -3680,6 +3715,22 @@ void SmartScript::OnUpdate(uint32 const diff) } } +void SmartScript::SortEvents(SmartAIEventList& events) +{ + std::sort(events.begin(), events.end()); +} + +void SmartScript::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::DEFAULT_PRIORITY) + { + e.priority = mCurrentPriority++; + mEventSortingRequired = true; + } +} + void SmartScript::FillScript(SmartAIEventList e, WorldObject* obj, AreaTriggerEntry const* at) { if (e.empty()) diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 7a533d689db..bd5d1756657 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -100,6 +100,9 @@ class TC_GAME_API SmartScript void SetPhase(uint32 p); bool IsInPhase(uint32 p) const; + void SortEvents(SmartAIEventList& events); + void RaisePriority(SmartScriptHolder& e); + SmartAIEventList mEvents; SmartAIEventList mInstallEvents; SmartAIEventList mTimedActionList; @@ -122,6 +125,8 @@ class TC_GAME_API SmartScript uint32 mLastTextID; uint32 mTalkerEntry; bool mUseTextTimer; + uint32 mCurrentPriority; + bool mEventSortingRequired; ObjectVectorMap _storedTargets; diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index 7792fa3af69..733f83f8abb 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -1543,7 +1543,7 @@ enum SmartCastFlags struct SmartScriptHolder { SmartScriptHolder() : entryOrGuid(0), source_type(SMART_SCRIPT_TYPE_CREATURE) - , event_id(0), link(0), event(), action(), target(), timer(0), active(false), runOnce(false) + , event_id(0), link(0), event(), action(), target(), timer(0), priority(DEFAULT_PRIORITY), active(false), runOnce(false) , enableTimed(false) { } int32 entryOrGuid; @@ -1561,11 +1561,19 @@ struct SmartScriptHolder uint32 GetTargetType() const { return (uint32)target.type; } uint32 timer; + uint32 priority; bool active; bool runOnce; bool enableTimed; operator bool() const { return entryOrGuid != 0; } + // Default comparision operator using priority field as first ordering field + bool operator<(SmartScriptHolder const& other) const + { + return std::tie(priority, entryOrGuid, source_type, event_id, link) < std::tie(other.priority, other.entryOrGuid, other.source_type, other.event_id, other.link); + } + + static constexpr uint32 DEFAULT_PRIORITY = std::numeric_limits<uint32>::max(); }; typedef std::vector<WorldObject*> ObjectVector; |