AzerothCore 3.3.5a
OpenSource WoW Emulator
Loading...
Searching...
No Matches
SmartScript Class Reference

#include "SmartScript.h"

Public Types

typedef std::unordered_map< uint32, uint32CounterMap
 

Public Member Functions

 SmartScript ()
 
 ~SmartScript ()
 
void OnInitialize (WorldObject *obj, AreaTrigger const *at=nullptr)
 
void GetScript ()
 
void FillScript (SmartAIEventList e, WorldObject *obj, AreaTrigger const *at)
 
void ProcessEventsFor (SMART_EVENT e, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr)
 
void ProcessEvent (SmartScriptHolder &e, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr)
 
bool CheckTimer (SmartScriptHolder const &e) const
 
void UpdateTimer (SmartScriptHolder &e, uint32 const diff)
 
void ProcessAction (SmartScriptHolder &e, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr)
 
void ProcessTimedAction (SmartScriptHolder &e, uint32 const &min, uint32 const &max, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr)
 
void GetTargets (ObjectVector &targets, SmartScriptHolder const &e, Unit *invoker=nullptr) const
 
void GetWorldObjectsInDist (ObjectVector &objects, float dist) const
 
void InstallTemplate (SmartScriptHolder const &e)
 
void AddEvent (SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
 
void SetPathId (uint32 id)
 
uint32 GetPathId () const
 
WorldObjectGetBaseObject () const
 
void OnUpdate (const uint32 diff)
 
void OnMoveInLineOfSight (Unit *who)
 
UnitDoSelectLowestHpFriendly (float range, uint32 MinHPDiff) const
 
UnitDoSelectLowestHpPercentFriendly (float range, uint32 minHpPct, uint32 maxHpPct) const
 
void DoFindFriendlyCC (std::vector< Creature * > &creatures, float range) const
 
void DoFindFriendlyMissingBuff (std::vector< Creature * > &creatures, float range, uint32 spellid) const
 
UnitDoFindClosestFriendlyInRange (float range, bool playerOnly) const
 
void StoreTargetList (ObjectVector const &targets, uint32 id)
 
bool IsSmart (Creature *c=nullptr)
 
bool IsSmartGO (GameObject *g=nullptr)
 
ObjectVector const * GetStoredTargetVector (uint32 id, WorldObject const &ref) const
 
void StoreCounter (uint32 id, uint32 value, uint32 reset, uint32 subtract)
 
uint32 GetCounterValue (uint32 id)
 
GameObjectFindGameObjectNear (WorldObject *searchObject, ObjectGuid::LowType guid) const
 
CreatureFindCreatureNear (WorldObject *searchObject, ObjectGuid::LowType guid) const
 
void OnReset ()
 
void ResetBaseObject ()
 
void SetScript9 (SmartScriptHolder &e, uint32 entry)
 
UnitGetLastInvoker (Unit *invoker=nullptr) const
 
void SetActualCombatDist (uint32 dist)
 
void RestoreMaxCombatDist ()
 
uint32 GetActualCombatDist () const
 
uint32 GetMaxCombatDist () const
 
void SetCasterActualDist (float dist)
 
void RestoreCasterMaxDist ()
 
Powers GetCasterPowerType () const
 
float GetCasterActualDist () const
 
float GetCasterMaxDist () const
 
bool AllowPhaseReset () const
 
void SetPhaseReset (bool allow)
 
void AddCreatureSummon (ObjectGuid const &guid)
 
void RemoveCreatureSummon (ObjectGuid const &guid)
 

Static Public Member Functions

static void RecalcTimer (SmartScriptHolder &e, uint32 min, uint32 max)
 
static void InitTimer (SmartScriptHolder &e)
 
static SmartScriptHolder CreateSmartEvent (SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
 
static bool IsUnit (WorldObject *obj)
 
static bool IsPlayer (WorldObject *obj)
 
static bool IsCreature (WorldObject *obj)
 
static bool IsCharmedCreature (WorldObject *obj)
 
static bool IsGameObject (WorldObject *obj)
 

Public Attributes

ObjectGuid mLastInvoker
 
CounterMap mCounterList
 

Private Member Functions

void IncPhase (uint32 p)
 
void DecPhase (uint32 p)
 
void SetPhase (uint32 p)
 
bool IsInPhase (uint32 p) const
 
void InstallEvents ()
 
void RemoveStoredEvent (uint32 id)
 
SmartScriptHolder FindLinkedEvent (uint32 link)
 

Private Attributes

SmartAIEventList mEvents
 
SmartAIEventList mInstallEvents
 
SmartAIEventList mTimedActionList
 
bool isProcessingTimedActionList
 
Creatureme
 
ObjectGuid meOrigGUID
 
GameObjectgo
 
ObjectGuid goOrigGUID
 
AreaTrigger const * trigger
 
SmartScriptType mScriptType
 
uint32 mEventPhase
 
std::unordered_map< int32, int32mStoredDecimals
 
uint32 mPathId
 
SmartAIEventStoredList mStoredEvents
 
std::list< uint32mRemIDs
 
uint32 mTextTimer
 
uint32 mLastTextID
 
uint32 mTalkerEntry
 
bool mUseTextTimer
 
uint32 mActualCombatDist
 
uint32 mMaxCombatDist
 
uint32 smartCasterActualDist
 
uint32 smartCasterMaxDist
 
Powers smartCasterPowerType
 
bool _allowPhaseReset
 
ObjectVectorMap _storedTargets
 
SMARTAI_TEMPLATE mTemplate
 
GuidUnorderedSet _summonList
 

Detailed Description

Member Typedef Documentation

◆ CounterMap

typedef std::unordered_map<uint32, uint32> SmartScript::CounterMap

Constructor & Destructor Documentation

◆ SmartScript()

SmartScript::SmartScript ( )
41{
42 go = nullptr;
43 me = nullptr;
44 trigger = nullptr;
45 mEventPhase = 0;
46 mPathId = 0;
47 mTextTimer = 0;
48 mLastTextID = 0;
49 mUseTextTimer = false;
50 mTalkerEntry = 0;
54
55 // Xinef: Fix Combat Movement
58
60 smartCasterMaxDist = 0.0f;
62
63 _allowPhaseReset = true;
64}
@ SMART_SCRIPT_TYPE_CREATURE
Definition: SmartScriptMgr.h:1705
@ SMARTAI_TEMPLATE_BASIC
Definition: SmartScriptMgr.h:1465
@ POWER_MANA
Definition: SharedDefines.h:241
uint32 mEventPhase
Definition: SmartScript.h:254
SMARTAI_TEMPLATE mTemplate
Definition: SmartScript.h:280
Creature * me
Definition: SmartScript.h:248
uint32 mPathId
Definition: SmartScript.h:257
SmartScriptType mScriptType
Definition: SmartScript.h:253
uint32 smartCasterActualDist
Definition: SmartScript.h:271
bool _allowPhaseReset
Definition: SmartScript.h:276
bool mUseTextTimer
Definition: SmartScript.h:264
uint32 mLastTextID
Definition: SmartScript.h:262
uint32 mTextTimer
Definition: SmartScript.h:261
GameObject * go
Definition: SmartScript.h:250
uint32 mMaxCombatDist
Definition: SmartScript.h:268
uint32 mActualCombatDist
Definition: SmartScript.h:267
AreaTrigger const * trigger
Definition: SmartScript.h:252
Powers smartCasterPowerType
Definition: SmartScript.h:273
uint32 mTalkerEntry
Definition: SmartScript.h:263
uint32 smartCasterMaxDist
Definition: SmartScript.h:272
bool isProcessingTimedActionList
Definition: SmartScript.h:247

References _allowPhaseReset, go, isProcessingTimedActionList, mActualCombatDist, me, mEventPhase, mLastTextID, mMaxCombatDist, mPathId, mScriptType, mTalkerEntry, mTemplate, mTextTimer, mUseTextTimer, POWER_MANA, SMART_SCRIPT_TYPE_CREATURE, SMARTAI_TEMPLATE_BASIC, smartCasterActualDist, smartCasterMaxDist, smartCasterPowerType, and trigger.

◆ ~SmartScript()

SmartScript::~SmartScript ( )
67{
68
69}

Member Function Documentation

◆ AddCreatureSummon()

void SmartScript::AddCreatureSummon ( ObjectGuid const &  guid)
4972{
4973 _summonList.insert(guid);
4974}
GuidUnorderedSet _summonList
Definition: SmartScript.h:313

References _summonList.

Referenced by SmartAI::JustSummoned().

◆ AddEvent()

void SmartScript::AddEvent ( SMART_EVENT  e,
uint32  event_flags,
uint32  event_param1,
uint32  event_param2,
uint32  event_param3,
uint32  event_param4,
uint32  event_param5,
uint32  event_param6,
SMART_ACTION  action,
uint32  action_param1,
uint32  action_param2,
uint32  action_param3,
uint32  action_param4,
uint32  action_param5,
uint32  action_param6,
SMARTAI_TARGETS  t,
uint32  target_param1,
uint32  target_param2,
uint32  target_param3,
uint32  target_param4,
uint32  phaseMask 
)
2999{
3000 mInstallEvents.push_back(CreateSmartEvent(e, event_flags, event_param1, event_param2, event_param3, event_param4, event_param5, event_param6, action, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, t, target_param1, target_param2, target_param3, target_param4, phaseMask));
3001}
SmartAIEventList mInstallEvents
Definition: SmartScript.h:245
static SmartScriptHolder CreateSmartEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
Definition: SmartScript.cpp:3003

References CreateSmartEvent(), and mInstallEvents.

Referenced by InstallTemplate().

◆ AllowPhaseReset()

bool SmartScript::AllowPhaseReset ( ) const
inline
232{ return _allowPhaseReset; }

References _allowPhaseReset.

Referenced by OnReset().

◆ CheckTimer()

bool SmartScript::CheckTimer ( SmartScriptHolder const &  e) const
4524{
4525 return e.active;
4526}

References SmartScriptHolder::active.

◆ CreateSmartEvent()

SmartScriptHolder SmartScript::CreateSmartEvent ( SMART_EVENT  e,
uint32  event_flags,
uint32  event_param1,
uint32  event_param2,
uint32  event_param3,
uint32  event_param4,
uint32  event_param5,
uint32  event_param6,
SMART_ACTION  action,
uint32  action_param1,
uint32  action_param2,
uint32  action_param3,
uint32  action_param4,
uint32  action_param5,
uint32  action_param6,
SMARTAI_TARGETS  t,
uint32  target_param1,
uint32  target_param2,
uint32  target_param3,
uint32  target_param4,
uint32  phaseMask 
)
static
3004{
3005 SmartScriptHolder script;
3006 script.event.type = e;
3007 script.event.raw.param1 = event_param1;
3008 script.event.raw.param2 = event_param2;
3009 script.event.raw.param3 = event_param3;
3010 script.event.raw.param4 = event_param4;
3011 script.event.raw.param5 = event_param5;
3012 script.event.raw.param6 = event_param6;
3013 script.event.event_phase_mask = phaseMask;
3014 script.event.event_flags = event_flags;
3015 script.event.event_chance = 100;
3016
3017 script.action.type = action;
3018 script.action.raw.param1 = action_param1;
3019 script.action.raw.param2 = action_param2;
3020 script.action.raw.param3 = action_param3;
3021 script.action.raw.param4 = action_param4;
3022 script.action.raw.param5 = action_param5;
3023 script.action.raw.param6 = action_param6;
3024
3025 script.target.type = t;
3026 script.target.raw.param1 = target_param1;
3027 script.target.raw.param2 = target_param2;
3028 script.target.raw.param3 = target_param3;
3029 script.target.raw.param4 = target_param4;
3030
3032 InitTimer(script);
3033 return script;
3034}
static void InitTimer(SmartScriptHolder &e)
Definition: SmartScript.cpp:4385
uint32 param1
Definition: SmartScriptMgr.h:542
uint32 event_flags
Definition: SmartScriptMgr.h:224
uint32 event_phase_mask
Definition: SmartScriptMgr.h:222
uint32 param2
Definition: SmartScriptMgr.h:543
uint32 param4
Definition: SmartScriptMgr.h:545
uint32 param3
Definition: SmartScriptMgr.h:544
struct SmartEvent::@30::@76 raw
uint32 param6
Definition: SmartScriptMgr.h:547
uint32 event_chance
Definition: SmartScriptMgr.h:223
uint32 param5
Definition: SmartScriptMgr.h:546
SMART_EVENT type
Definition: SmartScriptMgr.h:221
uint32 param3
Definition: SmartScriptMgr.h:1076
uint32 param5
Definition: SmartScriptMgr.h:1078
uint32 param1
Definition: SmartScriptMgr.h:1074
SMART_ACTION type
Definition: SmartScriptMgr.h:762
uint32 param4
Definition: SmartScriptMgr.h:1077
uint32 param6
Definition: SmartScriptMgr.h:1458
struct SmartAction::@77::@190 raw
uint32 param2
Definition: SmartScriptMgr.h:1075
uint32 param4
Definition: SmartScriptMgr.h:1685
uint32 param1
Definition: SmartScriptMgr.h:1682
uint32 param3
Definition: SmartScriptMgr.h:1684
struct SmartTarget::@191::@215 raw
SMARTAI_TARGETS type
Definition: SmartScriptMgr.h:1536
uint32 param2
Definition: SmartScriptMgr.h:1683
Definition: SmartScriptMgr.h:1888
SmartAction action
Definition: SmartScriptMgr.h:1899
SmartScriptType source_type
Definition: SmartScriptMgr.h:1894
SmartEvent event
Definition: SmartScriptMgr.h:1898
SmartTarget target
Definition: SmartScriptMgr.h:1900

References SmartScriptHolder::action, SmartScriptHolder::event, SmartEvent::event_chance, SmartEvent::event_flags, SmartEvent::event_phase_mask, InitTimer(), SmartEvent::param1, SmartAction::param1, SmartTarget::param1, SmartEvent::param2, SmartAction::param2, SmartTarget::param2, SmartEvent::param3, SmartAction::param3, SmartTarget::param3, SmartEvent::param4, SmartAction::param4, SmartTarget::param4, SmartEvent::param5, SmartAction::param5, SmartEvent::param6, SmartAction::param6, SmartEvent::raw, SmartAction::raw, SmartTarget::raw, SMART_SCRIPT_TYPE_CREATURE, SmartScriptHolder::source_type, SmartScriptHolder::target, SmartEvent::type, SmartAction::type, and SmartTarget::type.

Referenced by AddEvent().

◆ DecPhase()

void SmartScript::DecPhase ( uint32  p)
private
4938{
4939 if (p >= mEventPhase)
4940 {
4941 SetPhase(0);
4942 }
4943 else
4944 {
4945 SetPhase(mEventPhase - p);
4946 }
4947}
void SetPhase(uint32 p)
Definition: SmartScript.cpp:4949

References mEventPhase, and SetPhase().

Referenced by ProcessAction().

◆ DoFindClosestFriendlyInRange()

Unit * SmartScript::DoFindClosestFriendlyInRange ( float  range,
bool  playerOnly 
) const
4843{
4844 if (!me)
4845 return nullptr;
4846
4847 Unit* unit = nullptr;
4848 Acore::AnyFriendlyNotSelfUnitInObjectRangeCheck u_check(me, me, range, playerOnly);
4850 Cell::VisitAllObjects(me, searcher, range);
4851 return unit;
4852}
Definition: Unit.h:1302
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:207
Definition: GridNotifiers.h:403

References me, and Cell::VisitAllObjects().

Referenced by GetTargets().

◆ DoFindFriendlyCC()

void SmartScript::DoFindFriendlyCC ( std::vector< Creature * > &  creatures,
float  range 
) const
4823{
4824 if (!me)
4825 return;
4826
4827 Acore::FriendlyCCedInRange u_check(me, range);
4829 Cell::VisitGridObjects(me, searcher, range);
4830}
creatures
Definition: boss_prince_malchezaar.cpp:49
static void VisitGridObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:179
Definition: GridNotifiers.h:470
Definition: GridNotifiers.h:815

References me, and Cell::VisitGridObjects().

Referenced by ProcessEvent().

◆ DoFindFriendlyMissingBuff()

void SmartScript::DoFindFriendlyMissingBuff ( std::vector< Creature * > &  creatures,
float  range,
uint32  spellid 
) const
4833{
4834 if (!me)
4835 return;
4836
4837 Acore::FriendlyMissingBuffInRange u_check(me, range, spellid);
4839 Cell::VisitGridObjects(me, searcher, range);
4840}
Definition: GridNotifiers.h:833

References me, and Cell::VisitGridObjects().

Referenced by ProcessEvent().

◆ DoSelectLowestHpFriendly()

Unit * SmartScript::DoSelectLowestHpFriendly ( float  range,
uint32  MinHPDiff 
) const
4796{
4797 if (!me)
4798 return nullptr;
4799
4800 Unit* unit = nullptr;
4801
4802 Acore::MostHPMissingInRange u_check(me, range, MinHPDiff);
4804 Cell::VisitGridObjects(me, searcher, range);
4805 return unit;
4806}
Definition: GridNotifiers.h:772

References me, and Cell::VisitGridObjects().

Referenced by ProcessEvent().

◆ DoSelectLowestHpPercentFriendly()

Unit * SmartScript::DoSelectLowestHpPercentFriendly ( float  range,
uint32  minHpPct,
uint32  maxHpPct 
) const
4809{
4810 if (!me)
4811 {
4812 return nullptr;
4813 }
4814
4815 Unit* unit = nullptr;
4816 Acore::MostHPPercentMissingInRange u_check(me, range, minHpPct, maxHpPct);
4818 Cell::VisitGridObjects(me, searcher, range);
4819 return unit;
4820}
Definition: GridNotifiers.h:791

References me, and Cell::VisitGridObjects().

Referenced by ProcessEvent().

◆ FillScript()

void SmartScript::FillScript ( SmartAIEventList  e,
WorldObject obj,
AreaTrigger const *  at 
)
4602{
4603 (void)at; // ensure that the variable is referenced even if extra logs are disabled in order to pass compiler checks
4604
4605 if (e.empty())
4606 {
4607 if (obj)
4608 LOG_DEBUG("sql.sql", "SmartScript: EventMap for Entry {} is empty but is using SmartScript.", obj->GetEntry());
4609
4610 if (at)
4611 LOG_DEBUG("sql.sql", "SmartScript: EventMap for AreaTrigger {} is empty but is using SmartScript.", at->entry);
4612 return;
4613 }
4614 for (SmartAIEventList::iterator i = e.begin(); i != e.end(); ++i)
4615 {
4616#ifndef ACORE_DEBUG
4617 if ((*i).event.event_flags & SMART_EVENT_FLAG_DEBUG_ONLY)
4618 continue;
4619#endif
4620
4621 if ((*i).event.event_flags & SMART_EVENT_FLAG_DIFFICULTY_ALL)//if has instance flag add only if in it
4622 {
4623 if (obj && obj->GetMap()->IsDungeon())
4624 {
4625 if ((1 << (obj->GetMap()->GetSpawnMode() + 1)) & (*i).event.event_flags)
4626 {
4627 mEvents.push_back((*i));
4628 }
4629 }
4630 continue;
4631 }
4632 mEvents.push_back((*i));//NOTE: 'world(0)' events still get processed in ANY instance mode
4633 }
4634}
#define LOG_DEBUG(filterType__,...)
Definition: Log.h:171
@ SMART_EVENT_FLAG_DIFFICULTY_ALL
Definition: SmartScriptMgr.h:1870
@ SMART_EVENT_FLAG_DEBUG_ONLY
Definition: SmartScriptMgr.h:1866
SmartAIEventList mEvents
Definition: SmartScript.h:244
uint32 GetEntry() const
Definition: Object.h:109
Map * GetMap() const
Definition: Object.h:517
bool IsDungeon() const
Definition: Map.h:447
uint8 GetSpawnMode() const
Definition: Map.h:419

References AreaTrigger::entry, Object::GetEntry(), WorldObject::GetMap(), Map::GetSpawnMode(), Map::IsDungeon(), LOG_DEBUG, mEvents, SMART_EVENT_FLAG_DEBUG_ONLY, and SMART_EVENT_FLAG_DIFFICULTY_ALL.

Referenced by GetScript().

◆ FindCreatureNear()

Creature * SmartScript::FindCreatureNear ( WorldObject searchObject,
ObjectGuid::LowType  guid 
) const
inline
167 {
168 auto bounds = searchObject->GetMap()->GetCreatureBySpawnIdStore().equal_range(guid);
169 if (bounds.first == bounds.second)
170 return nullptr;
171
172 auto creatureItr = std::find_if(bounds.first, bounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair)
173 {
174 return pair.second->IsAlive();
175 });
176
177 return creatureItr != bounds.second ? creatureItr->second : bounds.first->second;
178 }
CreatureBySpawnIdContainer & GetCreatureBySpawnIdStore()
Definition: Map.h:518

References Map::GetCreatureBySpawnIdStore(), and WorldObject::GetMap().

Referenced by GetTargets(), and ProcessEvent().

◆ FindGameObjectNear()

GameObject * SmartScript::FindGameObjectNear ( WorldObject searchObject,
ObjectGuid::LowType  guid 
) const
inline
158 {
159 auto bounds = searchObject->GetMap()->GetGameObjectBySpawnIdStore().equal_range(guid);
160 if (bounds.first == bounds.second)
161 return nullptr;
162
163 return bounds.first->second;
164 }
GameObjectBySpawnIdContainer & GetGameObjectBySpawnIdStore()
Definition: Map.h:521

References Map::GetGameObjectBySpawnIdStore(), and WorldObject::GetMap().

Referenced by GetTargets(), and ProcessEvent().

◆ FindLinkedEvent()

SmartScriptHolder SmartScript::FindLinkedEvent ( uint32  link)
inlineprivate
298 {
299 if (!mEvents.empty())
300 {
301 for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
302 {
303 if (i->event_id == link)
304 {
305 return (*i);
306 }
307 }
308 }
310 return s;
311 }

References mEvents.

◆ GetActualCombatDist()

uint32 SmartScript::GetActualCombatDist ( ) const
inline
222{ return mActualCombatDist; }

References mActualCombatDist.

Referenced by SmartAI::AttackStart().

◆ GetBaseObject()

WorldObject * SmartScript::GetBaseObject ( ) const
inline
55 {
56 WorldObject* obj = nullptr;
57 if (me)
58 obj = me;
59 else if (go)
60 obj = go;
61 return obj;
62 }
Definition: Object.h:393

References go, and me.

Referenced by GetLastInvoker(), GetTargets(), GetWorldObjectsInDist(), InstallTemplate(), OnUpdate(), ProcessAction(), ProcessEvent(), ProcessEventsFor(), and ProcessTimedAction().

◆ GetCasterActualDist()

float SmartScript::GetCasterActualDist ( ) const
inline

◆ GetCasterMaxDist()

float SmartScript::GetCasterMaxDist ( ) const
inline
230{ return smartCasterMaxDist; }

References smartCasterMaxDist.

Referenced by ProcessAction().

◆ GetCasterPowerType()

Powers SmartScript::GetCasterPowerType ( ) const
inline
228{ return smartCasterPowerType; }

References smartCasterPowerType.

Referenced by ProcessAction().

◆ GetCounterValue()

uint32 SmartScript::GetCounterValue ( uint32  id)
inline
150 {
151 CounterMap::iterator itr = mCounterList.find(id);
152 if (itr != mCounterList.end())
153 return itr->second;
154 return 0;
155 }
CounterMap mCounterList
Definition: SmartScript.h:217

References mCounterList.

Referenced by ProcessEvent().

◆ GetLastInvoker()

Unit * SmartScript::GetLastInvoker ( Unit invoker = nullptr) const
4890{
4891 // Xinef: Look for invoker only on map of base object... Prevents multithreaded crashes
4892 if (GetBaseObject())
4894 // xinef: used for area triggers invoker cast
4895 else if (invoker)
4896 return ObjectAccessor::GetUnit(*invoker, mLastInvoker);
4897 return nullptr;
4898}
Unit * GetUnit(WorldObject const &, ObjectGuid const guid)
Definition: ObjectAccessor.cpp:204
ObjectGuid mLastInvoker
Definition: SmartScript.h:215
WorldObject * GetBaseObject() const
Definition: SmartScript.h:54

References GetBaseObject(), ObjectAccessor::GetUnit(), and mLastInvoker.

Referenced by GetTargets(), ProcessAction(), and ProcessEvent().

◆ GetMaxCombatDist()

uint32 SmartScript::GetMaxCombatDist ( ) const
inline
223{ return mMaxCombatDist; }

References mMaxCombatDist.

Referenced by ProcessAction().

◆ GetPathId()

uint32 SmartScript::GetPathId ( ) const
inline
53{ return mPathId; }

References mPathId.

Referenced by ProcessEvent().

◆ GetScript()

void SmartScript::GetScript ( )
4637{
4639 if (me)
4640 {
4641 e = sSmartScriptMgr->GetScript(-((int32)me->GetSpawnId()), mScriptType);
4642 if (e.empty())
4643 e = sSmartScriptMgr->GetScript((int32)me->GetEntry(), mScriptType);
4644
4645 FillScript(e, me, nullptr);
4646
4647 if (CreatureTemplate const* cInfo = me->GetCreatureTemplate())
4648 {
4649 if (cInfo->HasFlagsExtra(CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI))
4650 {
4651 e = sSmartScriptMgr->GetScript((int32)me->GetEntry(), mScriptType);
4652 FillScript(e, me, nullptr);
4653 }
4654 }
4655 }
4656 else if (go)
4657 {
4658 e = sSmartScriptMgr->GetScript(-((int32)go->GetSpawnId()), mScriptType);
4659 if (e.empty())
4660 e = sSmartScriptMgr->GetScript((int32)go->GetEntry(), mScriptType);
4661 FillScript(e, go, nullptr);
4662 }
4663 else if (trigger)
4664 {
4665 e = sSmartScriptMgr->GetScript((int32)trigger->entry, mScriptType);
4666 FillScript(e, nullptr, trigger);
4667 }
4668}
std::int32_t int32
Definition: Define.h:104
std::vector< SmartScriptHolder > SmartAIEventList
Definition: SmartScriptMgr.h:1975
#define sSmartScriptMgr
Definition: SmartScriptMgr.h:2149
@ CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI
Definition: CreatureData.h:76
void FillScript(SmartAIEventList e, WorldObject *obj, AreaTrigger const *at)
Definition: SmartScript.cpp:4601
ObjectGuid::LowType GetSpawnId() const
Definition: Creature.h:67
CreatureTemplate const * GetCreatureTemplate() const
Definition: Creature.h:197
Definition: CreatureData.h:176
ObjectGuid::LowType GetSpawnId() const
Definition: GameObject.h:146
uint32 entry
Definition: ObjectMgr.h:422

References CREATURE_FLAG_DONT_OVERRIDE_ENTRY_SAI, AreaTrigger::entry, FillScript(), Creature::GetCreatureTemplate(), Object::GetEntry(), Creature::GetSpawnId(), GameObject::GetSpawnId(), go, me, mScriptType, sSmartScriptMgr, and trigger.

Referenced by OnInitialize().

◆ GetStoredTargetVector()

ObjectVector const * SmartScript::GetStoredTargetVector ( uint32  id,
WorldObject const &  ref 
) const
inline
116 {
117 auto itr = _storedTargets.find(id);
118 if (itr != _storedTargets.end())
119 return itr->second.GetObjectVector(ref);
120 return nullptr;
121 }
ObjectVectorMap _storedTargets
Definition: SmartScript.h:278

References _storedTargets.

Referenced by SmartAI::EndPath(), and GetTargets().

◆ GetTargets()

void SmartScript::GetTargets ( ObjectVector targets,
SmartScriptHolder const &  e,
Unit invoker = nullptr 
) const
3037{
3038 Unit* scriptTrigger = nullptr;
3039 if (invoker)
3040 scriptTrigger = invoker;
3041 else if (Unit* tempLastInvoker = GetLastInvoker())
3042 scriptTrigger = tempLastInvoker;
3043
3044 WorldObject* baseObject = GetBaseObject();
3045
3046 switch (e.GetTargetType())
3047 {
3048 case SMART_TARGET_SELF:
3049 if (baseObject)
3050 targets.push_back(baseObject);
3051 break;
3053 if (me)
3054 if (Unit* victim = me->GetVictim())
3055 targets.push_back(victim);
3056 break;
3058 if (me)
3059 {
3060 if (e.target.hostileRandom.powerType)
3061 {
3062 if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
3063 targets.push_back(u);
3064 }
3065 else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MaxThreat, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
3066 targets.push_back(u);
3067 }
3068 break;
3070 if (me)
3071 {
3072 if (e.target.hostileRandom.powerType)
3073 {
3074 if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
3075 targets.push_back(u);
3076 }
3077 else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinThreat, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
3078 targets.push_back(u);
3079 }
3080 break;
3082 if (me)
3083 {
3084 if (e.target.hostileRandom.powerType)
3085 {
3086 if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
3087 targets.push_back(u);
3088 }
3089 else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 0, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
3090 targets.push_back(u);
3091 }
3092 break;
3094 if (me)
3095 {
3096 if (e.target.hostileRandom.powerType)
3097 {
3098 if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, PowerUsersSelector(me, Powers(e.target.hostileRandom.powerType - 1), (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly)))
3099 targets.push_back(u);
3100 }
3101 else if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::Random, 1, (float)e.target.hostileRandom.maxDist, e.target.hostileRandom.playerOnly))
3102 targets.push_back(u);
3103 }
3104 break;
3106 if (me)
3107 {
3108 if (Unit* u = me->AI()->SelectTarget(SelectTargetMethod::MinDistance, 0, FarthestTargetSelector(me, e.target.farthest.maxDist, e.target.farthest.playerOnly, e.target.farthest.isInLos)))
3109 targets.push_back(u);
3110 }
3111 break;
3113 if (scriptTrigger)
3114 targets.push_back(scriptTrigger);
3115 break;
3117 if (scriptTrigger && scriptTrigger->GetVehicle() && scriptTrigger->GetVehicle()->GetBase())
3118 targets.push_back(scriptTrigger->GetVehicle()->GetBase());
3119 break;
3121 if (scriptTrigger)
3122 {
3123 if (Player* player = scriptTrigger->ToPlayer())
3124 {
3125 if (Group* group = player->GetGroup())
3126 {
3127 for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
3128 if (Player* member = groupRef->GetSource())
3129 if (member->IsInMap(player))
3130 targets.push_back(member);
3131 }
3132 // We still add the player to the list if there is no group. If we do
3133 // this even if there is a group (thus the else-check), it will add the
3134 // same player to the list twice. We don't want that to happen.
3135 else
3136 targets.push_back(scriptTrigger);
3137 }
3138 }
3139 break;
3141 {
3142 WorldObject* ref = baseObject;
3143 if (!ref)
3144 ref = scriptTrigger;
3145
3146 if (!ref)
3147 {
3148 LOG_ERROR("scripts.ai.sai", "SMART_TARGET_CREATURE_RANGE: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker",
3149 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
3150 break;
3151 }
3152
3153 ObjectVector units;
3154 GetWorldObjectsInDist(units, static_cast<float>(e.target.unitRange.maxDist));
3155
3156 for (WorldObject* unit : units)
3157 {
3158 if (!IsCreature(unit))
3159 continue;
3160
3161 if (me && me->GetGUID() == unit->GetGUID())
3162 continue;
3163
3164 // check alive state - 1 alive, 2 dead, 0 both
3165 if (uint32 state = e.target.unitRange.livingState)
3166 {
3167 if (unit->ToCreature()->IsAlive() && state == 2)
3168 continue;
3169 if (!unit->ToCreature()->IsAlive() && state == 1)
3170 continue;
3171 }
3172
3173 if (((e.target.unitRange.creature && unit->ToCreature()->GetEntry() == e.target.unitRange.creature) || !e.target.unitRange.creature) && ref->IsInRange(unit, (float)e.target.unitRange.minDist, (float)e.target.unitRange.maxDist))
3174 targets.push_back(unit);
3175 }
3176
3177 break;
3178 }
3180 {
3181 ObjectVector units;
3182 GetWorldObjectsInDist(units, static_cast<float>(e.target.unitDistance.dist));
3183
3184 for (WorldObject* unit : units)
3185 {
3186 if (!IsCreature(unit))
3187 continue;
3188
3189 if (me && me->GetGUID() == unit->GetGUID())
3190 continue;
3191
3192 // check alive state - 1 alive, 2 dead, 0 both
3193 if (uint32 state = e.target.unitDistance.livingState)
3194 {
3195 if (unit->ToCreature()->IsAlive() && state == 2)
3196 continue;
3197 if (!unit->ToCreature()->IsAlive() && state == 1)
3198 continue;
3199 }
3200
3201 if ((e.target.unitDistance.creature && unit->ToCreature()->GetEntry() == e.target.unitDistance.creature) || !e.target.unitDistance.creature)
3202 targets.push_back(unit);
3203 }
3204
3205 break;
3206 }
3208 {
3209 ObjectVector units;
3210 GetWorldObjectsInDist(units, static_cast<float>(e.target.goDistance.dist));
3211
3212 for (WorldObject* unit : units)
3213 {
3214 if (!IsGameObject(unit))
3215 continue;
3216
3217 if (go && go->GetGUID() == unit->GetGUID())
3218 continue;
3219
3220 if ((e.target.goDistance.entry && unit->ToGameObject()->GetEntry() == e.target.goDistance.entry) || !e.target.goDistance.entry)
3221 targets.push_back(unit);
3222 }
3223
3224 break;
3225 }
3227 {
3228
3229 WorldObject* ref = baseObject;
3230 if (!ref)
3231 ref = scriptTrigger;
3232
3233 if (!ref)
3234 {
3235 LOG_ERROR("scripts.ai.sai", "SMART_TARGET_GAMEOBJECT_RANGE: Entry: {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
3236 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
3237 break;
3238 }
3239
3240 ObjectVector units;
3241 GetWorldObjectsInDist(units, static_cast<float>(e.target.goRange.maxDist));
3242
3243 for (WorldObject* unit : units)
3244 {
3245 if (!IsGameObject(unit))
3246 continue;
3247
3248 if (go && go->GetGUID() == unit->GetGUID())
3249 continue;
3250
3251 if (((e.target.goRange.entry && IsGameObject(unit) && unit->ToGameObject()->GetEntry() == e.target.goRange.entry) || !e.target.goRange.entry) && ref->IsInRange((unit), (float)e.target.goRange.minDist, (float)e.target.goRange.maxDist))
3252 targets.push_back(unit);
3253 }
3254
3255 break;
3256 }
3258 {
3259 if (!scriptTrigger && !baseObject)
3260 {
3261 LOG_ERROR("scripts.ai.sai", "SMART_TARGET_CREATURE_GUID: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
3262 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
3263 break;
3264 }
3265
3266 Creature* target = FindCreatureNear(scriptTrigger ? scriptTrigger : GetBaseObject(), e.target.unitGUID.dbGuid);
3267 if (target && (!e.target.unitGUID.entry || target->GetEntry() == e.target.unitGUID.entry))
3268 targets.push_back(target);
3269 break;
3270 }
3272 {
3273 if (!scriptTrigger && !GetBaseObject())
3274 {
3275 LOG_ERROR("scripts.ai.sai", "SMART_TARGET_GAMEOBJECT_GUID: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
3276 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
3277 break;
3278 }
3279
3280 GameObject* target = FindGameObjectNear(scriptTrigger ? scriptTrigger : GetBaseObject(), e.target.goGUID.dbGuid);
3281 if (target && (!e.target.goGUID.entry || target->GetEntry() == e.target.goGUID.entry))
3282 targets.push_back(target);
3283 break;
3284 }
3286 {
3287 ObjectVector units;
3288 GetWorldObjectsInDist(units, static_cast<float>(e.target.playerRange.maxDist));
3289
3290 if (!units.empty() && baseObject)
3291 for (WorldObject* unit : units)
3292 if (IsPlayer(unit) && baseObject->IsInRange(unit, float(e.target.playerRange.minDist), float(e.target.playerRange.maxDist)))
3293 targets.push_back(unit);
3294 break;
3295 }
3297 {
3298 ObjectVector units;
3299 GetWorldObjectsInDist(units, static_cast<float>(e.target.playerDistance.dist));
3300
3301 for (WorldObject* unit : units)
3302 if (IsPlayer(unit))
3303 targets.push_back(unit);
3304 break;
3305 }
3307 {
3308 WorldObject* ref = baseObject;
3309 if (!ref)
3310 ref = scriptTrigger;
3311
3312 if (!ref)
3313 {
3314 LOG_ERROR("scripts.ai.sai", "SMART_TARGET_STORED: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
3315 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
3316 break;
3317 }
3318
3319 if (ObjectVector const* stored = GetStoredTargetVector(e.target.stored.id, *ref))
3320 targets.assign(stored->begin(), stored->end());
3321 break;
3322 }
3324 {
3325 WorldObject* ref = baseObject;
3326
3327 if (!ref)
3328 ref = scriptTrigger;
3329
3330 if (!ref)
3331 {
3332 LOG_ERROR("scripts.ai.sai", "SMART_TARGET_CLOSEST_CREATURE: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
3333 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
3334 break;
3335 }
3336
3337 Creature* target = GetClosestCreatureWithEntry(ref, e.target.unitClosest.entry, (float)(e.target.unitClosest.dist ? e.target.unitClosest.dist : 100), !e.target.unitClosest.dead);
3338 if (target)
3339 targets.push_back(target);
3340 break;
3341 }
3343 {
3344 WorldObject* ref = baseObject;
3345
3346 if (!ref)
3347 ref = scriptTrigger;
3348
3349 if (!ref)
3350 {
3351 LOG_ERROR("scripts.ai.sai", "SMART_TARGET_CLOSEST_GAMEOBJECT: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
3352 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
3353 break;
3354 }
3355
3356 GameObject* target = GetClosestGameObjectWithEntry(ref, e.target.goClosest.entry, (float)(e.target.goClosest.dist ? e.target.goClosest.dist : 100), e.target.goClosest.onlySpawned);
3357 if (target)
3358 targets.push_back(target);
3359 break;
3360 }
3362 {
3363 WorldObject* ref = baseObject;
3364
3365 if (!ref)
3366 ref = scriptTrigger;
3367
3368 if (!ref)
3369 {
3370 LOG_ERROR("scripts.ai.sai", "SMART_TARGET_CLOSEST_PLAYER: Entry {} SourceType {} Event {} Action {} Target {} is missing base object or invoker.",
3371 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
3372 break;
3373 }
3374
3375 if (Player* target = ref->SelectNearestPlayer((float)e.target.playerDistance.dist))
3376 targets.push_back(target);
3377 break;
3378 }
3380 /*
3381 * Owners/Summoners should be WorldObjects. This allows to have other objects
3382 * such as gameobjects to execute SmartScripts using this type of target.
3383 * Otherwise, only Units like creatures can summon other creatures.
3384 */
3385 {
3386 if (me)
3387 {
3389 {
3390 targets.push_back(owner);
3391 }
3392 else if (me->IsSummon() && me->ToTempSummon()->GetSummonerUnit())
3393 {
3394 targets.push_back(me->ToTempSummon()->GetSummonerUnit());
3395 }
3396 }
3397 else if (go)
3398 {
3400 {
3401 targets.push_back(owner);
3402 }
3403 }
3404
3405 // xinef: Get owner of owner
3406 if (e.target.owner.useCharmerOrOwner && !targets.empty())
3407 {
3408 if (WorldObject* owner = targets.front())
3409 {
3410 targets.clear();
3411
3412 if (owner->ToCreature())
3413 {
3414 if (Unit* base = ObjectAccessor::GetUnit(*owner, owner->ToCreature()->GetCharmerOrOwnerGUID()))
3415 {
3416 targets.push_back(base);
3417 }
3418 }
3419 else
3420 {
3421 if (Unit* base = ObjectAccessor::GetUnit(*owner, owner->ToGameObject()->GetOwnerGUID()))
3422 {
3423 targets.push_back(base);
3424 }
3425 }
3426 }
3427 }
3428 break;
3429 }
3431 {
3432 if (me)
3433 {
3435 for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i)
3436 if (Unit* temp = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()))
3437 // Xinef: added distance check
3438 if (e.target.threatList.maxDist == 0 || me->IsWithinCombatRange(temp, (float)e.target.threatList.maxDist))
3439 targets.push_back(temp);
3440 }
3441 break;
3442 }
3444 {
3445 if (me)
3446 if (Unit* target = me->SelectNearestTarget(e.target.closestAttackable.maxDist, e.target.closestAttackable.playerOnly))
3447 targets.push_back(target);
3448
3449 break;
3450 }
3452 {
3453 if (me)
3454 if (Unit* target = DoFindClosestFriendlyInRange(e.target.closestFriendly.maxDist, e.target.closestFriendly.playerOnly))
3455 targets.push_back(target);
3456
3457 break;
3458 }
3460 {
3461 ObjectVector units;
3462 GetWorldObjectsInDist(units, static_cast<float>(e.target.playerDistance.dist));
3463
3464 for (WorldObject* unit : units)
3465 if (IsPlayer(unit) && unit->ToPlayer()->IsAlive() && !unit->ToPlayer()->IsGameMaster())
3466 if (GetBaseObject()->IsInRange(unit, (float)e.target.playerWithAura.distMin, (float)e.target.playerWithAura.distMax))
3467 if (bool(e.target.playerWithAura.negation) != unit->ToPlayer()->HasAura(e.target.playerWithAura.spellId))
3468 targets.push_back(unit);
3469
3470 if (e.target.o > 0)
3471 Acore::Containers::RandomResize(targets, e.target.o);
3472
3473 break;
3474 }
3476 {
3477 ObjectVector units;
3478 GetWorldObjectsInDist(units, static_cast<float>(e.target.playerDistance.dist));
3479 // 1 = Tanks, 2 = Healer, 4 = Damage
3480 uint32 roleMask = e.target.roleSelection.roleMask;
3481 for (WorldObject* unit : units)
3482 if (Player* targetPlayer = unit->ToPlayer())
3483 if (targetPlayer->IsAlive() && !targetPlayer->IsGameMaster())
3484 {
3485 if (roleMask & SMART_TARGET_ROLE_FLAG_TANKS)
3486 {
3487 if (targetPlayer->HasTankSpec())
3488 {
3489 targets.push_back(unit);
3490 continue;
3491 }
3492 }
3493 if (roleMask & SMART_TARGET_ROLE_FLAG_HEALERS)
3494 {
3495 if (targetPlayer->HasHealSpec())
3496 {
3497 targets.push_back(unit);
3498 continue;
3499 }
3500 }
3501 if (roleMask & SMART_TARGET_ROLE_FLAG_DAMAGERS)
3502 {
3503 if (targetPlayer->HasCasterSpec() || targetPlayer->HasMeleeSpec())
3504 {
3505 targets.push_back(unit);
3506 continue;
3507 }
3508 }
3509 }
3510
3511 if (e.target.roleSelection.resize > 0)
3512 Acore::Containers::RandomResize(targets, e.target.roleSelection.resize);
3513
3514 break;
3515 }
3517 {
3518 if (me && me->IsVehicle())
3519 {
3520 if (Unit* target = me->GetVehicleKit()->GetPassenger(e.target.vehicle.seatMask))
3521 {
3522 targets.push_back(target);
3523 }
3524 }
3525 break;
3526 }
3528 {
3529 if (me)
3530 {
3531 if (Group* lootGroup = me->GetLootRecipientGroup())
3532 {
3533 for (GroupReference* it = lootGroup->GetFirstMember(); it != nullptr; it = it->next())
3534 {
3535 if (Player* recipient = it->GetSource())
3536 {
3537 targets.push_back(recipient);
3538 }
3539 }
3540 }
3541 else
3542 {
3543 if (Player* recipient = me->GetLootRecipient())
3544 {
3545 targets.push_back(recipient);
3546 }
3547 }
3548 }
3549 break;
3550 }
3552 {
3553 if (me)
3554 {
3555 for (ObjectGuid const& guid : _summonList)
3556 {
3557 if (!e.target.summonedCreatures.entry || guid.GetEntry() == e.target.summonedCreatures.entry)
3558 {
3559 if (Creature* creature = me->GetMap()->GetCreature(guid))
3560 {
3561 targets.push_back(creature);
3562 }
3563 }
3564 }
3565 }
3566 break;
3567 }
3569 {
3570 if (InstanceScript* instance = GetBaseObject()->GetInstanceScript())
3571 {
3572 if (e.target.instanceStorage.type == 1)
3573 {
3574 if (Creature* creature = instance->GetCreature(e.target.instanceStorage.index))
3575 {
3576 targets.push_back(creature);
3577 }
3578 }
3579 else if (e.target.instanceStorage.type == 2)
3580 {
3581 if (GameObject* go = instance->GetGameObject(e.target.instanceStorage.index))
3582 {
3583 targets.push_back(go);
3584 }
3585 }
3586 }
3587 else
3588 {
3589 LOG_ERROR("scripts.ai.sai", "SMART_TARGET_INSTANCE_STORAGE: Entry {} SourceType {} Event {} Action {} Target {} called outside an instance map.",
3590 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
3591 }
3592
3593 break;
3594 }
3595 case SMART_TARGET_NONE:
3597 default:
3598 break;
3599 }
3600}
std::uint32_t uint32
Definition: Define.h:108
#define LOG_ERROR(filterType__,...)
Definition: Log.h:159
Creature * GetClosestCreatureWithEntry(WorldObject *source, uint32 entry, float maxSearchRange, bool alive)
Definition: ScriptedCreature.cpp:773
GameObject * GetClosestGameObjectWithEntry(WorldObject *source, uint32 entry, float maxSearchRange, bool onlySpawned)
Definition: ScriptedCreature.cpp:778
@ SMART_TARGET_ROLE_FLAG_HEALERS
Definition: SmartScriptMgr.h:1699
@ SMART_TARGET_ROLE_FLAG_TANKS
Definition: SmartScriptMgr.h:1698
@ SMART_TARGET_ROLE_FLAG_DAMAGERS
Definition: SmartScriptMgr.h:1700
@ SMART_TARGET_LOOT_RECIPIENTS
Definition: SmartScriptMgr.h:1503
@ SMART_TARGET_CLOSEST_CREATURE
Definition: SmartScriptMgr.h:1495
@ SMART_TARGET_CREATURE_DISTANCE
Definition: SmartScriptMgr.h:1487
@ SMART_TARGET_HOSTILE_RANDOM_NOT_TOP
Definition: SmartScriptMgr.h:1482
@ SMART_TARGET_INVOKER_PARTY
Definition: SmartScriptMgr.h:1492
@ SMART_TARGET_CLOSEST_FRIENDLY
Definition: SmartScriptMgr.h:1502
@ SMART_TARGET_CLOSEST_GAMEOBJECT
Definition: SmartScriptMgr.h:1496
@ SMART_TARGET_VEHICLE_PASSENGER
Definition: SmartScriptMgr.h:1505
@ SMART_TARGET_GAMEOBJECT_RANGE
Definition: SmartScriptMgr.h:1489
@ SMART_TARGET_CREATURE_GUID
Definition: SmartScriptMgr.h:1486
@ SMART_TARGET_PLAYER_RANGE
Definition: SmartScriptMgr.h:1493
@ SMART_TARGET_SUMMONED_CREATURES
Definition: SmartScriptMgr.h:1516
@ SMART_TARGET_VICTIM
Definition: SmartScriptMgr.h:1478
@ SMART_TARGET_GAMEOBJECT_DISTANCE
Definition: SmartScriptMgr.h:1491
@ SMART_TARGET_CREATURE_RANGE
Definition: SmartScriptMgr.h:1485
@ SMART_TARGET_CLOSEST_PLAYER
Definition: SmartScriptMgr.h:1497
@ SMART_TARGET_HOSTILE_RANDOM
Definition: SmartScriptMgr.h:1481
@ SMART_TARGET_GAMEOBJECT_GUID
Definition: SmartScriptMgr.h:1490
@ SMART_TARGET_HOSTILE_SECOND_AGGRO
Definition: SmartScriptMgr.h:1479
@ SMART_TARGET_OWNER_OR_SUMMONER
Definition: SmartScriptMgr.h:1499
@ SMART_TARGET_SELF
Definition: SmartScriptMgr.h:1477
@ SMART_TARGET_PLAYER_WITH_AURA
Definition: SmartScriptMgr.h:1513
@ SMART_TARGET_ROLE_SELECTION
Definition: SmartScriptMgr.h:1515
@ SMART_TARGET_ACTION_INVOKER
Definition: SmartScriptMgr.h:1483
@ SMART_TARGET_POSITION
Definition: SmartScriptMgr.h:1484
@ SMART_TARGET_HOSTILE_LAST_AGGRO
Definition: SmartScriptMgr.h:1480
@ SMART_TARGET_ACTION_INVOKER_VEHICLE
Definition: SmartScriptMgr.h:1498
@ SMART_TARGET_INSTANCE_STORAGE
Definition: SmartScriptMgr.h:1517
@ SMART_TARGET_FARTHEST
Definition: SmartScriptMgr.h:1504
@ SMART_TARGET_THREAT_LIST
Definition: SmartScriptMgr.h:1500
@ SMART_TARGET_CLOSEST_ENEMY
Definition: SmartScriptMgr.h:1501
@ SMART_TARGET_NONE
Definition: SmartScriptMgr.h:1476
@ SMART_TARGET_PLAYER_DISTANCE
Definition: SmartScriptMgr.h:1494
@ SMART_TARGET_STORED
Definition: SmartScriptMgr.h:1488
std::vector< WorldObject * > ObjectVector
Definition: SmartScriptMgr.h:1916
Powers
Definition: SharedDefines.h:240
void RandomResize(C &container, std::size_t requestedSize)
Definition: Containers.h:81
WorldObject * GetWorldObject(WorldObject const &, ObjectGuid const guid)
Definition: ObjectAccessor.cpp:120
Definition: UnitAI.h:124
Definition: UnitAI.h:154
Unit * SelectTarget(SelectTargetMethod targetType, uint32 position=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition: UnitAI.cpp:111
static bool IsPlayer(WorldObject *obj)
Definition: SmartScript.cpp:4905
Unit * GetLastInvoker(Unit *invoker=nullptr) const
Definition: SmartScript.cpp:4889
static bool IsCreature(WorldObject *obj)
Definition: SmartScript.cpp:4910
void GetWorldObjectsInDist(ObjectVector &objects, float dist) const
Definition: SmartScript.cpp:3602
Creature * FindCreatureNear(WorldObject *searchObject, ObjectGuid::LowType guid) const
Definition: SmartScript.h:166
static bool IsGameObject(WorldObject *obj)
Definition: SmartScript.cpp:4926
ObjectVector const * GetStoredTargetVector(uint32 id, WorldObject const &ref) const
Definition: SmartScript.h:115
Unit * DoFindClosestFriendlyInRange(float range, bool playerOnly) const
Definition: SmartScript.cpp:4842
GameObject * FindGameObjectNear(WorldObject *searchObject, ObjectGuid::LowType guid) const
Definition: SmartScript.h:157
std::list< HostileReference * > StorageType
Definition: ThreatMgr.h:148
ThreatContainer::StorageType const & GetThreatList() const
Definition: ThreatMgr.h:274
Definition: Creature.h:46
Player * GetLootRecipient() const
Definition: Creature.cpp:1278
Group * GetLootRecipientGroup() const
Definition: Creature.cpp:1285
Unit * SelectNearestTarget(float dist=0, bool playerOnly=false) const
Definition: Creature.cpp:2314
CreatureAI * AI() const
Definition: Creature.h:135
Unit * GetSummonerUnit() const
Definition: TemporarySummon.cpp:45
Definition: GameObject.h:122
ObjectGuid GetOwnerGUID() const
Definition: GameObject.h:175
Player * ToPlayer()
Definition: Object.h:195
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:106
Player * SelectNearestPlayer(float distance=0) const
Definition: Object.cpp:2461
bool IsInRange(WorldObject const *obj, float minRange, float maxRange, bool is3D=true) const
Definition: Object.cpp:1404
Definition: ObjectGuid.h:120
Definition: Player.h:1056
bool IsVehicle() const
Definition: Unit.h:1428
Vehicle * GetVehicle() const
Definition: Unit.h:2366
bool IsWithinCombatRange(Unit const *obj, float dist2compare) const
Definition: Unit.cpp:667
TempSummon * ToTempSummon()
Definition: Unit.h:2412
bool IsSummon() const
Definition: Unit.h:1422
Unit * GetVictim() const
Definition: Unit.h:1398
ThreatMgr & GetThreatMgr()
Definition: Unit.h:2157
Vehicle * GetVehicleKit() const
Definition: Unit.h:2365
ObjectGuid GetCharmerOrOwnerGUID() const
Definition: Unit.h:1842
Unit * GetBase() const
May be called from scripts.
Definition: Vehicle.h:39
Unit * GetPassenger(int8 seatId) const
Definition: Vehicle.cpp:226
Definition: Group.h:168
Definition: GroupReference.h:27
GroupReference * next()
Definition: GroupReference.h:36
Definition: InstanceScript.h:140
Creature * GetCreature(ObjectGuid const guid)
Definition: Map.cpp:3304

References _summonList, Creature::AI(), SmartTarget::closestAttackable, SmartTarget::closestFriendly, SmartTarget::creature, SmartTarget::dbGuid, SmartTarget::dead, SmartTarget::dist, SmartTarget::distMax, SmartTarget::distMin, DoFindClosestFriendlyInRange(), SmartTarget::entry, SmartScriptHolder::entryOrGuid, SmartScriptHolder::event_id, SmartTarget::farthest, FindCreatureNear(), FindGameObjectNear(), SmartScriptHolder::GetActionType(), Vehicle::GetBase(), GetBaseObject(), Unit::GetCharmerOrOwnerGUID(), GetClosestCreatureWithEntry(), GetClosestGameObjectWithEntry(), Map::GetCreature(), Object::GetEntry(), Object::GetGUID(), GetLastInvoker(), Creature::GetLootRecipient(), Creature::GetLootRecipientGroup(), WorldObject::GetMap(), GameObject::GetOwnerGUID(), Vehicle::GetPassenger(), SmartScriptHolder::GetScriptType(), GetStoredTargetVector(), TempSummon::GetSummonerUnit(), SmartScriptHolder::GetTargetType(), ThreatMgr::GetThreatList(), Unit::GetThreatMgr(), ObjectAccessor::GetUnit(), Unit::GetVehicle(), Unit::GetVehicleKit(), Unit::GetVictim(), ObjectAccessor::GetWorldObject(), GetWorldObjectsInDist(), go, SmartTarget::goClosest, SmartTarget::goDistance, SmartTarget::goGUID, SmartTarget::goRange, SmartTarget::hostileRandom, SmartTarget::id, SmartTarget::index, SmartTarget::instanceStorage, IsCreature(), IsGameObject(), SmartTarget::isInLos, WorldObject::IsInRange(), IsPlayer(), Unit::IsSummon(), Unit::IsVehicle(), Unit::IsWithinCombatRange(), SmartTarget::livingState, LOG_ERROR, SmartTarget::maxDist, me, SmartTarget::minDist, SmartTarget::negation, GroupReference::next(), SmartTarget::o, SmartTarget::onlySpawned, SmartTarget::owner, SmartTarget::playerDistance, SmartTarget::playerOnly, SmartTarget::playerRange, SmartTarget::playerWithAura, SmartTarget::powerType, Acore::Containers::RandomResize(), SmartTarget::resize, SmartTarget::roleMask, SmartTarget::roleSelection, SmartTarget::seatMask, WorldObject::SelectNearestPlayer(), Creature::SelectNearestTarget(), UnitAI::SelectTarget(), SMART_TARGET_ACTION_INVOKER, SMART_TARGET_ACTION_INVOKER_VEHICLE, SMART_TARGET_CLOSEST_CREATURE, SMART_TARGET_CLOSEST_ENEMY, SMART_TARGET_CLOSEST_FRIENDLY, SMART_TARGET_CLOSEST_GAMEOBJECT, SMART_TARGET_CLOSEST_PLAYER, SMART_TARGET_CREATURE_DISTANCE, SMART_TARGET_CREATURE_GUID, SMART_TARGET_CREATURE_RANGE, SMART_TARGET_FARTHEST, SMART_TARGET_GAMEOBJECT_DISTANCE, SMART_TARGET_GAMEOBJECT_GUID, SMART_TARGET_GAMEOBJECT_RANGE, SMART_TARGET_HOSTILE_LAST_AGGRO, SMART_TARGET_HOSTILE_RANDOM, SMART_TARGET_HOSTILE_RANDOM_NOT_TOP, SMART_TARGET_HOSTILE_SECOND_AGGRO, SMART_TARGET_INSTANCE_STORAGE, SMART_TARGET_INVOKER_PARTY, SMART_TARGET_LOOT_RECIPIENTS, SMART_TARGET_NONE, SMART_TARGET_OWNER_OR_SUMMONER, SMART_TARGET_PLAYER_DISTANCE, SMART_TARGET_PLAYER_RANGE, SMART_TARGET_PLAYER_WITH_AURA, SMART_TARGET_POSITION, SMART_TARGET_ROLE_FLAG_DAMAGERS, SMART_TARGET_ROLE_FLAG_HEALERS, SMART_TARGET_ROLE_FLAG_TANKS, SMART_TARGET_ROLE_SELECTION, SMART_TARGET_SELF, SMART_TARGET_STORED, SMART_TARGET_SUMMONED_CREATURES, SMART_TARGET_THREAT_LIST, SMART_TARGET_VEHICLE_PASSENGER, SMART_TARGET_VICTIM, SmartTarget::spellId, SmartTarget::stored, SmartTarget::summonedCreatures, SmartScriptHolder::target, SmartTarget::threatList, Object::ToPlayer(), Unit::ToTempSummon(), SmartTarget::type, SmartTarget::unitClosest, SmartTarget::unitDistance, SmartTarget::unitGUID, SmartTarget::unitRange, SmartTarget::useCharmerOrOwner, and SmartTarget::vehicle.

Referenced by ProcessAction(), and ProcessEvent().

◆ GetWorldObjectsInDist()

void SmartScript::GetWorldObjectsInDist ( ObjectVector objects,
float  dist 
) const
3603{
3604 WorldObject* obj = GetBaseObject();
3605 if (!obj)
3606 return;
3607
3608 Acore::AllWorldObjectsInRange u_check(obj, dist);
3610 Cell::VisitAllObjects(obj, searcher, dist);
3611}
Definition: GridNotifiers.h:236
Definition: GridNotifiers.h:1582

References GetBaseObject(), and Cell::VisitAllObjects().

Referenced by GetTargets(), ProcessAction(), and ProcessEvent().

◆ IncPhase()

void SmartScript::IncPhase ( uint32  p)
private
4932{
4933 // protect phase from overflowing
4934 SetPhase(std::min<uint32>(SMART_EVENT_PHASE_12, mEventPhase + p));
4935}
@ SMART_EVENT_PHASE_12
Definition: SmartScriptMgr.h:76

References mEventPhase, SetPhase(), and SMART_EVENT_PHASE_12.

Referenced by ProcessAction().

◆ InitTimer()

void SmartScript::InitTimer ( SmartScriptHolder e)
static
4386{
4387 switch (e.GetEventType())
4388 {
4389 //set only events which have initial timers
4390 case SMART_EVENT_RANGE:
4391 // If onlyFireOnRepeat is true set to 2 before entering combat. Will be set back to 1 after entering combat to ignore initial firing.
4394 // make it predictable
4395 RecalcTimer(e, 1200, 1200);
4396 break;
4399 break;
4403 break;
4404 case SMART_EVENT_UPDATE:
4408 break;
4410 case SMART_EVENT_IC_LOS:
4411 // Xinef: cooldown should be processed AFTER action is done, not before...
4412 //RecalcTimer(e, e.event.los.cooldownMin, e.event.los.cooldownMax);
4413 //break;
4417 break;
4421 break;
4424 break;
4425 default:
4426 e.active = true;
4427 break;
4428 }
4429}
@ SMART_EVENT_IC_LOS
Definition: SmartScriptMgr.h:144
@ SMART_EVENT_NEAR_PLAYERS_NEGATION
Definition: SmartScriptMgr.h:210
@ SMART_EVENT_AREA_CASTING
Definition: SmartScriptMgr.h:213
@ SMART_EVENT_DISTANCE_GAMEOBJECT
Definition: SmartScriptMgr.h:194
@ SMART_EVENT_RANGE
Definition: SmartScriptMgr.h:127
@ SMART_EVENT_NEAR_UNIT_NEGATION
Definition: SmartScriptMgr.h:212
@ SMART_EVENT_UPDATE_IC
Definition: SmartScriptMgr.h:118
@ SMART_EVENT_AREA_RANGE
Definition: SmartScriptMgr.h:214
@ SMART_EVENT_UPDATE
Definition: SmartScriptMgr.h:178
@ SMART_EVENT_UPDATE_OOC
Definition: SmartScriptMgr.h:119
@ SMART_EVENT_NEAR_UNIT
Definition: SmartScriptMgr.h:211
@ SMART_EVENT_DISTANCE_CREATURE
Definition: SmartScriptMgr.h:193
@ SMART_EVENT_OOC_LOS
Definition: SmartScriptMgr.h:128
@ SMART_EVENT_NEAR_PLAYERS
Definition: SmartScriptMgr.h:209
static void RecalcTimer(SmartScriptHolder &e, uint32 min, uint32 max)
Definition: SmartScript.cpp:4430
struct SmartEvent::@30::@32 minMaxRepeat
struct SmartEvent::@30::@33 rangeRepeat
struct SmartEvent::@30::@75 areaRange
uint32 repeat
Definition: SmartScriptMgr.h:473
uint32 min
Definition: SmartScriptMgr.h:229
struct SmartEvent::@30::@72 nearUnit
uint32 firstTimer
Definition: SmartScriptMgr.h:488
struct SmartEvent::@30::@70 nearPlayer
uint32 onlyFireOnRepeat
Definition: SmartScriptMgr.h:241
struct SmartEvent::@30::@74 areaCasting
uint32 max
Definition: SmartScriptMgr.h:230
uint32 timer
Definition: SmartScriptMgr.h:508
struct SmartEvent::@30::@68 distance
bool active
Definition: SmartScriptMgr.h:1909
uint32 GetEventType() const
Definition: SmartScriptMgr.h:1904

References SmartScriptHolder::active, SmartEvent::areaCasting, SmartEvent::areaRange, SmartEvent::distance, SmartScriptHolder::event, SmartEvent::firstTimer, SmartScriptHolder::GetEventType(), SmartEvent::max, SmartEvent::min, SmartEvent::minMaxRepeat, SmartEvent::nearPlayer, SmartEvent::nearUnit, SmartEvent::onlyFireOnRepeat, SmartEvent::rangeRepeat, RecalcTimer(), SmartEvent::repeat, SMART_EVENT_AREA_CASTING, SMART_EVENT_AREA_RANGE, SMART_EVENT_DISTANCE_CREATURE, SMART_EVENT_DISTANCE_GAMEOBJECT, SMART_EVENT_IC_LOS, SMART_EVENT_NEAR_PLAYERS, SMART_EVENT_NEAR_PLAYERS_NEGATION, SMART_EVENT_NEAR_UNIT, SMART_EVENT_NEAR_UNIT_NEGATION, SMART_EVENT_OOC_LOS, SMART_EVENT_RANGE, SMART_EVENT_UPDATE, SMART_EVENT_UPDATE_IC, SMART_EVENT_UPDATE_OOC, and SmartEvent::timer.

Referenced by CreateSmartEvent(), OnInitialize(), OnReset(), and SetScript9().

◆ InstallEvents()

void SmartScript::InstallEvents ( )
private
4529{
4530 if (!mInstallEvents.empty())
4531 {
4532 for (SmartAIEventList::iterator i = mInstallEvents.begin(); i != mInstallEvents.end(); ++i)
4533 mEvents.push_back(*i);//must be before UpdateTimers
4534
4535 mInstallEvents.clear();
4536 }
4537}

References mEvents, and mInstallEvents.

Referenced by OnInitialize(), and OnUpdate().

◆ InstallTemplate()

void SmartScript::InstallTemplate ( SmartScriptHolder const &  e)
2925{
2926 if (!GetBaseObject())
2927 return;
2929 {
2930 LOG_ERROR("sql.sql", "SmartScript::InstallTemplate: Entry {} SourceType {} AI Template can not be set more then once, skipped.", e.entryOrGuid, e.GetScriptType());
2931 return;
2932 }
2933 mTemplate = (SMARTAI_TEMPLATE)e.action.installTtemplate.id;
2934 switch ((SMARTAI_TEMPLATE)e.action.installTtemplate.id)
2935 {
2937 {
2938 AddEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, e.action.installTtemplate.param2, e.action.installTtemplate.param3, 0, 0, SMART_ACTION_CAST, e.action.installTtemplate.param1, e.target.raw.param1, 0, 0, 0, 0, SMART_TARGET_VICTIM, 0, 0, 0, 0, 1);
2939 AddEvent(SMART_EVENT_RANGE, 0, e.action.installTtemplate.param4, 300, 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
2940 AddEvent(SMART_EVENT_RANGE, 0, 0, e.action.installTtemplate.param4 > 10 ? e.action.installTtemplate.param4 - 10 : 0, 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
2941 AddEvent(SMART_EVENT_MANA_PCT, 0, e.action.installTtemplate.param5 - 15 > 100 ? 100 : e.action.installTtemplate.param5 + 15, 100, 1000, 1000, 0, 0, SMART_ACTION_SET_EVENT_PHASE, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
2942 AddEvent(SMART_EVENT_MANA_PCT, 0, 0, e.action.installTtemplate.param5, 1000, 1000, 0, 0, SMART_ACTION_SET_EVENT_PHASE, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
2943 AddEvent(SMART_EVENT_MANA_PCT, 0, 0, e.action.installTtemplate.param5, 1000, 1000, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
2944 break;
2945 }
2947 {
2948 AddEvent(SMART_EVENT_UPDATE_IC, 0, 0, 0, e.action.installTtemplate.param2, e.action.installTtemplate.param3, 0, 0, SMART_ACTION_CAST, e.action.installTtemplate.param1, e.target.raw.param1, 0, 0, 0, 0, SMART_TARGET_VICTIM, 0, 0, 0, 0, 0);
2949 AddEvent(SMART_EVENT_JUST_CREATED, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, 0, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
2950 break;
2951 }
2953 {
2954 if (!me)
2955 return;
2956 //store cage as id1
2957 AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 1, 0, 0, 0, 0, 0, SMART_TARGET_CLOSEST_GAMEOBJECT, e.action.installTtemplate.param1, 10, 0, 0, 0);
2958
2959 //reset(close) cage on hostage(me) respawn
2960 AddEvent(SMART_EVENT_UPDATE, SMART_EVENT_FLAG_NOT_REPEATABLE, 0, 0, 0, 0, 0, 0, SMART_ACTION_RESET_GOBJECT, 0, 0, 0, 0, 0, 0, SMART_TARGET_GAMEOBJECT_DISTANCE, e.action.installTtemplate.param1, 5, 0, 0, 0);
2961
2962 AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_SET_RUN, e.action.installTtemplate.param3, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
2963 AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_SET_EVENT_PHASE, 1, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
2964
2965 AddEvent(SMART_EVENT_UPDATE, SMART_EVENT_FLAG_NOT_REPEATABLE, 1000, 1000, 0, 0, 0, 0, SMART_ACTION_MOVE_FORWARD, e.action.installTtemplate.param4, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
2966 //phase 1: give quest credit on movepoint reached
2968 //phase 1: despawn after time on movepoint reached
2969 AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, 0, SMART_ACTION_FORCE_DESPAWN, e.action.installTtemplate.param2, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
2970
2971 if (sCreatureTextMgr->TextExist(me->GetEntry(), (uint8)e.action.installTtemplate.param5))
2972 AddEvent(SMART_EVENT_MOVEMENTINFORM, 0, POINT_MOTION_TYPE, SMART_RANDOM_POINT, 0, 0, 0, 0, SMART_ACTION_TALK, e.action.installTtemplate.param5, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 1);
2973 break;
2974 }
2976 {
2977 if (!go)
2978 return;
2979 //store hostage as id1
2980 AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 1, 0, 0, 0, 0, 0, SMART_TARGET_CLOSEST_CREATURE, e.action.installTtemplate.param1, 10, 0, 0, 0);
2981 //store invoker as id2
2982 AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_STORE_TARGET_LIST, 2, 0, 0, 0, 0, 0, SMART_TARGET_NONE, 0, 0, 0, 0, 0);
2983 //signal hostage
2984 AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_SET_DATA, 0, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 1, 0, 0, 0, 0);
2985 //when hostage raeched end point, give credit to invoker
2986 if (e.action.installTtemplate.param2)
2987 AddEvent(SMART_EVENT_DATA_SET, 0, 0, 0, 0, 0, 0, 0, SMART_ACTION_CALL_KILLEDMONSTER, e.action.installTtemplate.param1, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 2, 0, 0, 0, 0);
2988 else
2989 AddEvent(SMART_EVENT_GO_STATE_CHANGED, 0, 2, 0, 0, 0, 0, 0, SMART_ACTION_CALL_KILLEDMONSTER, e.action.installTtemplate.param1, 0, 0, 0, 0, 0, SMART_TARGET_STORED, 2, 0, 0, 0, 0);
2990 break;
2991 }
2993 default:
2994 return;
2995 }
2996}
std::uint8_t uint8
Definition: Define.h:110
SMARTAI_TEMPLATE
Definition: SmartScriptMgr.h:1464
@ SMARTAI_TEMPLATE_CAGED_GO_PART
Definition: SmartScriptMgr.h:1469
@ SMARTAI_TEMPLATE_CAGED_NPC_PART
Definition: SmartScriptMgr.h:1470
@ SMARTAI_TEMPLATE_CASTER
Definition: SmartScriptMgr.h:1466
@ SMARTAI_TEMPLATE_TURRET
Definition: SmartScriptMgr.h:1467
@ SMART_EVENT_FLAG_NOT_REPEATABLE
Definition: SmartScriptMgr.h:1859
@ SMART_ACTION_STORE_TARGET_LIST
Definition: SmartScriptMgr.h:634
@ SMART_ACTION_FORCE_DESPAWN
Definition: SmartScriptMgr.h:611
@ SMART_ACTION_CAST
Definition: SmartScriptMgr.h:581
@ SMART_ACTION_ALLOW_COMBAT_MOVEMENT
Definition: SmartScriptMgr.h:591
@ SMART_ACTION_MOVE_FORWARD
Definition: SmartScriptMgr.h:616
@ SMART_ACTION_CALL_KILLEDMONSTER
Definition: SmartScriptMgr.h:603
@ SMART_ACTION_TALK
Definition: SmartScriptMgr.h:571
@ SMART_ACTION_SET_DATA
Definition: SmartScriptMgr.h:615
@ SMART_ACTION_SET_RUN
Definition: SmartScriptMgr.h:629
@ SMART_ACTION_SET_EVENT_PHASE
Definition: SmartScriptMgr.h:592
@ SMART_ACTION_RESET_GOBJECT
Definition: SmartScriptMgr.h:602
@ SMART_EVENT_DATA_SET
Definition: SmartScriptMgr.h:156
@ SMART_EVENT_JUST_CREATED
Definition: SmartScriptMgr.h:181
@ SMART_EVENT_MOVEMENTINFORM
Definition: SmartScriptMgr.h:152
@ SMART_EVENT_MANA_PCT
Definition: SmartScriptMgr.h:121
@ SMART_EVENT_GO_STATE_CHANGED
Definition: SmartScriptMgr.h:188
@ SMART_RANDOM_POINT
Definition: SmartScriptMgr.h:58
@ POINT_MOTION_TYPE
Definition: MotionMaster.h:46
#define sCreatureTextMgr
Definition: CreatureTextMgr.h:119
void AddEvent(SMART_EVENT e, uint32 event_flags, uint32 event_param1, uint32 event_param2, uint32 event_param3, uint32 event_param4, uint32 event_param5, uint32 event_param6, SMART_ACTION action, uint32 action_param1, uint32 action_param2, uint32 action_param3, uint32 action_param4, uint32 action_param5, uint32 action_param6, SMARTAI_TARGETS t, uint32 target_param1, uint32 target_param2, uint32 target_param3, uint32 target_param4, uint32 phaseMask)
Definition: SmartScript.cpp:2998

References SmartScriptHolder::action, AddEvent(), SmartScriptHolder::entryOrGuid, GetBaseObject(), Object::GetEntry(), SmartScriptHolder::GetScriptType(), go, SmartAction::id, SmartAction::installTtemplate, LOG_ERROR, me, mTemplate, SmartAction::param1, SmartTarget::param1, SmartAction::param2, SmartAction::param3, SmartAction::param4, SmartAction::param5, POINT_MOTION_TYPE, SmartTarget::raw, sCreatureTextMgr, SMART_ACTION_ALLOW_COMBAT_MOVEMENT, SMART_ACTION_CALL_KILLEDMONSTER, SMART_ACTION_CAST, SMART_ACTION_FORCE_DESPAWN, SMART_ACTION_MOVE_FORWARD, SMART_ACTION_RESET_GOBJECT, SMART_ACTION_SET_DATA, SMART_ACTION_SET_EVENT_PHASE, SMART_ACTION_SET_RUN, SMART_ACTION_STORE_TARGET_LIST, SMART_ACTION_TALK, SMART_EVENT_DATA_SET, SMART_EVENT_FLAG_NOT_REPEATABLE, SMART_EVENT_GO_STATE_CHANGED, SMART_EVENT_JUST_CREATED, SMART_EVENT_MANA_PCT, SMART_EVENT_MOVEMENTINFORM, SMART_EVENT_RANGE, SMART_EVENT_UPDATE, SMART_EVENT_UPDATE_IC, SMART_RANDOM_POINT, SMART_TARGET_CLOSEST_CREATURE, SMART_TARGET_CLOSEST_GAMEOBJECT, SMART_TARGET_GAMEOBJECT_DISTANCE, SMART_TARGET_NONE, SMART_TARGET_STORED, SMART_TARGET_VICTIM, SMARTAI_TEMPLATE_BASIC, SMARTAI_TEMPLATE_CAGED_GO_PART, SMARTAI_TEMPLATE_CAGED_NPC_PART, SMARTAI_TEMPLATE_CASTER, SMARTAI_TEMPLATE_TURRET, and SmartScriptHolder::target.

Referenced by ProcessAction().

◆ IsCharmedCreature()

bool SmartScript::IsCharmedCreature ( WorldObject obj)
static
4916{
4917 if (!obj)
4918 return false;
4919
4920 if (Creature* creatureObj = obj->ToCreature())
4921 return creatureObj->IsCharmed();
4922
4923 return false;
4924}
Creature * ToCreature()
Definition: Object.h:197

References Object::ToCreature().

Referenced by ProcessEvent().

◆ IsCreature()

bool SmartScript::IsCreature ( WorldObject obj)
static
4911{
4912 return obj && obj->GetTypeId() == TYPEID_UNIT;
4913}
@ TYPEID_UNIT
Definition: ObjectGuid.h:37
TypeID GetTypeId() const
Definition: Object.h:121

References Object::GetTypeId(), and TYPEID_UNIT.

Referenced by GetTargets(), ProcessAction(), and ProcessEvent().

◆ IsGameObject()

bool SmartScript::IsGameObject ( WorldObject obj)
static
4927{
4928 return obj && obj->GetTypeId() == TYPEID_GAMEOBJECT;
4929}
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:39

References Object::GetTypeId(), and TYPEID_GAMEOBJECT.

Referenced by GetTargets(), ProcessAction(), and ProcessEvent().

◆ IsInPhase()

bool SmartScript::IsInPhase ( uint32  p) const
private
4962{
4963 if (mEventPhase == 0)
4964 {
4965 return false;
4966 }
4967
4968 return ((1 << (mEventPhase - 1)) & p) != 0;
4969}

References mEventPhase.

Referenced by ProcessEvent(), and UpdateTimer().

◆ IsPlayer()

bool SmartScript::IsPlayer ( WorldObject obj)
static
4906{
4907 return obj && obj->GetTypeId() == TYPEID_PLAYER;
4908}
@ TYPEID_PLAYER
Definition: ObjectGuid.h:38

References Object::GetTypeId(), and TYPEID_PLAYER.

Referenced by GetTargets(), SmartAI::IsEscortInvokerInRange(), ProcessAction(), and ProcessEvent().

◆ IsSmart()

bool SmartScript::IsSmart ( Creature c = nullptr)
inline
87 {
88 bool smart = true;
89 if (c && c->GetAIName() != "SmartAI")
90 smart = false;
91
92 if (!me || me->GetAIName() != "SmartAI")
93 smart = false;
94
95 if (!smart)
96 LOG_ERROR("sql.sql", "SmartScript: Action target Creature(entry: {}) is not using SmartAI, action skipped to prevent crash.", c ? c->GetEntry() : (me ? me->GetEntry() : 0));
97
98 return smart;
99 }
std::string const & GetAIName() const
Definition: Creature.cpp:2937

References Creature::GetAIName(), Object::GetEntry(), LOG_ERROR, and me.

Referenced by ProcessAction().

◆ IsSmartGO()

bool SmartScript::IsSmartGO ( GameObject g = nullptr)
inline
102 {
103 bool smart = true;
104 if (g && g->GetAIName() != "SmartGameObjectAI")
105 smart = false;
106
107 if (!go || go->GetAIName() != "SmartGameObjectAI")
108 smart = false;
109 if (!smart)
110 LOG_ERROR("sql.sql", "SmartScript: Action target GameObject(entry: {}) is not using SmartGameObjectAI, action skipped to prevent crash.", g ? g->GetEntry() : (go ? go->GetEntry() : 0));
111
112 return smart;
113 }
std::string const & GetAIName() const
Definition: GameObject.cpp:100

References GameObject::GetAIName(), Object::GetEntry(), go, and LOG_ERROR.

◆ IsUnit()

bool SmartScript::IsUnit ( WorldObject obj)
static
4901{
4902 return obj && (obj->GetTypeId() == TYPEID_UNIT || obj->GetTypeId() == TYPEID_PLAYER);
4903}

References Object::GetTypeId(), TYPEID_PLAYER, and TYPEID_UNIT.

Referenced by ProcessAction(), and ProcessEvent().

◆ OnInitialize()

void SmartScript::OnInitialize ( WorldObject obj,
AreaTrigger const *  at = nullptr 
)
4671{
4672 if (obj)//handle object based scripts
4673 {
4674 switch (obj->GetTypeId())
4675 {
4676 case TYPEID_UNIT:
4678 me = obj->ToCreature();
4679 LOG_DEBUG("sql.sql", "SmartScript::OnInitialize: source is Creature {}", me->GetEntry());
4680 break;
4681 case TYPEID_GAMEOBJECT:
4683 go = obj->ToGameObject();
4684 LOG_DEBUG("sql.sql", "SmartScript::OnInitialize: source is GameObject {}", go->GetEntry());
4685 break;
4686 default:
4687 LOG_ERROR("scripts.ai.sai", "SmartScript::OnInitialize: Unhandled TypeID !WARNING!");
4688 return;
4689 }
4690 }
4691 else if (at)
4692 {
4694 trigger = at;
4695 LOG_DEBUG("sql.sql", "SmartScript::OnInitialize: source is AreaTrigger {}", trigger->entry);
4696 }
4697 else
4698 {
4699 LOG_ERROR("scripts.ai.sai", "SmartScript::OnInitialize: !WARNING! Initialized objects are nullptr.");
4700 return;
4701 }
4702
4703 GetScript();//load copy of script
4704
4705 uint32 maxDisableDist = 0;
4706 uint32 minEnableDist = 0;
4707 for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
4708 {
4709 InitTimer((*i));//calculate timers for first time use
4710 if (i->GetEventType() == SMART_EVENT_RANGE && i->GetActionType() == SMART_ACTION_ALLOW_COMBAT_MOVEMENT)
4711 {
4712 if (i->action.combatMove.move == 1 && i->event.rangeRepeat.minRange > minEnableDist)
4713 minEnableDist = i->event.rangeRepeat.minRange;
4714 else if (i->action.combatMove.move == 0 && (i->event.rangeRepeat.maxRange < maxDisableDist || maxDisableDist == 0))
4715 maxDisableDist = i->event.rangeRepeat.maxRange;
4716 }
4717
4718 // Xinef: if smartcast combat move flag is present
4719 if (i->GetActionType() == SMART_ACTION_CAST && (i->action.cast.castFlags & SMARTCAST_COMBAT_MOVE))
4720 {
4721 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(i->action.cast.spell))
4722 {
4723 float maxRange = spellInfo->GetMaxRange(spellInfo->IsPositive());
4724 float minRange = spellInfo->GetMinRange(spellInfo->IsPositive());
4725
4726 if (maxRange > 0 && minRange <= maxRange)
4727 {
4728 smartCasterMaxDist = minRange + ((maxRange - minRange) * 0.65f);
4729 smartCasterPowerType = (Powers)spellInfo->PowerType;
4730 }
4731 }
4732 }
4733 }
4734 if (maxDisableDist > 0 && minEnableDist >= maxDisableDist)
4735 mMaxCombatDist = uint32(maxDisableDist + ((minEnableDist - maxDisableDist) / 2));
4736
4738 InstallEvents();
4740}
@ SMART_SCRIPT_TYPE_GAMEOBJECT
Definition: SmartScriptMgr.h:1706
@ SMART_SCRIPT_TYPE_AREATRIGGER
Definition: SmartScriptMgr.h:1707
@ SMART_EVENT_AI_INIT
Definition: SmartScriptMgr.h:155
@ SMARTCAST_COMBAT_MOVE
Definition: SmartScriptMgr.h:1882
#define sSpellMgr
Definition: SpellMgr.h:825
void ProcessEventsFor(SMART_EVENT e, Unit *unit=nullptr, uint32 var0=0, uint32 var1=0, bool bvar=false, SpellInfo const *spell=nullptr, GameObject *gob=nullptr)
Definition: SmartScript.cpp:95
void InstallEvents()
Definition: SmartScript.cpp:4528
void GetScript()
Definition: SmartScript.cpp:4636
GameObject * ToGameObject()
Definition: Object.h:202
Definition: SpellInfo.h:314

References AreaTrigger::entry, Object::GetEntry(), SpellInfo::GetMaxRange(), SpellInfo::GetMinRange(), GetScript(), Object::GetTypeId(), go, InitTimer(), InstallEvents(), SpellInfo::IsPositive(), LOG_DEBUG, LOG_ERROR, me, mEvents, mMaxCombatDist, mScriptType, SpellInfo::PowerType, ProcessEventsFor(), SMART_ACTION_ALLOW_COMBAT_MOVEMENT, SMART_ACTION_CAST, SMART_EVENT_AI_INIT, SMART_EVENT_JUST_CREATED, SMART_EVENT_RANGE, SMART_SCRIPT_TYPE_AREATRIGGER, SMART_SCRIPT_TYPE_CREATURE, SMART_SCRIPT_TYPE_GAMEOBJECT, SMARTCAST_COMBAT_MOVE, smartCasterMaxDist, smartCasterPowerType, sSpellMgr, Object::ToCreature(), Object::ToGameObject(), trigger, TYPEID_GAMEOBJECT, and TYPEID_UNIT.

Referenced by SmartAI::InitializeAI(), SmartGameObjectAI::InitializeAI(), and SmartTrigger::OnTrigger().

◆ OnMoveInLineOfSight()

void SmartScript::OnMoveInLineOfSight ( Unit who)
4743{
4744 if (!me)
4745 return;
4746
4748}
bool IsEngaged() const
Definition: Unit.h:1697

References Unit::IsEngaged(), me, ProcessEventsFor(), SMART_EVENT_IC_LOS, and SMART_EVENT_OOC_LOS.

Referenced by SmartAI::MoveInLineOfSight().

◆ OnReset()

void SmartScript::OnReset ( )
72{
73 // xinef: check if we allow phase reset
74 if (AllowPhaseReset())
75 SetPhase(0);
76
78 for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
79 {
80 if (!((*i).event.event_flags & SMART_EVENT_FLAG_DONT_RESET))
81 {
82 InitTimer((*i));
83 (*i).runOnce = false;
84 }
85 }
88 mCounterList.clear();
89
90 // Xinef: Fix Combat Movement
93}
@ SMART_EVENT_FLAG_DONT_RESET
Definition: SmartScriptMgr.h:1867
@ SMART_EVENT_RESET
Definition: SmartScriptMgr.h:143
void RestoreCasterMaxDist()
Definition: SmartScript.h:227
bool AllowPhaseReset() const
Definition: SmartScript.h:232
void RestoreMaxCombatDist()
Definition: SmartScript.h:221
void ResetBaseObject()
Definition: SmartScript.h:181
void Clear()
Definition: ObjectGuid.h:140

References AllowPhaseReset(), ObjectGuid::Clear(), InitTimer(), mCounterList, mEvents, mLastInvoker, ProcessEventsFor(), ResetBaseObject(), RestoreCasterMaxDist(), RestoreMaxCombatDist(), SetPhase(), SMART_EVENT_FLAG_DONT_RESET, and SMART_EVENT_RESET.

Referenced by SmartAI::EnterEvadeMode(), SmartAI::JustReachedHome(), and SmartGameObjectAI::Reset().

◆ OnUpdate()

void SmartScript::OnUpdate ( const uint32  diff)
4540{
4542 return;
4543
4544 InstallEvents();//before UpdateTimers
4545
4546 for (SmartAIEventList::iterator i = mEvents.begin(); i != mEvents.end(); ++i)
4547 UpdateTimer(*i, diff);
4548
4549 if (!mStoredEvents.empty())
4550 {
4551 SmartAIEventStoredList::iterator i, icurr;
4552 for (i = mStoredEvents.begin(); i != mStoredEvents.end();)
4553 {
4554 icurr = i++;
4555 UpdateTimer(*icurr, diff);
4556 }
4557 }
4558
4559 bool needCleanup = true;
4560 if (!mTimedActionList.empty())
4561 {
4563 for (SmartAIEventList::iterator i = mTimedActionList.begin(); i != mTimedActionList.end(); ++i)
4564 {
4565 if ((*i).enableTimed)
4566 {
4567 UpdateTimer(*i, diff);
4568 needCleanup = false;
4569 }
4570 }
4571
4573 }
4574 if (needCleanup)
4575 mTimedActionList.clear();
4576
4577 if (!mRemIDs.empty())
4578 {
4579 for (std::list<uint32>::const_iterator i = mRemIDs.begin(); i != mRemIDs.end(); ++i)
4581
4582 // xinef: clear list after cleaning...
4583 mRemIDs.clear();
4584 }
4585 if (mUseTextTimer && me)
4586 {
4587 if (mTextTimer < diff)
4588 {
4589 uint32 textID = mLastTextID;
4590 mLastTextID = 0;
4591 uint32 entry = mTalkerEntry;
4592 mTalkerEntry = 0;
4593 mTextTimer = 0;
4594 mUseTextTimer = false;
4595 ProcessEventsFor(SMART_EVENT_TEXT_OVER, nullptr, textID, entry);
4596 }
4597 else mTextTimer -= diff;
4598 }
4599}
@ SMART_EVENT_TEXT_OVER
Definition: SmartScriptMgr.h:170
void UpdateTimer(SmartScriptHolder &e, uint32 const diff)
Definition: SmartScript.cpp:4437
SmartAIEventStoredList mStoredEvents
Definition: SmartScript.h:258
std::list< uint32 > mRemIDs
Definition: SmartScript.h:259
SmartAIEventList mTimedActionList
Definition: SmartScript.h:246
void RemoveStoredEvent(uint32 id)
Definition: SmartScript.h:283

References GetBaseObject(), InstallEvents(), isProcessingTimedActionList, me, mEvents, mLastTextID, mRemIDs, mScriptType, mStoredEvents, mTalkerEntry, mTextTimer, mTimedActionList, mUseTextTimer, ProcessEventsFor(), RemoveStoredEvent(), SMART_EVENT_TEXT_OVER, SMART_SCRIPT_TYPE_CREATURE, SMART_SCRIPT_TYPE_GAMEOBJECT, and UpdateTimer().

Referenced by SmartAI::UpdateAI(), and SmartGameObjectAI::UpdateAI().

◆ ProcessAction()

void SmartScript::ProcessAction ( SmartScriptHolder e,
Unit unit = nullptr,
uint32  var0 = 0,
uint32  var1 = 0,
bool  bvar = false,
SpellInfo const *  spell = nullptr,
GameObject gob = nullptr 
)
115{
116 //calc random
117 if (e.event.event_chance < 100 && e.event.event_chance)
118 {
119 uint32 rnd = urand(1, 100);
120 if (e.event.event_chance <= rnd)
121 return;
122 }
123 e.runOnce = true;//used for repeat check
124
125 if (unit)
126 mLastInvoker = unit->GetGUID();
127
128 if (Unit* tempInvoker = GetLastInvoker())
129 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: Invoker: {} ({})", tempInvoker->GetName(), tempInvoker->GetGUID().ToString());
130
131 bool isControlled = e.action.moveToPos.controlled > 0;
132
133 ObjectVector targets;
134 GetTargets(targets, e, unit);
135
136 switch (e.GetActionType())
137 {
139 {
140 Creature* talker = e.target.type == 0 ? me : nullptr;
141 Unit* talkTarget = nullptr;
142
143 for (WorldObject* target : targets)
144 {
145 if (IsCreature((target)) && !target->ToCreature()->IsPet()) // Prevented sending text to pets.
146 {
148 {
149 talker = me;
150 talkTarget = target->ToCreature();
151 }
152 else
153 talker = target->ToCreature();
154 break;
155 }
156 else if (IsPlayer((target)))
157 {
158 talker = me; // xinef: added
159 talkTarget = target->ToPlayer();
160 break;
161 }
162 }
163
164 if (!talkTarget)
165 talkTarget = GetLastInvoker();
166
167 if (!talker)
168 break;
169
170 if (!sCreatureTextMgr->TextExist(talker->GetEntry(), uint8(e.action.talk.textGroupID)))
171 {
172 LOG_ERROR("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_TALK: EntryOrGuid {} SourceType {} EventType {} TargetType {} using non-existent Text id {} for talker {}, ignored.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetTargetType(), e.action.talk.textGroupID, talker->GetEntry());
173 break;
174 }
175
176 mTalkerEntry = talker->GetEntry();
179 mUseTextTimer = true;
180 sCreatureTextMgr->SendChat(talker, uint8(e.action.talk.textGroupID), talkTarget);
181 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_TALK: talker: {} ({}), textId: {}", talker->GetName(), talker->GetGUID().ToString(), mLastTextID);
182 break;
183 }
185 {
186 for (WorldObject* target : targets)
187 {
188 if (IsCreature(target))
189 sCreatureTextMgr->SendChat(target->ToCreature(), uint8(e.action.simpleTalk.textGroupID), IsPlayer(GetLastInvoker()) ? GetLastInvoker() : 0);
190 else if (IsPlayer(target) && me)
191 {
192 Unit* templastInvoker = GetLastInvoker();
193 sCreatureTextMgr->SendChat(me, uint8(e.action.simpleTalk.textGroupID), IsPlayer(templastInvoker) ? templastInvoker : 0, CHAT_MSG_ADDON, LANG_ADDON, TEXT_RANGE_NORMAL, 0, TEAM_NEUTRAL, false, target->ToPlayer());
194 }
195
196 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SIMPLE_TALK: talker: {} ({}), textGroupId: {}",
197 target->GetName(), target->GetGUID().ToString(), uint8(e.action.simpleTalk.textGroupID));
198 }
199 break;
200 }
202 {
203 for (WorldObject* target : targets)
204 {
205 if (IsUnit(target))
206 {
207 target->ToUnit()->HandleEmoteCommand(e.action.emote.emote);
208 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_PLAY_EMOTE: target: {} ({}), emote: {}",
209 target->GetName(), target->GetGUID().ToString(), e.action.emote.emote);
210 }
211 }
212 break;
213 }
215 {
216 for (WorldObject* target : targets)
217 {
218 if (IsUnit(target))
219 {
220 if (e.action.sound.distance == 1)
221 target->PlayDistanceSound(e.action.sound.sound, e.action.sound.onlySelf ? target->ToPlayer() : nullptr);
222 else
223 target->PlayDirectSound(e.action.sound.sound, e.action.sound.onlySelf ? target->ToPlayer() : nullptr);
224 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SOUND: target: {} ({}), sound: {}, onlyself: {}",
225 target->GetName(), target->GetGUID().ToString(), e.action.sound.sound, e.action.sound.onlySelf);
226 }
227 }
228 break;
229 }
231 {
232 uint32 sounds[4];
233 sounds[0] = e.action.randomSound.sound1;
234 sounds[1] = e.action.randomSound.sound2;
235 sounds[2] = e.action.randomSound.sound3;
236 sounds[3] = e.action.randomSound.sound4;
237 uint32 temp[4];
238 uint32 count = 0;
239 for (unsigned int sound : sounds)
240 {
241 if (sound)
242 {
243 temp[count] = sound;
244 ++count;
245 }
246 }
247
248 if (count == 0)
249 {
250 break;
251 }
252
253 for (WorldObject* target : targets)
254 {
255 if (IsUnit(target))
256 {
257 uint32 sound = temp[urand(0, count - 1)];
258 target->PlayDirectSound(sound, e.action.randomSound.onlySelf ? target->ToPlayer() : nullptr);
259 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_SOUND: target: {} ({}), sound: {}, onlyself: {}",
260 target->GetName(), target->GetGUID().ToString(), sound, e.action.randomSound.onlySelf);
261 }
262 }
263
264 break;
265 }
267 {
268 ObjectVector targets;
269
270 if (e.action.music.type > 0)
271 {
272 if (me && me->FindMap())
273 {
274 Map::PlayerList const& players = me->GetMap()->GetPlayers();
275
276 if (!players.IsEmpty())
277 {
278 for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
279 if (Player* player = i->GetSource())
280 {
281 if (player->GetZoneId() == me->GetZoneId())
282 {
283 if (e.action.music.type > 1)
284 {
285 if (player->GetAreaId() == me->GetAreaId())
286 targets.push_back(player);
287 }
288 else
289 targets.push_back(player);
290 }
291 }
292 }
293 }
294 }
295 else
296 GetTargets(targets, e);
297
298 if (!targets.empty())
299 {
300 for (WorldObject* target : targets)
301 {
302 if (IsUnit(target))
303 {
304 target->SendPlayMusic(e.action.music.sound, e.action.music.onlySelf > 0);
305 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_MUSIC: target: {} ({}), sound: {}, onlySelf: {}, type: {}",
306 target->GetName(), target->GetGUID().ToString(), e.action.music.sound, e.action.music.onlySelf, e.action.music.type);
307 }
308 }
309 }
310 break;
311 }
313 {
314 ObjectVector targets;
315
316 if (e.action.randomMusic.type > 0)
317 {
318 if (me && me->FindMap())
319 {
320 Map::PlayerList const& players = me->GetMap()->GetPlayers();
321
322 if (!players.IsEmpty())
323 {
324 for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
325 if (Player* player = i->GetSource())
326 {
327 if (player->GetZoneId() == me->GetZoneId())
328 {
329 if (e.action.randomMusic.type > 1)
330 {
331 if (player->GetAreaId() == me->GetAreaId())
332 targets.push_back(player);
333 }
334 else
335 targets.push_back(player);
336 }
337 }
338 }
339 }
340 }
341 else
342 GetTargets(targets, e);
343
344 if (targets.empty())
345 break;
346
347 uint32 sounds[4];
348 sounds[0] = e.action.randomMusic.sound1;
349 sounds[1] = e.action.randomMusic.sound2;
350 sounds[2] = e.action.randomMusic.sound3;
351 sounds[3] = e.action.randomMusic.sound4;
352 uint32 temp[4];
353 uint32 count = 0;
354 for (unsigned int sound : sounds)
355 {
356 if (sound)
357 {
358 temp[count] = sound;
359 ++count;
360 }
361 }
362
363 if (count == 0)
364 {
365 break;
366 }
367
368 for (WorldObject* target : targets)
369 {
370 if (IsUnit(target))
371 {
372 uint32 sound = temp[urand(0, count - 1)];
373 target->SendPlayMusic(sound, e.action.randomMusic.onlySelf > 0);
374 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_MUSIC: target: {} ({}), sound: {}, onlyself: {}, type: {}",
375 target->GetName(), target->GetGUID().ToString(), sound, e.action.randomMusic.onlySelf, e.action.randomMusic.type);
376 }
377 }
378
379 break;
380 }
382 {
383 for (WorldObject* target : targets)
384 {
385 if (IsCreature(target))
386 {
388 {
389 target->ToCreature()->SetFaction(e.action.faction.factionID);
390 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry {}, GuidLow {} set faction to {}",
391 target->GetEntry(), target->GetGUID().ToString(), e.action.faction.factionID);
392 }
393 else
394 {
395 if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(target->ToCreature()->GetEntry()))
396 {
397 if (target->ToCreature()->GetFaction() != ci->faction)
398 {
399 target->ToCreature()->SetFaction(ci->faction);
400 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry {}, GuidLow {} set faction to {}",
401 target->GetEntry(), target->GetGUID().ToString(), ci->faction);
402 }
403 }
404 }
405 }
406 }
407 break;
408 }
410 {
411 for (WorldObject* target : targets)
412 {
413 if (!IsCreature(target))
414 continue;
415
417 {
418 //set model based on entry from creature_template
420 {
421 if (CreatureTemplate const* ci = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature))
422 {
423 uint32 displayId = ObjectMgr::ChooseDisplayId(ci);
424 target->ToCreature()->SetDisplayId(displayId);
425 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry {}, GuidLow {} set displayid to {}",
426 target->GetEntry(), target->GetGUID().ToString(), displayId);
427 }
428 }
429 //if no param1, then use value from param2 (modelId)
430 else
431 {
432 target->ToCreature()->SetDisplayId(e.action.morphOrMount.model);
433 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry {}, GuidLow {} set displayid to {}",
434 target->GetEntry(), target->GetGUID().ToString(), e.action.morphOrMount.model);
435 }
436 }
437 else
438 {
439 target->ToCreature()->DeMorph();
440 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry {}, GuidLow {} demorphs.",
441 target->GetEntry(), target->GetGUID().ToString());
442 }
443 }
444 break;
445 }
447 {
448 for (WorldObject* target : targets)
449 {
450 if (IsPlayer(target))
451 {
452 target->ToPlayer()->FailQuest(e.action.quest.quest);
453 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_FAIL_QUEST: Player guidLow {} fails quest {}",
454 target->GetGUID().ToString(), e.action.quest.quest);
455 }
456 }
457 break;
458 }
460 {
461 for (WorldObject* target : targets)
462 {
463 if (Player* player = target->ToPlayer())
464 {
465 if (Quest const* q = sObjectMgr->GetQuestTemplate(e.action.questOffer.questID))
466 {
467 if (me && e.action.questOffer.directAdd == 0)
468 {
469 if (player->CanTakeQuest(q, true))
470 {
471 if (WorldSession* session = player->GetSession())
472 {
473 PlayerMenu menu(session);
474 menu.SendQuestGiverQuestDetails(q, me->GetGUID(), true);
475 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player guidLow {} - offering quest {}",
476 player->GetGUID().ToString(), e.action.questOffer.questID);
477 }
478 }
479 }
480 else
481 {
482 player->AddQuestAndCheckCompletion(q, nullptr);
483 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_OFFER_QUEST: Player guidLow {} - quest {} added",
484 player->GetGUID().ToString(), e.action.questOffer.questID);
485 }
486 }
487 }
488 }
489 break;
490 }
492 {
493 for (WorldObject* target : targets)
494 {
495 if (!IsCreature(target))
496 continue;
497
498 target->ToCreature()->SetReactState(ReactStates(e.action.react.state));
499 }
500 break;
501 }
503 {
504 std::vector<uint32> emotes;
505 std::copy_if(e.action.randomEmote.emotes.begin(), e.action.randomEmote.emotes.end(),
506 std::back_inserter(emotes), [](uint32 emote) { return emote != 0; });
507
508 for (WorldObject* target : targets)
509 {
510 if (IsUnit(target))
511 {
513 target->ToUnit()->HandleEmoteCommand(emote);
514 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_EMOTE: Creature guidLow {} handle random emote {}",
515 target->GetGUID().ToString(), emote);
516 }
517 }
518 break;
519 }
521 {
522 if (!me)
523 break;
524
526 for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i)
527 {
528 if (Unit* target = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()))
529 {
531 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_THREAT_ALL_PCT: Creature {} modify threat for unit {}, value {}",
532 me->GetGUID().ToString(), target->GetGUID().ToString(), e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC);
533 }
534 }
535 break;
536 }
538 {
539 if (!me)
540 break;
541
542 for (WorldObject* target : targets)
543 {
544 if (IsUnit(target))
545 {
547 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_THREAT_SINGLE_PCT: Creature guidLow {} modify threat for unit {}, value {}",
548 me->GetGUID().ToString(), target->GetGUID().ToString(), e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC);
549 }
550 }
551 break;
552 }
554 {
555 for (WorldObject* target : targets)
556 {
557 // Special handling for vehicles
558 if (IsUnit(target))
559 if (Vehicle* vehicle = target->ToUnit()->GetVehicleKit())
560 for (auto & Seat : vehicle->Seats)
561 if (Player* player = ObjectAccessor::GetPlayer(*target, Seat.second.Passenger.Guid))
562 player->AreaExploredOrEventHappens(e.action.quest.quest);
563
564 if (IsPlayer(target))
565 {
566 target->ToPlayer()->AreaExploredOrEventHappens(e.action.quest.quest);
567
568 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: Player guidLow {} credited quest {}",
569 target->GetGUID().ToString(), e.action.quest.quest);
570 }
571 }
572 break;
573 }
575 {
576 if (targets.empty())
577 break;
578
579 Unit* caster = me;
580 // Areatrigger Cast!
582 caster = unit->SummonTrigger(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ(), unit->GetOrientation(), 5000);
583
586
587 for (WorldObject* target : targets)
588 {
589 // may be nullptr
590 if (go)
591 {
592 go->CastSpell(target->ToUnit(), e.action.cast.spell);
593 }
594
595 if (!IsUnit(target))
596 continue;
597
598 if (caster && caster != me) // Areatrigger cast
599 {
600 caster->CastSpell(target->ToUnit(), e.action.cast.spell, (e.action.cast.castFlags & SMARTCAST_TRIGGERED));
601 }
602 else if (me && (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell)))
603 {
605 {
607 }
608
610 if (me->GetThreatMgr().GetThreatListSize() <= 1)
611 break;
612
613 TriggerCastFlags triggerFlags = TRIGGERED_NONE;
615 {
617 {
618 triggerFlags = TriggerCastFlags(e.action.cast.triggerFlags);
619 }
620 else
621 {
622 triggerFlags = TRIGGERED_FULL_MASK;
623 }
624 }
625
626 // Flag usable only if caster has max dist set.
628 {
629 // Check mana case only and operate movement accordingly, LoS and range is checked in targetet movement generator.
630 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.cast.spell);
631 int32 currentPower = me->GetPower(GetCasterPowerType());
632
633 if ((spellInfo && (currentPower < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask()) || me->IsSpellProhibited(spellInfo->GetSchoolMask()))) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED))
634 {
636 CAST_AI(SmartAI, me->AI())->SetForcedCombatMove(0);
637 }
638 else if (GetCasterActualDist() == 0.0f && me->GetPowerPct(GetCasterPowerType()) > 30.0f)
639 {
641 CAST_AI(SmartAI, me->AI())->SetForcedCombatMove(GetCasterActualDist());
642 }
643 }
644
645 me->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlags);
646 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CAST: Unit {} casts spell {} on target {} with castflags {}",
647 me->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
648 }
649 else
650 {
651 LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target {} already has the aura",
652 e.action.cast.spell, target->GetGUID().ToString());
653 }
654 }
655 break;
656 }
658 {
659 if (targets.empty())
660 break;
661
664
665 TriggerCastFlags triggerFlags = TRIGGERED_NONE;
667 {
669 {
670 triggerFlags = TriggerCastFlags(e.action.cast.triggerFlags);
671 }
672 else
673 {
674 triggerFlags = TRIGGERED_FULL_MASK;
675 }
676 }
677
678 for (WorldObject* target : targets)
679 {
680 Unit* uTarget = target->ToUnit();
681 if (!uTarget)
682 continue;
683
685 {
687 {
688 uTarget->InterruptNonMeleeSpells(false);
689 }
690
691 uTarget->CastSpell(uTarget, e.action.cast.spell, triggerFlags);
692 }
693 }
694 break;
695 }
697 {
698 // Can be used for area trigger cast
699 Unit* tempLastInvoker = GetLastInvoker(unit);
700 if (!tempLastInvoker)
701 break;
702
703 if (targets.empty())
704 break;
705
708
709 for (WorldObject* target : targets)
710 {
711 if (!IsUnit(target))
712 continue;
713
714 if (!(e.action.cast.castFlags & SMARTCAST_AURA_NOT_PRESENT) || !target->ToUnit()->HasAura(e.action.cast.spell))
715 {
717 {
718 tempLastInvoker->InterruptNonMeleeSpells(false);
719 }
720
721 TriggerCastFlags triggerFlags = TRIGGERED_NONE;
723 {
725 {
726 triggerFlags = TriggerCastFlags(e.action.cast.triggerFlags);
727 }
728 else
729 {
730 triggerFlags = TRIGGERED_FULL_MASK;
731 }
732 }
733
734 tempLastInvoker->CastSpell(target->ToUnit(), e.action.cast.spell, triggerFlags);
735 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_INVOKER_CAST: Invoker {} casts spell {} on target {} with castflags {}",
736 tempLastInvoker->GetGUID().ToString(), e.action.cast.spell, target->GetGUID().ToString(), e.action.cast.castFlags);
737 }
738 else
739 {
740 LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target {} already has the aura",
741 e.action.cast.spell, target->GetGUID().ToString());
742 }
743 }
744 break;
745 }
747 {
748 for (WorldObject* target : targets)
749 {
750 if (IsUnit(target))
751 {
752 target->ToUnit()->AddAura(e.action.cast.spell, target->ToUnit());
753 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_ADD_AURA: Adding aura {} to unit {}",
754 e.action.cast.spell, target->GetGUID().ToString());
755 }
756 }
757 break;
758 }
760 {
761 for (WorldObject* target : targets)
762 {
763 if (IsGameObject(target))
764 {
765 GameObject* go = target->ToGameObject();
766
767 // Activate
769 {
771 }
772
774 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_ACTIVATE_GOBJECT. Gameobject {} activated", go->GetGUID().ToString());
775 }
776 }
777
778 break;
779 }
781 {
782 for (WorldObject* target : targets)
783 {
784 if (IsGameObject(target))
785 {
786 target->ToGameObject()->ResetDoorOrButton();
787 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_RESET_GOBJECT. Gameobject {} (entry: {}) reset",
788 target->GetGUID().ToString(), target->GetEntry());
789 }
790 }
791 break;
792 }
794 {
795 for (WorldObject* target : targets)
796 {
797 if (IsUnit(target))
798 {
799 target->ToUnit()->SetUInt32Value(UNIT_NPC_EMOTESTATE, e.action.emote.emote);
800 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_EMOTE_STATE. Unit {} set emotestate to {}",
801 target->GetGUID().ToString(), e.action.emote.emote);
802 }
803 }
804 break;
805 }
807 {
808 for (WorldObject* target : targets)
809 {
810 if (IsUnit(target))
811 {
812 if (!e.action.unitFlag.type)
813 {
814 target->ToUnit()->SetFlag(UNIT_FIELD_FLAGS, e.action.unitFlag.flag);
815 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_UNIT_FLAG. Unit {} added flag {} to UNIT_FIELD_FLAGS",
816 target->GetGUID().ToString(), e.action.unitFlag.flag);
817 }
818 else
819 {
820 target->ToUnit()->SetFlag(UNIT_FIELD_FLAGS_2, e.action.unitFlag.flag);
821 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_SET_UNIT_FLAG. Unit {} added flag {} to UNIT_FIELD_FLAGS_2",
822 target->GetGUID().ToString(), e.action.unitFlag.flag);
823 }
824 }
825 }
826 break;
827 }
829 {
830 for (WorldObject* target : targets)
831 {
832 if (IsUnit(target))
833 {
834 if (!e.action.unitFlag.type)
835 {
836 target->ToUnit()->RemoveFlag(UNIT_FIELD_FLAGS, e.action.unitFlag.flag);
837 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_REMOVE_UNIT_FLAG. Unit {} removed flag {} to UNIT_FIELD_FLAGS",
838 target->GetGUID().ToString(), e.action.unitFlag.flag);
839 }
840 else
841 {
842 target->ToUnit()->RemoveFlag(UNIT_FIELD_FLAGS_2, e.action.unitFlag.flag);
843 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_REMOVE_UNIT_FLAG. Unit {} removed flag {} to UNIT_FIELD_FLAGS_2",
844 target->GetGUID().ToString(), e.action.unitFlag.flag);
845 }
846 }
847 }
848 break;
849 }
851 {
852 if (!IsSmart())
853 break;
854
855 CAST_AI(SmartAI, me->AI())->SetAutoAttack(e.action.autoAttack.attack);
856 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_AUTO_ATTACK: Creature: {} bool on = {}",
858 break;
859 }
861 {
862 if (!IsSmart())
863 break;
864
865 // Xinef: Fix Combat Movement
866 bool move = e.action.combatMove.move;
867 if (move && GetMaxCombatDist() && e.GetEventType() == SMART_EVENT_MANA_PCT)
868 {
870 CAST_AI(SmartAI, me->AI())->SetForcedCombatMove(0);
871 }
872 else
873 CAST_AI(SmartAI, me->AI())->SetCombatMove(move);
874 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_ALLOW_COMBAT_MOVEMENT: Creature {} bool on = {}",
876 break;
877 }
879 {
880 if (!GetBaseObject())
881 break;
882
884 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SET_EVENT_PHASE: Creature {} set event phase {}",
886 break;
887 }
889 {
890 if (!GetBaseObject())
891 break;
892
895 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_INC_EVENT_PHASE: Creature {} inc event phase by {}, "
896 "decrease by {}", GetBaseObject()->GetGUID().ToString(), e.action.incEventPhase.inc, e.action.incEventPhase.dec);
897 break;
898 }
900 {
901 if (!GetBaseObject())
902 break;
903
904 for (WorldObject* target : targets)
905 if (IsCreature(target))
906 if (target->ToCreature()->IsAIEnabled)
907 target->ToCreature()->AI()->EnterEvadeMode();
908
909 break;
910 }
912 {
913 // Xinef: do not allow to flee without control (stun, fear etc)
915 break;
916
918 if (e.action.flee.withEmote)
919 {
921 sCreatureTextMgr->SendChatPacket(me, builder, CHAT_MSG_MONSTER_EMOTE);
922 }
923 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_FLEE_FOR_ASSIST: Creature {} DoFleeToGetAssistance", me->GetGUID().ToString());
924 break;
925 }
927 {
928 if (!me)
929 break;
930
931 me->CombatStop(true);
932 break;
933 }
935 {
936 for (WorldObject* target : targets)
937 {
938 if (!IsUnit(target))
939 continue;
940
941 Unit* unitTarget = target->ToUnit();
942 // If invoker was pet or charm
943 Player* player = unitTarget->GetCharmerOrOwnerPlayerOrPlayerItself();
944 if (player && GetBaseObject())
945 {
946 player->GroupEventHappens(e.action.quest.quest, GetBaseObject());
947 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_GROUPEVENTHAPPENS: Player {}, group credit for quest {}",
948 player->GetGUID().ToString(), e.action.quest.quest);
949 }
950
951 // Special handling for vehicles
952 if (Vehicle* vehicle = unitTarget->GetVehicleKit())
953 {
954 for (auto& Seat : vehicle->Seats)
955 {
956 if (Player* player = ObjectAccessor::GetPlayer(*unitTarget, Seat.second.Passenger.Guid))
957 {
958 player->GroupEventHappens(e.action.quest.quest, GetBaseObject());
959 }
960 }
961 }
962 }
963 break;
964 }
966 {
967 for (WorldObject* target : targets)
968 {
969 if (!IsUnit(target))
970 continue;
971
972 if (e.action.removeAura.spell)
973 {
975 {
976 if (Aura* aur = target->ToUnit()->GetAura(e.action.removeAura.spell))
977 aur->ModCharges(-static_cast<int32>(e.action.removeAura.charges), AURA_REMOVE_BY_EXPIRE);
978 }
979 else
980 target->ToUnit()->RemoveAurasDueToSpell(e.action.removeAura.spell);
981 }
982 else
983 target->ToUnit()->RemoveAllAuras();
984
985 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_REMOVEAURASFROMSPELL: Unit {}, spell {}",
986 target->GetGUID().ToString(), e.action.removeAura.spell);
987 }
988 break;
989 }
991 {
992 if (!IsSmart())
993 break;
994
996 {
997 CAST_AI(SmartAI, me->AI())->StopFollow(false);
998 break;
999 }
1000
1001 for (WorldObject* target : targets)
1002 {
1003 if (IsUnit(target))
1004 {
1005 float angle = e.action.follow.angle > 6 ? (e.action.follow.angle * M_PI / 180.0f) : e.action.follow.angle;
1006 CAST_AI(SmartAI, me->AI())->SetFollow(target->ToUnit(), float(e.action.follow.dist) + 0.1f, angle, e.action.follow.credit, e.action.follow.entry, e.action.follow.creditType, e.action.follow.aliveState);
1007 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_FOLLOW: Creature {} following target {}",
1008 me->GetGUID().ToString(), target->GetGUID().ToString());
1009 break;
1010 }
1011 }
1012 break;
1013 }
1015 {
1016 if (!GetBaseObject())
1017 break;
1018
1019 std::vector<uint32> phases;
1020 std::copy_if(e.action.randomPhase.phases.begin(), e.action.randomPhase.phases.end(),
1021 std::back_inserter(phases), [](uint32 phase) { return phase != 0; });
1022
1024 SetPhase(phase);
1025 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE: Creature {} sets event phase to {}",
1026 GetBaseObject()->GetGUID().ToString(), phase);
1027 break;
1028 }
1030 {
1031 if (!GetBaseObject())
1032 break;
1033
1035 SetPhase(phase);
1036 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE_RANGE: Creature {} sets event phase to {}",
1037 GetBaseObject()->GetGUID().ToString(), phase);
1038 break;
1039 }
1041 {
1042 if (trigger && IsPlayer(unit))
1043 {
1045 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: (trigger == true) Player {}, Killcredit: {}",
1047 }
1048 else if (e.target.type == SMART_TARGET_NONE || e.target.type == SMART_TARGET_SELF) // Loot recipient and his group members
1049 {
1050 if (!me)
1051 break;
1052
1053 if (Player* player = me->GetLootRecipient())
1054 {
1056 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: Player {}, Killcredit: {}",
1058 }
1059 }
1060 else // Specific target type
1061 {
1062 for (WorldObject* target : targets)
1063 {
1064 if (!IsUnit(target))
1065 continue;
1066
1068 if (!player)
1069 continue;
1070
1072 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: Player {}, Killcredit: {}",
1073 target->GetGUID().ToString(), e.action.killedMonster.creature);
1074 }
1075 }
1076 break;
1077 }
1079 {
1080 WorldObject* obj = GetBaseObject();
1081 if (!obj)
1082 obj = unit;
1083
1084 if (!obj)
1085 break;
1086
1087 InstanceScript* instance = obj->GetInstanceScript();
1088 if (!instance)
1089 {
1090 LOG_ERROR("scripts.ai.sai", "SmartScript: Event {} attempt to set instance data without instance script. EntryOrGuid {}", e.GetEventType(), e.entryOrGuid);
1091 break;
1092 }
1093
1094 switch (e.action.setInstanceData.type)
1095 {
1096 case 0:
1097 {
1099 LOG_DEBUG("scripts.ai.sai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: Field: {}, data: {}", e.action.setInstanceData.field, e.action.setInstanceData.data);
1100 } break;
1101 case 1:
1102 {
1104 LOG_DEBUG("scripts.ai.sai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: SetBossState BossId: {}, State: {} ({})", e.action.setInstanceData.field, e.action.setInstanceData.data, InstanceScript::GetBossStateName(e.action.setInstanceData.data));
1105 } break;
1106 default:
1107 {
1108 break;
1109 }
1110 }
1111 break;
1112 }
1114 {
1115 WorldObject* obj = GetBaseObject();
1116 if (!obj)
1117 obj = unit;
1118
1119 if (!obj)
1120 break;
1121
1122 InstanceScript* instance = obj->GetInstanceScript();
1123 if (!instance)
1124 {
1125 LOG_ERROR("sql.sql", "SmartScript: Event {} attempt to set instance data without instance script. EntryOrGuid {}", e.GetEventType(), e.entryOrGuid);
1126 break;
1127 }
1128
1129 if (targets.empty())
1130 break;
1131
1132 instance->SetGuidData(e.action.setInstanceData64.field, targets.front()->GetGUID());
1133 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA64: Field: {}, data: {}",
1134 e.action.setInstanceData64.field, targets.front()->GetGUID().ToString());
1135 break;
1136 }
1138 {
1139 for (WorldObject* target : targets)
1140 if (IsCreature(target))
1141 target->ToCreature()->UpdateEntry(e.action.updateTemplate.creature, target->ToCreature()->GetCreatureData(), e.action.updateTemplate.updateLevel != 0);
1142 break;
1143 }
1144 case SMART_ACTION_DIE:
1145 {
1146 if (e.action.die.milliseconds)
1147 {
1148 if (me && !me->isDead())
1149 {
1151 {
1152 // We need to check again to see if we didn't die in the process.
1153 if (me && !me->isDead())
1154 {
1155 me->KillSelf();
1156 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_DIE: Creature {}", me->GetGUID().ToString());
1157 }
1159 }
1160 }
1161 else if (me && !me->isDead())
1162 {
1163 me->KillSelf();
1164 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_DIE: Creature {}", me->GetGUID().ToString());
1165 }
1166 break;
1167 }
1169 {
1170 if (targets.empty())
1171 break;
1172
1173 if (!me->GetMap()->IsDungeon())
1174 {
1175 ObjectVector units;
1176 GetWorldObjectsInDist(units, static_cast<float>(e.target.unitRange.maxDist));
1177
1178 if (!units.empty() && GetBaseObject())
1179 for (WorldObject* unit : units)
1180 if (IsPlayer(unit) && !unit->ToPlayer()->isDead())
1181 {
1182 me->SetInCombatWith(unit->ToPlayer());
1183 unit->ToPlayer()->SetInCombatWith(me);
1184 me->AddThreat(unit->ToPlayer(), 0.0f);
1185 }
1186 }
1187 else
1188 {
1189 for (WorldObject* target : targets)
1190 {
1191 if (IsCreature(target))
1192 {
1193 target->ToCreature()->SetInCombatWithZone();
1194 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature {}, target: {}",
1195 me->GetGUID().ToString(), target->GetGUID().ToString());
1196 }
1197 }
1198 }
1199
1200 break;
1201 }
1203 {
1204 for (WorldObject* target : targets)
1205 {
1206 if (IsCreature(target))
1207 {
1208 target->ToCreature()->CallForHelp(float(e.action.callHelp.range));
1210 {
1212 sCreatureTextMgr->SendChatPacket(target, builder, CHAT_MSG_MONSTER_EMOTE);
1213 }
1214 LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction: SMART_ACTION_CALL_FOR_HELP: Creature {}, target: {}",
1215 me->GetGUID().ToString(), target->GetGUID().ToString());
1216 }
1217 }
1218 break;
1219 }
1221 {
1222 if (me)
1223 {
1225 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction: SMART_ACTION_SET_SHEATH: Creature {}, State: {}",
1227 }
1228 break;
1229 }
1231 {
1232 for (WorldObject* target : targets)
1233 {
1234 Milliseconds despawnDelay(e.action.forceDespawn.delay);
1235
1236 // Wait at least one world update tick before despawn, so it doesn't break linked actions.
1237 if (despawnDelay <= 0ms)
1238 {
1239 despawnDelay = 1ms;
1240 }
1241
1242 Seconds forceRespawnTimer(e.action.forceDespawn.forceRespawnTimer);
1243 if (Creature* creature = target->ToCreature())
1244 {
1245 creature->DespawnOrUnsummon(despawnDelay, forceRespawnTimer);
1246 }
1247 else if (GameObject* go = target->ToGameObject())
1248 {
1249 go->DespawnOrUnsummon(despawnDelay, forceRespawnTimer);
1250 }
1251 }
1252
1253 break;
1254 }
1256 {
1257 for (WorldObject* target : targets)
1258 {
1259 if (IsUnit(target))
1260 target->ToUnit()->SetPhaseMask(e.action.ingamePhaseMask.mask, true);
1261 else if (IsGameObject(target))
1262 target->ToGameObject()->SetPhaseMask(e.action.ingamePhaseMask.mask, true);
1263 }
1264 break;
1265 }
1267 {
1268 for (WorldObject* target : targets)
1269 {
1270 if (!IsUnit(target))
1271 continue;
1272
1274 {
1275 if (e.action.morphOrMount.creature > 0)
1276 {
1277 if (CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature))
1278 target->ToUnit()->Mount(ObjectMgr::ChooseDisplayId(cInfo));
1279 }
1280 else
1281 target->ToUnit()->Mount(e.action.morphOrMount.model);
1282 }
1283 else
1284 target->ToUnit()->Dismount();
1285 }
1286 break;
1287 }
1289 {
1290 for (WorldObject* target : targets)
1291 {
1292 if (IsCreature(target))
1293 {
1294 SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI());
1295 if (!ai)
1296 continue;
1297
1298 if (e.action.invincHP.percent)
1299 ai->SetInvincibilityHpLevel(target->ToCreature()->CountPctFromMaxHealth(e.action.invincHP.percent));
1300 else
1302 }
1303 }
1304 break;
1305 }
1307 {
1308 for (WorldObject* target : targets)
1309 {
1310 if (IsCreature(target))
1311 target->ToCreature()->AI()->SetData(e.action.setData.field, e.action.setData.data);
1312 else if (IsGameObject(target))
1313 target->ToGameObject()->AI()->SetData(e.action.setData.field, e.action.setData.data);
1314 }
1315 break;
1316 }
1318 {
1319 if (!me)
1320 break;
1321
1322 float x, y, z;
1323 me->GetClosePoint(x, y, z, me->GetObjectSize() / 3, (float)e.action.moveRandom.distance);
1325 break;
1326 }
1328 {
1329 if (!me)
1330 break;
1331
1333 break;
1334 }
1336 {
1337 for (WorldObject* target : targets)
1338 if (IsUnit(target))
1339 target->ToUnit()->SetVisible(!!e.action.visibility.state);
1340
1341 break;
1342 }
1344 {
1345 for (WorldObject* target : targets)
1346 target->setActive(!!e.action.setActive.state);
1347 break;
1348 }
1350 {
1351 if (!me)
1352 break;
1353
1354 if (targets.empty())
1355 break;
1356
1357 // attack random target
1358 if (Unit* target = Acore::Containers::SelectRandomContainerElement(targets)->ToUnit())
1359 me->AI()->AttackStart(target);
1360 break;
1361 }
1363 {
1364 for (WorldObject* target : targets)
1365 if (Unit* unitTarget = target->ToUnit())
1366 unitTarget->AttackStop();
1367 break;
1368 }
1370 {
1372 bool preferUnit = flags.HasFlag(SmartActionSummonCreatureFlags::PreferUnit);
1373 WorldObject* summoner = preferUnit ? unit : Coalesce<WorldObject>(GetBaseObject(), unit);
1374 if (!summoner)
1375 break;
1376
1377 bool personalSpawn = flags.HasFlag(SmartActionSummonCreatureFlags::PersonalSpawn);
1378
1380 {
1381 float range = (float)e.target.randomPoint.range;
1382 Position randomPoint;
1383 Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o };
1384 for (uint32 i = 0; i < e.target.randomPoint.amount; i++)
1385 {
1386 if (e.target.randomPoint.self > 0)
1387 randomPoint = me->GetRandomPoint(me->GetPosition(), range);
1388 else
1389 randomPoint = me->GetRandomPoint(srcPos, range);
1390 if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, randomPoint, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration, 0, nullptr, personalSpawn))
1391 {
1392 if (unit && e.action.summonCreature.attackInvoker)
1393 summon->AI()->AttackStart(unit);
1395 summon->AI()->AttackStart(me);
1396 }
1397 }
1398 break;
1399 }
1400
1401 float x, y, z, o;
1402 for (WorldObject* target : targets)
1403 {
1404 target->GetPosition(x, y, z, o);
1405 x += e.target.x;
1406 y += e.target.y;
1407 z += e.target.z;
1408 o += e.target.o;
1409 if (Creature* summon = summoner->SummonCreature(e.action.summonCreature.creature, x, y, z, o, (TempSummonType)e.action.summonCreature.type, e.action.summonCreature.duration, nullptr, personalSpawn))
1410 {
1411 if (e.action.summonCreature.attackInvoker == 2) // pussywizard: proper attackInvoker implementation
1412 summon->AI()->AttackStart(unit);
1414 summon->AI()->AttackStart(target->ToUnit());
1416 summon->AI()->AttackStart(me);
1417 }
1418 }
1419
1421 break;
1422
1424 {
1425 if (unit && e.action.summonCreature.attackInvoker)
1426 summon->AI()->AttackStart(unit);
1428 summon->AI()->AttackStart(me);
1429 }
1430 break;
1431 }
1433 {
1434 if (!GetBaseObject())
1435 break;
1436
1437 if (!targets.empty())
1438 {
1439 float x, y, z, o;
1440 for (WorldObject* target : targets)
1441 {
1442 // xinef: allow gameobjects to summon gameobjects!
1443 //if(!IsUnit((*itr)))
1444 // continue;
1445
1446 target->GetPosition(x, y, z, o);
1447 x += e.target.x;
1448 y += e.target.y;
1449 z += e.target.z;
1450 o += e.target.o;
1453 else
1454 target->SummonGameObject(e.action.summonGO.entry, GetBaseObject()->GetPositionX(), GetBaseObject()->GetPositionY(), GetBaseObject()->GetPositionZ(), GetBaseObject()->GetOrientation(), 0, 0, 0, 0, e.action.summonGO.despawnTime);
1455 }
1456 }
1457
1459 break;
1460
1462 break;
1463 }
1465 {
1466 for (WorldObject* target : targets)
1467 {
1468 if (!IsUnit(target))
1469 continue;
1470
1471 Unit::Kill(target->ToUnit(), target->ToUnit());
1472 }
1473
1474 break;
1475 }
1477 {
1478 InstallTemplate(e);
1479 break;
1480 }
1482 {
1483 for (WorldObject* target : targets)
1484 {
1485 if (!IsPlayer(target))
1486 continue;
1487
1488 target->ToPlayer()->AddItem(e.action.item.entry, e.action.item.count);
1489 }
1490 break;
1491 }
1493 {
1494 for (WorldObject* target : targets)
1495 {
1496 if (!IsPlayer(target))
1497 continue;
1498
1499 target->ToPlayer()->DestroyItemCount(e.action.item.entry, e.action.item.count, true);
1500 }
1501 break;
1502 }
1504 {
1506 break;
1507 }
1509 {
1510 for (WorldObject* target : targets)
1511 {
1512 if (IsPlayer(target))
1513 target->ToPlayer()->TeleportTo(e.action.teleport.mapID, e.target.x, e.target.y, e.target.z, e.target.o);
1514 else if (IsCreature(target))
1515 target->ToCreature()->NearTeleportTo(e.target.x, e.target.y, e.target.z, e.target.o);
1516 }
1517 break;
1518 }
1520 {
1521 if (!IsSmart())
1522 break;
1523
1524 CAST_AI(SmartAI, me->AI())->SetFly(e.action.setFly.fly);
1525 // Xinef: Set speed if any
1526 if (e.action.setFly.speed)
1527 me->SetSpeed(MOVE_RUN, float(e.action.setFly.speed / 100.0f), true);
1528
1529 // Xinef: this wil be executed only if state is different
1531 break;
1532 }
1534 {
1535 for (WorldObject* target : targets)
1536 {
1537 if (IsCreature(target))
1538 {
1539 if (IsSmart(target->ToCreature()))
1540 CAST_AI(SmartAI, target->ToCreature()->AI())->SetRun(e.action.setRun.run);
1541 else
1542 target->ToCreature()->SetWalk(e.action.setRun.run ? false : true); // Xinef: reversed
1543 }
1544 }
1545
1546 break;
1547 }
1549 {
1550 if (!IsSmart())
1551 break;
1552
1553 CAST_AI(SmartAI, me->AI())->SetSwim(e.action.setSwim.swim);
1554 break;
1555 }
1557 {
1558 if (!targets.empty())
1559 {
1560 for (WorldObject* target : targets)
1561 {
1562 if (IsCreature(target))
1563 {
1564 if (SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI()))
1566 else
1567 LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartAI, skipping");
1568 }
1569 else if (IsGameObject(target))
1570 {
1571 if (SmartGameObjectAI* ai = CAST_AI(SmartGameObjectAI, target->ToGameObject()->AI()))
1573 else
1574 LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SET_COUNTER is not using SmartGameObjectAI, skipping");
1575 }
1576 }
1577 }
1578 else
1580 break;
1581 }
1583 {
1584 if (!IsSmart())
1585 break;
1586
1587 bool run = e.action.wpStart.run != 0;
1588 uint32 entry = e.action.wpStart.pathID;
1589 bool repeat = e.action.wpStart.repeat != 0;
1590
1591 for (WorldObject* target : targets)
1592 {
1593 if (IsPlayer(target))
1594 {
1596 break;
1597 }
1598 }
1599
1601 CAST_AI(SmartAI, me->AI())->StartPath(run, entry, repeat, unit);
1602
1603 uint32 quest = e.action.wpStart.quest;
1604 uint32 DespawnTime = e.action.wpStart.despawnTime;
1605 CAST_AI(SmartAI, me->AI())->mEscortQuestID = quest;
1606 CAST_AI(SmartAI, me->AI())->SetDespawnTime(DespawnTime);
1607 break;
1608 }
1610 {
1611 if (!IsSmart())
1612 break;
1613
1614 uint32 delay = e.action.wpPause.delay;
1615 CAST_AI(SmartAI, me->AI())->PausePath(delay, e.GetEventType() == SMART_EVENT_WAYPOINT_REACHED ? false : true);
1616 break;
1617 }
1619 {
1620 if (!IsSmart())
1621 break;
1622
1623 uint32 DespawnTime = e.action.wpStop.despawnTime;
1624 uint32 quest = e.action.wpStop.quest;
1625 bool fail = e.action.wpStop.fail;
1626 CAST_AI(SmartAI, me->AI())->StopPath(DespawnTime, quest, fail);
1627 break;
1628 }
1630 {
1631 if (!IsSmart())
1632 break;
1633
1634 CAST_AI(SmartAI, me->AI())->SetWPPauseTimer(0);
1635 break;
1636 }
1638 {
1639 if (!me)
1640 break;
1641
1642 if (e.action.orientation.random > 0)
1643 {
1644 float randomOri = frand(0.0f, 2 * M_PI);
1645 me->SetFacingTo(randomOri);
1647 me->SetOrientation(randomOri);
1648 break;
1649 }
1650
1652 {
1653 float turnOri = me->GetOrientation() + (static_cast<float>(e.action.orientation.turnAngle) * M_PI / 180.0f);
1654 me->SetFacingTo(turnOri);
1656 me->SetOrientation(turnOri);
1657 break;
1658 }
1659
1661 {
1665 }
1666 else if (e.GetTargetType() == SMART_TARGET_POSITION)
1667 {
1668 me->SetFacingTo(e.target.o);
1671 }
1672 else if (!targets.empty())
1673 {
1674 me->SetFacingToObject(*targets.begin());
1676 me->SetInFront(*targets.begin());
1677 }
1678
1679 break;
1680 }
1682 {
1683 for (WorldObject* target : targets)
1684 {
1685 if (!IsPlayer(target))
1686 continue;
1687
1688 target->ToPlayer()->SendMovieStart(e.action.movie.entry);
1689 }
1690 break;
1691 }
1693 {
1694 if (!IsSmart())
1695 break;
1696
1697 WorldObject* target = nullptr;
1698
1700 {
1701 if (me)
1702 {
1703 float range = (float)e.target.randomPoint.range;
1704 Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o };
1705 Position randomPoint = me->GetRandomPoint(srcPos, range);
1708 randomPoint.m_positionX,
1709 randomPoint.m_positionY,
1710 randomPoint.m_positionZ,
1711 true,
1712 true,
1714 );
1715 }
1716
1717 break;
1718 }
1719
1720 /*if (e.GetTargetType() == SMART_TARGET_CREATURE_RANGE || e.GetTargetType() == SMART_TARGET_CREATURE_GUID ||
1721 e.GetTargetType() == SMART_TARGET_CREATURE_DISTANCE || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_RANGE ||
1722 e.GetTargetType() == SMART_TARGET_GAMEOBJECT_GUID || e.GetTargetType() == SMART_TARGET_GAMEOBJECT_DISTANCE ||
1723 e.GetTargetType() == SMART_TARGET_CLOSEST_CREATURE || e.GetTargetType() == SMART_TARGET_CLOSEST_GAMEOBJECT ||
1724 e.GetTargetType() == SMART_TARGET_OWNER_OR_SUMMONER || e.GetTargetType() == SMART_TARGET_ACTION_INVOKER ||
1725 e.GetTargetType() == SMART_TARGET_CLOSEST_ENEMY || e.GetTargetType() == SMART_TARGET_CLOSEST_FRIENDLY ||
1726 e.GetTargetType() == SMART_TARGET_SELF || e.GetTargetType() == SMART_TARGET_STORED)) */
1727 {
1728 // we want to move to random element
1729 if (!targets.empty())
1731 }
1732
1733 if (!target)
1734 {
1735 G3D::Vector3 dest(e.target.x, e.target.y, e.target.z);
1737 if (TransportBase* trans = me->GetDirectTransport())
1738 trans->CalculatePassengerPosition(dest.x, dest.y, dest.z);
1739
1740 me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, dest.x, dest.y, dest.z, true, true,
1742 }
1743 else // Xinef: we can use dest.x, dest.y, dest.z to make offset
1744 {
1745 float x, y, z;
1746 target->GetPosition(x, y, z);
1748 {
1749 target->GetNearPoint(me, x, y, z, e.action.moveToPos.ContactDistance, 0, target->GetAngle(me));
1750 }
1751 me->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, x + e.target.x, y + e.target.y, z + e.target.z, true, true, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE);
1752 }
1753 break;
1754 }
1756 {
1757 for (WorldObject* target : targets)
1758 {
1759 if (IsCreature(target))
1760 {
1761 Creature* ctarget = target->ToCreature();
1762 ctarget->GetMotionMaster()->MovePoint(e.action.moveToPos.pointId, e.target.x, e.target.y, e.target.z, true, true, isControlled ? MOTION_SLOT_CONTROLLED : MOTION_SLOT_ACTIVE);
1763 }
1764 }
1765
1766 break;
1767 }
1769 {
1770 for (WorldObject* target : targets)
1771 {
1772 if (IsCreature(target))
1773 target->ToCreature()->Respawn();
1774 else if (IsGameObject(target))
1775 {
1776 // do not modify respawndelay of already spawned gameobjects
1777 if (target->ToGameObject()->isSpawnedByDefault())
1778 target->ToGameObject()->Respawn();
1779 else
1781 }
1782 }
1783 break;
1784 }
1786 {
1787 for (WorldObject* target : targets)
1788 if (IsPlayer(target))
1790 break;
1791 }
1792 case SMART_ACTION_EQUIP:
1793 {
1794 for (WorldObject* target : targets)
1795 {
1796 if (Creature* npc = target->ToCreature())
1797 {
1798 std::array<uint32, MAX_EQUIPMENT_ITEMS> slot;
1799 if (int8 equipId = static_cast<int8>(e.action.equip.entry))
1800 {
1801 EquipmentInfo const* eInfo = sObjectMgr->GetEquipmentInfo(npc->GetEntry(), equipId);
1802 if (!eInfo)
1803 {
1804 LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id {} for creature {}", equipId, npc->GetEntry());
1805 break;
1806 }
1807
1808 npc->SetCurrentEquipmentId(equipId);
1809
1810 std::copy(std::begin(eInfo->ItemEntry), std::end(eInfo->ItemEntry), std::begin(slot));
1811 }
1812 else
1813 std::copy(std::begin(e.action.equip.slots), std::end(e.action.equip.slots), std::begin(slot));
1814
1815 for (uint32 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)
1816 if (!e.action.equip.mask || (e.action.equip.mask & (1 << i)))
1817 npc->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, slot[i]);
1818 }
1819 }
1820 break;
1821 }
1823 {
1824 SmartEvent ne = SmartEvent();
1827 if (!ne.event_chance) ne.event_chance = 100;
1828
1833
1834 ne.event_flags = 0;
1837
1838 SmartAction ac = SmartAction();
1841
1843 ev.event = ne;
1844 ev.event_id = e.action.timeEvent.id;
1845 ev.target = e.target;
1846 ev.action = ac;
1847 InitTimer(ev);
1848 mStoredEvents.push_back(ev);
1849 break;
1850 }
1853
1854 // xinef: remove this event if not repeatable
1856 mRemIDs.push_back(e.action.timeEvent.id);
1857 break;
1859 mRemIDs.push_back(e.action.timeEvent.id);
1860 break;
1862 {
1863 for (WorldObject* target : targets)
1864 {
1865 if (IsCreature(target))
1866 {
1867 if (!meOrigGUID)
1869 if (!goOrigGUID)
1871 go = nullptr;
1872 me = target->ToCreature();
1873 break;
1874 }
1875 else if (IsGameObject(target))
1876 {
1877 if (!meOrigGUID)
1879 if (!goOrigGUID)
1881 go = target->ToGameObject();
1882 me = nullptr;
1883 break;
1884 }
1885 }
1886
1887 break;
1888 }
1891 break;
1893 OnReset();
1894 break;
1896 {
1897 if (!IsSmart())
1898 break;
1899
1900 float attackDistance = float(e.action.setRangedMovement.distance);
1901 float attackAngle = float(e.action.setRangedMovement.angle) / 180.0f * float(M_PI);
1902
1903 for (WorldObject* target : targets)
1904 if (Creature* creature = target->ToCreature())
1905 if (IsSmart(creature) && creature->GetVictim())
1906 if (CAST_AI(SmartAI, creature->AI())->CanCombatMove())
1907 creature->GetMotionMaster()->MoveChase(creature->GetVictim(), attackDistance, attackAngle);
1908
1909 break;
1910 }
1912 {
1914 {
1915 LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
1916 break;
1917 }
1918
1919 for (WorldObject* target : targets)
1920 {
1921 if (Creature* creature = target->ToCreature())
1922 {
1923 if (IsSmart(creature))
1924 CAST_AI(SmartAI, creature->AI())->SetScript9(e, e.action.timedActionList.id, GetLastInvoker());
1925 }
1926 else if (GameObject* go = target->ToGameObject())
1927 {
1928 if (IsSmartGO(go))
1930 }
1931 }
1932 break;
1933 }
1935 {
1936 for (WorldObject* target : targets)
1937 if (IsCreature(target))
1939 break;
1940 }
1942 {
1943 for (WorldObject* target : targets)
1944 if (IsCreature(target))
1946 break;
1947 }
1949 {
1950 for (WorldObject* target : targets)
1951 if (IsCreature(target))
1953 break;
1954 }
1956 {
1957 if (targets.empty())
1958 break;
1959
1960 ObjectVector casters;
1962
1963 for (WorldObject* caster : casters)
1964 {
1965 if (!IsUnit(caster))
1966 continue;
1967
1968 Unit* casterUnit = caster->ToUnit();
1969
1970 bool interruptedSpell = false;
1971
1972 for (WorldObject* target : targets)
1973 {
1974 if (!IsUnit(target))
1975 continue;
1976
1978 {
1979 if (!interruptedSpell && e.action.crossCast.flags & SMARTCAST_INTERRUPT_PREVIOUS)
1980 {
1981 casterUnit->InterruptNonMeleeSpells(false);
1982 interruptedSpell = true;
1983 }
1984
1985 casterUnit->CastSpell(target->ToUnit(), e.action.crossCast.spell, (e.action.crossCast.flags & SMARTCAST_TRIGGERED) != 0);
1986 }
1987 else
1988 LOG_DEBUG("scripts.ai", "Spell {} not cast because it has flag SMARTCAST_AURA_NOT_PRESENT and the target ({}) already has the aura", e.action.crossCast.spell, target->GetGUID().ToString());
1989 }
1990 }
1991 break;
1992 }
1994 {
1995 std::vector<uint32> actionLists;
1997 std::back_inserter(actionLists), [](uint32 actionList) { return actionList != 0; });
1998
2001 {
2002 LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
2003 break;
2004 }
2005
2006 for (WorldObject* target : targets)
2007 {
2008 if (Creature* creature = target->ToCreature())
2009 {
2010 if (IsSmart(creature))
2011 CAST_AI(SmartAI, creature->AI())->SetScript9(e, id, GetLastInvoker());
2012 }
2013 else if (GameObject* go = target->ToGameObject())
2014 {
2015 if (IsSmartGO(go))
2016 CAST_AI(SmartGameObjectAI, go->AI())->SetScript9(e, id, GetLastInvoker());
2017 }
2018 }
2019 break;
2020 }
2022 {
2025 {
2026 LOG_ERROR("sql.sql", "SmartScript: Entry {} SourceType {} Event {} Action {} is using TARGET_NONE(0) for Script9 target. Please correct target_type in database.", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
2027 break;
2028 }
2029
2030 for (WorldObject* target : targets)
2031 {
2032 if (Creature* creature = target->ToCreature())
2033 {
2034 if (IsSmart(creature))
2035 CAST_AI(SmartAI, creature->AI())->SetScript9(e, id, GetLastInvoker());
2036 }
2037 else if (GameObject* go = target->ToGameObject())
2038 {
2039 if (IsSmartGO(go))
2040 CAST_AI(SmartGameObjectAI, go->AI())->SetScript9(e, id, GetLastInvoker());
2041 }
2042 }
2043 break;
2044 }
2046 {
2047 for (WorldObject* target : targets)
2048 if (IsPlayer(target))
2050 break;
2051 }
2053 {
2054 bool foundTarget = false;
2055
2056 for (WorldObject* target : targets)
2057 {
2058 if (IsCreature((target)))
2059 {
2060 foundTarget = true;
2061
2064 else
2065 target->ToCreature()->GetMotionMaster()->MoveIdle();
2066 }
2067 }
2068
2069 if (!foundTarget && me && IsCreature(me) && me->IsAlive())
2070 {
2073 else
2075 }
2076 break;
2077 }
2079 {
2080 for (WorldObject* target : targets)
2081 if (IsUnit(target))
2083 break;
2084 }
2086 {
2087 for (WorldObject* target : targets)
2088 if (IsUnit(target))
2090 break;
2091 }
2093 {
2094 for (WorldObject* target : targets)
2095 if (IsUnit(target))
2097 break;
2098 }
2100 {
2101 for (WorldObject* target : targets)
2102 if (IsGameObject(target))
2104 break;
2105 }
2107 {
2108 for (WorldObject* target : targets)
2109 if (IsUnit(target))
2111 break;
2112 }
2114 {
2115 for (WorldObject* target : targets)
2116 if (IsUnit(target))
2118 break;
2119 }
2121 {
2122 for (WorldObject* target : targets)
2123 if (IsUnit(target))
2125 break;
2126 }
2128 {
2130 {
2131 if (me)
2132 {
2133 float range = (float)e.target.randomPoint.range;
2134 Position srcPos = { e.target.x, e.target.y, e.target.z, e.target.o };
2135 Position randomPoint = me->GetRandomPoint(srcPos, range);
2136 me->GetMotionMaster()->MoveJump(randomPoint, (float)e.action.jump.speedxy, (float)e.action.jump.speedz);
2137 }
2138
2139 break;
2140 }
2141
2142 if (targets.empty())
2143 break;
2144
2145 // xinef: my implementation
2146 if (e.action.jump.selfJump)
2147 {
2149 if (me)
2150 me->GetMotionMaster()->MoveJump(target->GetPositionX() + e.target.x, target->GetPositionY() + e.target.y, target->GetPositionZ() + e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz);
2151 }
2152 else
2153 {
2154 for (WorldObject* target : targets)
2155 if (WorldObject* obj = (target))
2156 {
2157 if (Creature* creature = obj->ToCreature())
2158 creature->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz);
2159 }
2160 }
2161
2162 break;
2163 }
2165 {
2166 for (WorldObject* target : targets)
2167 if (IsGameObject(target))
2169 break;
2170 }
2172 {
2173 for (WorldObject* target : targets)
2174 if (IsGameObject(target))
2176 break;
2177 }
2179 {
2180 WorldObject* ref = GetBaseObject();
2181
2182 if (!ref)
2183 ref = unit;
2184
2185 if (!ref)
2186 break;
2187
2188 ObjectVector const* storedTargets = GetStoredTargetVector(e.action.sendTargetToTarget.id, *ref);
2189 if (!storedTargets)
2190 break;
2191
2192 for (WorldObject* target : targets)
2193 {
2194 if (IsCreature(target))
2195 {
2196 if (SmartAI* ai = CAST_AI(SmartAI, target->ToCreature()->AI()))
2197 ai->GetScript()->StoreTargetList(ObjectVector(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list
2198 else
2199 LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartAI, skipping");
2200 }
2201 else if (IsGameObject(target))
2202 {
2204 ai->GetScript()->StoreTargetList(ObjectVector(*storedTargets), e.action.sendTargetToTarget.id); // store a copy of target list
2205 else
2206 LOG_ERROR("sql.sql", "SmartScript: Action target for SMART_ACTION_SEND_TARGET_TO_TARGET is not using SmartGameObjectAI, skipping");
2207 }
2208 }
2209 break;
2210 }
2212 {
2213 if (!GetBaseObject())
2214 break;
2215
2216 LOG_DEBUG("sql.sql", "SmartScript::ProcessAction:: SMART_ACTION_SEND_GOSSIP_MENU: gossipMenuId {}, gossipNpcTextId {}",
2218
2219 for (WorldObject* target : targets)
2220 if (Player* player = target->ToPlayer())
2221 {
2224 else
2225 ClearGossipMenuFor(player);
2226
2228 }
2229
2230 break;
2231 }
2233 {
2234 if (!targets.empty())
2235 {
2236 float x, y, z, o;
2237 for (WorldObject* target : targets)
2238 if (IsCreature(target))
2239 {
2241 {
2242 target->ToCreature()->GetRespawnPosition(x, y, z, &o);
2243 target->ToCreature()->SetHomePosition(x, y, z, o);
2244 }
2245 else
2246 target->ToCreature()->SetHomePosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation());
2247 }
2248 }
2249 else if (me && e.GetTargetType() == SMART_TARGET_POSITION)
2250 {
2252 {
2253 float x, y, z, o;
2254 me->GetRespawnPosition(x, y, z, &o);
2255 me->SetHomePosition(x, y, z, o);
2256 }
2257 else
2259 }
2260 break;
2261 }
2263 {
2264 for (WorldObject* target : targets)
2265 if (IsCreature(target))
2267
2268 break;
2269 }
2271 {
2272 for (WorldObject* target : targets)
2273 if (IsCreature(target))
2275 break;
2276 }
2278 {
2279 for (WorldObject* target : targets)
2280 if (IsGameObject(target))
2282 break;
2283 }
2285 {
2286 for (WorldObject* target : targets)
2287 if (IsGameObject(target))
2289 break;
2290 }
2292 {
2293 for (WorldObject* target : targets)
2294 if (IsGameObject(target))
2296 break;
2297 }
2299 {
2300 std::list<TempSummon*> summonList;
2302
2303 for (std::list<TempSummon*>::const_iterator itr = summonList.begin(); itr != summonList.end(); ++itr)
2304 {
2305 if (unit && e.action.creatureGroup.attackInvoker)
2306 (*itr)->AI()->AttackStart(unit);
2308 (*itr)->AI()->AttackStart(me);
2309 }
2310
2311 break;
2312 }
2314 {
2315 for (WorldObject* target : targets)
2316 if (IsUnit(target))
2318 break;
2319 }
2321 {
2322 for (WorldObject* target : targets)
2323 if (IsUnit(target))
2325 break;
2326 }
2328 {
2329 for (WorldObject* target : targets)
2330 if (IsUnit(target))
2332 break;
2333 }
2335 {
2336 uint32 eventId = e.action.gameEventStop.id;
2337 if (!sGameEventMgr->IsActiveEvent(eventId))
2338 {
2339 LOG_ERROR("scripts.ai.sai", "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_STOP, inactive event (id: {})", eventId);
2340 break;
2341 }
2342 sGameEventMgr->StopEvent(eventId, true);
2343 break;
2344 }
2346 {
2347 uint32 eventId = e.action.gameEventStart.id;
2348 if (sGameEventMgr->IsActiveEvent(eventId))
2349 {
2350 LOG_ERROR("scripts.ai.sai", "SmartScript::ProcessAction: At case SMART_ACTION_GAME_EVENT_START, already activated event (id: {})", eventId);
2351 break;
2352 }
2353 sGameEventMgr->StartEvent(eventId, true);
2354 break;
2355 }
2357 {
2358 std::vector<uint32> waypoints;
2359 std::copy_if(e.action.closestWaypointFromList.wps.begin(), e.action.closestWaypointFromList.wps.end(),
2360 std::back_inserter(waypoints), [](uint32 wp) { return wp != 0; });
2361
2362 float distanceToClosest = std::numeric_limits<float>::max();
2363 WayPoint* closestWp = nullptr;
2364
2365 for (WorldObject* target : targets)
2366 {
2367 if (Creature* creature = target->ToCreature())
2368 {
2369 if (IsSmart(creature))
2370 {
2371 for (uint32 wp : waypoints)
2372 {
2373 WPPath* path = sSmartWaypointMgr->GetPath(wp);
2374 if (!path || path->empty())
2375 continue;
2376
2377 auto itrWp = path->find(0);
2378 if (itrWp != path->end())
2379 {
2380 if (WayPoint* wp = itrWp->second)
2381 {
2382 float distToThisPath = creature->GetDistance(wp->x, wp->y, wp->z);
2383 if (distToThisPath < distanceToClosest)
2384 {
2385 distanceToClosest = distToThisPath;
2386 closestWp = wp;
2387 }
2388 }
2389 }
2390 }
2391
2392 if (closestWp)
2393 CAST_AI(SmartAI, creature->AI())->StartPath(false, closestWp->id, true);
2394 }
2395 }
2396 }
2397 break;
2398 }
2400 {
2401 for (WorldObject* target : targets)
2402 if (IsUnit(target))
2403 target->ToUnit()->ExitVehicle();
2404
2405 break;
2406 }
2408 {
2409 for (WorldObject* target : targets)
2410 if (IsUnit(target))
2411 {
2413 target->ToUnit()->SendMovementFlagUpdate();
2414 }
2415
2416 break;
2417 }
2419 {
2420 for (WorldObject* target : targets)
2421 if (IsCreature(target))
2423
2424 break;
2425 }
2427 {
2430 else
2432
2435 break;
2436 }
2438 {
2439 for (WorldObject* const target : targets)
2440 if (IsCreature(target))
2442 break;
2443 }
2444 case SMART_ACTION_FLEE:
2445 {
2446 for (WorldObject* const target : targets)
2447 if (IsCreature(target))
2449 break;
2450 }
2452 {
2453 for (WorldObject* const target : targets)
2454 if (IsUnit(target))
2455 me->AddThreat(target->ToUnit(), float(e.action.threatPCT.threatINC) - float(e.action.threatPCT.threatDEC));
2456 break;
2457 }
2459 {
2460 for (WorldObject* const target : targets)
2461 if (IsCreature(target))
2463 break;
2464 }
2466 {
2469 break;
2470 }
2472 {
2473 for (WorldObject* target : targets)
2474 if (IsUnit(target))
2475 target->ToUnit()->SetHover(e.action.setHover.state);
2476 break;
2477 }
2479 {
2480 for (WorldObject* target : targets)
2481 if (IsUnit(target))
2483
2484 break;
2485 }
2487 {
2488 for (WorldObject* target : targets)
2489 if (IsUnit(target))
2491 break;
2492 }
2493 case SMART_ACTION_FALL:
2494 {
2495 for (WorldObject* target : targets)
2496 if (IsUnit(target))
2497 target->ToUnit()->GetMotionMaster()->MoveFall();
2498
2499 break;
2500 }
2502 {
2504 break;
2505 }
2507 {
2508 for (WorldObject* const target : targets)
2509 if (IsUnit(target))
2510 target->ToUnit()->RemoveAllGameObjects();
2511 break;
2512 }
2514 {
2515 for (WorldObject* const target : targets)
2516 {
2517 if (IsUnit(target))
2518 {
2520 target->ToUnit()->StopMoving();
2522 target->ToUnit()->GetMotionMaster()->MovementExpired();
2523 }
2524 }
2525 break;
2526 }
2528 {
2529 for (WorldObject* target : targets)
2530 if (IsUnit(target))
2532
2533 break;
2534 }
2536 {
2537 for (WorldObject* target : targets)
2538 if (IsUnit(target))
2539 if (Player* player = target->ToUnit()->GetCharmerOrOwnerPlayerOrPlayerItself())
2540 {
2542 break;
2543 }
2544
2545 break;
2546 }
2548 {
2549 if (me && me->FindMap())
2550 me->FindMap()->LoadGrid(e.target.x, e.target.y);
2551 break;
2552 }
2554 {
2555 char const* text = sObjectMgr->GetAcoreString(e.action.playerTalk.textId, DEFAULT_LOCALE);
2556
2557 if (!targets.empty())
2558 for (WorldObject* target : targets)
2559 if (IsPlayer(target))
2560 !e.action.playerTalk.flag ? target->ToPlayer()->Say(text, LANG_UNIVERSAL) : target->ToPlayer()->Yell(text, LANG_UNIVERSAL);
2561
2562 break;
2563 }
2565 {
2566 if (!me)
2567 break;
2568
2569 for (WorldObject* target : targets)
2570 {
2571 if (IsUnit(target))
2572 {
2574 {
2576 }
2577
2579 {
2580 // If cast flag SMARTCAST_COMBAT_MOVE is set combat movement will not be allowed
2581 // unless target is outside spell range, out of mana, or LOS.
2582
2583 bool _allowMove = false;
2584 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.action.castCustom.spell); // AssertSpellInfo?
2585 int32 mana = me->GetPower(POWER_MANA);
2586
2587 if (me->GetDistance(target->ToUnit()) > spellInfo->GetMaxRange(true) ||
2588 me->GetDistance(target->ToUnit()) < spellInfo->GetMinRange(true) ||
2589 !me->IsWithinLOSInMap(target->ToUnit()) ||
2590 mana < spellInfo->CalcPowerCost(me, spellInfo->GetSchoolMask()))
2591 _allowMove = true;
2592
2593 CAST_AI(SmartAI, me->AI())->SetCombatMove(_allowMove);
2594 }
2595
2597 {
2598 CustomSpellValues values;
2599 if (e.action.castCustom.bp1)
2601 if (e.action.castCustom.bp2)
2603 if (e.action.castCustom.bp3)
2606 }
2607 }
2608 }
2609 break;
2610 }
2612 {
2613 if (!me)
2614 break;
2615
2616 if (targets.empty())
2617 break;
2618
2620
2621 float a = static_cast<float>(e.action.summonVortex.a);
2622 float k = static_cast<float>(e.action.summonVortex.k) / 1000.0f;
2623 float r_max = static_cast<float>(e.action.summonVortex.r_max);
2624 float delta_phi = M_PI * static_cast<float>(e.action.summonVortex.phi_delta) / 180.0f;
2625
2626 // r(phi) = a * e ^ (k * phi)
2627 // r(phi + delta_phi) = a * e ^ (k * (phi + delta_phi))
2628 // r(phi + delta_phi) = a * e ^ (k * phi) * e ^ (k * delta_phi)
2629 // r(phi + delta_phi) = r(phi) * e ^ (k * delta_phi)
2630 float factor = std::exp(k * delta_phi);
2631
2632 // r(0) = a * e ^ (k * 0) = a * e ^ 0 = a * 1 = a
2633 float summonRadius = a;
2634
2635 for (WorldObject* target : targets)
2636 {
2637 // Offset by orientation, should not count into radius calculation,
2638 // but is needed for vortex direction (polar coordinates)
2639 float