OregonCore  revision fb2a440-git
Your Favourite TBC server
SmartScriptMgr.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "DatabaseEnv.h"
19 #include "ObjectMgr.h"
20 #include "GridDefines.h"
21 #include "GridNotifiers.h"
22 #include "SpellMgr.h"
23 #include "Cell.h"
24 #include "GameEventMgr.h"
25 #include "CreatureTextMgr.h"
26 
27 #include "SmartScriptMgr.h"
28 
30 {
31  uint32 oldMSTime = getMSTime();
32 
33  for (UNORDERED_MAP<uint32, WPPath*>::iterator itr = waypoint_map.begin(); itr != waypoint_map.end(); ++itr)
34  {
35  for (WPPath::iterator pathItr = itr->second->begin(); pathItr != itr->second->end(); ++pathItr)
36  delete pathItr->second;
37 
38  delete itr->second;
39  }
40 
41  waypoint_map.clear();
42 
43  QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entry, pointid, position_x, position_y, position_z FROM waypoints ORDER BY entry, pointid");
44 
45  if (!result)
46  {
47  sLog.outString(">> Loaded 0 SmartAI Waypoint Paths. DB table `waypoints` is empty.");
48  return;
49  }
50 
51  uint32 count = 0;
52  uint32 total = 0;
53  uint32 last_entry = 0;
54  uint32 last_id = 1;
55 
56  do
57  {
58  Field* fields = result->Fetch();
59  uint32 entry = fields[0].GetUInt32();
60  uint32 id = fields[1].GetUInt32();
61  float x, y, z;
62  x = fields[2].GetFloat();
63  y = fields[3].GetFloat();
64  z = fields[4].GetFloat();
65 
66  if (last_entry != entry)
67  {
68  waypoint_map[entry] = new WPPath();
69  last_id = 1;
70  count++;
71  }
72 
73  if (last_id != id)
74  sLog.outError("SmartWaypointMgr::LoadFromDB: Path entry %u, unexpected point id %u, expected %u.", entry, id, last_id);
75 
76  last_id++;
77  (*waypoint_map[entry])[id] = new WayPoint(id, x, y, z);
78 
79  last_entry = entry;
80  total++;
81  }
82  while (result->NextRow());
83 
84  sLog.outString(">> Loaded %u SmartAI waypoint paths (total %u waypoints) in %u ms", count, total, GetMSTimeDiffToNow(oldMSTime));
85 }
86 
88 {
89  for (UNORDERED_MAP<uint32, WPPath*>::iterator itr = waypoint_map.begin(); itr != waypoint_map.end(); ++itr)
90  {
91  for (WPPath::iterator pathItr = itr->second->begin(); pathItr != itr->second->end(); ++pathItr)
92  delete pathItr->second;
93 
94  delete itr->second;
95  }
96 }
97 
99 {
100  LoadHelperStores();
101 
102  uint32 oldMSTime = getMSTime();
103 
104  for (uint8 i = 0; i < SMART_SCRIPT_TYPE_MAX; i++)
105  mEventMap[i].clear(); //Drop Existing SmartAI List
106 
107  QueryResult_AutoPtr result = WorldDatabase.Query("SELECT entryorguid, source_type, id, link, event_type, event_phase_mask, event_chance, event_flags, event_param1, event_param2, event_param3, event_param4, action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, target_type, target_param1, target_param2, target_param3, target_x, target_y, target_z, target_o FROM smart_scripts ORDER BY entryorguid, source_type, id, link");
108 
109  if (!result)
110  {
111  sLog.outString(">> Loaded 0 SmartAI scripts. DB table `smartai_scripts` is empty.");
112  return;
113  }
114 
115  uint32 count = 0;
116 
117  do
118  {
119  Field* fields = result->Fetch();
120 
121  SmartScriptHolder temp;
122 
123  temp.entryOrGuid = fields[0].GetInt32();
124  SmartScriptType source_type = (SmartScriptType)fields[1].GetUInt8();
125  if (source_type >= SMART_SCRIPT_TYPE_MAX)
126  {
127  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: invalid source_type (%u), skipped loading.", uint32(source_type));
128  continue;
129  }
130  if (temp.entryOrGuid >= 0)
131  {
132  switch (source_type)
133  {
135  {
136  CreatureInfo const* creatureInfo = sObjectMgr.GetCreatureTemplate((uint32)temp.entryOrGuid);
137  if (!creatureInfo)
138  {
139  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: Creature entry (%u) does not exist, skipped loading.", uint32(temp.entryOrGuid));
140  continue;
141  }
142 
143  if (creatureInfo->GetAIName() != "SmartAI")
144  {
145  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: Creature entry (%u) is not using SmartAI, skipped loading.", uint32(temp.entryOrGuid));
146  continue;
147  }
148  break;
149  }
151  {
152  GameObjectInfo const* gameObjectInfo = sObjectMgr.GetGameObjectInfo((uint32)temp.entryOrGuid);
153  if (!gameObjectInfo)
154  {
155  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: GameObject entry (%u) does not exist, skipped loading.", uint32(temp.entryOrGuid));
156  continue;
157  }
158 
159  if (gameObjectInfo->GetAIName() != "SmartGameObjectAI")
160  {
161  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: GameObject entry (%u) is not using SmartGameObjectAI, skipped loading.", uint32(temp.entryOrGuid));
162  continue;
163  }
164  break;
165  }
167  {
168  if (!sAreaTriggerStore.LookupEntry((uint32)temp.entryOrGuid))
169  {
170  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: AreaTrigger entry (%u) does not exist, skipped loading.", uint32(temp.entryOrGuid));
171  continue;
172  }
173  break;
174  }
176  break;//nothing to check, really
177  default:
178  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: not yet implemented source_type %u", (uint32)source_type);
179  continue;
180  }
181  }
182  else
183  {
184  CreatureData const* creature = sObjectMgr.GetCreatureData(uint32(std::abs(temp.entryOrGuid)));
185  if (!creature)
186  {
187  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: Creature guid (%u) does not exist, skipped loading.", uint32(std::abs(temp.entryOrGuid)));
188  continue;
189  }
190 
191  CreatureInfo const* creatureInfo = sObjectMgr.GetCreatureTemplate(creature->id);
192  if (!creatureInfo)
193  {
194  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: Creature entry (%u) guid (%u) does not exist, skipped loading.", creature->id, uint32(std::abs(temp.entryOrGuid)));
195  continue;
196  }
197 
198  if (creatureInfo->GetAIName() != "SmartAI")
199  {
200  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: Creature entry (%u) guid (%u) is not using SmartAI, skipped loading.", creature->id, uint32(std::abs(temp.entryOrGuid)));
201  continue;
202  }
203  }
204 
205  temp.source_type = source_type;
206  temp.event_id = fields[2].GetUInt16();
207  temp.link = fields[3].GetUInt16();
208  temp.event.type = (SMART_EVENT)fields[4].GetUInt8();
209  temp.event.event_phase_mask = fields[5].GetUInt8();
210  temp.event.event_chance = fields[6].GetUInt8();
211  temp.event.event_flags = fields[7].GetUInt8();
212 
213  temp.event.raw.param1 = fields[8].GetUInt32();
214  temp.event.raw.param2 = fields[9].GetUInt32();
215  temp.event.raw.param3 = fields[10].GetUInt32();
216  temp.event.raw.param4 = fields[11].GetUInt32();
217 
218  temp.action.type = (SMART_ACTION)fields[12].GetUInt8();
219  temp.action.raw.param1 = fields[13].GetUInt32();
220  temp.action.raw.param2 = fields[14].GetUInt32();
221  temp.action.raw.param3 = fields[15].GetUInt32();
222  temp.action.raw.param4 = fields[16].GetUInt32();
223  temp.action.raw.param5 = fields[17].GetUInt32();
224  temp.action.raw.param6 = fields[18].GetUInt32();
225 
226  temp.target.type = (SMARTAI_TARGETS)fields[19].GetUInt8();
227  temp.target.raw.param1 = fields[20].GetUInt32();
228  temp.target.raw.param2 = fields[21].GetUInt32();
229  temp.target.raw.param3 = fields[22].GetUInt32();
230  temp.target.x = fields[23].GetFloat();
231  temp.target.y = fields[24].GetFloat();
232  temp.target.z = fields[25].GetFloat();
233  temp.target.o = fields[26].GetFloat();
234 
235  //check target
236  if (!IsTargetValid(temp))
237  continue;
238 
239  // check all event and action params
240  if (!IsEventValid(temp))
241  continue;
242 
243  // creature entry / guid not found in storage, create empty event list for it and increase counters
244  if (mEventMap[source_type].find(temp.entryOrGuid) == mEventMap[source_type].end())
245  {
246  ++count;
247  SmartAIEventList eventList;
248  mEventMap[source_type][temp.entryOrGuid] = eventList;
249  }
250  // store the new event
251  mEventMap[source_type][temp.entryOrGuid].push_back(temp);
252  }
253  while (result->NextRow());
254 
255  // Post Loading Validation
256  for (uint8 i = 0; i < SMART_SCRIPT_TYPE_MAX; ++i)
257  {
258  for (SmartAIEventMap::iterator itr = mEventMap[i].begin(); itr != mEventMap[i].end(); ++itr)
259  {
260  for (SmartScriptHolder const& e : itr->second)
261  {
262  if (e.link)
263  {
264  if (!FindLinkedEvent(itr->second, e.link))
265  {
266  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: Entry %d SourceType %u, Event %u, Link Event %u not found or invalid.",
267  e.entryOrGuid, e.GetScriptType(), e.event_id, e.link);
268  }
269  }
270 
271  if (e.GetEventType() == SMART_EVENT_LINK)
272  {
273  if (!FindLinkedSourceEvent(itr->second, e.event_id))
274  {
275  sLog.outError("SmartAIMgr::LoadSmartAIFromDB: Entry %d SourceType %u, Event %u, Link Source Event not found or invalid. Event will never trigger.",
277  }
278  }
279  }
280  }
281  }
282 
283  sLog.outString(">> Loaded %u SmartAI scripts in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
284 
285  UnLoadHelperStores();
286 }
287 
289 {
290  if (std::abs(e.target.o) > 2 * float(M_PI))
291  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u has abs(`target.o` = %f) > 2*PI (orientation is expressed in radians)",
293 
295  return true; // AI template has special handling
296 
297  switch (e.GetTargetType())
298  {
301  {
302  if (e.target.unitDistance.creature && !sObjectMgr.GetCreatureTemplate(e.target.unitDistance.creature))
303  {
304  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Creature entry %u as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.unitDistance.creature);
305  return false;
306  }
307  break;
308  }
311  {
312  if (e.target.goDistance.entry && !sObjectMgr.GetGameObjectInfo(e.target.goDistance.entry))
313  {
314  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent GameObject entry %u as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.goDistance.entry);
315  return false;
316  }
317  break;
318  }
320  {
321  if (e.target.unitGUID.entry && !IsCreatureValid(e, e.target.unitGUID.entry))
322  return false;
323  break;
324  }
326  {
327  if (e.target.goGUID.entry && !IsGameObjectValid(e, e.target.goGUID.entry))
328  return false;
329  break;
330  }
333  {
334  if (e.target.playerDistance.dist == 0)
335  {
336  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u has maxDist 0 as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
337  return false;
338  }
339  break;
340  }
342  case SMART_TARGET_SELF:
343  case SMART_TARGET_VICTIM:
351  case SMART_TARGET_NONE:
359  case SMART_TARGET_STORED:
360  break;
361  default:
362  sLog.outError("SmartAIMgr: Not handled target_type(%u), Entry %d SourceType %u Event %u Action %u, skipped.", e.GetTargetType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
363  return false;
364  }
365  return true;
366 }
367 
369 {
370  if (e.event.type >= SMART_EVENT_END)
371  {
372  sLog.outError("SmartAIMgr: EntryOrGuid %d using event(%u) has invalid event type (%u), skipped.", e.entryOrGuid, e.event_id, e.GetEventType());
373  return false;
374  }
375 
376  // in SMART_SCRIPT_TYPE_TIMED_ACTIONLIST all event types are overriden by core
378  {
379  sLog.outError("SmartAIMgr: EntryOrGuid %d, event type %u can not be used for Script type %u", e.entryOrGuid, e.GetEventType(), e.GetScriptType());
380  return false;
381  }
382 
383  if (e.action.type <= 0 || e.action.type >= SMART_ACTION_END)
384  {
385  sLog.outError("SmartAIMgr: EntryOrGuid %d using event(%u) has invalid action type (%u), skipped.", e.entryOrGuid, e.event_id, e.GetActionType());
386  return false;
387  }
388 
390  {
391  sLog.outError("SmartAIMgr: EntryOrGuid %d using event(%u) has invalid phase mask (%u), skipped.", e.entryOrGuid, e.event_id, e.event.event_phase_mask);
392  return false;
393  }
394 
396  {
397  sLog.outError("SmartAIMgr: EntryOrGuid %d using event(%u) has invalid event flags (%u), skipped.", e.entryOrGuid, e.event_id, e.event.event_flags);
398  return false;
399  }
400 
401  if (e.link && e.link == e.event_id)
402  {
403  sLog.outError("SmartAIMgr: EntryOrGuid %d SourceType %u, Event %u, Event is linking self (infinite loop), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id);
404  return false;
405  }
406 
408  {
409  e.event.type = SMART_EVENT_UPDATE_OOC;//force default OOC, can change when calling the script!
410  if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max))
411  return false;
412 
413  if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax))
414  return false;
415  }
416  else
417  {
418  switch (e.GetEventType())
419  {
420  case SMART_EVENT_UPDATE:
427  case SMART_EVENT_RANGE:
428  case SMART_EVENT_DAMAGED:
431  if (!IsMinMaxValid(e, e.event.minMaxRepeat.min, e.event.minMaxRepeat.max))
432  return false;
433 
434  if (!IsMinMaxValid(e, e.event.minMaxRepeat.repeatMin, e.event.minMaxRepeat.repeatMax))
435  return false;
436  break;
439  if (e.event.spellHit.spell)
440  {
441  SpellEntry const* spellInfo = sSpellStore.LookupEntry(e.event.spellHit.spell);
442  if (!spellInfo)
443  {
444  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell);
445  return false;
446  }
447  if (e.event.spellHit.school && (e.event.spellHit.school & spellInfo->SchoolMask) != spellInfo->SchoolMask)
448  {
449  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses Spell entry %u with invalid school mask, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell);
450  return false;
451  }
452  }
453  if (!IsMinMaxValid(e, e.event.spellHit.cooldownMin, e.event.spellHit.cooldownMax))
454  return false;
455  break;
456  case SMART_EVENT_OOC_LOS:
457  case SMART_EVENT_IC_LOS:
458  if (!IsMinMaxValid(e, e.event.los.cooldownMin, e.event.los.cooldownMax))
459  return false;
460  break;
461  case SMART_EVENT_RESPAWN:
462  if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_MAP && !sMapStore.LookupEntry(e.event.respawn.map))
463  {
464  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map);
465  return false;
466  }
468  {
469  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area);
470  return false;
471  }
472  break;
474  if (!NotNULL(e, e.event.friendlyHealth.radius))
475  return false;
476 
477  if (!IsMinMaxValid(e, e.event.friendlyHealth.repeatMin, e.event.friendlyHealth.repeatMax))
478  return false;
479  break;
481  if (!IsMinMaxValid(e, e.event.friendlyCC.repeatMin, e.event.friendlyCC.repeatMax))
482  return false;
483  break;
485  {
486  if (!IsSpellValid(e, e.event.missingBuff.spell))
487  return false;
488 
489  if (!NotNULL(e, e.event.missingBuff.radius))
490  return false;
491 
492  if (!IsMinMaxValid(e, e.event.missingBuff.repeatMin, e.event.missingBuff.repeatMax))
493  return false;
494  break;
495  }
496  case SMART_EVENT_KILL:
497  if (!IsMinMaxValid(e, e.event.kill.cooldownMin, e.event.kill.cooldownMax))
498  return false;
499 
500  if (e.event.kill.creature && !IsCreatureValid(e, e.event.kill.creature))
501  return false;
502  break;
504  if (e.event.targetCasting.spellId > 0 && !sSpellStore.LookupEntry(e.event.targetCasting.spellId))
505  {
506  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Spell entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell);
507  return false;
508  }
509 
510  if (!IsMinMaxValid(e, e.event.targetCasting.repeatMin, e.event.targetCasting.repeatMax))
511  return false;
512  break;
515  if (!IsMinMaxValid(e, e.event.minMax.repeatMin, e.event.minMax.repeatMax))
516  return false;
517  break;
520  if (e.event.summoned.creature && !IsCreatureValid(e, e.event.summoned.creature))
521  return false;
522 
523  if (!IsMinMaxValid(e, e.event.summoned.cooldownMin, e.event.summoned.cooldownMax))
524  return false;
525  break;
528  if (e.event.quest.quest && !IsQuestValid(e, e.event.quest.quest))
529  return false;
530  break;
532  {
533  if (e.event.emote.emote && !IsTextEmoteValid(e, e.event.emote.emote))
534  return false;
535 
536  if (!IsMinMaxValid(e, e.event.emote.cooldownMin, e.event.emote.cooldownMax))
537  return false;
538  break;
539  }
542  {
543  if (!IsSpellValid(e, e.event.aura.spell))
544  return false;
545 
546  if (!IsMinMaxValid(e, e.event.aura.repeatMin, e.event.aura.repeatMax))
547  return false;
548  break;
549  }
551  {
552  if (e.event.transportAddCreature.creature && !IsCreatureValid(e, e.event.transportAddCreature.creature))
553  return false;
554  break;
555  }
557  {
559  {
560  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid Motion type %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.movementInform.type);
561  return false;
562  }
563  break;
564  }
566  {
567  if (!IsMinMaxValid(e, e.event.dataSet.cooldownMin, e.event.dataSet.cooldownMax))
568  return false;
569  break;
570  }
572  {
573  if (e.event.areatrigger.id && !IsAreaTriggerValid(e, e.event.areatrigger.id))
574  return false;
575  break;
576  }
578  if (!IsTextValid(e, e.event.textOver.textGroupID))
579  return false;
580  break;
582  {
583  if (!IsSpellValid(e, e.event.dummy.spell))
584  return false;
585 
586  if (e.event.dummy.effIndex > EFFECT_2)
587  return false;
588  break;
589  }
591  {
592  if (!IsMinMaxValid(e, e.event.behindTarget.cooldownMin, e.event.behindTarget.cooldownMax))
593  return false;
594  break;
595  }
598  {
599  GameEventMgr::GameEventDataMap const& events = sGameEventMgr.GetEventMap();
600  if (e.event.gameEvent.gameEventId >= events.size() || !events[e.event.gameEvent.gameEventId].isValid())
601  return false;
602  break;
603  }
605  {
606  if (e.event.doAction.eventId > EVENT_CHARGE)
607  {
608  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid event id %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.doAction.eventId);
609  return false;
610  }
611  break;
612  }
614  if (!IsMinMaxValid(e, e.event.friendlyHealthPct.repeatMin, e.event.friendlyHealthPct.repeatMax))
615  return false;
616 
617  if (e.event.friendlyHealthPct.maxHpPct > 100 || e.event.friendlyHealthPct.minHpPct > 100)
618  {
619  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u has pct value above 100, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
620  return false;
621  }
622 
623  switch (e.GetTargetType())
624  {
632  break;
633  default:
634  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid target_type %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
635  return false;
636  }
637  break;
639  if (e.event.distance.guid == 0 && e.event.distance.entry == 0)
640  {
641  sLog.outError("SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE did not provide creature guid or entry, skipped.");
642  return false;
643  }
644 
645  if (e.event.distance.guid != 0 && e.event.distance.entry != 0)
646  {
647  sLog.outError("SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE provided both an entry and guid, skipped.");
648  return false;
649  }
650 
651  if (e.event.distance.guid != 0 && !sObjectMgr.GetCreatureData(e.event.distance.guid))
652  {
653  sLog.outError("SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature guid %u, skipped.", e.event.distance.guid);
654  return false;
655  }
656 
657  if (e.event.distance.entry != 0 && !sObjectMgr.GetCreatureTemplate(e.event.distance.entry))
658  {
659  sLog.outError("SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature entry %u, skipped.", e.event.distance.entry);
660  return false;
661  }
662  break;
664  if (e.event.distance.guid == 0 && e.event.distance.entry == 0)
665  {
666  sLog.outError("SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT did not provide gameobject guid or entry, skipped.");
667  return false;
668  }
669 
670  if (e.event.distance.guid != 0 && e.event.distance.entry != 0)
671  {
672  sLog.outError("SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT provided both an entry and guid, skipped.");
673  return false;
674  }
675 
676  if (e.event.distance.guid != 0 && !sObjectMgr.GetGOData(e.event.distance.guid))
677  {
678  sLog.outError("SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject guid %u, skipped.", e.event.distance.guid);
679  return false;
680  }
681 
682  if (e.event.distance.entry != 0 && !sObjectMgr.GetGameObjectInfo(e.event.distance.entry))
683  {
684  sLog.outError("SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject entry %u, skipped.", e.event.distance.entry);
685  return false;
686  }
687  break;
689  if (!IsMinMaxValid(e, e.event.counter.cooldownMin, e.event.counter.cooldownMax))
690  return false;
691 
692  if (e.event.counter.id == 0)
693  {
694  sLog.outError("SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid counter id %u, skipped.", e.event.counter.id);
695  return false;
696  }
697 
698  if (e.event.counter.value == 0)
699  {
700  sLog.outError("SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid value %u, skipped.", e.event.counter.value);
701  return false;
702  }
703  break;
704  case SMART_EVENT_LINK:
710  case SMART_EVENT_CHARMED:
713  case SMART_EVENT_AI_INIT:
716  case SMART_EVENT_AGGRO:
717  case SMART_EVENT_DEATH:
718  case SMART_EVENT_EVADE:
720  case SMART_EVENT_RESET:
738  break;
739  default:
740  sLog.outError("SmartAIMgr: Not handled event_type(%u), Entry %d SourceType %u Event %u Action %u, skipped.", e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
741  return false;
742  }
743  }
744 
745  switch (e.GetActionType())
746  {
747  case SMART_ACTION_TALK:
749  if (!IsTextValid(e, e.action.talk.textGroupID))
750  return false;
751  break;
753  if (e.action.faction.factionID && !sFactionTemplateStore.LookupEntry(e.action.faction.factionID))
754  {
755  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Faction %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.faction.factionID);
756  return false;
757  }
758  break;
761  if (e.action.morphOrMount.creature || e.action.morphOrMount.model)
762  {
763  if (e.action.morphOrMount.creature > 0 && !sObjectMgr.GetCreatureTemplate(e.action.morphOrMount.creature))
764  {
765  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Creature entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.morphOrMount.creature);
766  return false;
767  }
768 
769  if (e.action.morphOrMount.model)
770  {
771  if (e.action.morphOrMount.creature)
772  {
773  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u has ModelID set with also set CreatureId, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
774  return false;
775  }
776  else if (!sCreatureDisplayInfoStore.LookupEntry(e.action.morphOrMount.model))
777  {
778  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Model id %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.morphOrMount.model);
779  return false;
780  }
781  }
782  }
783  break;
784  case SMART_ACTION_SOUND:
785  if (!IsSoundValid(e, e.action.sound.sound))
786  return false;
787  break;
790  if (!IsEmoteValid(e, e.action.emote.emote))
791  return false;
792  break;
795  if (!e.action.quest.quest || !IsQuestValid(e, e.action.quest.quest))
796  return false;
797  break;
799  {
800  if (!sTaxiPathStore.LookupEntry(e.action.taxi.id))
801  {
802  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses invalid Taxi path ID %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.taxi.id);
803  return false;
804  }
805  break;
806  }
808  if (e.action.randomEmote.emote1 && !IsEmoteValid(e, e.action.randomEmote.emote1))
809  return false;
810 
811  if (e.action.randomEmote.emote2 && !IsEmoteValid(e, e.action.randomEmote.emote2))
812  return false;
813 
814  if (e.action.randomEmote.emote3 && !IsEmoteValid(e, e.action.randomEmote.emote3))
815  return false;
816 
817  if (e.action.randomEmote.emote4 && !IsEmoteValid(e, e.action.randomEmote.emote4))
818  return false;
819 
820  if (e.action.randomEmote.emote5 && !IsEmoteValid(e, e.action.randomEmote.emote5))
821  return false;
822 
823  if (e.action.randomEmote.emote6 && !IsEmoteValid(e, e.action.randomEmote.emote6))
824  return false;
825  break;
827  for (uint8 i = 0; i < SMART_ACTION_PARAM_COUNT - 1; i++)
828  {
829  if (e.action.randomSound.sound[i] && !IsSoundValid(e, e.action.randomSound.sound[i]))
830  return false;
831  }
832  break;
833  case SMART_ACTION_CAST:
834  {
835  if (!IsSpellValid(e, e.action.cast.spell))
836  return false;
837 
838  SpellEntry const* spellInfo = sSpellStore.LookupEntry(e.action.cast.spell);
839  for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
840  {
841  if (spellInfo->HasEffect(j, SPELL_EFFECT_KILL_CREDIT))
842  {
843  if (spellInfo->EffectImplicitTargetA[j] == TARGET_UNIT_CASTER)
844  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u Effect: SPELL_EFFECT_KILL_CREDIT: (SpellId: %u targetA: %u - targetB: %u) has invalid target for this Action",
845  e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.cast.spell, spellInfo->EffectImplicitTargetA[j], spellInfo->EffectImplicitTargetB);
846  }
847  }
848  break;
849  }
852  if (!IsSpellValid(e, e.action.cast.spell))
853  return false;
854  break;
857  if (Quest const* qid = sObjectMgr.GetQuestTemplate(e.action.quest.quest))
858  {
859  if (!qid->HasSpecialFlag(QUEST_SPECIAL_FLAGS_EXPLORATION_OR_EVENT))
860  {
861  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u SpecialFlags for Quest entry %u does not include FLAGS_EXPLORATION_OR_EVENT(2), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest);
862  return false;
863  }
864  }
865  else
866  {
867  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Quest entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest);
868  return false;
869  }
870  break;
873  {
874  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to set phase %u. Phase mask cannot be used past phase %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setEventPhase.phase, SMART_EVENT_PHASE_MAX - 1);
875  return false;
876  }
877  break;
879  if (!e.action.incEventPhase.inc && !e.action.incEventPhase.dec)
880  {
881  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u is incrementing phase by 0, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
882  return false;
883  }
885  {
886  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to increment phase by too large value, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
887  return false;
888  }
889  break;
891  if (e.action.removeAura.spell != 0 && !IsSpellValid(e, e.action.removeAura.spell))
892  return false;
893  break;
895  {
896  if (e.action.randomPhase.phase1 >= SMART_EVENT_PHASE_MAX ||
902  {
903  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
904  return false;
905  }
906  }
907  break;
908  case SMART_ACTION_RANDOM_PHASE_RANGE: //PhaseMin, PhaseMax
909  {
910  if (e.action.randomPhaseRange.phaseMin >= SMART_EVENT_PHASE_MAX ||
912  {
913  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
914  return false;
915  }
916 
917  if (!IsMinMaxValid(e, e.action.randomPhaseRange.phaseMin, e.action.randomPhaseRange.phaseMax))
918  return false;
919  break;
920  }
922  {
923  if (!IsCreatureValid(e, e.action.summonCreature.creature))
924  return false;
925 
926  CacheSpellContainerBounds sBounds = GetSummonCreatureSpellContainerBounds(e.action.summonCreature.creature);
927  for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
928  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u creature summon: There is a summon spell for creature entry %u (SpellId: %u, effect: %u)",
929  e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonCreature.creature, itr->second.first, itr->second.second);
930 
932  {
933  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses incorrect TempSummonType %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonCreature.type);
934  return false;
935  }
936  break;
937  }
939  {
940  if (!IsCreatureValid(e, e.action.killedMonster.creature))
941  return false;
942 
943  CacheSpellContainerBounds sBounds = GetKillCreditSpellContainerBounds(e.action.killedMonster.creature);
944  for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
945  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u Kill Credit: There is a killcredit spell for creatureEntry %u (SpellId: %u effect: %u)",
946  e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.killedMonster.creature, itr->second.first, itr->second.second);
947 
949  {
950  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses incorrect TargetType %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
951  return false;
952  }
953  break;
954  }
956  if (!IsCreatureValid(e, e.action.updateTemplate.creature))
957  return false;
958  break;
960  if (e.action.setSheath.sheath && e.action.setSheath.sheath >= MAX_SHEATH_STATE)
961  {
962  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses incorrect Sheath state %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setSheath.sheath);
963  return false;
964  }
965  break;
967  {
968  if (e.action.react.state > REACT_AGGRESSIVE)
969  {
970  sLog.outError("SmartAIMgr: Creature %d Event %u Action %u uses invalid React State %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.react.state);
971  return false;
972  }
973  break;
974  }
976  {
977  if (!IsGameObjectValid(e, e.action.summonGO.entry))
978  return false;
979 
980  CacheSpellContainerBounds sBounds = GetSummonGameObjectSpellContainerBounds(e.action.summonGO.entry);
981  for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
982  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u gameobject summon: There is a summon spell for gameobject entry %u (SpellId: %u, effect: %u)",
983  e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonGO.entry, itr->second.first, itr->second.second);
984  break;
985  }
987  if (!IsItemValid(e, e.action.item.entry))
988  return false;
989 
990  if (!NotNULL(e, e.action.item.count))
991  return false;
992  break;
994  {
995  if (!IsItemValid(e, e.action.item.entry))
996  return false;
997 
998  if (!NotNULL(e, e.action.item.count))
999  return false;
1000 
1001  CacheSpellContainerBounds sBounds = GetCreateItemSpellContainerBounds(e.action.item.entry);
1002  for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1003  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u Create Item: There is a create item spell for item %u (SpellId: %u effect: %u)",
1004  e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.item.entry, itr->second.first, itr->second.second);
1005  break;
1006  }
1007  case SMART_ACTION_TELEPORT:
1008  if (!sMapStore.LookupEntry(e.action.teleport.mapID))
1009  {
1010  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.teleport.mapID);
1011  return false;
1012  }
1013  break;
1015  if (e.action.setCounter.counterId == 0)
1016  {
1017  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses wrong counterId %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setCounter.counterId);
1018  return false;
1019  }
1020 
1021  if (e.action.setCounter.value == 0)
1022  {
1023  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses wrong value %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setCounter.value);
1024  return false;
1025  }
1026 
1027  break;
1030  {
1031  sLog.outError("SmartAIMgr: Creature %d Event %u Action %u uses non-existent AI template id %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.installTtemplate.id);
1032  return false;
1033  }
1034  break;
1035  case SMART_ACTION_WP_STOP:
1036  if (e.action.wpStop.quest && !IsQuestValid(e, e.action.wpStop.quest))
1037  return false;
1038  break;
1039  case SMART_ACTION_WP_START:
1040  {
1041  if (!sSmartWaypointMgr->GetPath(e.action.wpStart.pathID))
1042  {
1043  sLog.outError("SmartAIMgr: Creature %d Event %u Action %u uses non-existent WaypointPath id %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.pathID);
1044  return false;
1045  }
1046  if (e.action.wpStart.quest && !IsQuestValid(e, e.action.wpStart.quest))
1047  return false;
1048  if (e.action.wpStart.reactState > REACT_AGGRESSIVE)
1049  {
1050  sLog.outError("SmartAIMgr: Creature %d Event %u Action %u uses invalid React State %u, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.reactState);
1051  return false;
1052  }
1053  break;
1054  }
1056  {
1057  if (!IsMinMaxValid(e, e.action.timeEvent.min, e.action.timeEvent.max))
1058  return false;
1059 
1060  if (!IsMinMaxValid(e, e.action.timeEvent.repeatMin, e.action.timeEvent.repeatMax))
1061  return false;
1062  break;
1063  }
1065  {
1066  if (!IsMinMaxValid(e, e.action.randTimedActionList.entry1, e.action.randTimedActionList.entry2))
1067  return false;
1068  break;
1069  }
1073  if (e.action.power.powerType > MAX_POWERS)
1074  {
1075  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Power %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.power.powerType);
1076  return false;
1077  }
1078  break;
1080  {
1081  uint32 eventId = e.action.gameEventStop.id;
1082 
1083  GameEventMgr::GameEventDataMap const& events = sGameEventMgr.GetEventMap();
1084  if (eventId < 1 || eventId >= events.size())
1085  {
1086  sLog.outError("SmartAIMgr: Entry %u SourceType %u Event %u Action %u uses non-existent event, eventId %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.gameEventStop.id);
1087  return false;
1088  }
1089 
1090  GameEventData const& eventData = events[eventId];
1091  if (!eventData.isValid())
1092  {
1093  sLog.outError("SmartAIMgr: Entry %u SourceType %u Event %u Action %u uses non-existent event, eventId %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.gameEventStop.id);
1094  return false;
1095  }
1096  break;
1097  }
1099  {
1100  uint32 eventId = e.action.gameEventStart.id;
1101 
1102  GameEventMgr::GameEventDataMap const& events = sGameEventMgr.GetEventMap();
1103  if (eventId < 1 || eventId >= events.size())
1104  {
1105  sLog.outError("SmartAIMgr: Entry %u SourceType %u Event %u Action %u uses non-existent event, eventId %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.gameEventStart.id);
1106  return false;
1107  }
1108 
1109  GameEventData const& eventData = events[eventId];
1110  if (!eventData.isValid())
1111  {
1112  sLog.outError("SmartAIMgr: Entry %u SourceType %u Event %u Action %u uses non-existent event, eventId %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.gameEventStart.id);
1113  return false;
1114  }
1115  break;
1116  }
1117  case SMART_ACTION_EQUIP:
1118  {
1120  {
1121  uint32 equipId = e.action.equip.entry;
1122 
1123  if (equipId)
1124  {
1125  EquipmentInfo const* einfo = sObjectMgr.GetEquipmentInfo(equipId);
1126  if (!einfo)
1127  {
1128  sLog.outError("SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id %u for creature %u, skipped.", equipId, e.entryOrGuid);
1129  return false;
1130  }
1131  }
1132  }
1133  break;
1134  }
1136  case SMART_ACTION_FOLLOW:
1139  case SMART_ACTION_EVADE:
1142  case SMART_ACTION_DIE:
1157  case SMART_ACTION_SET_DATA:
1160  case SMART_ACTION_WP_PAUSE:
1161  case SMART_ACTION_SET_FLY:
1162  case SMART_ACTION_SET_RUN:
1163  case SMART_ACTION_SET_SWIM:
1199  case SMART_ACTION_SET_ROOT:
1204  break;
1205  default:
1206  sLog.outError("SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
1207  return false;
1208  }
1209 
1210  return true;
1211 }
1212 
1214 {
1216  return true;
1217 
1218  uint32 entry = 0;
1219 
1221  {
1222  entry = e.event.textOver.creatureEntry;
1223  }
1224  else
1225  {
1226  switch (e.GetTargetType())
1227  {
1231  return true; // ignore
1232  default:
1233  if (e.entryOrGuid < 0)
1234  {
1235  int32 guid = -e.entryOrGuid;
1236  CreatureData const* data = sObjectMgr.GetCreatureData((uint32)guid);
1237  if (!data)
1238  {
1239  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u using non-existent Creature guid %d, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), guid);
1240  return false;
1241  }
1242  else
1243  entry = data->id;
1244  }
1245  else
1246  entry = uint32(e.entryOrGuid);
1247  break;
1248  }
1249  }
1250 
1251  if (!entry || !sCreatureTextMgr->TextExist(entry, uint8(id)))
1252  {
1253  sLog.outError("SmartAIMgr: Entry %d SourceType %u Event %u Action %u using non-existent Text id %d, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), id);
1254  return false;
1255  }
1256 
1257  return true;
1258 }
1259 
1261 {
1262  uint32 oldMSTime = getMSTime();
1263 
1264  SpellEntry const* spellInfo = NULL;
1265  for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
1266  {
1267  SpellEntry const* spellInfo = sSpellStore.LookupEntry(i);
1268  if (!spellInfo)
1269  continue;
1270 
1271  for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
1272  {
1273  if (spellInfo->HasEffect(j, SPELL_EFFECT_SUMMON))
1274  SummonCreatureSpellStore.insert(std::make_pair(uint32(spellInfo->EffectMiscValue[j]), std::make_pair(i, SpellEffIndex(j))));
1275 
1276  else if (spellInfo->HasEffect(j, SPELL_EFFECT_SUMMON_OBJECT_WILD))
1277  SummonGameObjectSpellStore.insert(std::make_pair(uint32(spellInfo->EffectMiscValue[j]), std::make_pair(i, SpellEffIndex(j))));
1278 
1279  else if (spellInfo->HasEffect(j, SPELL_EFFECT_KILL_CREDIT))
1280  KillCreditSpellStore.insert(std::make_pair(uint32(spellInfo->EffectMiscValue[j]), std::make_pair(i, SpellEffIndex(j))));
1281 
1282  else if (spellInfo->HasEffect(j, SPELL_EFFECT_CREATE_ITEM))
1283  CreateItemSpellStore.insert(std::make_pair(uint32(spellInfo->EffectItemType[j]), std::make_pair(i, SpellEffIndex(j))));
1284  }
1285  }
1286 
1287  sLog.outString(">> Loaded SmartAIMgr Helpers in %u ms", GetMSTimeDiffToNow(oldMSTime));
1288 }
1289 
1291 {
1292  SummonCreatureSpellStore.clear();
1293  SummonGameObjectSpellStore.clear();
1294  KillCreditSpellStore.clear();
1295  CreateItemSpellStore.clear();
1296 }
1297 
1299 {
1300  return SummonCreatureSpellStore.equal_range(creatureEntry);
1301 }
1302 
1304 {
1305  return SummonGameObjectSpellStore.equal_range(gameObjectEntry);
1306 }
1307 
1309 {
1310  return KillCreditSpellStore.equal_range(killCredit);
1311 }
1312 
1314 {
1315  return CreateItemSpellStore.equal_range(itemId);
1316 }
1317 
despawns when UnSummon() is called
AreaTableEntry const * GetAreaEntryByAreaID(uint32 area_id)
Definition: DBCStores.cpp:623
struct SmartAction::@162::@209 setCounter
SmartScriptType
struct SmartEvent::@125::@136 missingBuff
struct SmartAction::@162::@199 taxi
struct SmartAction::@162::@197 summonGO
const uint32 SmartAITypeMask[SMART_SCRIPT_TYPE_MAX][2]
bool IsEventValid(SmartScriptHolder &e)
uint32 event_phase_mask
CacheSpellContainerBounds GetKillCreditSpellContainerBounds(uint32 killCredit) const
struct SmartEvent::@125::@130 los
CacheSpellContainerBounds GetCreateItemSpellContainerBounds(uint32 itemId) const
struct SmartAction::@162::@184 randomPhaseRange
DatabaseType WorldDatabase
Accessor to the world database.
Definition: Main.cpp:53
uint32 id
Definition: Creature.h:269
struct SmartEvent::@125::@154 gameEvent
void UnLoadHelperStores()
void LoadSmartAIFromDB()
struct SmartAction::@162::@236 gameEventStop
SMARTAI_TARGETS type
UNORDERED_MAP< uint32, WPPath * > waypoint_map
std::vector< SmartScriptHolder > SmartAIEventList
struct SmartAction::@162::@179 setEventPhase
struct SmartEvent::@125::@142 movementInform
Definition: Field.h:24
struct SmartEvent::@125::@132 minMax
DBCStorage< FactionTemplateEntry > sFactionTemplateStore(FactionTemplateEntryfmt)
struct SmartTarget::@241::@250 goGUID
struct SmartAction::@162::@237 gameEventStart
uint32 GetEventType() const
uint32 getMSTime()
Definition: Timer.h:32
#define sLog
Log class singleton.
Definition: Log.h:187
std::string GetAIName() const
Definition: Creature.h:221
ACE_INT32 int32
Definition: Define.h:67
QueryResult_AutoPtr Query(const char *sql)
Definition: Database.cpp:383
SMART_ACTION
DBCStorage< AreaTriggerEntry > sAreaTriggerStore(AreaTriggerEntryfmt)
bool HasEffect(uint8 effect) const
Definition: DBCStructure.h:783
struct SmartAction::@162::@204 installTtemplate
struct SmartEvent::@125::@131 respawn
const uint32 SmartAIEventMask[SMART_EVENT_END][2]
struct SmartAction::@162::@203 item
#define MAX_POWERS
uint32 event_flags
#define sObjectMgr
Definition: ObjectMgr.h:1285
struct SmartEvent::@125::@143 dataSet
struct SmartEvent::@125::@145 transportAddCreature
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
struct SmartTarget::@241::@256 raw
DBCStorage< SpellEntry > sSpellStore(SpellEntryfmt)
struct SmartEvent::@125::@134 friendlyHealth
DBCStorage< CreatureDisplayInfoEntry > sCreatureDisplayInfoStore(CreatureDisplayInfofmt)
struct SmartEvent::@125::@159 distance
struct SmartEvent::@125::@129 spellHit
struct SmartAction::@162::@185 killedMonster
struct SmartAction::@162::@165 faction
struct SmartEvent::@125::@152 dummy
bool IsTextValid(SmartScriptHolder const &e, uint32 id)
struct SmartAction::@162::@171 randomEmote
struct SmartAction::@162::@220 randTimedActionList
ACE_UINT8 uint8
Definition: Define.h:73
struct SmartAction::@162::@164 talk
struct SmartAction::@162::@212 timeEvent
std::pair< CacheSpellContainer::const_iterator, CacheSpellContainer::const_iterator > CacheSpellContainerBounds
struct SmartAction::@162::@183 randomPhase
#define MAX_SHEATH_STATE
Definition: Unit.h:227
struct SmartEvent::@125::@157 doAction
struct SmartEvent::@125::@128 kill
struct SmartAction::@162::@200 wpStart
uint32 EffectImplicitTargetB[MAX_SPELL_EFFECTS]
Definition: DBCStructure.h:732
struct SmartTarget::@241::@246 playerDistance
SpellEffIndex
Definition: SharedDefines.h:24
#define sCreatureTextMgr
SMART_EVENT
struct SmartEvent::@125::@158 friendlyHealthPct
uint32 EffectImplicitTargetA[MAX_SPELL_EFFECTS]
Definition: DBCStructure.h:731
uint32 EffectItemType[MAX_SPELL_EFFECTS]
Definition: DBCStructure.h:738
#define sSmartWaypointMgr
struct SmartAction::@162::@214 equip
struct SmartAction::@162::@188 updateTemplate
struct SmartAction::@162::@172 cast
SMART_EVENT type
uint32 SchoolMask
Definition: DBCStructure.h:772
struct SmartEvent::@125::@140 aura
int32 EffectMiscValue[MAX_SPELL_EFFECTS]
Definition: DBCStructure.h:739
struct SmartAction::@162::@239 randomSound
std::string GetAIName() const
Definition: GameObject.h:507
struct SmartEvent::@125::@149 textOver
struct SmartEvent::@125::@135 friendlyCC
despawns after a specified time OR when the creature disappears
#define sGameEventMgr
Definition: GameEventMgr.h:179
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition: Timer.h:94
struct SmartEvent::@125::@161 raw
UNORDERED_MAP< uint32, WayPoint * > WPPath
ACE_Refcounted_Auto_Ptr< QueryResult, ACE_Null_Mutex > QueryResult_AutoPtr
Definition: QueryResult.h:113
uint32 GetActionType() const
struct SmartTarget::@241::@251 goDistance
uint32 GetScriptType() const
CacheSpellContainerBounds GetSummonGameObjectSpellContainerBounds(uint32 gameObjectEntry) const
struct SmartAction::@162::@170 react
struct SmartEvent::@125::@137 summoned
struct SmartEvent::@125::@160 counter
struct SmartAction::@162::@235 power
struct SmartAction::@162::@173 summonCreature
std::vector< GameEventData > GameEventDataMap
Definition: GameEventMgr.h:94
bool IsTargetValid(SmartScriptHolder const &e)
#define MAX_SPELL_EFFECTS
Definition: DBCStructure.h:670
SmartScriptType source_type
struct SmartAction::@162::@190 setSheath
uint32 GetTargetType() const
struct SmartAction::@162::@181 removeAura
struct SmartEvent::@125::@153 behindTarget
uint32 event_chance
struct SmartAction::@162::@166 morphOrMount
ACE_UINT32 uint32
Definition: Define.h:71
void LoadHelperStores()
struct SmartAction::@162::@202 wpStop
struct SmartAction::@162::@240 raw
struct SmartEvent::@125::@133 targetCasting
DBCStorage< TaxiPathEntry > sTaxiPathStore(TaxiPathEntryfmt)
CacheSpellContainerBounds GetSummonCreatureSpellContainerBounds(uint32 creatureEntry) const
struct SmartTarget::@241::@244 unitGUID
struct SmartAction::@162::@180 incEventPhase
bool isValid() const
Definition: GameEventMgr.h:64
struct SmartEvent::@125::@127 minMaxRepeat
struct SmartEvent::@125::@148 areatrigger
SMARTAI_TARGETS
SMART_ACTION type
struct SmartAction::@162::@208 teleport
struct SmartTarget::@241::@245 unitDistance