aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
authorGiacomo Pozzoni <giacomopoz@gmail.com>2020-08-16 16:50:04 +0200
committerShauren <shauren.trinity@gmail.com>2022-01-26 22:26:08 +0100
commitf2ee365da43f851181c8a486e10325a95b75c55d (patch)
treeb8cfec65fe1a6537b9e6e42cffe107880dee4b7e /src/server
parent2d1a1d8ac31564744f30e001486ddc90f7ed0449 (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/server')
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp55
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h5
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h11
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;