TrinityCore
Loading...
Searching...
No Matches
SmartScriptMgr.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore 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 "SmartScriptMgr.h"
20#include "AreaTriggerTemplate.h"
22#include "CreatureTextMgr.h"
23#include "DB2Stores.h"
24#include "DatabaseEnv.h"
25#include "GameEventMgr.h"
26#include "InstanceScript.h"
27#include "Log.h"
28#include "MovementDefines.h"
29#include "ObjectAccessor.h"
30#include "ObjectMgr.h"
31#include "SpellInfo.h"
32#include "SpellMgr.h"
33#include "StringConvert.h"
34#include "Timer.h"
35#include "UnitDefines.h"
36#include "Util.h"
37#include "WaypointDefines.h"
38#include "WaypointManager.h"
39#include "advstd.h"
40#include <algorithm>
41
42#define TC_SAI_IS_BOOLEAN_VALID(e, value) \
43{ \
44 if (value > 1) \
45 { \
46 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses param {} of type Boolean with value {}, valid values are 0 or 1, skipped.", \
47 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), STRINGIZE(value), value); \
48 return false; \
49 } \
50}
51
52SmartAIMgr::SmartAIMgr() = default;
53SmartAIMgr::~SmartAIMgr() = default;
54
60
62{
64
65 uint32 oldMSTime = getMSTime();
66
67 for (SmartAIEventMap& eventmap : mEventMap)
68 eventmap.clear(); //Drop Existing SmartAI List
69
71 PreparedQueryResult result = WorldDatabase.Query(stmt);
72
73 if (!result)
74 {
75 TC_LOG_INFO("server.loading", ">> Loaded 0 SmartAI scripts. DB table `smartai_scripts` is empty.");
76 return;
77 }
78
79 uint32 count = 0;
80
81 do
82 {
83 Field* fields = result->Fetch();
84
86
87 temp.entryOrGuid = fields[0].GetInt64();
88 if (!temp.entryOrGuid)
89 {
90 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: invalid entryorguid (0), skipped loading.");
91 continue;
92 }
93
94 SmartScriptType source_type = (SmartScriptType)fields[1].GetUInt8();
95 if (source_type >= SMART_SCRIPT_TYPE_MAX)
96 {
97 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: invalid source_type ({}), skipped loading.", uint32(source_type));
98 continue;
99 }
100 if (temp.entryOrGuid >= 0)
101 {
102 switch (source_type)
103 {
105 {
106 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate((uint32)temp.entryOrGuid);
107 if (!creatureInfo)
108 {
109 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature entry ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
110 continue;
111 }
112
113 if (creatureInfo->AIName != "SmartAI")
114 {
115 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature entry ({}) is not using SmartAI, skipped loading.", uint32(temp.entryOrGuid));
116 continue;
117 }
118 break;
119 }
121 {
122 GameObjectTemplate const* gameObjectInfo = sObjectMgr->GetGameObjectTemplate((uint32)temp.entryOrGuid);
123 if (!gameObjectInfo)
124 {
125 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GameObject entry ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
126 continue;
127 }
128
129 if (gameObjectInfo->AIName != "SmartGameObjectAI")
130 {
131 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GameObject entry ({}) is not using SmartGameObjectAI, skipped loading.", uint32(temp.entryOrGuid));
132 continue;
133 }
134 break;
135 }
137 {
138 if (!sAreaTriggerStore.LookupEntry((uint32)temp.entryOrGuid))
139 {
140 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: AreaTrigger entry ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
141 continue;
142 }
143 break;
144 }
146 {
147 if (!sObjectMgr->IsValidEvent((uint32)temp.entryOrGuid))
148 {
149 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Event id ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
150 continue;
151 }
152 break;
153 }
155 {
156 if (!sObjectMgr->GetQuestTemplate((uint32)temp.entryOrGuid))
157 {
158 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Quest entry ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
159 continue;
160 }
161 break;
162 }
164 {
165 if (!sObjectMgr->GetSceneTemplate((uint32)temp.entryOrGuid))
166 {
167 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Scene id ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
168 continue;
169 }
170 break;
171 }
173 break;//nothing to check, really
175 {
176 if (!sAreaTriggerDataStore->GetAreaTriggerTemplate({ (uint32)temp.entryOrGuid, false }))
177 {
178 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: AreaTrigger entry ({} IsCustom false) does not exist, skipped loading.", uint32(temp.entryOrGuid));
179 continue;
180 }
181 break;
182 }
184 {
185 if (!sAreaTriggerDataStore->GetAreaTriggerTemplate({ (uint32)temp.entryOrGuid, true }))
186 {
187 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: AreaTrigger entry ({} IsCustom true) does not exist, skipped loading.", uint32(temp.entryOrGuid));
188 continue;
189 }
190 break;
191 }
192 default:
193 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: not yet implemented source_type {}", (uint32)source_type);
194 continue;
195 }
196 }
197 else
198 {
199 switch (source_type)
200 {
202 {
203 CreatureData const* creature = sObjectMgr->GetCreatureData(uint64(-temp.entryOrGuid));
204 if (!creature)
205 {
206 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature guid ({}) does not exist, skipped loading.", -temp.entryOrGuid);
207 continue;
208 }
209
210 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creature->id);
211 if (!creatureInfo)
212 {
213 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature entry ({}) guid ({}) does not exist, skipped loading.", creature->id, -temp.entryOrGuid);
214 continue;
215 }
216
217 if (creatureInfo->AIName != "SmartAI")
218 {
219 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature entry ({}) guid ({}) is not using SmartAI, skipped loading.", creature->id, -temp.entryOrGuid);
220 continue;
221 }
222 break;
223 }
225 {
226 GameObjectData const* gameObject = sObjectMgr->GetGameObjectData(uint64(-temp.entryOrGuid));
227 if (!gameObject)
228 {
229 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GameObject guid ({}) does not exist, skipped loading.", -temp.entryOrGuid);
230 continue;
231 }
232
233 GameObjectTemplate const* gameObjectInfo = sObjectMgr->GetGameObjectTemplate(gameObject->id);
234 if (!gameObjectInfo)
235 {
236 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GameObject entry ({}) guid ({}) does not exist, skipped loading.", gameObject->id, -temp.entryOrGuid);
237 continue;
238 }
239
240 if (gameObjectInfo->AIName != "SmartGameObjectAI")
241 {
242 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GameObject entry ({}) guid ({}) is not using SmartGameObjectAI, skipped loading.", gameObject->id, -temp.entryOrGuid);
243 continue;
244 }
245 break;
246 }
247 default:
248 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GUID-specific scripting not yet implemented for source_type {}", (uint32)source_type);
249 continue;
250 }
251 }
252
253 temp.source_type = source_type;
254 temp.event_id = fields[2].GetUInt16();
255 temp.link = fields[3].GetUInt16();
256
257 bool invalidDifficulties = false;
258 for (std::string_view token : Trinity::Tokenize(fields[4].GetStringView(), ',', false))
259 {
260 std::optional<std::underlying_type_t<Difficulty>> tokenValue = Trinity::StringTo<std::underlying_type_t<Difficulty>>(token);
261 if (!tokenValue.has_value())
262 {
263 invalidDifficulties = true;
264 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Invalid difficulties for entryorguid ({}) source_type ({}) id ({}), skipped loading.",
265 temp.entryOrGuid, temp.GetScriptType(), temp.event_id);
266 break;
267 }
268
269 Difficulty difficultyId = Difficulty(tokenValue.value());
270 if (difficultyId && !sDifficultyStore.LookupEntry(difficultyId))
271 {
272 invalidDifficulties = true;
273 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Invalid difficulty id ({}) for entryorguid ({}) source_type ({}) id ({}), skipped loading.",
274 difficultyId, temp.entryOrGuid, temp.GetScriptType(), temp.event_id);
275 break;
276 }
277
278 temp.Difficulties.push_back(difficultyId);
279 }
280
281 if (invalidDifficulties)
282 continue;
283
284 temp.event.type = (SMART_EVENT)fields[5].GetUInt8();
285 temp.event.event_phase_mask = fields[6].GetUInt16();
286 temp.event.event_chance = fields[7].GetUInt8();
287 temp.event.event_flags = fields[8].GetUInt16();
288
289 temp.event.raw.param1 = fields[9].GetUInt32();
290 temp.event.raw.param2 = fields[10].GetUInt32();
291 temp.event.raw.param3 = fields[11].GetUInt32();
292 temp.event.raw.param4 = fields[12].GetUInt32();
293 temp.event.raw.param5 = fields[13].GetUInt32();
294
295 temp.event.param_string = fields[14].GetString();
296
297 temp.action.type = (SMART_ACTION)fields[15].GetUInt8();
298 temp.action.raw.param1 = fields[16].GetUInt32();
299 temp.action.raw.param2 = fields[17].GetUInt32();
300 temp.action.raw.param3 = fields[18].GetUInt32();
301 temp.action.raw.param4 = fields[19].GetUInt32();
302 temp.action.raw.param5 = fields[20].GetUInt32();
303 temp.action.raw.param6 = fields[21].GetUInt32();
304 temp.action.raw.param7 = fields[22].GetUInt32();
305 temp.action.param_string = fields[23].GetString();
306
307 temp.target.type = (SMARTAI_TARGETS)fields[24].GetUInt8();
308 temp.target.raw.param1 = fields[25].GetUInt32();
309 temp.target.raw.param2 = fields[26].GetUInt32();
310 temp.target.raw.param3 = fields[27].GetUInt32();
311 temp.target.raw.param4 = fields[28].GetUInt32();
312 temp.target.param_string = fields[29].GetString();
313 temp.target.x = fields[30].GetFloat();
314 temp.target.y = fields[31].GetFloat();
315 temp.target.z = fields[32].GetFloat();
316 temp.target.o = fields[33].GetFloat();
317
318 //check target
319 if (!IsTargetValid(temp))
320 continue;
321
322 // check all event and action params
323 if (!IsEventValid(temp))
324 continue;
325
326 // specific check for timed events
327 switch (temp.event.type)
328 {
340 {
342 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Entry {} SourceType {}, Event {}, Missing Repeat flag.",
343 temp.entryOrGuid, temp.GetScriptType(), temp.event_id);
344 }
345 break;
348 {
350 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Entry {} SourceType {}, Event {}, Missing Repeat flag.",
351 temp.entryOrGuid, temp.GetScriptType(), temp.event_id);
352 }
353 break;
356 {
358 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Entry {} SourceType {}, Event {}, Missing Repeat flag.",
359 temp.entryOrGuid, temp.GetScriptType(), temp.event_id);
360 }
361 break;
362 default:
363 break;
364 }
365
366 // creature entry / guid not found in storage, create empty event list for it and increase counters
367 if (mEventMap[source_type].find(temp.entryOrGuid) == mEventMap[source_type].end())
368 {
369 ++count;
370 SmartAIEventList eventList;
371 mEventMap[source_type][temp.entryOrGuid] = eventList;
372 }
373 // store the new event
374 mEventMap[source_type][temp.entryOrGuid].push_back(temp);
375 }
376 while (result->NextRow());
377
378 // Post Loading Validation
379 for (SmartAIEventMap& eventmap : mEventMap)
380 {
381 for (std::pair<int64 const, SmartAIEventList>& eventlistpair : eventmap)
382 {
383 for (SmartScriptHolder const& e : eventlistpair.second)
384 {
385 if (e.link)
386 {
387 if (!FindLinkedEvent(eventlistpair.second, e.link))
388 {
389 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Entry {} SourceType {}, Event {}, Link Event {} not found or invalid.",
390 e.entryOrGuid, e.GetScriptType(), e.event_id, e.link);
391 }
392 }
393
394 if (e.GetEventType() == SMART_EVENT_LINK)
395 {
396 if (!FindLinkedSourceEvent(eventlistpair.second, e.event_id))
397 {
398 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Entry {} SourceType {}, Event {}, Link Source Event not found or invalid. Event will never trigger.",
399 e.entryOrGuid, e.GetScriptType(), e.event_id);
400 }
401 }
402 }
403 }
404 }
405
406 TC_LOG_INFO("server.loading", ">> Loaded {} SmartAI scripts in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
407
409}
410
412{
413 SmartAIEventList temp;
414 if (mEventMap[uint32(type)].find(entry) != mEventMap[uint32(type)].end())
415 return mEventMap[uint32(type)][entry];
416 else
417 {
418 if (entry > 0)//first search is for guid (negative), do not drop error if not found
419 TC_LOG_DEBUG("scripts.ai", "SmartAIMgr::GetScript: Could not load Script for Entry {} ScriptType {}.", entry, uint32(type));
420 return temp;
421 }
422}
423
425{
426 SmartAIEventList::iterator itr = std::find_if(list.begin(), list.end(),
427 [eventId](SmartScriptHolder& source) { return source.link == eventId; });
428
429 if (itr != list.end())
430 return *itr;
431
432 static SmartScriptHolder SmartScriptHolderDummy;
433 return SmartScriptHolderDummy;
434}
435
437{
438 SmartAIEventList::iterator itr = std::find_if(list.begin(), list.end(),
439 [link](SmartScriptHolder& linked) { return linked.event_id == link && linked.GetEventType() == SMART_EVENT_LINK; });
440
441 if (itr != list.end())
442 return *itr;
443
444 static SmartScriptHolder SmartScriptHolderDummy;
445 return SmartScriptHolderDummy;
446}
447
449{
450 switch (event)
451 { // white list of events that actually have an invoker passed to them
454 case SMART_EVENT_KILL:
499 return true;
500 default:
501 return false;
502 }
503}
504
506{
507 if (std::abs(e.target.o) > 2 * float(M_PI))
508 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has abs(`target.o` = {}) > 2*PI (orientation is expressed in radians)",
510
511 switch (e.GetTargetType())
512 {
515 {
516 if (e.target.unitDistance.creature && !sObjectMgr->GetCreatureTemplate(e.target.unitDistance.creature))
517 {
518 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Creature entry {} as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.unitDistance.creature);
519 return false;
520 }
521 break;
522 }
525 {
526 if (e.target.goDistance.entry && !sObjectMgr->GetGameObjectTemplate(e.target.goDistance.entry))
527 {
528 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent GameObject entry {} as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.goDistance.entry);
529 return false;
530 }
531 break;
532 }
534 {
536 return false;
537
539 CreatureData const* data = sObjectMgr->GetCreatureData(guid);
540 if (!data)
541 {
542 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} using invalid creature guid {} as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), guid);
543 return false;
544 }
545 else if (e.target.unitGUID.entry && e.target.unitGUID.entry != data->id)
546 {
547 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} using invalid creature entry {} (expected {}) for guid {} as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.unitGUID.entry, data->id, guid);
548 return false;
549 }
550 break;
551 }
553 {
555 return false;
556
558 GameObjectData const* data = sObjectMgr->GetGameObjectData(guid);
559 if (!data)
560 {
561 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} using invalid gameobject guid {} as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), guid);
562 return false;
563 }
564 else if (e.target.goGUID.entry && e.target.goGUID.entry != data->id)
565 {
566 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} using invalid gameobject entry {} (expected {}) for guid {} as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.target.goGUID.entry, data->id, guid);
567 return false;
568 }
569 break;
570 }
573 {
574 if (e.target.playerDistance.dist == 0)
575 {
576 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has maxDist 0 as target_param1, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
577 return false;
578 }
579 break;
580 }
585 {
586 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invoker target, but event does not provide any invoker!", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
587 return false;
588 }
589 break;
595 break;
599 break;
601 {
603 {
604 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invalid alive state {}", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType(), e.target.unitClosest.findCreatureAliveState);
605 return false;
606 }
607 break;
608 }
611 break;
614 break;
617 break;
629 break;
630 default:
631 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Not handled target_type({}), Entry {} SourceType {} Event {} Action {}, skipped.", e.GetTargetType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
632 return false;
633 }
634
636 return false;
637
638 return true;
639}
640
642{
643 if (max < min)
644 {
645 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses min/max params wrong ({}/{}), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), min, max);
646 return false;
647 }
648 return true;
649}
650
652{
653 if (!data)
654 {
655 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Parameter can not be NULL, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
656 return false;
657 }
658 return true;
659}
660
662{
663 if (!sObjectMgr->GetCreatureTemplate(entry))
664 {
665 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Creature entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
666 return false;
667 }
668 return true;
669}
670
672{
673 if (!sObjectMgr->GetQuestTemplate(entry))
674 {
675 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Quest entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
676 return false;
677 }
678 return true;
679}
680
682{
683 if (!sObjectMgr->GetGameObjectTemplate(entry))
684 {
685 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent GameObject entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
686 return false;
687 }
688 return true;
689}
690
692{
693 if (!sSpellMgr->GetSpellInfo(entry, DIFFICULTY_NONE))
694 {
695 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Spell entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
696 return false;
697 }
698 return true;
699}
700
702{
703 if (!sItemStore.LookupEntry(entry))
704 {
705 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Item entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
706 return false;
707 }
708 return true;
709}
710
712{
713 if (!sEmotesTextStore.LookupEntry(entry))
714 {
715 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Text Emote entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
716 return false;
717 }
718 return true;
719}
720
722{
723 if (!sEmotesStore.LookupEntry(entry))
724 {
725 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Emote entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
726 return false;
727 }
728 return true;
729}
730
732{
733 if (!sSoundKitStore.LookupEntry(entry))
734 {
735 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Sound entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
736 return false;
737 }
738 return true;
739}
740
742{
743 if (!sAnimKitStore.LookupEntry(entry))
744 {
745 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent AnimKit entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
746 return false;
747 }
748 return true;
749}
750
752{
753 if (!sSpellVisualKitStore.LookupEntry(entry))
754 {
755 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent SpellVisualKit entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
756 return false;
757 }
758 return true;
759}
760
762{
763 size_t paramsStructSize = [&]() -> size_t
764 {
765 constexpr size_t NO_PARAMS = size_t(0);
766 switch (e.event.type)
767 {
772 case SMART_EVENT_AGGRO: return NO_PARAMS;
773 case SMART_EVENT_KILL: return sizeof(SmartEvent::kill);
774 case SMART_EVENT_DEATH: return NO_PARAMS;
775 case SMART_EVENT_EVADE: return NO_PARAMS;
776 case SMART_EVENT_SPELLHIT: return sizeof(SmartEvent::spellHit);
777 case SMART_EVENT_RANGE: return sizeof(SmartEvent::minMaxRepeat);
778 case SMART_EVENT_OOC_LOS: return sizeof(SmartEvent::los);
779 case SMART_EVENT_RESPAWN: return sizeof(SmartEvent::respawn);
785 case SMART_EVENT_REWARD_QUEST: return sizeof(SmartEvent::quest);
786 case SMART_EVENT_REACHED_HOME: return NO_PARAMS;
787 case SMART_EVENT_RECEIVE_EMOTE: return sizeof(SmartEvent::emote);
788 case SMART_EVENT_HAS_AURA: return sizeof(SmartEvent::aura);
789 case SMART_EVENT_TARGET_BUFFED: return sizeof(SmartEvent::aura);
790 case SMART_EVENT_RESET: return NO_PARAMS;
791 case SMART_EVENT_IC_LOS: return sizeof(SmartEvent::los);
794 case SMART_EVENT_CHARMED: return sizeof(SmartEvent::charm);
800 case SMART_EVENT_CORPSE_REMOVED: return NO_PARAMS;
801 case SMART_EVENT_AI_INIT: return NO_PARAMS;
802 case SMART_EVENT_DATA_SET: return sizeof(SmartEvent::dataSet);
804 case SMART_EVENT_TRANSPORT_ADDPLAYER: return NO_PARAMS;
806 case SMART_EVENT_TRANSPORT_REMOVE_PLAYER: return NO_PARAMS;
809 case SMART_EVENT_AREATRIGGER_ENTER: return NO_PARAMS;
810 case SMART_EVENT_QUEST_ACCEPTED: return NO_PARAMS;
811 case SMART_EVENT_QUEST_OBJ_COMPLETION: return NO_PARAMS;
812 case SMART_EVENT_QUEST_COMPLETION: return NO_PARAMS;
813 case SMART_EVENT_QUEST_REWARDED: return NO_PARAMS;
814 case SMART_EVENT_QUEST_FAIL: return NO_PARAMS;
815 case SMART_EVENT_TEXT_OVER: return sizeof(SmartEvent::textOver);
817 case SMART_EVENT_JUST_SUMMONED: return NO_PARAMS;
823 case SMART_EVENT_UPDATE: return sizeof(SmartEvent::minMaxRepeat);
824 case SMART_EVENT_LINK: return NO_PARAMS;
826 case SMART_EVENT_JUST_CREATED: return NO_PARAMS;
828 case SMART_EVENT_FOLLOW_COMPLETED: return NO_PARAMS;
834 case SMART_EVENT_ON_SPELLCLICK: return NO_PARAMS;
838 case SMART_EVENT_COUNTER_SET: return sizeof(SmartEvent::counter);
839 case SMART_EVENT_SCENE_START: return NO_PARAMS;
840 case SMART_EVENT_SCENE_TRIGGER: return NO_PARAMS;
841 case SMART_EVENT_SCENE_CANCEL: return NO_PARAMS;
842 case SMART_EVENT_SCENE_COMPLETE: return NO_PARAMS;
849 case SMART_EVENT_ON_DESPAWN: return NO_PARAMS;
850 case SMART_EVENT_SEND_EVENT_TRIGGER: return NO_PARAMS;
851 case SMART_EVENT_AREATRIGGER_EXIT: return NO_PARAMS;
852 default:
853 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} is using an event with no unused params specified in SmartAIMgr::CheckUnusedEventParams(), please report this.",
855 return sizeof(SmartEvent::raw);
856 }
857 }();
858
859 constexpr size_t rawCount = sizeof(SmartEvent::raw) / sizeof(uint32);
860 size_t paramsCount = paramsStructSize / sizeof(uint32);
861
862 for (size_t index = paramsCount; index < rawCount; index++)
863 {
864 uint32 value = ((uint32*)&e.event.raw)[index];
865 if (value != 0)
866 {
867 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused event_param{} with value {}, it should be 0.",
868 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), index + 1, value);
869 }
870 }
871
872 bool eventUsesStringParam = [&]
873 {
874 switch (e.GetEventType())
875 {
877 return true;
878 default:
879 break;
880 }
881
882 return false;
883 }();
884
885 if (!eventUsesStringParam && !e.event.param_string.empty())
886 {
887 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused event_param_string with value {}, it should be NULL.",
889 }
890
891 return true;
892}
893
895{
896 size_t paramsStructSize = [&]() -> size_t
897 {
898 constexpr size_t NO_PARAMS = size_t(0);
899 switch (e.action.type)
900 {
901 case SMART_ACTION_NONE: return NO_PARAMS;
902 case SMART_ACTION_TALK: return sizeof(SmartAction::talk);
905 case SMART_ACTION_SOUND: return sizeof(SmartAction::sound);
906 case SMART_ACTION_PLAY_EMOTE: return sizeof(SmartAction::emote);
907 case SMART_ACTION_FAIL_QUEST: return sizeof(SmartAction::quest);
910 case SMART_ACTION_ACTIVATE_GOBJECT: return NO_PARAMS;
912 case SMART_ACTION_CAST: return sizeof(SmartAction::cast);
922 case SMART_ACTION_EVADE: return sizeof(SmartAction::evade);
924 case SMART_ACTION_COMBAT_STOP: return NO_PARAMS;
926 case SMART_ACTION_FOLLOW: return sizeof(SmartAction::follow);
929 case SMART_ACTION_RESET_GOBJECT: return NO_PARAMS;
934 case SMART_ACTION_DIE: return NO_PARAMS;
935 case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: return NO_PARAMS;
942 case SMART_ACTION_SET_DATA: return sizeof(SmartAction::setData);
943 case SMART_ACTION_ATTACK_STOP: return NO_PARAMS;
945 case SMART_ACTION_SET_ACTIVE: return sizeof(SmartAction::active);
946 case SMART_ACTION_ATTACK_START: return NO_PARAMS;
948 case SMART_ACTION_KILL_UNIT: return NO_PARAMS;
950 case SMART_ACTION_WP_START: return sizeof(SmartAction::wpStart);
951 case SMART_ACTION_WP_PAUSE: return sizeof(SmartAction::wpPause);
952 case SMART_ACTION_WP_STOP: return sizeof(SmartAction::wpStop);
953 case SMART_ACTION_ADD_ITEM: return sizeof(SmartAction::item);
954 case SMART_ACTION_REMOVE_ITEM: return sizeof(SmartAction::item);
955 case SMART_ACTION_SET_RUN: return sizeof(SmartAction::setRun);
957 case SMART_ACTION_TELEPORT: return sizeof(SmartAction::teleport);
960 case SMART_ACTION_WP_RESUME: return NO_PARAMS;
961 case SMART_ACTION_SET_ORIENTATION: return NO_PARAMS;
963 case SMART_ACTION_PLAYMOVIE: return sizeof(SmartAction::movie);
966 case SMART_ACTION_EQUIP: return sizeof(SmartAction::equip);
967 case SMART_ACTION_CLOSE_GOSSIP: return NO_PARAMS;
970 case SMART_ACTION_CALL_SCRIPT_RESET: return NO_PARAMS;
973 case SMART_ACTION_SET_NPC_FLAG: return sizeof(SmartAction::flag);
974 case SMART_ACTION_ADD_NPC_FLAG: return sizeof(SmartAction::flag);
977 case SMART_ACTION_SELF_CAST: return sizeof(SmartAction::cast);
985 case SMART_ACTION_JUMP_TO_POS: return sizeof(SmartAction::jump);
989 case SMART_ACTION_SET_HOME_POS: return NO_PARAMS;
991 case SMART_ACTION_SET_ROOT: return sizeof(SmartAction::setRoot);
993 case SMART_ACTION_SET_POWER: return sizeof(SmartAction::power);
994 case SMART_ACTION_ADD_POWER: return sizeof(SmartAction::power);
1004 case SMART_ACTION_ADD_THREAT: return sizeof(SmartAction::threat);
1009 case SMART_ACTION_SCENE_PLAY: return sizeof(SmartAction::scene);
1010 case SMART_ACTION_SCENE_CANCEL: return sizeof(SmartAction::scene);
1014 case SMART_ACTION_INVOKER_CAST: return sizeof(SmartAction::cast);
1020 case SMART_ACTION_SET_AI_ANIM_KIT: return NO_PARAMS;
1021 case SMART_ACTION_SET_HOVER: return sizeof(SmartAction::setHover);
1031 case SMART_ACTION_DO_ACTION: return sizeof(SmartAction::doAction);
1033 case SMART_ACTION_CREDIT_QUEST_OBJECTIVE_TALK_TO: return NO_PARAMS;
1037 case SMART_ACTION_EXIT_VEHICLE: return NO_PARAMS;
1038 case SMART_ACTION_FALL: return sizeof(SmartAction::fall);
1039 default:
1040 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} is using an action with no unused params specified in SmartAIMgr::CheckUnusedActionParams(), please report this.",
1042 return sizeof(SmartAction::raw);
1043 }
1044 }();
1045
1046 constexpr size_t rawCount = sizeof(SmartAction::raw) / sizeof(uint32);
1047 size_t paramsCount = paramsStructSize / sizeof(uint32);
1048
1049 for (size_t index = paramsCount; index < rawCount; index++)
1050 {
1051 uint32 value = ((uint32*)&e.action.raw)[index];
1052 if (value != 0)
1053 {
1054 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused action_param{} with value {}, it should be 0.",
1055 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), index + 1, value);
1056 }
1057 }
1058
1059 bool actionUsesStringParam = [&]
1060 {
1061 switch (e.GetActionType())
1062 {
1064 return true;
1065 default:
1066 break;
1067 }
1068
1069 return false;
1070 }();
1071
1072 if (!actionUsesStringParam && !e.action.param_string.empty())
1073 {
1074 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused action_param_string with value {}, it should be NULL.",
1076 }
1077
1078 return true;
1079}
1080
1082{
1083 size_t paramsStructSize = [&]() -> size_t
1084 {
1085 constexpr size_t NO_PARAMS = size_t(0);
1086 switch (e.target.type)
1087 {
1088 case SMART_TARGET_NONE: return NO_PARAMS;
1089 case SMART_TARGET_SELF: return NO_PARAMS;
1090 case SMART_TARGET_VICTIM: return NO_PARAMS;
1095 case SMART_TARGET_ACTION_INVOKER: return NO_PARAMS;
1096 case SMART_TARGET_POSITION: return NO_PARAMS; //uses x,y,z,o
1100 case SMART_TARGET_STORED: return sizeof(SmartTarget::stored);
1104 case SMART_TARGET_INVOKER_PARTY: return NO_PARAMS;
1110 case SMART_TARGET_ACTION_INVOKER_VEHICLE: return NO_PARAMS;
1115 case SMART_TARGET_LOOT_RECIPIENTS: return NO_PARAMS;
1116 case SMART_TARGET_FARTHEST: return sizeof(SmartTarget::farthest);
1119 default:
1120 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} is using a target with no unused params specified in SmartAIMgr::CheckUnusedTargetParams(), please report this.",
1122 return sizeof(SmartTarget::raw);
1123 }
1124 }();
1125
1126 constexpr size_t rawCount = sizeof(SmartTarget::raw) / sizeof(uint32);
1127 size_t paramsCount = paramsStructSize / sizeof(uint32);
1128
1129 for (size_t index = paramsCount; index < rawCount; index++)
1130 {
1131 uint32 value = ((uint32*)&e.target.raw)[index];
1132 if (value != 0)
1133 {
1134 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused target_param{} with value {}, it should be 0.",
1135 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), index + 1, value);
1136 }
1137 }
1138
1139 bool targetUsesStringParam = [&]
1140 {
1141 switch (e.GetTargetType())
1142 {
1149 return true;
1150 default:
1151 break;
1152 }
1153
1154 return false;
1155 }();
1156
1157 if (!targetUsesStringParam && !e.target.param_string.empty())
1158 {
1159 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused target_param_string with value {}, it should be NULL.",
1161 }
1162
1163 return true;
1164}
1165
1167{
1168 if (e.event.type >= SMART_EVENT_END)
1169 {
1170 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event({}) has invalid event type ({}), skipped.", e.entryOrGuid, e.event_id, e.GetEventType());
1171 return false;
1172 }
1173
1174 // in SMART_SCRIPT_TYPE_TIMED_ACTIONLIST all event types are overriden by core
1176 {
1177 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {}, event type {} can not be used for Script type {}", e.entryOrGuid, e.GetEventType(), e.GetScriptType());
1178 return false;
1179 }
1180
1181 if (e.action.type <= 0 || e.action.type >= SMART_ACTION_END)
1182 {
1183 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has invalid action type ({}), skipped.", e.entryOrGuid, e.event_id, e.GetActionType());
1184 return false;
1185 }
1186
1188 {
1189 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has invalid phase mask ({}), skipped.", e.entryOrGuid, e.event_id, e.event.event_phase_mask);
1190 return false;
1191 }
1192
1194 {
1195 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has invalid event flags ({}), skipped.", e.entryOrGuid, e.event_id, e.event.event_flags);
1196 return false;
1197 }
1198
1200 {
1201 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has deprecated event flags ({}), skipped.", e.entryOrGuid, e.event_id, e.event.event_flags);
1202 return false;
1203 }
1204
1205 if (e.link && e.link == e.event_id)
1206 {
1207 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} SourceType {}, Event {}, Event is linking self (infinite loop), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id);
1208 return false;
1209 }
1210
1212 {
1213 e.event.type = SMART_EVENT_UPDATE_OOC;//force default OOC, can change when calling the script!
1215 return false;
1216
1218 return false;
1219 }
1220 else
1221 {
1222 switch (e.GetEventType())
1223 {
1224 case SMART_EVENT_UPDATE:
1229 case SMART_EVENT_RANGE:
1234 return false;
1235
1237 return false;
1238 break;
1241 if (e.event.spellHit.spell)
1242 {
1243 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.event.spellHit.spell, DIFFICULTY_NONE);
1244 if (!spellInfo)
1245 {
1246 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Spell entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell);
1247 return false;
1248 }
1249 if (e.event.spellHit.school && (e.event.spellHit.school & spellInfo->SchoolMask) != spellInfo->SchoolMask)
1250 {
1251 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses Spell entry {} with invalid school mask, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell);
1252 return false;
1253 }
1254 }
1256 return false;
1257 break;
1263 {
1264 if (!IsSpellValid(e, e.event.spellCast.spell))
1265 return false;
1266
1268 return false;
1269 break;
1270 }
1272 case SMART_EVENT_IC_LOS:
1274 return false;
1276 {
1277 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses hostilityMode with invalid value {} (max allowed value {}), skipped.",
1279 return false;
1280 }
1281
1283 break;
1286 {
1287 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Map entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map);
1288 return false;
1289 }
1291 {
1292 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Area entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area);
1293 return false;
1294 }
1295 break;
1298 return false;
1299 break;
1301 {
1303 return false;
1304
1305 if (!NotNULL(e, e.event.missingBuff.radius))
1306 return false;
1307
1309 return false;
1310 break;
1311 }
1312 case SMART_EVENT_KILL:
1314 return false;
1315
1317 return false;
1318
1320 break;
1323 {
1324 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Spell entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.spellHit.spell);
1325 return false;
1326 }
1327
1329 return false;
1330 break;
1334 return false;
1335 break;
1340 return false;
1341
1343 return false;
1344 break;
1347 if (e.event.quest.quest && !IsQuestValid(e, e.event.quest.quest))
1348 return false;
1349
1350 if (!IsMinMaxValid(e, e.event.quest.cooldownMin, e.event.quest.cooldownMax))
1351 return false;
1352 break;
1354 {
1355 if (e.event.emote.emote && !IsTextEmoteValid(e, e.event.emote.emote))
1356 return false;
1357
1358 if (!IsMinMaxValid(e, e.event.emote.cooldownMin, e.event.emote.cooldownMax))
1359 return false;
1360 break;
1361 }
1364 {
1365 if (!IsSpellValid(e, e.event.aura.spell))
1366 return false;
1367
1369 return false;
1370 break;
1371 }
1373 {
1375 return false;
1376 break;
1377 }
1379 {
1381 {
1382 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses invalid Motion type {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.movementInform.type);
1383 return false;
1384 }
1385 break;
1386 }
1388 {
1390 return false;
1391 break;
1392 }
1395 return false;
1396 break;
1399 {
1400 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
1401 if (e.event.gameEvent.gameEventId >= events.size() || !events[e.event.gameEvent.gameEventId].isValid())
1402 return false;
1403 break;
1404 }
1407 return false;
1408
1410 {
1411 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has pct value above 100, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
1412 return false;
1413 }
1414
1415 switch (e.GetTargetType())
1416 {
1424 break;
1427 return false;
1428 break;
1429 default:
1430 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses invalid target_type {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
1431 return false;
1432 }
1433 break;
1435 if (e.event.distance.guid == 0 && e.event.distance.entry == 0)
1436 {
1437 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE did not provide creature guid or entry, skipped.");
1438 return false;
1439 }
1440
1441 if (e.event.distance.guid != 0 && e.event.distance.entry != 0)
1442 {
1443 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE provided both an entry and guid, skipped.");
1444 return false;
1445 }
1446
1447 if (e.event.distance.guid != 0 && !sObjectMgr->GetCreatureData(e.event.distance.guid))
1448 {
1449 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature guid {}, skipped.", e.event.distance.guid);
1450 return false;
1451 }
1452
1453 if (e.event.distance.entry != 0 && !sObjectMgr->GetCreatureTemplate(e.event.distance.entry))
1454 {
1455 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature entry {}, skipped.", e.event.distance.entry);
1456 return false;
1457 }
1458 break;
1460 if (e.event.distance.guid == 0 && e.event.distance.entry == 0)
1461 {
1462 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT did not provide gameobject guid or entry, skipped.");
1463 return false;
1464 }
1465
1466 if (e.event.distance.guid != 0 && e.event.distance.entry != 0)
1467 {
1468 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT provided both an entry and guid, skipped.");
1469 return false;
1470 }
1471
1472 if (e.event.distance.guid != 0 && !sObjectMgr->GetGameObjectData(e.event.distance.guid))
1473 {
1474 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject guid {}, skipped.", e.event.distance.guid);
1475 return false;
1476 }
1477
1478 if (e.event.distance.entry != 0 && !sObjectMgr->GetGameObjectTemplate(e.event.distance.entry))
1479 {
1480 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject entry {}, skipped.", e.event.distance.entry);
1481 return false;
1482 }
1483 break;
1486 return false;
1487
1488 if (e.event.counter.id == 0)
1489 {
1490 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid counter id {}, skipped.", e.event.counter.id);
1491 return false;
1492 }
1493
1494 if (e.event.counter.value == 0)
1495 {
1496 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid value {}, skipped.", e.event.counter.value);
1497 return false;
1498 }
1499 break;
1500 case SMART_EVENT_RESET:
1502 {
1503 // There might be SMART_TARGET_* cases where this should be allowed, they will be handled if needed
1504 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} uses event SMART_EVENT_RESET and action SMART_ACTION_CALL_SCRIPT_RESET, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id);
1505 return false;
1506 }
1507 break;
1510 break;
1512 if (!sObjectMgr->GetQuestObjective(e.event.questObjective.id))
1513 {
1514 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_QUEST_OBJ_COMPLETION using invalid objective id {}, skipped.", e.event.questObjective.id);
1515 return false;
1516 }
1517 break;
1522 break;
1523 case SMART_EVENT_LINK:
1534 case SMART_EVENT_AGGRO:
1535 case SMART_EVENT_DEATH:
1536 case SMART_EVENT_EVADE:
1557 break;
1558 // Unused
1566 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Unused event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
1567 return false;
1568 default:
1569 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Not handled event_type({}), Entry {} SourceType {} Event {} Action {}, skipped.", e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
1570 return false;
1571 }
1573 {
1574 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {}, uses SMART_EVENT_FLAG_ACTIONLIST_WAITS but is not part of a timed actionlist.",
1576 return false;
1577 }
1578 }
1579
1580 if (!CheckUnusedEventParams(e))
1581 return false;
1582
1583 switch (e.GetActionType())
1584 {
1585 case SMART_ACTION_TALK:
1588 return false;
1589 break;
1592 return false;
1593 break;
1596 {
1597 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Faction {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.faction.factionID);
1598 return false;
1599 }
1600 break;
1604 {
1605 if (e.action.morphOrMount.creature > 0 && !sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature))
1606 {
1607 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Creature entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.morphOrMount.creature);
1608 return false;
1609 }
1610
1612 {
1614 {
1615 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has ModelID set with also set CreatureId, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
1616 return false;
1617 }
1618 else if (!sCreatureDisplayInfoStore.LookupEntry(e.action.morphOrMount.model))
1619 {
1620 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Model id {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.morphOrMount.model);
1621 return false;
1622 }
1623 }
1624 }
1625 break;
1626 case SMART_ACTION_SOUND:
1627 if (!IsSoundValid(e, e.action.sound.sound))
1628 return false;
1629 TC_SAI_IS_BOOLEAN_VALID(e, e.action.sound.onlySelf);
1630 break;
1633 if (!IsEmoteValid(e, e.action.emote.emote))
1634 return false;
1635 break;
1637 if (e.action.animKit.animKit && !IsAnimKitValid(e, e.action.animKit.animKit))
1638 return false;
1639
1640 if (e.action.animKit.type > 3)
1641 {
1642 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses invalid AnimKit type {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.animKit.type);
1643 return false;
1644 }
1645 break;
1648 return false;
1649 break;
1652 return false;
1653
1655 break;
1657 if (!IsQuestValid(e, e.action.quest.quest))
1658 return false;
1659 break;
1661 {
1662 if (!sTaxiPathStore.LookupEntry(e.action.taxi.id))
1663 {
1664 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses invalid Taxi path ID {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.taxi.id);
1665 return false;
1666 }
1667 break;
1668 }
1670 {
1671 if (std::all_of(std::begin(e.action.randomEmote.emotes), std::end(e.action.randomEmote.emotes), [](uint32 emote) { return emote == 0; }))
1672 {
1673 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero emote",
1675 return false;
1676 }
1677
1678 for (uint32 emote : e.action.randomEmote.emotes)
1679 if (emote && !IsEmoteValid(e, emote))
1680 return false;
1681 break;
1682 }
1684 {
1685 if (std::all_of(std::begin(e.action.randTimedActionList.actionLists), std::end(e.action.randTimedActionList.actionLists), [](uint32 actionList) { return actionList == 0; }))
1686 {
1687 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero action list",
1689 return false;
1690 }
1691 break;
1692 }
1694 {
1695 if (std::all_of(std::begin(e.action.closestWaypointFromList.wps), std::end(e.action.closestWaypointFromList.wps), [](uint32 wp) { return wp == 0; }))
1696 {
1697 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero waypoint id",
1699 return false;
1700 }
1701 break;
1702 }
1704 {
1705 if (std::all_of(std::begin(e.action.randomSound.sounds), std::end(e.action.randomSound.sounds), [](uint32 sound) { return sound == 0; }))
1706 {
1707 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero sound",
1709 return false;
1710 }
1711
1712 for (uint32 sound : e.action.randomSound.sounds)
1713 if (sound && !IsSoundValid(e, sound))
1714 return false;
1715
1717 break;
1718 }
1719 case SMART_ACTION_CAST:
1720 {
1721 if (!IsSpellValid(e, e.action.cast.spell))
1722 return false;
1723
1724 for (SpellEffectInfo const& spellEffectInfo : sSpellMgr->AssertSpellInfo(e.action.cast.spell, DIFFICULTY_NONE)->GetEffects())
1725 {
1726 if (spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT) || spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT2))
1727 {
1728 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_CASTER)
1729 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Effect: SPELL_EFFECT_KILL_CREDIT: (SpellId: {} targetA: {} - targetB: {}) has invalid target for this Action",
1730 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.cast.spell, spellEffectInfo.TargetA.GetTarget(), spellEffectInfo.TargetB.GetTarget());
1731 }
1732 }
1734 {
1735 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses SMARTCAST_WAIT_FOR_HIT but is not part of actionlist event that has SMART_EVENT_FLAG_ACTIONLIST_WAITS",
1737 return false;
1738 }
1739 break;
1740 }
1742 {
1744 return false;
1745
1746 uint32 targetType = e.action.crossCast.targetType;
1747 if (targetType == SMART_TARGET_CREATURE_GUID || targetType == SMART_TARGET_GAMEOBJECT_GUID)
1748 {
1750 {
1752 return false;
1754 return false;
1755 }
1756
1759 SpawnData const* data = sObjectMgr->GetSpawnData(spawnType, guid);
1760 if (!data)
1761 {
1762 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} specifies invalid CasterTargetType guid ({},{})", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), AsUnderlyingType(spawnType), guid);
1763 return false;
1764 }
1765 else if (e.action.crossCast.targetParam2 && e.action.crossCast.targetParam2 != data->id)
1766 {
1767 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} specifies invalid entry {} (expected {}) for CasterTargetType guid ({},{})", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.crossCast.targetParam2, data->id, AsUnderlyingType(spawnType), guid);
1768 return false;
1769 }
1770 }
1772 {
1773 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses SMARTCAST_WAIT_FOR_HIT but is not part of actionlist event that has SMART_EVENT_FLAG_ACTIONLIST_WAITS",
1775 return false;
1776 }
1777 break;
1778 }
1781 {
1782 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has invoker cast action, but event does not provide any invoker!", e.entryOrGuid, e.GetScriptType(), e.GetEventType(), e.GetActionType());
1783 return false;
1784 }
1785 [[fallthrough]];
1787 if (!IsSpellValid(e, e.action.cast.spell))
1788 return false;
1790 {
1791 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses SMARTCAST_WAIT_FOR_HIT but is not part of actionlist event that has SMART_EVENT_FLAG_ACTIONLIST_WAITS",
1793 return false;
1794 }
1795 break;
1798 {
1799 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} attempts to set phase {}. Phase mask cannot be used past phase {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setEventPhase.phase, SMART_EVENT_PHASE_MAX - 1);
1800 return false;
1801 }
1802 break;
1805 {
1806 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} is incrementing phase by 0, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
1807 return false;
1808 }
1810 {
1811 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} attempts to increment phase by too large value, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
1812 return false;
1813 }
1814 break;
1817 return false;
1818
1820 break;
1822 {
1823 if (std::all_of(std::begin(e.action.randomPhase.phases), std::end(e.action.randomPhase.phases), [](uint32 phase) { return phase == 0; }))
1824 {
1825 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero phase",
1827 return false;
1828 }
1829
1830 if (std::any_of(std::begin(e.action.randomPhase.phases), std::end(e.action.randomPhase.phases), [](uint32 phase) { return phase >= SMART_EVENT_PHASE_MAX; }))
1831 {
1832 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
1833 return false;
1834 }
1835 break;
1836 }
1837 case SMART_ACTION_RANDOM_PHASE_RANGE: //PhaseMin, PhaseMax
1838 {
1841 {
1842 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} attempts to set invalid phase, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
1843 return false;
1844 }
1845
1847 return false;
1848 break;
1849 }
1851 {
1853 return false;
1854
1856 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1857 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} creature summon: There is a summon spell for creature entry {} (SpellId: {}, effect: {})",
1858 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonCreature.creature, itr->second.first, itr->second.second);
1859
1861 {
1862 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses incorrect TempSummonType {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonCreature.type);
1863 return false;
1864 }
1865
1867 {
1869 return false;
1870
1871 bool propertiesFound = std::ranges::any_of(sSpellMgr->AssertSpellInfo(e.action.summonCreature.createdBySpell, DIFFICULTY_NONE)->GetEffects(),
1872 [](SpellEffectInfo const& spellEffectInfo)
1873 {
1874 return spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON) && sSummonPropertiesStore.HasRecord(spellEffectInfo.MiscValueB);
1875 });
1876
1877 if (!propertiesFound)
1878 {
1879 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Spell {} is not a summon creature spell.",
1881 return false;
1882 }
1883 }
1884 break;
1885 }
1887 {
1889 return false;
1890
1892 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1893 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Kill Credit: There is a killcredit spell for creatureEntry {} (SpellId: {} effect: {})",
1894 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.killedMonster.creature, itr->second.first, itr->second.second);
1895
1897 {
1898 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses incorrect TargetType {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.GetTargetType());
1899 return false;
1900 }
1901 break;
1902 }
1905 return false;
1906
1908 break;
1911 {
1912 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses incorrect Sheath state {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setSheath.sheath);
1913 return false;
1914 }
1915 break;
1917 {
1919 {
1920 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Creature {} Event {} Action {} uses invalid React State {}, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.react.state);
1921 return false;
1922 }
1923 break;
1924 }
1926 {
1928 return false;
1929
1931 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1932 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} gameobject summon: There is a summon spell for gameobject entry {} (SpellId: {}, effect: {})",
1933 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonGO.entry, itr->second.first, itr->second.second);
1934 break;
1935 }
1937 if (!IsItemValid(e, e.action.item.entry))
1938 return false;
1939
1940 if (!NotNULL(e, e.action.item.count))
1941 return false;
1942 break;
1944 {
1945 if (!IsItemValid(e, e.action.item.entry))
1946 return false;
1947
1948 if (!NotNULL(e, e.action.item.count))
1949 return false;
1950
1952 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1953 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Create Item: There is a create item spell for item {} (SpellId: {} effect: {})",
1954 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.item.entry, itr->second.first, itr->second.second);
1955 break;
1956 }
1958 if (!sMapStore.LookupEntry(e.action.teleport.mapID))
1959 {
1960 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Map entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.teleport.mapID);
1961 return false;
1962 }
1963 break;
1966 return false;
1968 break;
1970 {
1971 WaypointPath const* path = sWaypointMgr->GetPath(e.action.wpStart.pathID);
1972 if (!path || path->Nodes.empty())
1973 {
1974 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Creature {} Event {} Action {} uses non-existent WaypointPath id {}, skipped.", e.entryOrGuid, e.event_id, e.GetActionType(), e.action.wpStart.pathID);
1975 return false;
1976 }
1978 return false;
1979
1982 break;
1983 }
1985 {
1987 return false;
1988
1990 return false;
1991 break;
1992 }
1994 {
1996 return false;
1997 break;
1998 }
2003 {
2004 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Power {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.power.powerType);
2005 return false;
2006 }
2007 break;
2009 {
2010 uint32 eventId = e.action.gameEventStop.id;
2011
2012 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
2013 if (eventId < 1 || eventId >= events.size())
2014 {
2015 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent event, eventId {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.gameEventStop.id);
2016 return false;
2017 }
2018
2019 GameEventData const& eventData = events[eventId];
2020 if (!eventData.isValid())
2021 {
2022 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent event, eventId {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.gameEventStop.id);
2023 return false;
2024 }
2025 break;
2026 }
2028 {
2029 uint32 eventId = e.action.gameEventStart.id;
2030
2031 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
2032 if (eventId < 1 || eventId >= events.size())
2033 {
2034 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent event, eventId {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.gameEventStart.id);
2035 return false;
2036 }
2037
2038 GameEventData const& eventData = events[eventId];
2039 if (!eventData.isValid())
2040 {
2041 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent event, eventId {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.gameEventStart.id);
2042 return false;
2043 }
2044 break;
2045 }
2046 case SMART_ACTION_EQUIP:
2047 {
2049 {
2050 if (int8 equipId = static_cast<int8>(e.action.equip.entry))
2051 {
2052 EquipmentInfo const* eInfo = sObjectMgr->GetEquipmentInfo(e.entryOrGuid, equipId);
2053 if (!eInfo)
2054 {
2055 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id {} for creature {}, skipped.", equipId, e.entryOrGuid);
2056 return false;
2057 }
2058 }
2059
2060 auto isValidEquipmentSlot = [&](uint32 itemEntry, uint8 slot)
2061 {
2062 ItemEntry const* dbcItem = sItemStore.LookupEntry(itemEntry);
2063 if (!dbcItem)
2064 {
2065 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses unknown item {} (slot {}) for creature {}, skipped.", itemEntry, slot, e.entryOrGuid);
2066 return false;
2067 }
2068
2070 {
2071 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses item {} (slot {}) not equipable in a hand for creature {}, skipped.", itemEntry, slot, e.entryOrGuid);
2072 return false;
2073 }
2074
2075 return true;
2076 };
2077
2078 if (e.action.equip.slot1 && !isValidEquipmentSlot(e.action.equip.slot1, 0))
2079 return false;
2080
2081 if (e.action.equip.slot2 && !isValidEquipmentSlot(e.action.equip.slot2, 1))
2082 return false;
2083
2084 if (e.action.equip.slot3 && !isValidEquipmentSlot(e.action.equip.slot3, 2))
2085 return false;
2086 }
2087 break;
2088 }
2090 {
2091 if (e.action.setInstanceData.type > 1)
2092 {
2093 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses invalid data type {} (value range 0-1), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setInstanceData.type);
2094 return false;
2095 }
2096 else if (e.action.setInstanceData.type == 1)
2097 {
2099 {
2100 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses invalid boss state {} (value range 0-5), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.setInstanceData.data);
2101 return false;
2102 }
2103 }
2104 break;
2105 }
2107 {
2108 uint32 phaseId = e.action.ingamePhaseId.id;
2109 uint32 apply = e.action.ingamePhaseId.apply;
2110
2111 if (apply != 0 && apply != 1)
2112 {
2113 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_ID uses invalid apply value {} (Should be 0 or 1) for creature {}, skipped", apply, e.entryOrGuid);
2114 return false;
2115 }
2116
2117 if (!sPhaseStore.LookupEntry(phaseId))
2118 {
2119 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_ID uses invalid phaseid {} for creature {}, skipped", phaseId, e.entryOrGuid);
2120 return false;
2121 }
2122 break;
2123 }
2125 {
2126 uint32 phaseGroup = e.action.ingamePhaseGroup.groupId;
2128
2129 if (apply != 0 && apply != 1)
2130 {
2131 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid apply value {} (Should be 0 or 1) for creature {}, skipped", apply, e.entryOrGuid);
2132 return false;
2133 }
2134
2135 if (!sDB2Manager.GetPhasesForGroup(phaseGroup))
2136 {
2137 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid phase group id {} for creature {}, skipped", phaseGroup, e.entryOrGuid);
2138 return false;
2139 }
2140 break;
2141 }
2143 {
2144 if (!sObjectMgr->GetSceneTemplate(e.action.scene.sceneId))
2145 {
2146 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SCENE_PLAY uses sceneId {} but scene don't exist, skipped", e.action.scene.sceneId);
2147 return false;
2148 }
2149
2150 break;
2151 }
2153 {
2154 if (!sObjectMgr->GetSceneTemplate(e.action.scene.sceneId))
2155 {
2156 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SCENE_CANCEL uses sceneId {} but scene don't exist, skipped", e.action.scene.sceneId);
2157 return false;
2158 }
2159
2160 break;
2161 }
2163 {
2165 {
2166 TC_LOG_ERROR("sql.sql", "Entry {} SourceType {} Event {} Action {} specifies invalid spawn data ({},{})", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.respawnData.spawnType, e.action.respawnData.spawnId);
2167 return false;
2168 }
2169 break;
2170 }
2172 {
2174 {
2175 TC_LOG_ERROR("sql.sql", "Entry {} SourceType {} Event {} Action {} does not specify duration", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
2176 return false;
2177 }
2178
2179 break;
2180 }
2182 {
2183 if (!sCinematicSequencesStore.LookupEntry(e.action.cinematic.entry))
2184 {
2185 TC_LOG_ERROR("sql.sql", "SmartAIMgr: SMART_ACTION_PLAY_CINEMATIC Entry {} SourceType {} Event {} Action {} uses invalid entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.cinematic.entry);
2186 return false;
2187 }
2188
2189 break;
2190 }
2192 {
2194 {
2195 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not specify pause duration", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
2196 return false;
2197 }
2198
2200 break;
2201 }
2203 {
2205 {
2206 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses invalid movementType {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.movementSpeed.movementType);
2207 return false;
2208 }
2209
2211 {
2212 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses speed 0, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
2213 return false;
2214 }
2215
2216 break;
2217 }
2219 {
2220 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(e.action.overrideLight.zoneId);
2221 if (!areaEntry)
2222 {
2223 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent zoneId {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.overrideLight.zoneId);
2224 return false;
2225 }
2226
2227 if (areaEntry->ParentAreaID != 0 && areaEntry->GetFlags().HasFlag(AreaFlags::IsSubzone))
2228 {
2229 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses subzone (ID: {}) instead of zone, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.overrideLight.zoneId);
2230 return false;
2231 }
2232
2233 if (!sLightStore.LookupEntry(e.action.overrideLight.areaLightId))
2234 {
2235 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent areaLightId {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.overrideLight.areaLightId);
2236 return false;
2237 }
2238
2240 {
2241 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent overrideLightId {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.overrideLight.overrideLightId);
2242 return false;
2243 }
2244
2245 break;
2246 }
2248 {
2249 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(e.action.overrideWeather.zoneId);
2250 if (!areaEntry)
2251 {
2252 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent zoneId {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.overrideWeather.zoneId);
2253 return false;
2254 }
2255
2256 if (areaEntry->ParentAreaID != 0 && areaEntry->GetFlags().HasFlag(AreaFlags::IsSubzone))
2257 {
2258 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses subzone (ID: {}) instead of zone, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.overrideWeather.zoneId);
2259 return false;
2260 }
2261
2262 break;
2263 }
2265 {
2266 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Deprecated action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
2267 break;
2268 }
2270 {
2272 {
2273 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} is trying to set invalid HP percent {}, skipped.",
2275 return false;
2276 }
2277 break;
2278 }
2280 {
2282 break;
2283 }
2285 {
2287 break;
2288 }
2290 {
2292 break;
2293 }
2295 {
2297 break;
2298 }
2300 {
2302 break;
2303 }
2305 {
2307 break;
2308 }
2310 {
2312 break;
2313 }
2315 {
2317 break;
2318 }
2320 {
2322 break;
2323 }
2325 {
2328 break;
2329 }
2331 {
2333 break;
2334 }
2336 {
2339 break;
2340 }
2342 {
2344 break;
2345 }
2347 {
2349 break;
2350 }
2352 {
2354 break;
2355 }
2357 {
2359 break;
2360 }
2361 case SMART_ACTION_EVADE:
2362 {
2364 break;
2365 }
2367 {
2369 break;
2370 }
2372 {
2373 if (!sConversationDataStore->GetConversationTemplate(e.action.conversation.id))
2374 {
2375 TC_LOG_ERROR("sql.sql", "SmartAIMgr: SMART_ACTION_CREATE_CONVERSATION Entry {} SourceType {} Event {} Action {} uses invalid entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.conversation.id);
2376 return false;
2377 }
2378
2379 break;
2380 }
2382 {
2384 break;
2385 }
2387 {
2389 break;
2390 }
2392 {
2394 break;
2395 }
2397 {
2399 return false;
2400
2402 {
2403 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has gameObjectAction parameter out of range (max allowed {}, current value {}), skipped.",
2405 return false;
2406 }
2407 break;
2408 }
2413 case SMART_ACTION_DIE:
2456 case SMART_ACTION_FALL:
2457 break;
2459 {
2461 {
2462 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses incorrect TempSummonType {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.becomePersonalClone.type);
2463 return false;
2464 }
2465 break;
2466 }
2468 {
2470 break;
2471 }
2473 {
2474 if (Quest const* quest = sObjectMgr->GetQuestTemplate(e.action.quest.quest))
2475 {
2476 if (!quest->HasFlag(QUEST_FLAGS_COMPLETION_EVENT) && !quest->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER) && !quest->HasFlag(QUEST_FLAGS_TRACKING_EVENT))
2477 {
2478 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Flags for Quest entry {} does not include QUEST_FLAGS_COMPLETION_EVENT or QUEST_FLAGS_COMPLETION_AREA_TRIGGER or QUEST_FLAGS_TRACKING_EVENT, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest);
2479 return false;
2480 }
2481 }
2482 else
2483 {
2484 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent Quest entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest);
2485 return false;
2486 }
2487 break;
2488 }
2490 {
2492 {
2493 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-valid SourceType (only valid for SourceType {}), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), SMART_SCRIPT_TYPE_CREATURE);
2494 return false;
2495 }
2496 break;
2497 }
2499 {
2500 if (!sConversationDataStore->GetConversationTemplate(e.action.destroyConversation.id))
2501 {
2502 TC_LOG_ERROR("sql.sql", "SmartAIMgr: SMART_ACTION_DESTROY_CONVERSATION Entry {} SourceType {} Event {} Action {} uses invalid entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.destroyConversation.id);
2503 return false;
2504 }
2505
2507 break;
2508 }
2511 {
2513 {
2514 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses incorrect seat id (out of range 0 - {}), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), MAX_VEHICLE_SEATS - 1);
2515 return false;
2516 }
2517 break;
2518 }
2519 // Unused
2539 case SMART_ACTION_FLEE:
2541 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Unused action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
2542 return false;
2543 default:
2544 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Not handled action_type({}), event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
2545 return false;
2546 }
2547
2549 return false;
2550
2551 return true;
2552}
2553
2555{
2557 return true;
2558
2559 uint32 entry = 0;
2560
2562 {
2563 entry = e.event.textOver.creatureEntry;
2564 }
2565 else
2566 {
2567 switch (e.GetTargetType())
2568 {
2572 return true; // ignore
2573 default:
2574 if (e.entryOrGuid < 0)
2575 {
2577 CreatureData const* data = sObjectMgr->GetCreatureData(guid);
2578 if (!data)
2579 {
2580 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} using non-existent Creature guid {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), guid);
2581 return false;
2582 }
2583 else
2584 entry = data->id;
2585 }
2586 else
2587 entry = uint32(e.entryOrGuid);
2588 break;
2589 }
2590 }
2591
2592 if (!entry || !sCreatureTextMgr->TextExist(entry, uint8(id)))
2593 {
2594 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {}SourceType {} Event {} Action {} using non-existent Text id {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), id);
2595 return false;
2596 }
2597
2598 return true;
2599}
2600
2602{
2603 uint32 oldMSTime = getMSTime();
2604
2605 sSpellMgr->ForEachSpellInfo([this](SpellInfo const* spellInfo)
2606 {
2607 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2608 {
2609 if (spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON))
2610 SummonCreatureSpellStore.insert(std::make_pair(uint32(spellEffectInfo.MiscValue), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2611 else if (spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON_OBJECT_WILD))
2612 SummonGameObjectSpellStore.insert(std::make_pair(uint32(spellEffectInfo.MiscValue), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2613 else if (spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT) || spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT2))
2614 KillCreditSpellStore.insert(std::make_pair(uint32(spellEffectInfo.MiscValue), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2615 else if (spellEffectInfo.IsEffect(SPELL_EFFECT_CREATE_ITEM))
2616 CreateItemSpellStore.insert(std::make_pair(uint32(spellEffectInfo.ItemType), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2617 }
2618 });
2619
2620 TC_LOG_INFO("server.loading", ">> Loaded SmartAIMgr Helpers in {} ms", GetMSTimeDiffToNow(oldMSTime));
2621}
2622
2630
2632{
2633 return SummonCreatureSpellStore.equal_range(creatureEntry);
2634}
2635
2637{
2638 return SummonGameObjectSpellStore.equal_range(gameObjectEntry);
2639}
2640
2642{
2643 return KillCreditSpellStore.equal_range(killCredit);
2644}
2645
2650
2651ObjectGuidVector::ObjectGuidVector(ObjectVector const& objectVector) : _objectVector(objectVector)
2652{
2653 _guidVector.reserve(_objectVector.size());
2654 for (WorldObject* obj : _objectVector)
2655 _guidVector.push_back(obj->GetGUID());
2656}
2657
2659{
2660 _objectVector.clear();
2661
2662 for (ObjectGuid const& guid : _guidVector)
2663 if (WorldObject* obj = ObjectAccessor::GetWorldObject(ref, guid))
2664 _objectVector.push_back(obj);
2665}
#define sAreaTriggerDataStore
#define M_PI
Definition Common.h:118
#define sConversationDataStore
#define sCreatureTextMgr
DB2Storage< LightEntry > sLightStore("Light.db2", &LightLoadInfo::Instance)
DB2Storage< PhaseEntry > sPhaseStore("Phase.db2", &PhaseLoadInfo::Instance)
DB2Storage< DifficultyEntry > sDifficultyStore("Difficulty.db2", &DifficultyLoadInfo::Instance)
DB2Storage< ItemEntry > sItemStore("Item.db2", &ItemLoadInfo::Instance)
DB2Storage< EmotesTextEntry > sEmotesTextStore("EmotesText.db2", &EmotesTextLoadInfo::Instance)
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
DB2Storage< AnimKitEntry > sAnimKitStore("AnimKit.db2", &AnimKitLoadInfo::Instance)
DB2Storage< SpellVisualKitEntry > sSpellVisualKitStore("SpellVisualKit.db2", &SpellVisualKitLoadInfo::Instance)
DB2Storage< AreaTriggerEntry > sAreaTriggerStore("AreaTrigger.db2", &AreaTriggerLoadInfo::Instance)
DB2Storage< EmotesEntry > sEmotesStore("Emotes.db2", &EmotesLoadInfo::Instance)
DB2Storage< CreatureDisplayInfoEntry > sCreatureDisplayInfoStore("CreatureDisplayInfo.db2", &CreatureDisplayInfoLoadInfo::Instance)
DB2Storage< FactionTemplateEntry > sFactionTemplateStore("FactionTemplate.db2", &FactionTemplateLoadInfo::Instance)
DB2Storage< SoundKitEntry > sSoundKitStore("SoundKit.db2", &SoundKitLoadInfo::Instance)
DB2Storage< AreaTableEntry > sAreaTableStore("AreaTable.db2", &AreaTableLoadInfo::Instance)
DB2Storage< TaxiPathEntry > sTaxiPathStore("TaxiPath.db2", &TaxiPathLoadInfo::Instance)
DB2Storage< CinematicSequencesEntry > sCinematicSequencesStore("CinematicSequences.db2", &CinematicSequencesLoadInfo::Instance)
#define sDB2Manager
Definition DB2Stores.h:569
#define MAX_VEHICLE_SEATS
Difficulty
Definition DBCEnums.h:932
@ DIFFICULTY_NONE
Definition DBCEnums.h:933
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint8_t uint8
Definition Define.h:156
int8_t int8
Definition Define.h:152
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
uint32_t uint32
Definition Define.h:154
#define sGameEventMgr
@ TO_BE_DECIDED
constexpr std::array< InventoryType, 10 > InventoryTypesEquipable
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:181
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
#define TC_LOG_WARN(filterType__, message__,...)
Definition Log.h:187
bool IsInvalidMovementGeneratorType(uint8 const type)
@ TEMPSUMMON_MANUAL_DESPAWN
@ TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
#define sObjectMgr
Definition ObjectMgr.h:1885
@ QUEST_FLAGS_COMPLETION_AREA_TRIGGER
Definition QuestDef.h:220
@ QUEST_FLAGS_COMPLETION_EVENT
Definition QuestDef.h:219
@ QUEST_FLAGS_TRACKING_EVENT
Definition QuestDef.h:228
@ TARGET_UNIT_CASTER
@ SPELL_EFFECT_KILL_CREDIT
@ SPELL_EFFECT_SUMMON
@ SPELL_EFFECT_KILL_CREDIT2
@ SPELL_EFFECT_SUMMON_OBJECT_WILD
@ SPELL_EFFECT_CREATE_ITEM
@ MAX_POWERS
#define TC_SAI_IS_BOOLEAN_VALID(e, value)
SmartScriptType
@ SMART_SCRIPT_TYPE_TIMED_ACTIONLIST
@ SMART_SCRIPT_TYPE_MAX
@ SMART_SCRIPT_TYPE_CREATURE
@ SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY_CUSTOM
@ SMART_SCRIPT_TYPE_GAMEOBJECT
@ SMART_SCRIPT_TYPE_AREATRIGGER
@ SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY
@ SMART_SCRIPT_TYPE_EVENT
@ SMART_SCRIPT_TYPE_SCENE
@ SMART_SCRIPT_TYPE_QUEST
std::vector< SmartScriptHolder > SmartAIEventList
@ SMART_EVENT_FLAGS_DEPRECATED
@ SMART_EVENT_FLAG_ACTIONLIST_WAITS
@ SMART_EVENT_FLAGS_ALL
@ SMART_EVENT_FLAG_NOT_REPEATABLE
SMARTAI_TARGETS
@ SMART_TARGET_LOOT_RECIPIENTS
@ SMART_TARGET_CLOSEST_CREATURE
@ SMART_TARGET_CREATURE_DISTANCE
@ SMART_TARGET_HOSTILE_RANDOM_NOT_TOP
@ SMART_TARGET_INVOKER_PARTY
@ SMART_TARGET_CLOSEST_FRIENDLY
@ SMART_TARGET_CLOSEST_GAMEOBJECT
@ SMART_TARGET_VEHICLE_PASSENGER
@ SMART_TARGET_GAMEOBJECT_RANGE
@ SMART_TARGET_CREATURE_GUID
@ SMART_TARGET_PLAYER_RANGE
@ SMART_TARGET_CLOSEST_UNSPAWNED_GAMEOBJECT
@ SMART_TARGET_VICTIM
@ SMART_TARGET_GAMEOBJECT_DISTANCE
@ SMART_TARGET_CREATURE_RANGE
@ SMART_TARGET_CLOSEST_PLAYER
@ SMART_TARGET_HOSTILE_RANDOM
@ SMART_TARGET_GAMEOBJECT_GUID
@ SMART_TARGET_HOSTILE_SECOND_AGGRO
@ SMART_TARGET_OWNER_OR_SUMMONER
@ SMART_TARGET_SELF
@ SMART_TARGET_ACTION_INVOKER
@ SMART_TARGET_POSITION
@ SMART_TARGET_HOSTILE_LAST_AGGRO
@ SMART_TARGET_ACTION_INVOKER_VEHICLE
@ SMART_TARGET_FARTHEST
@ SMART_TARGET_THREAT_LIST
@ SMART_TARGET_CLOSEST_ENEMY
@ SMART_TARGET_NONE
@ SMART_TARGET_PLAYER_DISTANCE
@ SMART_TARGET_STORED
std::unordered_map< int64, SmartAIEventList > SmartAIEventMap
std::vector< WorldObject * > ObjectVector
const uint32 SmartAIEventMask[SMART_EVENT_END][2]
@ SMART_SCRIPT_RESPAWN_CONDITION_AREA
@ SMART_SCRIPT_RESPAWN_CONDITION_MAP
SMART_ACTION
@ SMART_ACTION_REMOVE_TIMED_EVENT
@ SMART_ACTION_NONE
@ SMART_ACTION_SET_GO_FLAG
@ SMART_ACTION_WP_RESUME
@ SMART_ACTION_UPDATE_TEMPLATE
@ SMART_ACTION_STORE_TARGET_LIST
@ SMART_ACTION_SET_HEALTH_REGEN
@ SMART_ACTION_ACTIVATE_GOBJECT
@ SMART_ACTION_FORCE_DESPAWN
@ SMART_ACTION_GAME_EVENT_START
@ SMART_ACTION_CREATE_CONVERSATION
@ SMART_ACTION_DESTROY_CONVERSATION
@ SMART_ACTION_CALL_RANDOM_RANGE_TIMED_ACTIONLIST
@ SMART_ACTION_REMOVE_UNIT_FIELD_BYTES_1
@ SMART_ACTION_SET_DISABLE_GRAVITY
@ SMART_ACTION_SET_INST_DATA64
@ SMART_ACTION_SET_FACTION
@ SMART_ACTION_THREAT_SINGLE_PCT
@ SMART_ACTION_OFFER_QUEST
@ SMART_ACTION_OVERRIDE_LIGHT
@ SMART_ACTION_REMOVE_ALL_GAMEOBJECTS
@ SMART_ACTION_SET_UNIT_FIELD_BYTES_1
@ SMART_ACTION_CLOSE_GOSSIP
@ SMART_ACTION_DISABLE_EVADE
@ SMART_ACTION_ADD_GO_FLAG
@ SMART_ACTION_ADD_DYNAMIC_FLAG
@ SMART_ACTION_KILL_UNIT
@ SMART_ACTION_LOAD_EQUIPMENT
@ SMART_ACTION_END
@ SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS
@ SMART_ACTION_ATTACK_START
@ SMART_ACTION_SET_UNIT_FLAG
@ SMART_ACTION_BECOME_PERSONAL_CLONE_FOR_PLAYER
@ SMART_ACTION_CALL_GROUPEVENTHAPPENS
@ SMART_ACTION_MOUNT_TO_ENTRY_OR_MODEL
@ SMART_ACTION_INVOKER_CAST
@ SMART_ACTION_SCENE_PLAY
@ SMART_ACTION_JUMP_TO_POS
@ SMART_ACTION_CALL_RANDOM_TIMED_ACTIONLIST
@ SMART_ACTION_SEND_GOSSIP_MENU
@ SMART_ACTION_SET_COUNTER
@ SMART_ACTION_FLEE_FOR_ASSIST
@ SMART_ACTION_EQUIP
@ SMART_ACTION_SET_ROOT
@ SMART_ACTION_ATTACK_STOP
@ SMART_ACTION_SUMMON_GO
@ SMART_ACTION_SET_HOVER
@ SMART_ACTION_WP_PAUSE
@ SMART_ACTION_SIMPLE_TALK
@ SMART_ACTION_REMOVE_AURAS_BY_TYPE
@ SMART_ACTION_CAST
@ SMART_ACTION_SPAWN_SPAWNGROUP
@ SMART_ACTION_ALLOW_COMBAT_MOVEMENT
@ SMART_ACTION_ADD_AURA
@ SMART_ACTION_THREAT_ALL_PCT
@ SMART_ACTION_SOUND
@ SMART_ACTION_SET_MOVEMENT_SPEED
@ SMART_ACTION_PLAY_CINEMATIC
@ SMART_ACTION_ADD_NPC_FLAG
@ SMART_ACTION_EVADE
@ SMART_ACTION_FAIL_QUEST
@ SMART_ACTION_INTERRUPT_SPELL
@ SMART_ACTION_ENTER_VEHICLE
@ SMART_ACTION_ADD_POWER
@ SMART_ACTION_REMOVE_DYNAMIC_FLAG
@ SMART_ACTION_RANDOM_SOUND
@ SMART_ACTION_SET_IMMUNE_PC
@ SMART_ACTION_SCENE_CANCEL
@ SMART_ACTION_SET_AI_ANIM_KIT
@ SMART_ACTION_SET_POWER
@ SMART_ACTION_SEND_TARGET_TO_TARGET
@ SMART_ACTION_SET_INGAME_PHASE_ID
@ SMART_ACTION_REMOVE_POWER
@ SMART_ACTION_SET_DYNAMIC_FLAG
@ SMART_ACTION_FALL
@ SMART_ACTION_GO_SET_GO_STATE
@ SMART_ACTION_MOVE_OFFSET
@ SMART_ACTION_REMOVE_ITEM
@ SMART_ACTION_SEND_GO_CUSTOM_ANIM
@ SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL
@ SMART_ACTION_REMOVE_UNIT_FLAG
@ SMART_ACTION_RANDOM_PHASE
@ SMART_ACTION_SET_EMOTE_STATE
@ SMART_ACTION_CROSS_CAST
@ SMART_ACTION_WP_STOP
@ SMART_ACTION_GAME_EVENT_STOP
@ SMART_ACTION_CALL_KILLEDMONSTER
@ SMART_ACTION_TRIGGER_GAME_EVENT
@ SMART_ACTION_TALK
@ SMART_ACTION_CALL_SCRIPT_RESET
@ SMART_ACTION_SET_DATA
@ SMART_ACTION_PLAY_SPELL_VISUAL_KIT
@ SMART_ACTION_WP_START
@ SMART_ACTION_BOARD_PASSENGER
@ SMART_ACTION_COMBAT_STOP
@ SMART_ACTION_EXIT_VEHICLE
@ SMART_ACTION_SET_INGAME_PHASE_GROUP
@ SMART_ACTION_SET_RUN
@ SMART_ACTION_ACTIVATE_GAMEOBJECT
@ SMART_ACTION_ADD_TO_STORED_TARGET_LIST
@ SMART_ACTION_SET_HEALTH_PCT
@ SMART_ACTION_AUTO_ATTACK
@ SMART_ACTION_SET_INVINCIBILITY_HP_LEVEL
@ SMART_ACTION_SET_VISIBILITY
@ SMART_ACTION_RANDOM_PHASE_RANGE
@ SMART_ACTION_GO_SET_LOOT_STATE
@ SMART_ACTION_CREDIT_QUEST_OBJECTIVE_TALK_TO
@ SMART_ACTION_SELF_CAST
@ SMART_ACTION_SET_SWIM
@ SMART_ACTION_SET_SIGHT_DIST
@ SMART_ACTION_SET_INST_DATA
@ SMART_ACTION_PLAY_ANIMKIT
@ SMART_ACTION_REMOVE_GO_FLAG
@ SMART_ACTION_CALL_FOR_HELP
@ SMART_ACTION_SET_UNINTERACTIBLE
@ SMART_ACTION_OVERRIDE_WEATHER
@ SMART_ACTION_ADD_THREAT
@ SMART_ACTION_TELEPORT
@ SMART_ACTION_PLAYMOVIE
@ SMART_ACTION_TRIGGER_RANDOM_TIMED_EVENT
@ SMART_ACTION_FOLLOW
@ SMART_ACTION_PLAY_EMOTE
@ SMART_ACTION_SET_EVENT_PHASE
@ SMART_ACTION_DESPAWN_SPAWNGROUP
@ SMART_ACTION_SET_CORPSE_DELAY
@ SMART_ACTION_SET_SHEATH
@ SMART_ACTION_SET_ORIENTATION
@ SMART_ACTION_RESPAWN_BY_SPAWNID
@ SMART_ACTION_SET_NPC_FLAG
@ SMART_ACTION_MOVE_TO_POS
@ SMART_ACTION_RANDOM_EMOTE
@ SMART_ACTION_INC_EVENT_PHASE
@ SMART_ACTION_ENABLE_TEMP_GOBJ
@ SMART_ACTION_CREATE_TIMED_EVENT
@ SMART_ACTION_DIE
@ SMART_ACTION_RESET_SCRIPT_BASE_OBJECT
@ SMART_ACTION_REMOVE_NPC_FLAG
@ SMART_ACTION_COMPLETE_QUEST
@ SMART_ACTION_INSTALL_AI_TEMPLATE
@ SMART_ACTION_SUMMON_CREATURE
@ SMART_ACTION_RESET_GOBJECT
@ SMART_ACTION_CALL_TIMED_ACTIONLIST
@ SMART_ACTION_SET_IN_COMBAT_WITH_ZONE
@ SMART_ACTION_DO_ACTION
@ SMART_ACTION_SET_CAN_FLY
@ SMART_ACTION_SET_HOME_POS
@ SMART_ACTION_ADD_ITEM
@ SMART_ACTION_SET_ACTIVE
@ SMART_ACTION_SET_RANGED_MOVEMENT
@ SMART_ACTION_ACTIVATE_TAXI
@ SMART_ACTION_START_CLOSEST_WAYPOINT
@ SMART_ACTION_SUMMON_CREATURE_GROUP
@ SMART_ACTION_SET_REACT_STATE
@ SMART_ACTION_RANDOM_MOVE
@ SMART_ACTION_OVERRIDE_SCRIPT_BASE_OBJECT
@ SMART_ACTION_SET_IMMUNE_NPC
@ SMART_ACTION_TRIGGER_TIMED_EVENT
@ SMART_ACTION_REMOVEAURASFROMSPELL
@ SMART_ACTION_FLEE
@ SMART_ACTION_PAUSE_MOVEMENT
SMART_EVENT
@ SMART_EVENT_IC_LOS
@ SMART_EVENT_EVADE
@ SMART_EVENT_ACTION_DONE
@ SMART_EVENT_SUMMON_DESPAWNED
@ SMART_EVENT_SPELLHIT
@ SMART_EVENT_SCENE_START
@ SMART_EVENT_RECEIVE_EMOTE
@ SMART_EVENT_FRIENDLY_HEALTH_PCT
@ SMART_EVENT_QUEST_FAIL
@ SMART_EVENT_ON_AURA_APPLIED
@ SMART_EVENT_DATA_SET
@ SMART_EVENT_RECEIVE_HEAL
@ SMART_EVENT_TIMED_EVENT_TRIGGERED
@ SMART_EVENT_SCENE_COMPLETE
@ SMART_EVENT_CHARMED_TARGET
@ SMART_EVENT_TARGET_MANA_PCT
@ SMART_EVENT_QUEST_COMPLETION
@ SMART_EVENT_JUST_CREATED
@ SMART_EVENT_HEALTH_PCT
@ SMART_EVENT_EVENT_PHASE_CHANGE
@ SMART_EVENT_DISTANCE_GAMEOBJECT
@ SMART_EVENT_ON_SPELLCLICK
@ SMART_EVENT_MOVEMENTINFORM
@ SMART_EVENT_RANGE
@ SMART_EVENT_MANA_PCT
@ SMART_EVENT_PASSENGER_REMOVED
@ SMART_EVENT_ON_AURA_REMOVED
@ SMART_EVENT_INSTANCE_PLAYER_ENTER
@ SMART_EVENT_LINK
@ SMART_EVENT_WAYPOINT_PAUSED
@ SMART_EVENT_REACHED_HOME
@ SMART_EVENT_TRANSPORT_ADDCREATURE
@ SMART_EVENT_REWARD_QUEST
@ SMART_EVENT_END
@ SMART_EVENT_GO_EVENT_INFORM
@ SMART_EVENT_AREATRIGGER_EXIT
@ SMART_EVENT_GO_LOOT_STATE_CHANGED
@ SMART_EVENT_UPDATE_IC
@ SMART_EVENT_RESET
@ SMART_EVENT_SCENE_CANCEL
@ SMART_EVENT_JUST_SUMMONED
@ SMART_EVENT_CHARMED
@ SMART_EVENT_AI_INIT
@ SMART_EVENT_WAYPOINT_START
@ SMART_EVENT_ON_SPELL_CAST
@ SMART_EVENT_SPELLHIT_TARGET
@ SMART_EVENT_GAME_EVENT_START
@ SMART_EVENT_KILL
@ SMART_EVENT_TRANSPORT_REMOVE_PLAYER
@ SMART_EVENT_GOSSIP_HELLO
@ SMART_EVENT_GOSSIP_SELECT
@ SMART_EVENT_CORPSE_REMOVED
@ SMART_EVENT_PASSENGER_BOARDED
@ SMART_EVENT_SCENE_TRIGGER
@ SMART_EVENT_UPDATE
@ SMART_EVENT_AREATRIGGER_ENTER
@ SMART_EVENT_TRANSPORT_ADDPLAYER
@ SMART_EVENT_WAYPOINT_ENDED
@ SMART_EVENT_IS_BEHIND_TARGET
@ SMART_EVENT_UPDATE_OOC
@ SMART_EVENT_ACCEPTED_QUEST
@ SMART_EVENT_COUNTER_SET
@ SMART_EVENT_FRIENDLY_MISSING_BUFF
@ SMART_EVENT_WAYPOINT_RESUMED
@ SMART_EVENT_ON_SPELL_FAILED
@ SMART_EVENT_WAYPOINT_REACHED
@ SMART_EVENT_TARGET_BUFFED
@ SMART_EVENT_RESPAWN
@ SMART_EVENT_QUEST_ACCEPTED
@ SMART_EVENT_FRIENDLY_HEALTH
@ SMART_EVENT_QUEST_REWARDED
@ SMART_EVENT_TEXT_OVER
@ SMART_EVENT_DEATH
@ SMART_EVENT_TRANSPORT_RELOCATE
@ SMART_EVENT_GAME_EVENT_END
@ SMART_EVENT_DAMAGED
@ SMART_EVENT_FOLLOW_COMPLETED
@ SMART_EVENT_QUEST_OBJ_COMPLETION
@ SMART_EVENT_DISTANCE_CREATURE
@ SMART_EVENT_WAYPOINT_STOPPED
@ SMART_EVENT_SUMMONED_UNIT_DIES
@ SMART_EVENT_FRIENDLY_IS_CC
@ SMART_EVENT_SEND_EVENT_TRIGGER
@ SMART_EVENT_OOC_LOS
@ SMART_EVENT_ON_SPELL_START
@ SMART_EVENT_ON_DESPAWN
@ SMART_EVENT_AGGRO
@ SMART_EVENT_TARGET_HEALTH_PCT
@ SMART_EVENT_VICTIM_CASTING
@ SMART_EVENT_DAMAGED_TARGET
@ SMART_EVENT_HAS_AURA
@ SMART_EVENT_SUMMONED_UNIT
@ SMART_EVENT_PHASE_ALL
@ SMARTCAST_WAIT_FOR_HIT
@ SMART_EVENT_PHASE_MAX
const uint32 SmartAITypeMask[SMART_SCRIPT_TYPE_MAX][2]
std::pair< CacheSpellContainer::const_iterator, CacheSpellContainer::const_iterator > CacheSpellContainerBounds
SpawnObjectType
Definition SpawnData.h:35
@ SPAWN_TYPE_GAMEOBJECT
Definition SpawnData.h:37
@ SPAWN_TYPE_CREATURE
Definition SpawnData.h:36
#define sSpellMgr
Definition SpellMgr.h:812
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
@ REACT_AGGRESSIVE
#define MAX_MOVE_TYPE
@ MAX_SHEATH_STATE
Definition UnitDefines.h:86
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
#define sWaypointMgr
@ WORLD_SEL_SMART_SCRIPTS
Class used to access individual fields of database query result.
Definition Field.h:94
float GetFloat() const noexcept
Definition Field.cpp:85
uint32 GetUInt32() const noexcept
Definition Field.cpp:57
uint16 GetUInt16() const noexcept
Definition Field.cpp:43
uint8 GetUInt8() const noexcept
Definition Field.cpp:29
std::string GetString() const noexcept
Definition Field.cpp:113
int64 GetInt64() const noexcept
Definition Field.cpp:78
std::vector< GameEventData > GameEventDataMap
ObjectVector _objectVector
void UpdateObjects(WorldObject const &ref) const
ObjectGuidVector(ObjectVector const &objectVector)
uint64 LowType
Definition ObjectGuid.h:321
SmartAIEventMap mEventMap[SMART_SCRIPT_TYPE_MAX]
CacheSpellContainer SummonCreatureSpellStore
void UnLoadHelperStores()
CacheSpellContainerBounds GetSummonCreatureSpellContainerBounds(uint32 creatureEntry) const
SmartAIEventList GetScript(int32 entry, SmartScriptType type)
static bool IsTextEmoteValid(SmartScriptHolder const &e, uint32 entry)
bool IsTargetValid(SmartScriptHolder const &e)
static bool NotNULL(SmartScriptHolder const &e, uint32 data)
CacheSpellContainer CreateItemSpellStore
void LoadHelperStores()
static bool IsSoundValid(SmartScriptHolder const &e, uint32 entry)
static SmartScriptHolder & FindLinkedEvent(SmartAIEventList &list, uint32 link)
bool IsEventValid(SmartScriptHolder &e)
static bool IsGameObjectValid(SmartScriptHolder const &e, uint32 entry)
static bool CheckUnusedTargetParams(SmartScriptHolder const &e)
static bool IsAnimKitValid(SmartScriptHolder const &e, uint32 entry)
bool IsMinMaxValid(SmartScriptHolder const &e, uint32 min, uint32 max)
static bool EventHasInvoker(SMART_EVENT event)
static bool IsSpellVisualKitValid(SmartScriptHolder const &e, uint32 entry)
CacheSpellContainerBounds GetCreateItemSpellContainerBounds(uint32 itemId) const
CacheSpellContainer SummonGameObjectSpellStore
static bool IsQuestValid(SmartScriptHolder const &e, uint32 entry)
static bool IsCreatureValid(SmartScriptHolder const &e, uint32 entry)
static bool IsTextValid(SmartScriptHolder const &e, uint32 id)
CacheSpellContainerBounds GetSummonGameObjectSpellContainerBounds(uint32 gameObjectEntry) const
static bool CheckUnusedEventParams(SmartScriptHolder const &e)
static SmartAIMgr * instance()
void LoadSmartAIFromDB()
CacheSpellContainerBounds GetKillCreditSpellContainerBounds(uint32 killCredit) const
static bool CheckUnusedActionParams(SmartScriptHolder const &e)
static bool IsItemValid(SmartScriptHolder const &e, uint32 entry)
CacheSpellContainer KillCreditSpellStore
static SmartScriptHolder & FindLinkedSourceEvent(SmartAIEventList &list, uint32 eventId)
static bool IsEmoteValid(SmartScriptHolder const &e, uint32 entry)
static bool IsSpellValid(SmartScriptHolder const &e, uint32 entry)
uint32 const Id
Definition SpellInfo.h:328
uint32 SchoolMask
Definition SpellInfo.h:419
std::vector< SpellEffectInfo > const & GetEffects() const
Definition SpellInfo.h:587
TC_GAME_API WorldObject * GetWorldObject(WorldObject const &, ObjectGuid const &)
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition Util.cpp:57
struct advstd::ranges::Contains contains
EnumFlag< AreaFlags > GetFlags() const
std::string AIName
bool isValid() const
int8 InventoryType
std::string param_string
uint32 sounds[4]
uint32 targetParam2
struct SmartAction::@61::@148 scene
struct SmartAction::@61::@142 groupSpawn
struct SmartAction::@61::@70 questOffer
struct SmartAction::@61::@112 timeEvent
struct SmartAction::@61::@129 setRangedMovement
struct SmartAction::@61::@116 setunitByte
struct SmartAction::@61::@168 raw
struct SmartAction::@61::@66 morphOrMount
struct SmartAction::@61::@165 doAction
struct SmartAction::@61::@125 moveToPos
struct SmartAction::@61::@164 triggerGameEvent
struct SmartAction::@61::@137 closestWaypointFromList
uint32 gameObjectAction
struct SmartAction::@61::@63 talk
struct SmartAction::@61::@105 wpStop
struct SmartAction::@61::@97 moveRandom
struct SmartAction::@61::@132 goState
struct SmartAction::@61::@161 activateGameObject
struct SmartAction::@61::@92 forceDespawn
struct SmartAction::@61::@160 setUninteractible
SAIBool regenHealth
uint32 wps[SMART_ACTION_PARAM_COUNT]
SAIBool allowOverride
struct SmartAction::@61::@121 interruptSpellCasting
struct SmartAction::@61::@98 visibility
struct SmartAction::@61::@77 threat
struct SmartAction::@61::@158 setImmunePC
struct SmartAction::@61::@64 simpleTalk
struct SmartAction::@61::@71 react
struct SmartAction::@61::@76 threatPCT
uint32 emotes[SMART_ACTION_PARAM_COUNT]
SAIBool withDelayed
struct SmartAction::@61::@79 combatMove
struct SmartAction::@61::@103 wpStart
struct SmartAction::@61::@84 randomPhase
SAIBool withInstant
struct SmartAction::@61::@140 corpseDelay
struct SmartAction::@61::@81 incEventPhase
struct SmartAction::@61::@118 timedActionList
struct SmartAction::@61::@72 randomEmote
struct SmartAction::@61::@82 removeAura
struct SmartAction::@61::@95 ingamePhaseGroup
struct SmartAction::@61::@141 disableEvade
uint32 targetParam1
struct SmartAction::@61::@99 summonGO
struct SmartAction::@61::@128 sendTargetToTarget
struct SmartAction::@61::@138 moveOffset
SAIBool toRespawnPosition
struct SmartAction::@61::@75 summonCreature
struct SmartAction::@61::@150 movementSpeed
SAIBool useTalkTarget
struct SmartAction::@61::@93 invincHP
SAIBool uninteractible
struct SmartAction::@61::@123 fleeAssist
struct SmartAction::@61::@65 faction
struct SmartAction::@61::@120 randRangeTimedActionList
struct SmartAction::@61::@149 cinematic
uint32 spellVisualKitId
struct SmartAction::@61::@122 jump
struct SmartAction::@61::@156 setHealthPct
struct SmartAction::@61::@154 setHover
struct SmartAction::@61::@101 taxi
struct SmartAction::@61::@94 ingamePhaseId
struct SmartAction::@61::@155 evade
struct SmartAction::@61::@96 setData
struct SmartAction::@61::@133 creatureGroup
struct SmartAction::@61::@113 movie
struct SmartAction::@61::@85 randomPhaseRange
struct SmartAction::@61::@111 storeTargets
struct SmartAction::@61::@153 overrideWeather
struct SmartAction::@61::@124 enableTempGO
struct SmartAction::@61::@74 crossCast
SAIBool updateLevel
uint32 actionLists[SMART_ACTION_PARAM_COUNT]
SMART_ACTION type
struct SmartAction::@61::@100 active
struct SmartAction::@61::@157 conversation
uint32 phases[SMART_ACTION_PARAM_COUNT]
struct SmartAction::@61::@162 addToStoredTargets
struct SmartAction::@61::@130 setHealthRegen
struct SmartAction::@61::@163 becomePersonalClone
struct SmartAction::@61::@126 sendGossipMenu
struct SmartAction::@61::@131 setRoot
SAIBool onlyOwnedAuras
struct SmartAction::@61::@90 callHelp
uint32 overrideLightId
struct SmartAction::@61::@139 randomSound
struct SmartAction::@61::@108 setDisableGravity
struct SmartAction::@61::@104 wpPause
struct SmartAction::@61::@106 item
struct SmartAction::@61::@146 respawnData
struct SmartAction::@61::@143 loadEquipment
struct SmartAction::@61::@117 delunitByte
SAIBool disablePathfinding
struct SmartAction::@61::@166 enterVehicle
struct SmartAction::@61::@134 power
struct SmartAction::@61::@110 setCounter
struct SmartAction::@61::@78 autoAttack
struct SmartAction::@61::@159 setImmuneNPC
struct SmartAction::@61::@144 randomTimedEvent
struct SmartAction::@61::@152 overrideLight
SAIBool withEmote
SAIBool useSaiTargetAsGameEventSource
struct SmartAction::@61::@89 updateTemplate
struct SmartAction::@61::@87 setInstanceData
struct SmartAction::@61::@119 randTimedActionList
SAIBool directAdd
struct SmartAction::@61::@114 equip
struct SmartAction::@61::@102 fall
struct SmartAction::@61::@86 killedMonster
uint32 createdBySpell
struct SmartAction::@61::@136 gameEventStart
struct SmartAction::@61::@107 setRun
struct SmartAction::@61::@145 pauseMovement
struct SmartAction::@61::@167 destroyConversation
struct SmartAction::@61::@109 teleport
struct SmartAction::@61::@88 setInstanceData64
struct SmartAction::@61::@91 setSheath
struct SmartAction::@61::@73 cast
struct SmartAction::@61::@135 gameEventStop
struct SmartAction::@61::@127 setGoLootState
struct SmartAction::@61::@83 follow
struct SmartAction::@61::@80 setEventPhase
struct SmartAction::@61::@151 spellVisualKit
struct SmartEvent::@25::@48 textOver
uint32 event_flags
struct SmartEvent::@25::@34 friendlyCC
struct SmartEvent::@25::@52 gameEvent
struct SmartEvent::@25::@50 gossipHello
uint32 event_phase_mask
struct SmartEvent::@25::@56 friendlyHealthPct
struct SmartEvent::@25::@40 aura
struct SmartEvent::@25::@33 targetCasting
struct SmartEvent::@25::@49 timedEvent
struct SmartEvent::@25::@44 waypoint
std::string param_string
uint32 cooldownMax
struct SmartEvent::@25::@47 instancePlayerEnter
struct SmartEvent::@25::@54 eventInform
struct SmartEvent::@25::@42 movementInform
struct SmartEvent::@25::@60 raw
struct SmartEvent::@25::@31 respawn
struct SmartEvent::@25::@53 goLootStateChanged
struct SmartEvent::@25::@58 counter
struct SmartEvent::@25::@59 spellCast
struct SmartEvent::@25::@51 gossip
struct SmartEvent::@25::@28 kill
uint32 hostilityMode
Hostility mode of the event. 0: hostile, 1: not hostile, 2: any.
struct SmartEvent::@25::@46 transportRelocate
uint32 event_chance
SAIBool playerOnly
struct SmartEvent::@25::@45 transportAddCreature
struct SmartEvent::@25::@32 minMax
struct SmartEvent::@25::@30 los
uint32 creatureEntry
struct SmartEvent::@25::@36 summoned
struct SmartEvent::@25::@35 missingBuff
struct SmartEvent::@25::@38 questObjective
uint32 gameEventId
struct SmartEvent::@25::@55 doAction
uint32 textGroupID
uint32 cooldownMin
struct SmartEvent::@25::@29 spellHit
struct SmartEvent::@25::@41 charm
struct SmartEvent::@25::@57 distance
struct SmartEvent::@25::@27 minMaxRepeat
SAIBool onRemove
struct SmartEvent::@25::@43 dataSet
SMART_EVENT type
uint32 GetScriptType() const
uint32 GetEventType() const
uint32 GetTargetType() const
std::vector< Difficulty > Difficulties
SmartScriptType source_type
uint32 GetActionType() const
struct SmartTarget::@169::@186 owner
struct SmartTarget::@169::@175 unitDistance
std::string param_string
struct SmartTarget::@169::@176 playerDistance
SAIBool useCharmerOrOwner
struct SmartTarget::@169::@178 stored
struct SmartTarget::@169::@185 closestFriendly
struct SmartTarget::@169::@187 vehicle
struct SmartTarget::@169::@184 closestAttackable
struct SmartTarget::@169::@180 goGUID
struct SmartTarget::@169::@172 farthest
struct SmartTarget::@169::@177 playerRange
struct SmartTarget::@169::@183 goClosest
struct SmartTarget::@169::@182 unitClosest
struct SmartTarget::@169::@189 raw
struct SmartTarget::@169::@179 goRange
SMARTAI_TARGETS type
struct SmartTarget::@169::@171 hostilRandom
struct SmartTarget::@169::@188 threatList
struct SmartTarget::@169::@173 unitRange
uint32 findCreatureAliveState
struct SmartTarget::@169::@174 unitGUID
struct SmartTarget::@169::@181 goDistance
uint32 id
Definition SpawnData.h:135
std::vector< WaypointNode > Nodes