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;
1039 case SMART_ACTION_FALL: return sizeof(SmartAction::fall);
1040 default:
1041 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.",
1043 return sizeof(SmartAction::raw);
1044 }
1045 }();
1046
1047 constexpr size_t rawCount = sizeof(SmartAction::raw) / sizeof(uint32);
1048 size_t paramsCount = paramsStructSize / sizeof(uint32);
1049
1050 for (size_t index = paramsCount; index < rawCount; index++)
1051 {
1052 uint32 value = ((uint32*)&e.action.raw)[index];
1053 if (value != 0)
1054 {
1055 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused action_param{} with value {}, it should be 0.",
1056 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), index + 1, value);
1057 }
1058 }
1059
1060 bool actionUsesStringParam = [&]
1061 {
1062 switch (e.GetActionType())
1063 {
1065 return true;
1066 default:
1067 break;
1068 }
1069
1070 return false;
1071 }();
1072
1073 if (!actionUsesStringParam && !e.action.param_string.empty())
1074 {
1075 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused action_param_string with value {}, it should be NULL.",
1077 }
1078
1079 return true;
1080}
1081
1083{
1084 size_t paramsStructSize = [&]() -> size_t
1085 {
1086 constexpr size_t NO_PARAMS = size_t(0);
1087 switch (e.target.type)
1088 {
1089 case SMART_TARGET_NONE: return NO_PARAMS;
1090 case SMART_TARGET_SELF: return NO_PARAMS;
1091 case SMART_TARGET_VICTIM: return NO_PARAMS;
1096 case SMART_TARGET_ACTION_INVOKER: return NO_PARAMS;
1097 case SMART_TARGET_POSITION: return NO_PARAMS; //uses x,y,z,o
1101 case SMART_TARGET_STORED: return sizeof(SmartTarget::stored);
1105 case SMART_TARGET_INVOKER_PARTY: return NO_PARAMS;
1111 case SMART_TARGET_ACTION_INVOKER_VEHICLE: return NO_PARAMS;
1116 case SMART_TARGET_LOOT_RECIPIENTS: return NO_PARAMS;
1117 case SMART_TARGET_FARTHEST: return sizeof(SmartTarget::farthest);
1120 default:
1121 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.",
1123 return sizeof(SmartTarget::raw);
1124 }
1125 }();
1126
1127 constexpr size_t rawCount = sizeof(SmartTarget::raw) / sizeof(uint32);
1128 size_t paramsCount = paramsStructSize / sizeof(uint32);
1129
1130 for (size_t index = paramsCount; index < rawCount; index++)
1131 {
1132 uint32 value = ((uint32*)&e.target.raw)[index];
1133 if (value != 0)
1134 {
1135 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused target_param{} with value {}, it should be 0.",
1136 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), index + 1, value);
1137 }
1138 }
1139
1140 bool targetUsesStringParam = [&]
1141 {
1142 switch (e.GetTargetType())
1143 {
1150 return true;
1151 default:
1152 break;
1153 }
1154
1155 return false;
1156 }();
1157
1158 if (!targetUsesStringParam && !e.target.param_string.empty())
1159 {
1160 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused target_param_string with value {}, it should be NULL.",
1162 }
1163
1164 return true;
1165}
1166
1168{
1169 if (e.event.type >= SMART_EVENT_END)
1170 {
1171 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event({}) has invalid event type ({}), skipped.", e.entryOrGuid, e.event_id, e.GetEventType());
1172 return false;
1173 }
1174
1175 // in SMART_SCRIPT_TYPE_TIMED_ACTIONLIST all event types are overriden by core
1177 {
1178 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {}, event type {} can not be used for Script type {}", e.entryOrGuid, e.GetEventType(), e.GetScriptType());
1179 return false;
1180 }
1181
1182 if (e.action.type <= 0 || e.action.type >= SMART_ACTION_END)
1183 {
1184 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has invalid action type ({}), skipped.", e.entryOrGuid, e.event_id, e.GetActionType());
1185 return false;
1186 }
1187
1189 {
1190 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has invalid phase mask ({}), skipped.", e.entryOrGuid, e.event_id, e.event.event_phase_mask);
1191 return false;
1192 }
1193
1195 {
1196 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has invalid event flags ({}), skipped.", e.entryOrGuid, e.event_id, e.event.event_flags);
1197 return false;
1198 }
1199
1201 {
1202 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has deprecated event flags ({}), skipped.", e.entryOrGuid, e.event_id, e.event.event_flags);
1203 return false;
1204 }
1205
1206 if (e.link && e.link == e.event_id)
1207 {
1208 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} SourceType {}, Event {}, Event is linking self (infinite loop), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id);
1209 return false;
1210 }
1211
1213 {
1214 e.event.type = SMART_EVENT_UPDATE_OOC;//force default OOC, can change when calling the script!
1216 return false;
1217
1219 return false;
1220 }
1221 else
1222 {
1223 switch (e.GetEventType())
1224 {
1225 case SMART_EVENT_UPDATE:
1230 case SMART_EVENT_RANGE:
1235 return false;
1236
1238 return false;
1239 break;
1242 if (e.event.spellHit.spell)
1243 {
1244 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.event.spellHit.spell, DIFFICULTY_NONE);
1245 if (!spellInfo)
1246 {
1247 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);
1248 return false;
1249 }
1250 if (e.event.spellHit.school && (e.event.spellHit.school & spellInfo->SchoolMask) != spellInfo->SchoolMask)
1251 {
1252 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);
1253 return false;
1254 }
1255 }
1257 return false;
1258 break;
1264 {
1265 if (!IsSpellValid(e, e.event.spellCast.spell))
1266 return false;
1267
1269 return false;
1270 break;
1271 }
1273 case SMART_EVENT_IC_LOS:
1275 return false;
1277 {
1278 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses hostilityMode with invalid value {} (max allowed value {}), skipped.",
1280 return false;
1281 }
1282
1284 break;
1287 {
1288 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);
1289 return false;
1290 }
1292 {
1293 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);
1294 return false;
1295 }
1296 break;
1299 return false;
1300 break;
1302 {
1304 return false;
1305
1306 if (!NotNULL(e, e.event.missingBuff.radius))
1307 return false;
1308
1310 return false;
1311 break;
1312 }
1313 case SMART_EVENT_KILL:
1315 return false;
1316
1318 return false;
1319
1321 break;
1324 {
1325 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);
1326 return false;
1327 }
1328
1330 return false;
1331 break;
1335 return false;
1336 break;
1341 return false;
1342
1344 return false;
1345 break;
1348 if (e.event.quest.quest && !IsQuestValid(e, e.event.quest.quest))
1349 return false;
1350
1351 if (!IsMinMaxValid(e, e.event.quest.cooldownMin, e.event.quest.cooldownMax))
1352 return false;
1353 break;
1355 {
1356 if (e.event.emote.emote && !IsTextEmoteValid(e, e.event.emote.emote))
1357 return false;
1358
1359 if (!IsMinMaxValid(e, e.event.emote.cooldownMin, e.event.emote.cooldownMax))
1360 return false;
1361 break;
1362 }
1365 {
1366 if (!IsSpellValid(e, e.event.aura.spell))
1367 return false;
1368
1370 return false;
1371 break;
1372 }
1374 {
1376 return false;
1377 break;
1378 }
1380 {
1382 {
1383 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);
1384 return false;
1385 }
1386 break;
1387 }
1389 {
1391 return false;
1392 break;
1393 }
1396 return false;
1397 break;
1400 {
1401 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
1402 if (e.event.gameEvent.gameEventId >= events.size() || !events[e.event.gameEvent.gameEventId].isValid())
1403 return false;
1404 break;
1405 }
1408 return false;
1409
1411 {
1412 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());
1413 return false;
1414 }
1415
1416 switch (e.GetTargetType())
1417 {
1425 break;
1428 return false;
1429 break;
1430 default:
1431 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());
1432 return false;
1433 }
1434 break;
1436 if (e.event.distance.guid == 0 && e.event.distance.entry == 0)
1437 {
1438 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE did not provide creature guid or entry, skipped.");
1439 return false;
1440 }
1441
1442 if (e.event.distance.guid != 0 && e.event.distance.entry != 0)
1443 {
1444 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE provided both an entry and guid, skipped.");
1445 return false;
1446 }
1447
1448 if (e.event.distance.guid != 0 && !sObjectMgr->GetCreatureData(e.event.distance.guid))
1449 {
1450 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature guid {}, skipped.", e.event.distance.guid);
1451 return false;
1452 }
1453
1454 if (e.event.distance.entry != 0 && !sObjectMgr->GetCreatureTemplate(e.event.distance.entry))
1455 {
1456 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature entry {}, skipped.", e.event.distance.entry);
1457 return false;
1458 }
1459 break;
1461 if (e.event.distance.guid == 0 && e.event.distance.entry == 0)
1462 {
1463 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT did not provide gameobject guid or entry, skipped.");
1464 return false;
1465 }
1466
1467 if (e.event.distance.guid != 0 && e.event.distance.entry != 0)
1468 {
1469 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT provided both an entry and guid, skipped.");
1470 return false;
1471 }
1472
1473 if (e.event.distance.guid != 0 && !sObjectMgr->GetGameObjectData(e.event.distance.guid))
1474 {
1475 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject guid {}, skipped.", e.event.distance.guid);
1476 return false;
1477 }
1478
1479 if (e.event.distance.entry != 0 && !sObjectMgr->GetGameObjectTemplate(e.event.distance.entry))
1480 {
1481 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject entry {}, skipped.", e.event.distance.entry);
1482 return false;
1483 }
1484 break;
1487 return false;
1488
1489 if (e.event.counter.id == 0)
1490 {
1491 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid counter id {}, skipped.", e.event.counter.id);
1492 return false;
1493 }
1494
1495 if (e.event.counter.value == 0)
1496 {
1497 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid value {}, skipped.", e.event.counter.value);
1498 return false;
1499 }
1500 break;
1501 case SMART_EVENT_RESET:
1503 {
1504 // There might be SMART_TARGET_* cases where this should be allowed, they will be handled if needed
1505 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);
1506 return false;
1507 }
1508 break;
1511 break;
1513 if (!sObjectMgr->GetQuestObjective(e.event.questObjective.id))
1514 {
1515 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_QUEST_OBJ_COMPLETION using invalid objective id {}, skipped.", e.event.questObjective.id);
1516 return false;
1517 }
1518 break;
1523 break;
1524 case SMART_EVENT_LINK:
1535 case SMART_EVENT_AGGRO:
1536 case SMART_EVENT_DEATH:
1537 case SMART_EVENT_EVADE:
1558 break;
1559 // Unused
1567 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Unused event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
1568 return false;
1569 default:
1570 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());
1571 return false;
1572 }
1574 {
1575 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {}, uses SMART_EVENT_FLAG_ACTIONLIST_WAITS but is not part of a timed actionlist.",
1577 return false;
1578 }
1579 }
1580
1581 if (!CheckUnusedEventParams(e))
1582 return false;
1583
1584 switch (e.GetActionType())
1585 {
1586 case SMART_ACTION_TALK:
1589 return false;
1590 break;
1593 return false;
1594 break;
1597 {
1598 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);
1599 return false;
1600 }
1601 break;
1605 {
1606 if (e.action.morphOrMount.creature > 0 && !sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature))
1607 {
1608 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);
1609 return false;
1610 }
1611
1613 {
1615 {
1616 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());
1617 return false;
1618 }
1619 else if (!sCreatureDisplayInfoStore.LookupEntry(e.action.morphOrMount.model))
1620 {
1621 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);
1622 return false;
1623 }
1624 }
1625 }
1626 break;
1627 case SMART_ACTION_SOUND:
1628 if (!IsSoundValid(e, e.action.sound.sound))
1629 return false;
1630 TC_SAI_IS_BOOLEAN_VALID(e, e.action.sound.onlySelf);
1631 break;
1634 if (!IsEmoteValid(e, e.action.emote.emote))
1635 return false;
1636 break;
1638 if (e.action.animKit.animKit && !IsAnimKitValid(e, e.action.animKit.animKit))
1639 return false;
1640
1641 if (e.action.animKit.type > 3)
1642 {
1643 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);
1644 return false;
1645 }
1646 break;
1649 return false;
1650 break;
1653 return false;
1654
1656 break;
1658 if (!IsQuestValid(e, e.action.quest.quest))
1659 return false;
1660 break;
1662 {
1663 if (!sTaxiPathStore.LookupEntry(e.action.taxi.id))
1664 {
1665 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);
1666 return false;
1667 }
1668 break;
1669 }
1671 {
1672 if (std::all_of(std::begin(e.action.randomEmote.emotes), std::end(e.action.randomEmote.emotes), [](uint32 emote) { return emote == 0; }))
1673 {
1674 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero emote",
1676 return false;
1677 }
1678
1679 for (uint32 emote : e.action.randomEmote.emotes)
1680 if (emote && !IsEmoteValid(e, emote))
1681 return false;
1682 break;
1683 }
1685 {
1686 if (std::all_of(std::begin(e.action.randTimedActionList.actionLists), std::end(e.action.randTimedActionList.actionLists), [](uint32 actionList) { return actionList == 0; }))
1687 {
1688 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero action list",
1690 return false;
1691 }
1692 break;
1693 }
1695 {
1696 if (std::all_of(std::begin(e.action.closestWaypointFromList.wps), std::end(e.action.closestWaypointFromList.wps), [](uint32 wp) { return wp == 0; }))
1697 {
1698 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero waypoint id",
1700 return false;
1701 }
1702 break;
1703 }
1705 {
1706 if (std::all_of(std::begin(e.action.randomSound.sounds), std::end(e.action.randomSound.sounds), [](uint32 sound) { return sound == 0; }))
1707 {
1708 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero sound",
1710 return false;
1711 }
1712
1713 for (uint32 sound : e.action.randomSound.sounds)
1714 if (sound && !IsSoundValid(e, sound))
1715 return false;
1716
1718 break;
1719 }
1720 case SMART_ACTION_CAST:
1721 {
1722 if (!IsSpellValid(e, e.action.cast.spell))
1723 return false;
1724
1725 for (SpellEffectInfo const& spellEffectInfo : sSpellMgr->AssertSpellInfo(e.action.cast.spell, DIFFICULTY_NONE)->GetEffects())
1726 {
1727 if (spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT) || spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT2))
1728 {
1729 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_CASTER)
1730 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Effect: SPELL_EFFECT_KILL_CREDIT: (SpellId: {} targetA: {} - targetB: {}) has invalid target for this Action",
1731 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.cast.spell, spellEffectInfo.TargetA.GetTarget(), spellEffectInfo.TargetB.GetTarget());
1732 }
1733 }
1735 {
1736 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",
1738 return false;
1739 }
1740 break;
1741 }
1743 {
1745 return false;
1746
1747 uint32 targetType = e.action.crossCast.targetType;
1748 if (targetType == SMART_TARGET_CREATURE_GUID || targetType == SMART_TARGET_GAMEOBJECT_GUID)
1749 {
1751 {
1753 return false;
1755 return false;
1756 }
1757
1760 SpawnData const* data = sObjectMgr->GetSpawnData(spawnType, guid);
1761 if (!data)
1762 {
1763 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);
1764 return false;
1765 }
1766 else if (e.action.crossCast.targetParam2 && e.action.crossCast.targetParam2 != data->id)
1767 {
1768 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);
1769 return false;
1770 }
1771 }
1773 {
1774 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",
1776 return false;
1777 }
1778 break;
1779 }
1782 {
1783 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());
1784 return false;
1785 }
1786 [[fallthrough]];
1788 if (!IsSpellValid(e, e.action.cast.spell))
1789 return false;
1791 {
1792 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",
1794 return false;
1795 }
1796 break;
1799 {
1800 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);
1801 return false;
1802 }
1803 break;
1806 {
1807 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());
1808 return false;
1809 }
1811 {
1812 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());
1813 return false;
1814 }
1815 break;
1818 return false;
1819
1821 break;
1823 {
1824 if (std::all_of(std::begin(e.action.randomPhase.phases), std::end(e.action.randomPhase.phases), [](uint32 phase) { return phase == 0; }))
1825 {
1826 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero phase",
1828 return false;
1829 }
1830
1831 if (std::any_of(std::begin(e.action.randomPhase.phases), std::end(e.action.randomPhase.phases), [](uint32 phase) { return phase >= SMART_EVENT_PHASE_MAX; }))
1832 {
1833 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());
1834 return false;
1835 }
1836 break;
1837 }
1838 case SMART_ACTION_RANDOM_PHASE_RANGE: //PhaseMin, PhaseMax
1839 {
1842 {
1843 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());
1844 return false;
1845 }
1846
1848 return false;
1849 break;
1850 }
1852 {
1854 return false;
1855
1857 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1858 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} creature summon: There is a summon spell for creature entry {} (SpellId: {}, effect: {})",
1859 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonCreature.creature, itr->second.first, itr->second.second);
1860
1862 {
1863 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);
1864 return false;
1865 }
1866
1868 {
1870 return false;
1871
1872 bool propertiesFound = std::ranges::any_of(sSpellMgr->AssertSpellInfo(e.action.summonCreature.createdBySpell, DIFFICULTY_NONE)->GetEffects(),
1873 [](SpellEffectInfo const& spellEffectInfo)
1874 {
1875 return spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON) && sSummonPropertiesStore.HasRecord(spellEffectInfo.MiscValueB);
1876 });
1877
1878 if (!propertiesFound)
1879 {
1880 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Spell {} is not a summon creature spell.",
1882 return false;
1883 }
1884 }
1885 break;
1886 }
1888 {
1890 return false;
1891
1893 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1894 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Kill Credit: There is a killcredit spell for creatureEntry {} (SpellId: {} effect: {})",
1895 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.killedMonster.creature, itr->second.first, itr->second.second);
1896
1898 {
1899 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());
1900 return false;
1901 }
1902 break;
1903 }
1906 return false;
1907
1909 break;
1912 {
1913 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);
1914 return false;
1915 }
1916 break;
1918 {
1920 {
1921 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);
1922 return false;
1923 }
1924 break;
1925 }
1927 {
1929 return false;
1930
1932 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1933 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} gameobject summon: There is a summon spell for gameobject entry {} (SpellId: {}, effect: {})",
1934 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonGO.entry, itr->second.first, itr->second.second);
1935 break;
1936 }
1938 if (!IsItemValid(e, e.action.item.entry))
1939 return false;
1940
1941 if (!NotNULL(e, e.action.item.count))
1942 return false;
1943 break;
1945 {
1946 if (!IsItemValid(e, e.action.item.entry))
1947 return false;
1948
1949 if (!NotNULL(e, e.action.item.count))
1950 return false;
1951
1953 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1954 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Create Item: There is a create item spell for item {} (SpellId: {} effect: {})",
1955 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.item.entry, itr->second.first, itr->second.second);
1956 break;
1957 }
1959 if (!sMapStore.LookupEntry(e.action.teleport.mapID))
1960 {
1961 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);
1962 return false;
1963 }
1964 break;
1967 return false;
1969 break;
1971 {
1972 WaypointPath const* path = sWaypointMgr->GetPath(e.action.wpStart.pathID);
1973 if (!path || path->Nodes.empty())
1974 {
1975 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);
1976 return false;
1977 }
1979 return false;
1980
1983 break;
1984 }
1986 {
1988 return false;
1989
1991 return false;
1992 break;
1993 }
1995 {
1997 return false;
1998 break;
1999 }
2004 {
2005 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);
2006 return false;
2007 }
2008 break;
2010 {
2011 uint32 eventId = e.action.gameEventStop.id;
2012
2013 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
2014 if (eventId < 1 || eventId >= events.size())
2015 {
2016 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);
2017 return false;
2018 }
2019
2020 GameEventData const& eventData = events[eventId];
2021 if (!eventData.isValid())
2022 {
2023 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);
2024 return false;
2025 }
2026 break;
2027 }
2029 {
2030 uint32 eventId = e.action.gameEventStart.id;
2031
2032 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
2033 if (eventId < 1 || eventId >= events.size())
2034 {
2035 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);
2036 return false;
2037 }
2038
2039 GameEventData const& eventData = events[eventId];
2040 if (!eventData.isValid())
2041 {
2042 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);
2043 return false;
2044 }
2045 break;
2046 }
2047 case SMART_ACTION_EQUIP:
2048 {
2050 {
2051 if (int8 equipId = static_cast<int8>(e.action.equip.entry))
2052 {
2053 EquipmentInfo const* eInfo = sObjectMgr->GetEquipmentInfo(e.entryOrGuid, equipId);
2054 if (!eInfo)
2055 {
2056 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id {} for creature {}, skipped.", equipId, e.entryOrGuid);
2057 return false;
2058 }
2059 }
2060
2061 auto isValidEquipmentSlot = [&](uint32 itemEntry, uint8 slot)
2062 {
2063 ItemEntry const* dbcItem = sItemStore.LookupEntry(itemEntry);
2064 if (!dbcItem)
2065 {
2066 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses unknown item {} (slot {}) for creature {}, skipped.", itemEntry, slot, e.entryOrGuid);
2067 return false;
2068 }
2069
2071 {
2072 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses item {} (slot {}) not equipable in a hand for creature {}, skipped.", itemEntry, slot, e.entryOrGuid);
2073 return false;
2074 }
2075
2076 return true;
2077 };
2078
2079 if (e.action.equip.slot1 && !isValidEquipmentSlot(e.action.equip.slot1, 0))
2080 return false;
2081
2082 if (e.action.equip.slot2 && !isValidEquipmentSlot(e.action.equip.slot2, 1))
2083 return false;
2084
2085 if (e.action.equip.slot3 && !isValidEquipmentSlot(e.action.equip.slot3, 2))
2086 return false;
2087 }
2088 break;
2089 }
2091 {
2092 if (e.action.setInstanceData.type > 1)
2093 {
2094 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);
2095 return false;
2096 }
2097 else if (e.action.setInstanceData.type == 1)
2098 {
2100 {
2101 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);
2102 return false;
2103 }
2104 }
2105 break;
2106 }
2108 {
2109 uint32 phaseId = e.action.ingamePhaseId.id;
2110 uint32 apply = e.action.ingamePhaseId.apply;
2111
2112 if (apply != 0 && apply != 1)
2113 {
2114 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);
2115 return false;
2116 }
2117
2118 if (!sPhaseStore.LookupEntry(phaseId))
2119 {
2120 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_ID uses invalid phaseid {} for creature {}, skipped", phaseId, e.entryOrGuid);
2121 return false;
2122 }
2123 break;
2124 }
2126 {
2127 uint32 phaseGroup = e.action.ingamePhaseGroup.groupId;
2129
2130 if (apply != 0 && apply != 1)
2131 {
2132 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);
2133 return false;
2134 }
2135
2136 if (!sDB2Manager.GetPhasesForGroup(phaseGroup))
2137 {
2138 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid phase group id {} for creature {}, skipped", phaseGroup, e.entryOrGuid);
2139 return false;
2140 }
2141 break;
2142 }
2144 {
2145 if (!sObjectMgr->GetSceneTemplate(e.action.scene.sceneId))
2146 {
2147 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SCENE_PLAY uses sceneId {} but scene don't exist, skipped", e.action.scene.sceneId);
2148 return false;
2149 }
2150
2151 break;
2152 }
2154 {
2155 if (!sObjectMgr->GetSceneTemplate(e.action.scene.sceneId))
2156 {
2157 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SCENE_CANCEL uses sceneId {} but scene don't exist, skipped", e.action.scene.sceneId);
2158 return false;
2159 }
2160
2161 break;
2162 }
2164 {
2166 {
2167 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);
2168 return false;
2169 }
2170 break;
2171 }
2173 {
2175 {
2176 TC_LOG_ERROR("sql.sql", "Entry {} SourceType {} Event {} Action {} does not specify duration", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
2177 return false;
2178 }
2179
2180 break;
2181 }
2183 {
2184 if (!sCinematicSequencesStore.LookupEntry(e.action.cinematic.entry))
2185 {
2186 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);
2187 return false;
2188 }
2189
2190 break;
2191 }
2193 {
2195 break;
2196 }
2198 {
2200 {
2201 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);
2202 return false;
2203 }
2204
2206 {
2207 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses speed 0, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
2208 return false;
2209 }
2210
2211 break;
2212 }
2214 {
2215 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(e.action.overrideLight.zoneId);
2216 if (!areaEntry)
2217 {
2218 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);
2219 return false;
2220 }
2221
2222 if (areaEntry->ParentAreaID != 0 && areaEntry->GetFlags().HasFlag(AreaFlags::IsSubzone))
2223 {
2224 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);
2225 return false;
2226 }
2227
2228 if (!sLightStore.LookupEntry(e.action.overrideLight.areaLightId))
2229 {
2230 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);
2231 return false;
2232 }
2233
2235 {
2236 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);
2237 return false;
2238 }
2239
2240 break;
2241 }
2243 {
2244 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(e.action.overrideWeather.zoneId);
2245 if (!areaEntry)
2246 {
2247 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);
2248 return false;
2249 }
2250
2251 if (areaEntry->ParentAreaID != 0 && areaEntry->GetFlags().HasFlag(AreaFlags::IsSubzone))
2252 {
2253 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);
2254 return false;
2255 }
2256
2257 break;
2258 }
2260 {
2261 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);
2262 break;
2263 }
2265 {
2267 {
2268 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} is trying to set invalid HP percent {}, skipped.",
2270 return false;
2271 }
2272 break;
2273 }
2275 {
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 {
2323 break;
2324 }
2326 {
2328 break;
2329 }
2331 {
2334 break;
2335 }
2337 {
2339 break;
2340 }
2342 {
2344 break;
2345 }
2347 {
2349 break;
2350 }
2352 {
2354 break;
2355 }
2356 case SMART_ACTION_EVADE:
2357 {
2359 break;
2360 }
2362 {
2364 break;
2365 }
2367 {
2368 if (!sConversationDataStore->GetConversationTemplate(e.action.conversation.id))
2369 {
2370 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);
2371 return false;
2372 }
2373
2374 break;
2375 }
2377 {
2379 break;
2380 }
2382 {
2384 break;
2385 }
2387 {
2389 break;
2390 }
2392 {
2394 return false;
2395
2397 {
2398 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has gameObjectAction parameter out of range (max allowed {}, current value {}), skipped.",
2400 return false;
2401 }
2402 break;
2403 }
2408 case SMART_ACTION_DIE:
2452 case SMART_ACTION_FALL:
2453 break;
2455 {
2457 {
2458 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);
2459 return false;
2460 }
2461 break;
2462 }
2464 {
2466 break;
2467 }
2469 {
2470 if (Quest const* quest = sObjectMgr->GetQuestTemplate(e.action.quest.quest))
2471 {
2472 if (!quest->HasFlag(QUEST_FLAGS_COMPLETION_EVENT) && !quest->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER) && !quest->HasFlag(QUEST_FLAGS_TRACKING_EVENT))
2473 {
2474 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);
2475 return false;
2476 }
2477 }
2478 else
2479 {
2480 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);
2481 return false;
2482 }
2483 break;
2484 }
2486 {
2488 {
2489 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);
2490 return false;
2491 }
2492 break;
2493 }
2495 {
2496 if (!sConversationDataStore->GetConversationTemplate(e.action.destroyConversation.id))
2497 {
2498 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);
2499 return false;
2500 }
2501
2503 break;
2504 }
2507 {
2509 {
2510 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);
2511 return false;
2512 }
2513 break;
2514 }
2515 // Unused
2535 case SMART_ACTION_FLEE:
2537 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);
2538 return false;
2539 default:
2540 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);
2541 return false;
2542 }
2543
2545 return false;
2546
2547 return true;
2548}
2549
2551{
2553 return true;
2554
2555 uint32 entry = 0;
2556
2558 {
2559 entry = e.event.textOver.creatureEntry;
2560 }
2561 else
2562 {
2563 switch (e.GetTargetType())
2564 {
2568 return true; // ignore
2569 default:
2570 if (e.entryOrGuid < 0)
2571 {
2573 CreatureData const* data = sObjectMgr->GetCreatureData(guid);
2574 if (!data)
2575 {
2576 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);
2577 return false;
2578 }
2579 else
2580 entry = data->id;
2581 }
2582 else
2583 entry = uint32(e.entryOrGuid);
2584 break;
2585 }
2586 }
2587
2588 if (!entry || !sCreatureTextMgr->TextExist(entry, uint8(id)))
2589 {
2590 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);
2591 return false;
2592 }
2593
2594 return true;
2595}
2596
2598{
2599 uint32 oldMSTime = getMSTime();
2600
2601 sSpellMgr->ForEachSpellInfo([this](SpellInfo const* spellInfo)
2602 {
2603 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2604 {
2605 if (spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON))
2606 SummonCreatureSpellStore.insert(std::make_pair(uint32(spellEffectInfo.MiscValue), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2607 else if (spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON_OBJECT_WILD))
2608 SummonGameObjectSpellStore.insert(std::make_pair(uint32(spellEffectInfo.MiscValue), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2609 else if (spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT) || spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT2))
2610 KillCreditSpellStore.insert(std::make_pair(uint32(spellEffectInfo.MiscValue), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2611 else if (spellEffectInfo.IsEffect(SPELL_EFFECT_CREATE_ITEM))
2612 CreateItemSpellStore.insert(std::make_pair(uint32(spellEffectInfo.ItemType), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2613 }
2614 });
2615
2616 TC_LOG_INFO("server.loading", ">> Loaded SmartAIMgr Helpers in {} ms", GetMSTimeDiffToNow(oldMSTime));
2617}
2618
2626
2628{
2629 return SummonCreatureSpellStore.equal_range(creatureEntry);
2630}
2631
2633{
2634 return SummonGameObjectSpellStore.equal_range(gameObjectEntry);
2635}
2636
2638{
2639 return KillCreditSpellStore.equal_range(killCredit);
2640}
2641
2646
2647ObjectGuidVector::ObjectGuidVector(ObjectVector const& objectVector) : _objectVector(objectVector)
2648{
2649 _guidVector.reserve(_objectVector.size());
2650 for (WorldObject* obj : _objectVector)
2651 _guidVector.push_back(obj->GetGUID());
2652}
2653
2655{
2656 _objectVector.clear();
2657
2658 for (ObjectGuid const& guid : _guidVector)
2659 if (WorldObject* obj = ObjectAccessor::GetWorldObject(ref, guid))
2660 _objectVector.push_back(obj);
2661}
#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:579
#define MAX_VEHICLE_SEATS
Difficulty
Definition DBCEnums.h:935
@ DIFFICULTY_NONE
Definition DBCEnums.h:936
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:173
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:176
#define TC_LOG_WARN(filterType__, message__,...)
Definition Log.h:179
bool IsInvalidMovementGeneratorType(uint8 const type)
@ TEMPSUMMON_MANUAL_DESPAWN
@ TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
#define sObjectMgr
Definition ObjectMgr.h:1873
@ QUEST_FLAGS_COMPLETION_AREA_TRIGGER
Definition QuestDef.h:216
@ QUEST_FLAGS_COMPLETION_EVENT
Definition QuestDef.h:215
@ QUEST_FLAGS_TRACKING_EVENT
Definition QuestDef.h:224
@ SPELL_EFFECT_KILL_CREDIT
@ SPELL_EFFECT_SUMMON
@ SPELL_EFFECT_KILL_CREDIT2
@ SPELL_EFFECT_SUMMON_OBJECT_WILD
@ SPELL_EFFECT_CREATE_ITEM
@ TARGET_UNIT_CASTER
@ 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_RESUME_MOVEMENT
@ 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:589
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::@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::@169 raw
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::@168 resumeMovement
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::@170::@183 unitClosest
struct SmartTarget::@170::@182 goDistance
struct SmartTarget::@170::@184 goClosest
struct SmartTarget::@170::@176 unitDistance
std::string param_string
struct SmartTarget::@170::@188 vehicle
struct SmartTarget::@170::@174 unitRange
SAIBool useCharmerOrOwner
struct SmartTarget::@170::@189 threatList
struct SmartTarget::@170::@180 goRange
struct SmartTarget::@170::@173 farthest
struct SmartTarget::@170::@178 playerRange
struct SmartTarget::@170::@186 closestFriendly
struct SmartTarget::@170::@172 hostilRandom
struct SmartTarget::@170::@190 raw
struct SmartTarget::@170::@175 unitGUID
struct SmartTarget::@170::@177 playerDistance
struct SmartTarget::@170::@181 goGUID
SMARTAI_TARGETS type
struct SmartTarget::@170::@185 closestAttackable
uint32 findCreatureAliveState
struct SmartTarget::@170::@187 owner
struct SmartTarget::@170::@179 stored
uint32 id
Definition SpawnData.h:135
std::vector< WaypointNode > Nodes