diff options
author | Giacomo Pozzoni <giacomopoz@gmail.com> | 2020-08-16 16:50:04 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-01-26 22:26:08 +0100 |
commit | f2ee365da43f851181c8a486e10325a95b75c55d (patch) | |
tree | b8cfec65fe1a6537b9e6e42cffe107880dee4b7e /src | |
parent | 2d1a1d8ac31564744f30e001486ddc90f7ed0449 (diff) |
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 (#25238)
* 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
* Core/SAI: Re-sort the events only when needed
* Fix some priority reset and wrong mEventSortingRequired handling
* Code cleanup.
Sort only events loaded from db (not stored events, not timed action list).
* Code cleanup.
Raise priority of failed casts so they are retried before other spells
* Keep priority of the action fails and is rescheduled on next update
* Don't try recasting a spell in SMART_ACTION_CAST if there are multiple targets and at least 1 was successful
(cherry picked from commit ca25e8d0199730c0976ebc37317e9407aceccc34)
Diffstat (limited to 'src')
-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 | 11 |
3 files changed, 68 insertions, 3 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index dfee4bf1e2e..d1ab3e5932f 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -61,6 +61,8 @@ SmartScript::SmartScript() mTemplate = SMARTAI_TEMPLATE_BASIC; mScriptType = SMART_SCRIPT_TYPE_CREATURE; isProcessingTimedActionList = false; + mCurrentPriority = 0; + mEventSortingRequired = false; } SmartScript::~SmartScript() @@ -186,6 +188,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(); @@ -541,6 +549,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 @@ -576,7 +586,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); @@ -587,6 +599,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: @@ -3754,7 +3770,7 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff) { if (me && me->HasUnitState(UNIT_STATE_CASTING)) { - e.timer = 1; + RaisePriority(e); return; } } @@ -3771,6 +3787,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: @@ -3814,6 +3831,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; @@ -3922,6 +3951,12 @@ void SmartScript::OnUpdate(uint32 const diff) InstallEvents();//before UpdateTimers + if (mEventSortingRequired) + { + SortEvents(mEvents); + mEventSortingRequired = false; + } + for (SmartScriptHolder& mEvent : mEvents) UpdateTimer(mEvent, diff); @@ -3979,6 +4014,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, SceneTemplate const* scene, Quest const* quest) { if (e.empty()) diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 4dd0faf5522..5e88f2608fe 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -105,6 +105,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; @@ -130,6 +133,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 87ea61dd5c4..bc2fb36e5e5 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -21,6 +21,7 @@ #include "Define.h" #include "ObjectGuid.h" #include "WaypointDefines.h" +#include <limits> #include <map> #include <string> #include <unordered_map> @@ -1623,7 +1624,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) { } int64 entryOrGuid; @@ -1641,11 +1642,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; |