aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/AI
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game/AI')
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp16
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.h2
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.cpp82
-rw-r--r--src/server/game/AI/SmartScripts/SmartScript.h5
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.cpp76
-rw-r--r--src/server/game/AI/SmartScripts/SmartScriptMgr.h16
6 files changed, 173 insertions, 24 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index a203aeb6b97..23dea877776 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -412,26 +412,12 @@ void SmartAI::MovementInform(uint32 MovementType, uint32 Data)
MovepointReached(Data);
}
-void SmartAI::RemoveAuras()
-{
- /// @fixme: duplicated logic in CreatureAI::_EnterEvadeMode (could use RemoveAllAurasExceptType)
- Unit::AuraApplicationMap& appliedAuras = me->GetAppliedAuras();
- for (Unit::AuraApplicationMap::iterator iter = appliedAuras.begin(); iter != appliedAuras.end();)
- {
- Aura const* aura = iter->second->GetBase();
- if (!aura->IsPassive() && !aura->HasEffectType(SPELL_AURA_CONTROL_VEHICLE) && !aura->HasEffectType(SPELL_AURA_CLONE_CASTER) && aura->GetCasterGUID() != me->GetGUID())
- me->RemoveAura(iter);
- else
- ++iter;
- }
-}
-
void SmartAI::EnterEvadeMode()
{
if (!me->IsAlive() || me->IsInEvadeMode())
return;
- RemoveAuras();
+ me->RemoveAllAurasExceptType(SPELL_AURA_CONTROL_VEHICLE, SPELL_AURA_CLONE_CASTER);
me->AddUnitState(UNIT_STATE_EVADE);
me->DeleteThreatList();
diff --git a/src/server/game/AI/SmartScripts/SmartAI.h b/src/server/game/AI/SmartScripts/SmartAI.h
index dcf64b657f8..4d66b976746 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.h
+++ b/src/server/game/AI/SmartScripts/SmartAI.h
@@ -193,8 +193,6 @@ class SmartAI : public CreatureAI
}
void StartDespawn() { mDespawnState = 2; }
- void RemoveAuras();
-
void OnSpellClick(Unit* clicker, bool& result);
private:
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp
index 99ac2ca6f25..006ee4b69ad 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScript.cpp
@@ -76,6 +76,7 @@ SmartScript::SmartScript()
goOrigGUID = 0;
mLastInvoker = 0;
mScriptType = SMART_SCRIPT_TYPE_CREATURE;
+ isProcessingTimedActionList = false;
}
SmartScript::~SmartScript()
@@ -511,7 +512,7 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u
// unless target is outside spell range, out of mana, or LOS.
bool _allowMove = false;
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.cast.spell);
+ SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(e.action.cast.spell);
int32 mana = me->GetPower(POWER_MANA);
if (me->GetDistance(*itr) > spellInfo->GetMaxRange(true) ||
@@ -3116,6 +3117,68 @@ void SmartScript::ProcessEvent(SmartScriptHolder& e, Unit* unit, uint32 var0, ui
ProcessTimedAction(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax, target);
break;
}
+ case SMART_EVENT_DISTANCE_CREATURE:
+ {
+ if (!me)
+ return;
+
+ WorldObject* creature = NULL;
+
+ if (e.event.distance.guid != 0)
+ {
+ creature = FindCreatureNear(me, e.event.distance.guid);
+
+ if (!creature)
+ return;
+
+ if (!me->IsInRange(creature, 0, (float)e.event.distance.dist))
+ return;
+ }
+ else if (e.event.distance.entry != 0)
+ {
+ std::list<Creature*> list;
+ me->GetCreatureListWithEntryInGrid(list, e.event.distance.entry, (float)e.event.distance.dist);
+
+ if (list.size() > 0)
+ creature = list.front();
+ }
+
+ if (creature)
+ ProcessTimedAction(e, e.event.distance.repeat, e.event.distance.repeat);
+
+ break;
+ }
+ case SMART_EVENT_DISTANCE_GAMEOBJECT:
+ {
+ if (!me)
+ return;
+
+ WorldObject* gameobject = NULL;
+
+ if (e.event.distance.guid != 0)
+ {
+ gameobject = FindGameObjectNear(me, e.event.distance.guid);
+
+ if (!gameobject)
+ return;
+
+ if (!me->IsInRange(gameobject, 0, (float)e.event.distance.dist))
+ return;
+ }
+ else if (e.event.distance.entry != 0)
+ {
+ std::list<GameObject*> list;
+ me->GetGameObjectListWithEntryInGrid(list, e.event.distance.entry, (float)e.event.distance.dist);
+
+ if (list.size() > 0)
+ gameobject = list.front();
+ }
+
+ if (gameobject)
+ ProcessTimedAction(e, e.event.distance.repeat, e.event.distance.repeat);
+
+ break;
+ }
default:
TC_LOG_ERROR("sql.sql", "SmartScript::ProcessEvent: Unhandled Event type %u", e.GetEventType());
break;
@@ -3136,6 +3199,10 @@ void SmartScript::InitTimer(SmartScriptHolder& e)
case SMART_EVENT_OOC_LOS:
RecalcTimer(e, e.event.los.cooldownMin, e.event.los.cooldownMax);
break;
+ case SMART_EVENT_DISTANCE_CREATURE:
+ case SMART_EVENT_DISTANCE_GAMEOBJECT:
+ RecalcTimer(e, e.event.distance.repeat, e.event.distance.repeat);
+ break;
default:
e.active = true;
break;
@@ -3196,6 +3263,8 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff)
case SMART_EVENT_TARGET_BUFFED:
case SMART_EVENT_IS_BEHIND_TARGET:
case SMART_EVENT_FRIENDLY_HEALTH_PCT:
+ case SMART_EVENT_DISTANCE_CREATURE:
+ case SMART_EVENT_DISTANCE_GAMEOBJECT:
{
ProcessEvent(e);
if (e.GetScriptType() == SMART_SCRIPT_TYPE_TIMED_ACTIONLIST)
@@ -3252,6 +3321,7 @@ void SmartScript::OnUpdate(uint32 const diff)
bool needCleanup = true;
if (!mTimedActionList.empty())
{
+ isProcessingTimedActionList = true;
for (SmartAIEventList::iterator i = mTimedActionList.begin(); i != mTimedActionList.end(); ++i)
{
if ((*i).enableTimed)
@@ -3260,6 +3330,8 @@ void SmartScript::OnUpdate(uint32 const diff)
needCleanup = false;
}
}
+
+ isProcessingTimedActionList = false;
}
if (needCleanup)
mTimedActionList.clear();
@@ -3501,6 +3573,14 @@ Unit* SmartScript::DoFindClosestFriendlyInRange(float range, bool playerOnly)
void SmartScript::SetScript9(SmartScriptHolder& e, uint32 entry)
{
+ //do NOT clear mTimedActionList if it's being iterated because it will invalidate the iterator and delete
+ // any SmartScriptHolder contained like the "e" parameter passed to this function
+ if (isProcessingTimedActionList)
+ {
+ TC_LOG_ERROR("scripts.ai", "Entry %d SourceType %u Event %u Action %u is trying to overwrite timed action list from a timed action, this is not allowed!.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
+ return;
+ }
+
mTimedActionList.clear();
mTimedActionList = sSmartScriptMgr->GetScript(entry, SMART_SCRIPT_TYPE_TIMED_ACTIONLIST);
if (mTimedActionList.empty())
diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h
index 2e1068d1bff..244728a3037 100644
--- a/src/server/game/AI/SmartScripts/SmartScript.h
+++ b/src/server/game/AI/SmartScripts/SmartScript.h
@@ -118,7 +118,7 @@ class SmartScript
smart = false;
if (!smart)
- TC_LOG_ERROR("sql.sql", "SmartScript: Action target Creature (GUID: %u Entry: %u) is not using SmartAI, action skipped to prevent crash.", c ? c->GetDBTableGUIDLow() : (me ? me->GetDBTableGUIDLow() : 0), c ? c->GetEntry() : (me ? me->GetEntry() : 0));
+ TC_LOG_ERROR("sql.sql", "SmartScript: Action target Creature (GUID: %u Entry: %u) is not using SmartAI, action called by Creature (GUID: %u Entry: %u) skipped to prevent crash.", c ? c->GetDBTableGUIDLow() : 0, c ? c->GetEntry() : 0, me ? me->GetDBTableGUIDLow() : 0, me ? me->GetEntry() : 0);
return smart;
}
@@ -132,7 +132,7 @@ class SmartScript
if (!go || go->GetAIName() != "SmartGameObjectAI")
smart = false;
if (!smart)
- TC_LOG_ERROR("sql.sql", "SmartScript: Action target GameObject (GUID: %u Entry: %u) is not using SmartGameObjectAI, action skipped to prevent crash.", g ? g->GetDBTableGUIDLow() : (go ? go->GetDBTableGUIDLow() : 0), g ? g->GetEntry() : (go ? go->GetEntry() : 0));
+ TC_LOG_ERROR("sql.sql", "SmartScript: Action target GameObject (GUID: %u Entry: %u) is not using SmartGameObjectAI, action called by GameObject (GUID: %u Entry: %u) skipped to prevent crash.", g ? g->GetDBTableGUIDLow() : 0, g ? g->GetEntry() : 0, go ? go->GetDBTableGUIDLow() : 0, go ? go->GetEntry() : 0);
return smart;
}
@@ -222,6 +222,7 @@ class SmartScript
SmartAIEventList mEvents;
SmartAIEventList mInstallEvents;
SmartAIEventList mTimedActionList;
+ bool isProcessingTimedActionList;
Creature* me;
uint64 meOrigGUID;
GameObject* go;
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
index d912de2a72c..993e6967ba5 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@@ -583,6 +583,56 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
}
break;
+ case SMART_EVENT_DISTANCE_CREATURE:
+ if (e.event.distance.guid == 0 && e.event.distance.entry == 0)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE did not provide creature guid or entry, skipped.");
+ return false;
+ }
+
+ if (e.event.distance.guid != 0 && e.event.distance.entry != 0)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE provided both an entry and guid, skipped.");
+ return false;
+ }
+
+ if (e.event.distance.guid != 0 && !sObjectMgr->GetCreatureData(e.event.distance.guid))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature guid %u, skipped.", e.event.distance.guid);
+ return false;
+ }
+
+ if (e.event.distance.entry != 0 && !sObjectMgr->GetCreatureTemplate(e.event.distance.entry))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature entry %u, skipped.", e.event.distance.entry);
+ return false;
+ }
+ break;
+ case SMART_EVENT_DISTANCE_GAMEOBJECT:
+ if (e.event.distance.guid == 0 && e.event.distance.entry == 0)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT did not provide gameobject guid or entry, skipped.");
+ return false;
+ }
+
+ if (e.event.distance.guid != 0 && e.event.distance.entry != 0)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT provided both an entry and guid, skipped.");
+ return false;
+ }
+
+ if (e.event.distance.guid != 0 && !sObjectMgr->GetGOData(e.event.distance.guid))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject guid %u, skipped.", e.event.distance.guid);
+ return false;
+ }
+
+ if (e.event.distance.entry != 0 && !sObjectMgr->GetGameObjectTemplate(e.event.distance.entry))
+ {
+ TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject entry %u, skipped.", e.event.distance.entry);
+ return false;
+ }
+ break;
case SMART_EVENT_GO_STATE_CHANGED:
case SMART_EVENT_GO_EVENT_INFORM:
case SMART_EVENT_TIMED_EVENT_TRIGGERED:
@@ -887,6 +937,12 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
return false;
break;
}
+ case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST:
+ {
+ if (!IsMinMaxValid(e, e.action.randTimedActionList.entry1, e.action.randTimedActionList.entry2))
+ return false;
+ break;
+ }
case SMART_ACTION_SET_POWER:
case SMART_ACTION_ADD_POWER:
case SMART_ACTION_REMOVE_POWER:
@@ -934,6 +990,24 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
}
break;
}
+ case SMART_ACTION_EQUIP:
+ {
+ if (e.GetScriptType() == SMART_SCRIPT_TYPE_CREATURE)
+ {
+ int8 equipId = (int8)e.action.equip.entry;
+
+ if (equipId)
+ {
+ EquipmentInfo const* einfo = sObjectMgr->GetEquipmentInfo(e.entryOrGuid, equipId);
+ if (!einfo)
+ {
+ TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id %u for creature %u, skipped.", equipId, e.entryOrGuid);
+ return false;
+ }
+ }
+ }
+ break;
+ }
case SMART_ACTION_FOLLOW:
case SMART_ACTION_SET_ORIENTATION:
case SMART_ACTION_STORE_TARGET_LIST:
@@ -970,7 +1044,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_MOVE_TO_POS:
case SMART_ACTION_RESPAWN_TARGET:
case SMART_ACTION_CLOSE_GOSSIP:
- case SMART_ACTION_EQUIP:
case SMART_ACTION_TRIGGER_TIMED_EVENT:
case SMART_ACTION_REMOVE_TIMED_EVENT:
case SMART_ACTION_OVERRIDE_SCRIPT_BASE_OBJECT:
@@ -986,7 +1059,6 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)
case SMART_ACTION_SIMPLE_TALK:
case SMART_ACTION_CROSS_CAST:
case SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST:
- case SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST:
case SMART_ACTION_RANDOM_MOVE:
case SMART_ACTION_SET_UNIT_FIELD_BYTES_1:
case SMART_ACTION_REMOVE_UNIT_FIELD_BYTES_1:
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
index d47dbeae600..78a26e7e836 100644
--- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h
+++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h
@@ -166,8 +166,10 @@ enum SMART_EVENT
SMART_EVENT_ACTION_DONE = 72, // eventId (SharedDefines.EventId)
SMART_EVENT_ON_SPELLCLICK = 73, // clicker (unit)
SMART_EVENT_FRIENDLY_HEALTH_PCT = 74, // minHpPct, maxHpPct, repeatMin, repeatMax
+ SMART_EVENT_DISTANCE_CREATURE = 75, // guid, entry, distance, repeat
+ SMART_EVENT_DISTANCE_GAMEOBJECT = 76, // guid, entry, distance, repeat
- SMART_EVENT_END = 75
+ SMART_EVENT_END = 77
};
struct SmartEvent
@@ -389,6 +391,14 @@ struct SmartEvent
struct
{
+ uint32 guid;
+ uint32 entry;
+ uint32 dist;
+ uint32 repeat;
+ } distance;
+
+ struct
+ {
uint32 param1;
uint32 param2;
uint32 param3;
@@ -1221,7 +1231,7 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] =
{SMART_EVENT_REACHED_HOME, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_RECEIVE_EMOTE, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_HAS_AURA, SMART_SCRIPT_TYPE_MASK_CREATURE },
- {SMART_EVENT_TARGET_BUFFED, SMART_SCRIPT_TYPE_MASK_CREATURE + SMART_SCRIPT_TYPE_MASK_GAMEOBJECT },
+ {SMART_EVENT_TARGET_BUFFED, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_RESET, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_IC_LOS, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_PASSENGER_BOARDED, SMART_SCRIPT_TYPE_MASK_CREATURE },
@@ -1272,6 +1282,8 @@ const uint32 SmartAIEventMask[SMART_EVENT_END][2] =
{SMART_EVENT_ACTION_DONE, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_ON_SPELLCLICK, SMART_SCRIPT_TYPE_MASK_CREATURE },
{SMART_EVENT_FRIENDLY_HEALTH_PCT, SMART_SCRIPT_TYPE_MASK_CREATURE },
+ {SMART_EVENT_DISTANCE_CREATURE, SMART_SCRIPT_TYPE_MASK_CREATURE },
+ {SMART_EVENT_DISTANCE_GAMEOBJECT, SMART_SCRIPT_TYPE_MASK_CREATURE },
};
enum SmartEventFlags