TrinityCore
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 <algorithm>
40
41#define TC_SAI_IS_BOOLEAN_VALID(e, value) \
42{ \
43 if (value > 1) \
44 { \
45 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses param {} of type Boolean with value {}, valid values are 0 or 1, skipped.", \
46 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), STRINGIZE(value), value); \
47 return false; \
48 } \
49}
50
52{
53 static SmartAIMgr instance;
54 return &instance;
55}
56
58{
60
61 uint32 oldMSTime = getMSTime();
62
63 for (SmartAIEventMap& eventmap : mEventMap)
64 eventmap.clear(); //Drop Existing SmartAI List
65
67 PreparedQueryResult result = WorldDatabase.Query(stmt);
68
69 if (!result)
70 {
71 TC_LOG_INFO("server.loading", ">> Loaded 0 SmartAI scripts. DB table `smartai_scripts` is empty.");
72 return;
73 }
74
75 uint32 count = 0;
76
77 do
78 {
79 Field* fields = result->Fetch();
80
82
83 temp.entryOrGuid = fields[0].GetInt64();
84 if (!temp.entryOrGuid)
85 {
86 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: invalid entryorguid (0), skipped loading.");
87 continue;
88 }
89
90 SmartScriptType source_type = (SmartScriptType)fields[1].GetUInt8();
91 if (source_type >= SMART_SCRIPT_TYPE_MAX)
92 {
93 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: invalid source_type ({}), skipped loading.", uint32(source_type));
94 continue;
95 }
96 if (temp.entryOrGuid >= 0)
97 {
98 switch (source_type)
99 {
101 {
102 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate((uint32)temp.entryOrGuid);
103 if (!creatureInfo)
104 {
105 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature entry ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
106 continue;
107 }
108
109 if (creatureInfo->AIName != "SmartAI")
110 {
111 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature entry ({}) is not using SmartAI, skipped loading.", uint32(temp.entryOrGuid));
112 continue;
113 }
114 break;
115 }
117 {
118 GameObjectTemplate const* gameObjectInfo = sObjectMgr->GetGameObjectTemplate((uint32)temp.entryOrGuid);
119 if (!gameObjectInfo)
120 {
121 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GameObject entry ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
122 continue;
123 }
124
125 if (gameObjectInfo->AIName != "SmartGameObjectAI")
126 {
127 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GameObject entry ({}) is not using SmartGameObjectAI, skipped loading.", uint32(temp.entryOrGuid));
128 continue;
129 }
130 break;
131 }
133 {
134 if (!sAreaTriggerStore.LookupEntry((uint32)temp.entryOrGuid))
135 {
136 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: AreaTrigger entry ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
137 continue;
138 }
139 break;
140 }
142 {
143 if (!sObjectMgr->IsValidEvent((uint32)temp.entryOrGuid))
144 {
145 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Event id ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
146 continue;
147 }
148 break;
149 }
151 {
152 if (!sObjectMgr->GetQuestTemplate((uint32)temp.entryOrGuid))
153 {
154 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Quest entry ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
155 continue;
156 }
157 break;
158 }
160 {
161 if (!sObjectMgr->GetSceneTemplate((uint32)temp.entryOrGuid))
162 {
163 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Scene id ({}) does not exist, skipped loading.", uint32(temp.entryOrGuid));
164 continue;
165 }
166 break;
167 }
169 break;//nothing to check, really
171 {
172 if (!sAreaTriggerDataStore->GetAreaTriggerTemplate({ (uint32)temp.entryOrGuid, false }))
173 {
174 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: AreaTrigger entry ({} IsServerSide false) does not exist, skipped loading.", uint32(temp.entryOrGuid));
175 continue;
176 }
177 break;
178 }
180 {
181 if (!sAreaTriggerDataStore->GetAreaTriggerTemplate({ (uint32)temp.entryOrGuid, true }))
182 {
183 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: AreaTrigger entry ({} IsCustom true) does not exist, skipped loading.", uint32(temp.entryOrGuid));
184 continue;
185 }
186 break;
187 }
188 default:
189 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: not yet implemented source_type {}", (uint32)source_type);
190 continue;
191 }
192 }
193 else
194 {
195 switch (source_type)
196 {
198 {
199 CreatureData const* creature = sObjectMgr->GetCreatureData(uint64(-temp.entryOrGuid));
200 if (!creature)
201 {
202 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature guid ({}) does not exist, skipped loading.", -temp.entryOrGuid);
203 continue;
204 }
205
206 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(creature->id);
207 if (!creatureInfo)
208 {
209 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature entry ({}) guid ({}) does not exist, skipped loading.", creature->id, -temp.entryOrGuid);
210 continue;
211 }
212
213 if (creatureInfo->AIName != "SmartAI")
214 {
215 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Creature entry ({}) guid ({}) is not using SmartAI, skipped loading.", creature->id, -temp.entryOrGuid);
216 continue;
217 }
218 break;
219 }
221 {
222 GameObjectData const* gameObject = sObjectMgr->GetGameObjectData(uint64(-temp.entryOrGuid));
223 if (!gameObject)
224 {
225 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GameObject guid ({}) does not exist, skipped loading.", -temp.entryOrGuid);
226 continue;
227 }
228
229 GameObjectTemplate const* gameObjectInfo = sObjectMgr->GetGameObjectTemplate(gameObject->id);
230 if (!gameObjectInfo)
231 {
232 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GameObject entry ({}) guid ({}) does not exist, skipped loading.", gameObject->id, -temp.entryOrGuid);
233 continue;
234 }
235
236 if (gameObjectInfo->AIName != "SmartGameObjectAI")
237 {
238 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GameObject entry ({}) guid ({}) is not using SmartGameObjectAI, skipped loading.", gameObject->id, -temp.entryOrGuid);
239 continue;
240 }
241 break;
242 }
243 default:
244 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: GUID-specific scripting not yet implemented for source_type {}", (uint32)source_type);
245 continue;
246 }
247 }
248
249 temp.source_type = source_type;
250 temp.event_id = fields[2].GetUInt16();
251 temp.link = fields[3].GetUInt16();
252
253 bool invalidDifficulties = false;
254 for (std::string_view token : Trinity::Tokenize(fields[4].GetStringView(), ',', false))
255 {
256 std::optional<std::underlying_type_t<Difficulty>> tokenValue = Trinity::StringTo<std::underlying_type_t<Difficulty>>(token);
257 if (!tokenValue.has_value())
258 {
259 invalidDifficulties = true;
260 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Invalid difficulties for entryorguid ({}) source_type ({}) id ({}), skipped loading.",
261 temp.entryOrGuid, temp.GetScriptType(), temp.event_id);
262 break;
263 }
264
265 Difficulty difficultyId = Difficulty(tokenValue.value());
266 if (difficultyId && !sDifficultyStore.LookupEntry(difficultyId))
267 {
268 invalidDifficulties = true;
269 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Invalid difficulty id ({}) for entryorguid ({}) source_type ({}) id ({}), skipped loading.",
270 difficultyId, temp.entryOrGuid, temp.GetScriptType(), temp.event_id);
271 break;
272 }
273
274 temp.Difficulties.push_back(difficultyId);
275 }
276
277 if (invalidDifficulties)
278 continue;
279
280 temp.event.type = (SMART_EVENT)fields[5].GetUInt8();
281 temp.event.event_phase_mask = fields[6].GetUInt16();
282 temp.event.event_chance = fields[7].GetUInt8();
283 temp.event.event_flags = fields[8].GetUInt16();
284
285 temp.event.raw.param1 = fields[9].GetUInt32();
286 temp.event.raw.param2 = fields[10].GetUInt32();
287 temp.event.raw.param3 = fields[11].GetUInt32();
288 temp.event.raw.param4 = fields[12].GetUInt32();
289 temp.event.raw.param5 = fields[13].GetUInt32();
290
291 temp.event.param_string = fields[14].GetString();
292
293 temp.action.type = (SMART_ACTION)fields[15].GetUInt8();
294 temp.action.raw.param1 = fields[16].GetUInt32();
295 temp.action.raw.param2 = fields[17].GetUInt32();
296 temp.action.raw.param3 = fields[18].GetUInt32();
297 temp.action.raw.param4 = fields[19].GetUInt32();
298 temp.action.raw.param5 = fields[20].GetUInt32();
299 temp.action.raw.param6 = fields[21].GetUInt32();
300 temp.action.raw.param7 = fields[22].GetUInt32();
301
302 temp.target.type = (SMARTAI_TARGETS)fields[23].GetUInt8();
303 temp.target.raw.param1 = fields[24].GetUInt32();
304 temp.target.raw.param2 = fields[25].GetUInt32();
305 temp.target.raw.param3 = fields[26].GetUInt32();
306 temp.target.raw.param4 = fields[27].GetUInt32();
307 temp.target.x = fields[28].GetFloat();
308 temp.target.y = fields[29].GetFloat();
309 temp.target.z = fields[30].GetFloat();
310 temp.target.o = fields[31].GetFloat();
311
312 //check target
313 if (!IsTargetValid(temp))
314 continue;
315
316 // check all event and action params
317 if (!IsEventValid(temp))
318 continue;
319
320 // specific check for timed events
321 switch (temp.event.type)
322 {
334 {
336 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Entry {} SourceType {}, Event {}, Missing Repeat flag.",
337 temp.entryOrGuid, temp.GetScriptType(), temp.event_id);
338 }
339 break;
343 {
345 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Entry {} SourceType {}, Event {}, Missing Repeat flag.",
346 temp.entryOrGuid, temp.GetScriptType(), temp.event_id);
347 }
348 break;
351 {
353 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Entry {} SourceType {}, Event {}, Missing Repeat flag.",
354 temp.entryOrGuid, temp.GetScriptType(), temp.event_id);
355 }
356 break;
357 default:
358 break;
359 }
360
361 // creature entry / guid not found in storage, create empty event list for it and increase counters
362 if (mEventMap[source_type].find(temp.entryOrGuid) == mEventMap[source_type].end())
363 {
364 ++count;
365 SmartAIEventList eventList;
366 mEventMap[source_type][temp.entryOrGuid] = eventList;
367 }
368 // store the new event
369 mEventMap[source_type][temp.entryOrGuid].push_back(temp);
370 }
371 while (result->NextRow());
372
373 // Post Loading Validation
374 for (SmartAIEventMap& eventmap : mEventMap)
375 {
376 for (std::pair<int64 const, SmartAIEventList>& eventlistpair : eventmap)
377 {
378 for (SmartScriptHolder const& e : eventlistpair.second)
379 {
380 if (e.link)
381 {
382 if (!FindLinkedEvent(eventlistpair.second, e.link))
383 {
384 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Entry {} SourceType {}, Event {}, Link Event {} not found or invalid.",
386 }
387 }
388
390 {
391 if (!FindLinkedSourceEvent(eventlistpair.second, e.event_id))
392 {
393 TC_LOG_ERROR("sql.sql", "SmartAIMgr::LoadSmartAIFromDB: Entry {} SourceType {}, Event {}, Link Source Event not found or invalid. Event will never trigger.",
395 }
396 }
397 }
398 }
399 }
400
401 TC_LOG_INFO("server.loading", ">> Loaded {} SmartAI scripts in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
402
404}
405
407{
408 SmartAIEventList temp;
409 if (mEventMap[uint32(type)].find(entry) != mEventMap[uint32(type)].end())
410 return mEventMap[uint32(type)][entry];
411 else
412 {
413 if (entry > 0)//first search is for guid (negative), do not drop error if not found
414 TC_LOG_DEBUG("scripts.ai", "SmartAIMgr::GetScript: Could not load Script for Entry {} ScriptType {}.", entry, uint32(type));
415 return temp;
416 }
417}
418
420{
421 SmartAIEventList::iterator itr = std::find_if(list.begin(), list.end(),
422 [eventId](SmartScriptHolder& source) { return source.link == eventId; });
423
424 if (itr != list.end())
425 return *itr;
426
427 static SmartScriptHolder SmartScriptHolderDummy;
428 return SmartScriptHolderDummy;
429}
430
432{
433 SmartAIEventList::iterator itr = std::find_if(list.begin(), list.end(),
434 [link](SmartScriptHolder& linked) { return linked.event_id == link && linked.GetEventType() == SMART_EVENT_LINK; });
435
436 if (itr != list.end())
437 return *itr;
438
439 static SmartScriptHolder SmartScriptHolderDummy;
440 return SmartScriptHolderDummy;
441}
442
444{
445 switch (event)
446 { // white list of events that actually have an invoker passed to them
449 case SMART_EVENT_KILL:
493 return true;
494 default:
495 return false;
496 }
497}
498
500{
501 if (std::abs(e.target.o) > 2 * float(M_PI))
502 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has abs(`target.o` = {}) > 2*PI (orientation is expressed in radians)",
504
505 switch (e.GetTargetType())
506 {
509 {
510 if (e.target.unitDistance.creature && !sObjectMgr->GetCreatureTemplate(e.target.unitDistance.creature))
511 {
512 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);
513 return false;
514 }
515 break;
516 }
519 {
520 if (e.target.goDistance.entry && !sObjectMgr->GetGameObjectTemplate(e.target.goDistance.entry))
521 {
522 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);
523 return false;
524 }
525 break;
526 }
528 {
530 return false;
531
533 CreatureData const* data = sObjectMgr->GetCreatureData(guid);
534 if (!data)
535 {
536 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);
537 return false;
538 }
539 else if (e.target.unitGUID.entry && e.target.unitGUID.entry != data->id)
540 {
541 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);
542 return false;
543 }
544 break;
545 }
547 {
549 return false;
550
552 GameObjectData const* data = sObjectMgr->GetGameObjectData(guid);
553 if (!data)
554 {
555 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);
556 return false;
557 }
558 else if (e.target.goGUID.entry && e.target.goGUID.entry != data->id)
559 {
560 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);
561 return false;
562 }
563 break;
564 }
567 {
568 if (e.target.playerDistance.dist == 0)
569 {
570 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());
571 return false;
572 }
573 break;
574 }
579 {
580 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());
581 return false;
582 }
583 break;
589 break;
593 break;
596 break;
599 break;
602 break;
605 break;
617 break;
618 default:
619 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());
620 return false;
621 }
622
624 return false;
625
626 return true;
627}
628
630{
631 if (max < min)
632 {
633 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);
634 return false;
635 }
636 return true;
637}
638
640{
641 if (!data)
642 {
643 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());
644 return false;
645 }
646 return true;
647}
648
650{
651 if (!sObjectMgr->GetCreatureTemplate(entry))
652 {
653 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);
654 return false;
655 }
656 return true;
657}
658
660{
661 if (!sObjectMgr->GetQuestTemplate(entry))
662 {
663 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);
664 return false;
665 }
666 return true;
667}
668
670{
671 if (!sObjectMgr->GetGameObjectTemplate(entry))
672 {
673 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);
674 return false;
675 }
676 return true;
677}
678
680{
681 if (!sSpellMgr->GetSpellInfo(entry, DIFFICULTY_NONE))
682 {
683 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);
684 return false;
685 }
686 return true;
687}
688
690{
691 if (!sItemStore.LookupEntry(entry))
692 {
693 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);
694 return false;
695 }
696 return true;
697}
698
700{
701 if (!sEmotesTextStore.LookupEntry(entry))
702 {
703 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);
704 return false;
705 }
706 return true;
707}
708
710{
711 if (!sEmotesStore.LookupEntry(entry))
712 {
713 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);
714 return false;
715 }
716 return true;
717}
718
720{
721 if (!sAreaTriggerStore.LookupEntry(entry))
722 {
723 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses non-existent AreaTrigger entry {}, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), entry);
724 return false;
725 }
726 return true;
727}
728
730{
731 if (!sSoundKitStore.LookupEntry(entry))
732 {
733 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);
734 return false;
735 }
736 return true;
737}
738
740{
741 if (!sAnimKitStore.LookupEntry(entry))
742 {
743 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);
744 return false;
745 }
746 return true;
747}
748
750{
751 if (!sSpellVisualKitStore.LookupEntry(entry))
752 {
753 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);
754 return false;
755 }
756 return true;
757}
758
760{
761 size_t paramsStructSize = [&]() -> size_t
762 {
763 constexpr size_t NO_PARAMS = size_t(0);
764 switch (e.event.type)
765 {
770 case SMART_EVENT_AGGRO: return NO_PARAMS;
771 case SMART_EVENT_KILL: return sizeof(SmartEvent::kill);
772 case SMART_EVENT_DEATH: return NO_PARAMS;
773 case SMART_EVENT_EVADE: return NO_PARAMS;
774 case SMART_EVENT_SPELLHIT: return sizeof(SmartEvent::spellHit);
775 case SMART_EVENT_RANGE: return sizeof(SmartEvent::minMaxRepeat);
776 case SMART_EVENT_OOC_LOS: return sizeof(SmartEvent::los);
777 case SMART_EVENT_RESPAWN: return sizeof(SmartEvent::respawn);
783 case SMART_EVENT_REWARD_QUEST: return sizeof(SmartEvent::quest);
784 case SMART_EVENT_REACHED_HOME: return NO_PARAMS;
785 case SMART_EVENT_RECEIVE_EMOTE: return sizeof(SmartEvent::emote);
786 case SMART_EVENT_HAS_AURA: return sizeof(SmartEvent::aura);
787 case SMART_EVENT_TARGET_BUFFED: return sizeof(SmartEvent::aura);
788 case SMART_EVENT_RESET: return NO_PARAMS;
789 case SMART_EVENT_IC_LOS: return sizeof(SmartEvent::los);
792 case SMART_EVENT_CHARMED: return sizeof(SmartEvent::charm);
798 case SMART_EVENT_CORPSE_REMOVED: return NO_PARAMS;
799 case SMART_EVENT_AI_INIT: return NO_PARAMS;
800 case SMART_EVENT_DATA_SET: return sizeof(SmartEvent::dataSet);
802 case SMART_EVENT_TRANSPORT_ADDPLAYER: return NO_PARAMS;
804 case SMART_EVENT_TRANSPORT_REMOVE_PLAYER: return NO_PARAMS;
808 case SMART_EVENT_QUEST_ACCEPTED: return NO_PARAMS;
809 case SMART_EVENT_QUEST_OBJ_COMPLETION: return NO_PARAMS;
810 case SMART_EVENT_QUEST_COMPLETION: return NO_PARAMS;
811 case SMART_EVENT_QUEST_REWARDED: return NO_PARAMS;
812 case SMART_EVENT_QUEST_FAIL: return NO_PARAMS;
813 case SMART_EVENT_TEXT_OVER: return sizeof(SmartEvent::textOver);
815 case SMART_EVENT_JUST_SUMMONED: return NO_PARAMS;
821 case SMART_EVENT_UPDATE: return sizeof(SmartEvent::minMaxRepeat);
822 case SMART_EVENT_LINK: return NO_PARAMS;
824 case SMART_EVENT_JUST_CREATED: return NO_PARAMS;
826 case SMART_EVENT_FOLLOW_COMPLETED: return NO_PARAMS;
832 case SMART_EVENT_ON_SPELLCLICK: return NO_PARAMS;
836 case SMART_EVENT_COUNTER_SET: return sizeof(SmartEvent::counter);
837 case SMART_EVENT_SCENE_START: return NO_PARAMS;
838 case SMART_EVENT_SCENE_TRIGGER: return NO_PARAMS;
839 case SMART_EVENT_SCENE_CANCEL: return NO_PARAMS;
840 case SMART_EVENT_SCENE_COMPLETE: return NO_PARAMS;
845 case SMART_EVENT_ON_DESPAWN: return NO_PARAMS;
846 case SMART_EVENT_SEND_EVENT_TRIGGER: return NO_PARAMS;
847 default:
848 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.",
850 return sizeof(SmartEvent::raw);
851 }
852 }();
853
854 static size_t rawCount = sizeof(SmartEvent::raw) / sizeof(uint32);
855 size_t paramsCount = paramsStructSize / sizeof(uint32);
856
857 for (size_t index = paramsCount; index < rawCount; index++)
858 {
859 uint32 value = ((uint32*)&e.event.raw)[index];
860 if (value != 0)
861 {
862 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused event_param{} with value {}, it should be 0.",
863 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), index + 1, value);
864 }
865 }
866
867 return true;
868}
869
871{
872 size_t paramsStructSize = [&]() -> size_t
873 {
874 constexpr size_t NO_PARAMS = size_t(0);
875 switch (e.action.type)
876 {
877 case SMART_ACTION_NONE: return NO_PARAMS;
878 case SMART_ACTION_TALK: return sizeof(SmartAction::talk);
881 case SMART_ACTION_SOUND: return sizeof(SmartAction::sound);
882 case SMART_ACTION_PLAY_EMOTE: return sizeof(SmartAction::emote);
883 case SMART_ACTION_FAIL_QUEST: return sizeof(SmartAction::quest);
886 case SMART_ACTION_ACTIVATE_GOBJECT: return NO_PARAMS;
888 case SMART_ACTION_CAST: return sizeof(SmartAction::cast);
899 case SMART_ACTION_EVADE: return sizeof(SmartAction::evade);
902 case SMART_ACTION_COMBAT_STOP: return NO_PARAMS;
904 case SMART_ACTION_FOLLOW: return sizeof(SmartAction::follow);
907 case SMART_ACTION_RESET_GOBJECT: return NO_PARAMS;
912 case SMART_ACTION_DIE: return NO_PARAMS;
913 case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: return NO_PARAMS;
920 case SMART_ACTION_SET_DATA: return sizeof(SmartAction::setData);
921 case SMART_ACTION_ATTACK_STOP: return NO_PARAMS;
923 case SMART_ACTION_SET_ACTIVE: return sizeof(SmartAction::active);
924 case SMART_ACTION_ATTACK_START: return NO_PARAMS;
926 case SMART_ACTION_KILL_UNIT: return NO_PARAMS;
928 case SMART_ACTION_WP_START: return sizeof(SmartAction::wpStart);
929 case SMART_ACTION_WP_PAUSE: return sizeof(SmartAction::wpPause);
930 case SMART_ACTION_WP_STOP: return sizeof(SmartAction::wpStop);
931 case SMART_ACTION_ADD_ITEM: return sizeof(SmartAction::item);
932 case SMART_ACTION_REMOVE_ITEM: return sizeof(SmartAction::item);
933 case SMART_ACTION_SET_RUN: return sizeof(SmartAction::setRun);
935 case SMART_ACTION_TELEPORT: return sizeof(SmartAction::teleport);
938 case SMART_ACTION_WP_RESUME: return NO_PARAMS;
939 case SMART_ACTION_SET_ORIENTATION: return NO_PARAMS;
941 case SMART_ACTION_PLAYMOVIE: return sizeof(SmartAction::movie);
944 case SMART_ACTION_EQUIP: return sizeof(SmartAction::equip);
945 case SMART_ACTION_CLOSE_GOSSIP: return NO_PARAMS;
948 case SMART_ACTION_CALL_SCRIPT_RESET: return NO_PARAMS;
951 case SMART_ACTION_SET_NPC_FLAG: return sizeof(SmartAction::flag);
952 case SMART_ACTION_ADD_NPC_FLAG: return sizeof(SmartAction::flag);
955 case SMART_ACTION_SELF_CAST: return sizeof(SmartAction::cast);
963 case SMART_ACTION_JUMP_TO_POS: return sizeof(SmartAction::jump);
967 case SMART_ACTION_SET_HOME_POS: return NO_PARAMS;
969 case SMART_ACTION_SET_ROOT: return sizeof(SmartAction::setRoot);
971 case SMART_ACTION_SET_POWER: return sizeof(SmartAction::power);
972 case SMART_ACTION_ADD_POWER: return sizeof(SmartAction::power);
982 case SMART_ACTION_ADD_THREAT: return sizeof(SmartAction::threat);
987 case SMART_ACTION_SCENE_PLAY: return sizeof(SmartAction::scene);
992 case SMART_ACTION_INVOKER_CAST: return sizeof(SmartAction::cast);
998 case SMART_ACTION_SET_AI_ANIM_KIT: return NO_PARAMS;
1009 case SMART_ACTION_DO_ACTION: return sizeof(SmartAction::doAction);
1010 default:
1011 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.",
1013 return sizeof(SmartAction::raw);
1014 }
1015 }();
1016
1017 static size_t rawCount = sizeof(SmartAction::raw) / sizeof(uint32);
1018 size_t paramsCount = paramsStructSize / sizeof(uint32);
1019
1020 for (size_t index = paramsCount; index < rawCount; index++)
1021 {
1022 uint32 value = ((uint32*)&e.action.raw)[index];
1023 if (value != 0)
1024 {
1025 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused action_param{} with value {}, it should be 0.",
1026 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), index + 1, value);
1027 }
1028 }
1029
1030 return true;
1031}
1032
1034{
1035 size_t paramsStructSize = [&]() -> size_t
1036 {
1037 constexpr size_t NO_PARAMS = size_t(0);
1038 switch (e.target.type)
1039 {
1040 case SMART_TARGET_NONE: return NO_PARAMS;
1041 case SMART_TARGET_SELF: return NO_PARAMS;
1042 case SMART_TARGET_VICTIM: return NO_PARAMS;
1047 case SMART_TARGET_ACTION_INVOKER: return NO_PARAMS;
1048 case SMART_TARGET_POSITION: return NO_PARAMS; //uses x,y,z,o
1052 case SMART_TARGET_STORED: return sizeof(SmartTarget::stored);
1056 case SMART_TARGET_INVOKER_PARTY: return NO_PARAMS;
1062 case SMART_TARGET_ACTION_INVOKER_VEHICLE: return NO_PARAMS;
1067 case SMART_TARGET_LOOT_RECIPIENTS: return NO_PARAMS;
1068 case SMART_TARGET_FARTHEST: return sizeof(SmartTarget::farthest);
1071 default:
1072 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.",
1074 return sizeof(SmartTarget::raw);
1075 }
1076 }();
1077
1078 static size_t rawCount = sizeof(SmartTarget::raw) / sizeof(uint32);
1079 size_t paramsCount = paramsStructSize / sizeof(uint32);
1080
1081 for (size_t index = paramsCount; index < rawCount; index++)
1082 {
1083 uint32 value = ((uint32*)&e.target.raw)[index];
1084 if (value != 0)
1085 {
1086 TC_LOG_WARN("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has unused target_param{} with value {}, it should be 0.",
1087 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), index + 1, value);
1088 }
1089 }
1090
1091 return true;
1092}
1093
1095{
1096 if (e.event.type >= SMART_EVENT_END)
1097 {
1098 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event({}) has invalid event type ({}), skipped.", e.entryOrGuid, e.event_id, e.GetEventType());
1099 return false;
1100 }
1101
1102 // in SMART_SCRIPT_TYPE_TIMED_ACTIONLIST all event types are overriden by core
1104 {
1105 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {}, event type {} can not be used for Script type {}", e.entryOrGuid, e.GetEventType(), e.GetScriptType());
1106 return false;
1107 }
1108
1109 if (e.action.type <= 0 || e.action.type >= SMART_ACTION_END)
1110 {
1111 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has invalid action type ({}), skipped.", e.entryOrGuid, e.event_id, e.GetActionType());
1112 return false;
1113 }
1114
1116 {
1117 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has invalid phase mask ({}), skipped.", e.entryOrGuid, e.event_id, e.event.event_phase_mask);
1118 return false;
1119 }
1120
1122 {
1123 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has invalid event flags ({}), skipped.", e.entryOrGuid, e.event_id, e.event.event_flags);
1124 return false;
1125 }
1126
1128 {
1129 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} using event ({}) has deprecated event flags ({}), skipped.", e.entryOrGuid, e.event_id, e.event.event_flags);
1130 return false;
1131 }
1132
1133 if (e.link && e.link == e.event_id)
1134 {
1135 TC_LOG_ERROR("sql.sql", "SmartAIMgr: EntryOrGuid {} SourceType {}, Event {}, Event is linking self (infinite loop), skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id);
1136 return false;
1137 }
1138
1140 {
1141 e.event.type = SMART_EVENT_UPDATE_OOC;//force default OOC, can change when calling the script!
1143 return false;
1144
1146 return false;
1147 }
1148 else
1149 {
1150 switch (e.GetEventType())
1151 {
1152 case SMART_EVENT_UPDATE:
1157 case SMART_EVENT_RANGE:
1162 return false;
1163
1165 return false;
1166 break;
1169 if (e.event.spellHit.spell)
1170 {
1171 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(e.event.spellHit.spell, DIFFICULTY_NONE);
1172 if (!spellInfo)
1173 {
1174 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);
1175 return false;
1176 }
1177 if (e.event.spellHit.school && (e.event.spellHit.school & spellInfo->SchoolMask) != spellInfo->SchoolMask)
1178 {
1179 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);
1180 return false;
1181 }
1182 }
1184 return false;
1185 break;
1189 {
1190 if (!IsSpellValid(e, e.event.spellCast.spell))
1191 return false;
1192
1194 return false;
1195 break;
1196 }
1198 case SMART_EVENT_IC_LOS:
1200 return false;
1202 {
1203 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses hostilityMode with invalid value {} (max allowed value {}), skipped.",
1205 return false;
1206 }
1207
1209 break;
1212 {
1213 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);
1214 return false;
1215 }
1217 {
1218 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);
1219 return false;
1220 }
1221 break;
1224 return false;
1225 break;
1227 {
1229 return false;
1230
1231 if (!NotNULL(e, e.event.missingBuff.radius))
1232 return false;
1233
1235 return false;
1236 break;
1237 }
1238 case SMART_EVENT_KILL:
1240 return false;
1241
1243 return false;
1244
1246 break;
1249 {
1250 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);
1251 return false;
1252 }
1253
1255 return false;
1256 break;
1260 return false;
1261 break;
1266 return false;
1267
1269 return false;
1270 break;
1273 if (e.event.quest.quest && !IsQuestValid(e, e.event.quest.quest))
1274 return false;
1275
1276 if (!IsMinMaxValid(e, e.event.quest.cooldownMin, e.event.quest.cooldownMax))
1277 return false;
1278 break;
1280 {
1281 if (e.event.emote.emote && !IsTextEmoteValid(e, e.event.emote.emote))
1282 return false;
1283
1284 if (!IsMinMaxValid(e, e.event.emote.cooldownMin, e.event.emote.cooldownMax))
1285 return false;
1286 break;
1287 }
1290 {
1291 if (!IsSpellValid(e, e.event.aura.spell))
1292 return false;
1293
1295 return false;
1296 break;
1297 }
1299 {
1301 return false;
1302 break;
1303 }
1305 {
1307 {
1308 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);
1309 return false;
1310 }
1311 break;
1312 }
1314 {
1316 return false;
1317 break;
1318 }
1320 {
1322 {
1323 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} areatrigger param not supported for SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY and SMART_SCRIPT_TYPE_AREATRIGGER_ENTITY_CUSTOM, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
1324 return false;
1325 }
1327 return false;
1328 break;
1329 }
1332 return false;
1333 break;
1336 {
1337 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
1338 if (e.event.gameEvent.gameEventId >= events.size() || !events[e.event.gameEvent.gameEventId].isValid())
1339 return false;
1340 break;
1341 }
1344 return false;
1345
1347 {
1348 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());
1349 return false;
1350 }
1351
1352 switch (e.GetTargetType())
1353 {
1361 break;
1364 return false;
1365 break;
1366 default:
1367 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());
1368 return false;
1369 }
1370 break;
1372 if (e.event.distance.guid == 0 && e.event.distance.entry == 0)
1373 {
1374 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE did not provide creature guid or entry, skipped.");
1375 return false;
1376 }
1377
1378 if (e.event.distance.guid != 0 && e.event.distance.entry != 0)
1379 {
1380 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE provided both an entry and guid, skipped.");
1381 return false;
1382 }
1383
1384 if (e.event.distance.guid != 0 && !sObjectMgr->GetCreatureData(e.event.distance.guid))
1385 {
1386 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature guid {}, skipped.", e.event.distance.guid);
1387 return false;
1388 }
1389
1390 if (e.event.distance.entry != 0 && !sObjectMgr->GetCreatureTemplate(e.event.distance.entry))
1391 {
1392 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_CREATURE using invalid creature entry {}, skipped.", e.event.distance.entry);
1393 return false;
1394 }
1395 break;
1397 if (e.event.distance.guid == 0 && e.event.distance.entry == 0)
1398 {
1399 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT did not provide gameobject guid or entry, skipped.");
1400 return false;
1401 }
1402
1403 if (e.event.distance.guid != 0 && e.event.distance.entry != 0)
1404 {
1405 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT provided both an entry and guid, skipped.");
1406 return false;
1407 }
1408
1409 if (e.event.distance.guid != 0 && !sObjectMgr->GetGameObjectData(e.event.distance.guid))
1410 {
1411 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject guid {}, skipped.", e.event.distance.guid);
1412 return false;
1413 }
1414
1415 if (e.event.distance.entry != 0 && !sObjectMgr->GetGameObjectTemplate(e.event.distance.entry))
1416 {
1417 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_DISTANCE_GAMEOBJECT using invalid gameobject entry {}, skipped.", e.event.distance.entry);
1418 return false;
1419 }
1420 break;
1423 return false;
1424
1425 if (e.event.counter.id == 0)
1426 {
1427 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid counter id {}, skipped.", e.event.counter.id);
1428 return false;
1429 }
1430
1431 if (e.event.counter.value == 0)
1432 {
1433 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_COUNTER_SET using invalid value {}, skipped.", e.event.counter.value);
1434 return false;
1435 }
1436 break;
1437 case SMART_EVENT_RESET:
1439 {
1440 // There might be SMART_TARGET_* cases where this should be allowed, they will be handled if needed
1441 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);
1442 return false;
1443 }
1444 break;
1447 break;
1449 if (!sObjectMgr->GetQuestObjective(e.event.questObjective.id))
1450 {
1451 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Event SMART_EVENT_QUEST_OBJ_COMPLETION using invalid objective id {}, skipped.", e.event.questObjective.id);
1452 return false;
1453 }
1454 break;
1459 break;
1460 case SMART_EVENT_LINK:
1471 case SMART_EVENT_AGGRO:
1472 case SMART_EVENT_DEATH:
1473 case SMART_EVENT_EVADE:
1492 break;
1493 // Unused
1501 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Unused event_type({}), Entry {} SourceType {} Event {}, skipped.", e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id);
1502 return false;
1503 default:
1504 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());
1505 return false;
1506 }
1507 }
1508
1509 if (!CheckUnusedEventParams(e))
1510 return false;
1511
1512 switch (e.GetActionType())
1513 {
1514 case SMART_ACTION_TALK:
1517 return false;
1518 break;
1521 return false;
1522 break;
1525 {
1526 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);
1527 return false;
1528 }
1529 break;
1533 {
1534 if (e.action.morphOrMount.creature > 0 && !sObjectMgr->GetCreatureTemplate(e.action.morphOrMount.creature))
1535 {
1536 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);
1537 return false;
1538 }
1539
1541 {
1543 {
1544 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());
1545 return false;
1546 }
1547 else if (!sCreatureDisplayInfoStore.LookupEntry(e.action.morphOrMount.model))
1548 {
1549 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);
1550 return false;
1551 }
1552 }
1553 }
1554 break;
1555 case SMART_ACTION_SOUND:
1556 if (!IsSoundValid(e, e.action.sound.sound))
1557 return false;
1558 TC_SAI_IS_BOOLEAN_VALID(e, e.action.sound.onlySelf);
1559 break;
1562 if (!IsEmoteValid(e, e.action.emote.emote))
1563 return false;
1564 break;
1566 if (e.action.animKit.animKit && !IsAnimKitValid(e, e.action.animKit.animKit))
1567 return false;
1568
1569 if (e.action.animKit.type > 3)
1570 {
1571 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);
1572 return false;
1573 }
1574 break;
1577 return false;
1578 break;
1581 return false;
1582
1584 break;
1586 if (!IsQuestValid(e, e.action.quest.quest))
1587 return false;
1588 break;
1590 {
1591 if (!sTaxiPathStore.LookupEntry(e.action.taxi.id))
1592 {
1593 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);
1594 return false;
1595 }
1596 break;
1597 }
1599 {
1600 if (std::all_of(std::begin(e.action.randomEmote.emotes), std::end(e.action.randomEmote.emotes), [](uint32 emote) { return emote == 0; }))
1601 {
1602 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero emote",
1604 return false;
1605 }
1606
1607 for (uint32 emote : e.action.randomEmote.emotes)
1608 if (emote && !IsEmoteValid(e, emote))
1609 return false;
1610 break;
1611 }
1613 {
1614 if (std::all_of(std::begin(e.action.randTimedActionList.actionLists), std::end(e.action.randTimedActionList.actionLists), [](uint32 actionList) { return actionList == 0; }))
1615 {
1616 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero action list",
1618 return false;
1619 }
1620 break;
1621 }
1623 {
1624 if (std::all_of(std::begin(e.action.closestWaypointFromList.wps), std::end(e.action.closestWaypointFromList.wps), [](uint32 wp) { return wp == 0; }))
1625 {
1626 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero waypoint id",
1628 return false;
1629 }
1630 break;
1631 }
1633 {
1634 if (std::all_of(std::begin(e.action.randomSound.sounds), std::end(e.action.randomSound.sounds), [](uint32 sound) { return sound == 0; }))
1635 {
1636 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero sound",
1638 return false;
1639 }
1640
1641 for (uint32 sound : e.action.randomSound.sounds)
1642 if (sound && !IsSoundValid(e, sound))
1643 return false;
1644
1646 break;
1647 }
1648 case SMART_ACTION_CAST:
1649 {
1650 if (!IsSpellValid(e, e.action.cast.spell))
1651 return false;
1652
1653 for (SpellEffectInfo const& spellEffectInfo : sSpellMgr->AssertSpellInfo(e.action.cast.spell, DIFFICULTY_NONE)->GetEffects())
1654 {
1655 if (spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT) || spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT2))
1656 {
1657 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_CASTER)
1658 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Effect: SPELL_EFFECT_KILL_CREDIT: (SpellId: {} targetA: {} - targetB: {}) has invalid target for this Action",
1659 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.cast.spell, spellEffectInfo.TargetA.GetTarget(), spellEffectInfo.TargetB.GetTarget());
1660 }
1661 }
1662 break;
1663 }
1665 {
1667 return false;
1668
1669 uint32 targetType = e.action.crossCast.targetType;
1670 if (targetType == SMART_TARGET_CREATURE_GUID || targetType == SMART_TARGET_GAMEOBJECT_GUID)
1671 {
1673 {
1675 return false;
1677 return false;
1678 }
1679
1682 SpawnData const* data = sObjectMgr->GetSpawnData(spawnType, guid);
1683 if (!data)
1684 {
1685 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);
1686 return false;
1687 }
1688 else if (e.action.crossCast.targetParam2 && e.action.crossCast.targetParam2 != data->id)
1689 {
1690 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);
1691 return false;
1692 }
1693 }
1694 break;
1695 }
1698 {
1699 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());
1700 return false;
1701 }
1702 [[fallthrough]];
1704 if (!IsSpellValid(e, e.action.cast.spell))
1705 return false;
1706 break;
1709 if (Quest const* qid = sObjectMgr->GetQuestTemplate(e.action.quest.quest))
1710 {
1711 if (!qid->HasFlag(QUEST_FLAGS_COMPLETION_EVENT) && !qid->HasFlag(QUEST_FLAGS_COMPLETION_AREA_TRIGGER))
1712 {
1713 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, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.quest.quest);
1714 return false;
1715 }
1716 }
1717 else
1718 {
1719 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);
1720 return false;
1721 }
1722 break;
1725 {
1726 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);
1727 return false;
1728 }
1729 break;
1732 {
1733 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());
1734 return false;
1735 }
1737 {
1738 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());
1739 return false;
1740 }
1741 break;
1744 return false;
1745
1747 break;
1749 {
1750 if (std::all_of(std::begin(e.action.randomPhase.phases), std::end(e.action.randomPhase.phases), [](uint32 phase) { return phase == 0; }))
1751 {
1752 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not have any non-zero phase",
1754 return false;
1755 }
1756
1757 if (std::any_of(std::begin(e.action.randomPhase.phases), std::end(e.action.randomPhase.phases), [](uint32 phase) { return phase >= SMART_EVENT_PHASE_MAX; }))
1758 {
1759 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());
1760 return false;
1761 }
1762 break;
1763 }
1764 case SMART_ACTION_RANDOM_PHASE_RANGE: //PhaseMin, PhaseMax
1765 {
1768 {
1769 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());
1770 return false;
1771 }
1772
1774 return false;
1775 break;
1776 }
1778 {
1780 return false;
1781
1783 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1784 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} creature summon: There is a summon spell for creature entry {} (SpellId: {}, effect: {})",
1785 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonCreature.creature, itr->second.first, itr->second.second);
1786
1788 {
1789 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);
1790 return false;
1791 }
1792
1794 break;
1795 }
1797 {
1799 return false;
1800
1802 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1803 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Kill Credit: There is a killcredit spell for creatureEntry {} (SpellId: {} effect: {})",
1804 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.killedMonster.creature, itr->second.first, itr->second.second);
1805
1807 {
1808 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());
1809 return false;
1810 }
1811 break;
1812 }
1815 return false;
1816
1818 break;
1821 {
1822 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);
1823 return false;
1824 }
1825 break;
1827 {
1829 {
1830 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);
1831 return false;
1832 }
1833 break;
1834 }
1836 {
1838 return false;
1839
1841 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1842 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} gameobject summon: There is a summon spell for gameobject entry {} (SpellId: {}, effect: {})",
1843 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.summonGO.entry, itr->second.first, itr->second.second);
1844 break;
1845 }
1847 if (!IsItemValid(e, e.action.item.entry))
1848 return false;
1849
1850 if (!NotNULL(e, e.action.item.count))
1851 return false;
1852 break;
1854 {
1855 if (!IsItemValid(e, e.action.item.entry))
1856 return false;
1857
1858 if (!NotNULL(e, e.action.item.count))
1859 return false;
1860
1862 for (CacheSpellContainer::const_iterator itr = sBounds.first; itr != sBounds.second; ++itr)
1863 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} Create Item: There is a create item spell for item {} (SpellId: {} effect: {})",
1864 e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.action.item.entry, itr->second.first, itr->second.second);
1865 break;
1866 }
1868 if (!sMapStore.LookupEntry(e.action.teleport.mapID))
1869 {
1870 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);
1871 return false;
1872 }
1873 break;
1876 return false;
1878 break;
1880 {
1881 WaypointPath const* path = sWaypointMgr->GetPath(e.action.wpStart.pathID);
1882 if (!path || path->Nodes.empty())
1883 {
1884 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);
1885 return false;
1886 }
1888 return false;
1889
1892 break;
1893 }
1895 {
1897 return false;
1898
1900 return false;
1901 break;
1902 }
1904 {
1906 return false;
1907 break;
1908 }
1913 {
1914 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);
1915 return false;
1916 }
1917 break;
1919 {
1920 uint32 eventId = e.action.gameEventStop.id;
1921
1922 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
1923 if (eventId < 1 || eventId >= events.size())
1924 {
1925 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);
1926 return false;
1927 }
1928
1929 GameEventData const& eventData = events[eventId];
1930 if (!eventData.isValid())
1931 {
1932 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);
1933 return false;
1934 }
1935 break;
1936 }
1938 {
1939 uint32 eventId = e.action.gameEventStart.id;
1940
1941 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
1942 if (eventId < 1 || eventId >= events.size())
1943 {
1944 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);
1945 return false;
1946 }
1947
1948 GameEventData const& eventData = events[eventId];
1949 if (!eventData.isValid())
1950 {
1951 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);
1952 return false;
1953 }
1954 break;
1955 }
1956 case SMART_ACTION_EQUIP:
1957 {
1959 {
1960 if (int8 equipId = static_cast<int8>(e.action.equip.entry))
1961 {
1962 EquipmentInfo const* eInfo = sObjectMgr->GetEquipmentInfo(e.entryOrGuid, equipId);
1963 if (!eInfo)
1964 {
1965 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_EQUIP uses non-existent equipment info id {} for creature {}, skipped.", equipId, e.entryOrGuid);
1966 return false;
1967 }
1968 }
1969 }
1970 break;
1971 }
1973 {
1974 if (e.action.setInstanceData.type > 1)
1975 {
1976 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);
1977 return false;
1978 }
1979 else if (e.action.setInstanceData.type == 1)
1980 {
1982 {
1983 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);
1984 return false;
1985 }
1986 }
1987 break;
1988 }
1990 {
1991 uint32 phaseId = e.action.ingamePhaseId.id;
1993
1994 if (apply != 0 && apply != 1)
1995 {
1996 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);
1997 return false;
1998 }
1999
2000 if (!sPhaseStore.LookupEntry(phaseId))
2001 {
2002 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_ID uses invalid phaseid {} for creature {}, skipped", phaseId, e.entryOrGuid);
2003 return false;
2004 }
2005 break;
2006 }
2008 {
2009 uint32 phaseGroup = e.action.ingamePhaseGroup.groupId;
2011
2012 if (apply != 0 && apply != 1)
2013 {
2014 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);
2015 return false;
2016 }
2017
2018 if (!sDB2Manager.GetPhasesForGroup(phaseGroup))
2019 {
2020 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SET_INGAME_PHASE_GROUP uses invalid phase group id {} for creature {}, skipped", phaseGroup, e.entryOrGuid);
2021 return false;
2022 }
2023 break;
2024 }
2026 {
2027 if (!sObjectMgr->GetSceneTemplate(e.action.scene.sceneId))
2028 {
2029 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SCENE_PLAY uses sceneId {} but scene don't exist, skipped", e.action.scene.sceneId);
2030 return false;
2031 }
2032
2033 break;
2034 }
2036 {
2037 if (!sObjectMgr->GetSceneTemplate(e.action.scene.sceneId))
2038 {
2039 TC_LOG_ERROR("sql.sql", "SmartScript: SMART_ACTION_SCENE_CANCEL uses sceneId {} but scene don't exist, skipped", e.action.scene.sceneId);
2040 return false;
2041 }
2042
2043 break;
2044 }
2046 {
2048 {
2049 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);
2050 return false;
2051 }
2052 break;
2053 }
2055 {
2057 {
2058 TC_LOG_ERROR("sql.sql", "Entry {} SourceType {} Event {} Action {} does not specify duration", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
2059 return false;
2060 }
2061
2062 break;
2063 }
2065 {
2066 if (!sCinematicSequencesStore.LookupEntry(e.action.cinematic.entry))
2067 {
2068 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);
2069 return false;
2070 }
2071
2072 break;
2073 }
2075 {
2077 {
2078 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} does not specify pause duration", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
2079 return false;
2080 }
2081
2083 break;
2084 }
2086 {
2088 {
2089 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);
2090 return false;
2091 }
2092
2094 {
2095 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} uses speed 0, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType());
2096 return false;
2097 }
2098
2099 break;
2100 }
2102 {
2103 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(e.action.overrideLight.zoneId);
2104 if (!areaEntry)
2105 {
2106 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);
2107 return false;
2108 }
2109
2110 if (areaEntry->ParentAreaID != 0 && areaEntry->GetFlags().HasFlag(AreaFlags::IsSubzone))
2111 {
2112 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);
2113 return false;
2114 }
2115
2116 if (!sLightStore.LookupEntry(e.action.overrideLight.areaLightId))
2117 {
2118 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);
2119 return false;
2120 }
2121
2123 {
2124 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);
2125 return false;
2126 }
2127
2128 break;
2129 }
2131 {
2132 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(e.action.overrideWeather.zoneId);
2133 if (!areaEntry)
2134 {
2135 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);
2136 return false;
2137 }
2138
2139 if (areaEntry->ParentAreaID != 0 && areaEntry->GetFlags().HasFlag(AreaFlags::IsSubzone))
2140 {
2141 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);
2142 return false;
2143 }
2144
2145 break;
2146 }
2148 {
2149 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);
2150 break;
2151 }
2153 {
2155 {
2156 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} is trying to set invalid HP percent {}, skipped.",
2158 return false;
2159 }
2160 break;
2161 }
2163 {
2165 break;
2166 }
2168 {
2170 break;
2171 }
2173 {
2175 break;
2176 }
2178 {
2180 break;
2181 }
2183 {
2185 break;
2186 }
2188 {
2190 break;
2191 }
2193 {
2195 break;
2196 }
2198 {
2200 break;
2201 }
2203 {
2205 break;
2206 }
2208 {
2211 break;
2212 }
2214 {
2216 break;
2217 }
2219 {
2222 break;
2223 }
2225 {
2227 break;
2228 }
2230 {
2232 break;
2233 }
2235 {
2237 break;
2238 }
2240 {
2242 break;
2243 }
2244 case SMART_ACTION_EVADE:
2245 {
2247 break;
2248 }
2250 {
2252 break;
2253 }
2255 {
2256 if (!sConversationDataStore->GetConversationTemplate(e.action.conversation.id))
2257 {
2258 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);
2259 return false;
2260 }
2261
2262 break;
2263 }
2265 {
2267 break;
2268 }
2270 {
2272 break;
2273 }
2275 {
2277 break;
2278 }
2280 {
2282 return false;
2283
2285 {
2286 TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry {} SourceType {} Event {} Action {} has gameObjectAction parameter out of range (max allowed {}, current value {}), skipped.",
2288 return false;
2289 }
2290 break;
2291 }
2296 case SMART_ACTION_DIE:
2338 break;
2340 {
2342 {
2343 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);
2344 return false;
2345 }
2346 break;
2347 }
2349 {
2351 break;
2352 }
2353 // Unused
2371 case SMART_ACTION_FLEE:
2373 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);
2374 return false;
2375 default:
2376 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);
2377 return false;
2378 }
2379
2381 return false;
2382
2383 return true;
2384}
2385
2387{
2389 return true;
2390
2391 uint32 entry = 0;
2392
2394 {
2395 entry = e.event.textOver.creatureEntry;
2396 }
2397 else
2398 {
2399 switch (e.GetTargetType())
2400 {
2404 return true; // ignore
2405 default:
2406 if (e.entryOrGuid < 0)
2407 {
2409 CreatureData const* data = sObjectMgr->GetCreatureData(guid);
2410 if (!data)
2411 {
2412 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);
2413 return false;
2414 }
2415 else
2416 entry = data->id;
2417 }
2418 else
2419 entry = uint32(e.entryOrGuid);
2420 break;
2421 }
2422 }
2423
2424 if (!entry || !sCreatureTextMgr->TextExist(entry, uint8(id)))
2425 {
2426 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);
2427 return false;
2428 }
2429
2430 return true;
2431}
2432
2434{
2435 uint32 oldMSTime = getMSTime();
2436
2437 sSpellMgr->ForEachSpellInfo([this](SpellInfo const* spellInfo)
2438 {
2439 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2440 {
2441 if (spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON))
2442 SummonCreatureSpellStore.insert(std::make_pair(uint32(spellEffectInfo.MiscValue), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2443 else if (spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON_OBJECT_WILD))
2444 SummonGameObjectSpellStore.insert(std::make_pair(uint32(spellEffectInfo.MiscValue), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2445 else if (spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT) || spellEffectInfo.IsEffect(SPELL_EFFECT_KILL_CREDIT2))
2446 KillCreditSpellStore.insert(std::make_pair(uint32(spellEffectInfo.MiscValue), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2447 else if (spellEffectInfo.IsEffect(SPELL_EFFECT_CREATE_ITEM))
2448 CreateItemSpellStore.insert(std::make_pair(uint32(spellEffectInfo.ItemType), std::make_pair(spellInfo->Id, spellEffectInfo.EffectIndex)));
2449 }
2450 });
2451
2452 TC_LOG_INFO("server.loading", ">> Loaded SmartAIMgr Helpers in {} ms", GetMSTimeDiffToNow(oldMSTime));
2453}
2454
2456{
2459 KillCreditSpellStore.clear();
2460 CreateItemSpellStore.clear();
2461}
2462
2464{
2465 return SummonCreatureSpellStore.equal_range(creatureEntry);
2466}
2467
2469{
2470 return SummonGameObjectSpellStore.equal_range(gameObjectEntry);
2471}
2472
2474{
2475 return KillCreditSpellStore.equal_range(killCredit);
2476}
2477
2479{
2480 return CreateItemSpellStore.equal_range(itemId);
2481}
2482
2483ObjectGuidVector::ObjectGuidVector(ObjectVector const& objectVector) : _objectVector(objectVector)
2484{
2485 _guidVector.reserve(_objectVector.size());
2486 for (WorldObject* obj : _objectVector)
2487 _guidVector.push_back(obj->GetGUID());
2488}
2489
2491{
2492 _objectVector.clear();
2493
2494 for (ObjectGuid const& guid : _guidVector)
2495 if (WorldObject* obj = ObjectAccessor::GetWorldObject(ref, guid))
2496 _objectVector.push_back(obj);
2497}
#define sAreaTriggerDataStore
#define M_PI
Definition: Common.h:115
#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:538
Difficulty
Definition: DBCEnums.h:873
@ DIFFICULTY_NONE
Definition: DBCEnums.h:874
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
Definition: DatabaseEnv.cpp:20
uint8_t uint8
Definition: Define.h:144
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
uint32_t uint32
Definition: Define.h:142
#define sGameEventMgr
Definition: GameEventMgr.h:177
@ TO_BE_DECIDED
#define TC_LOG_WARN(filterType__,...)
Definition: Log.h:162
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
bool IsInvalidMovementGeneratorType(uint8 const type)
@ TEMPSUMMON_MANUAL_DESPAWN
Definition: ObjectDefines.h:70
@ TEMPSUMMON_TIMED_OR_DEAD_DESPAWN
Definition: ObjectDefines.h:63
#define sObjectMgr
Definition: ObjectMgr.h:1946
@ QUEST_FLAGS_COMPLETION_AREA_TRIGGER
Definition: QuestDef.h:196
@ QUEST_FLAGS_COMPLETION_EVENT
Definition: QuestDef.h:195
@ TARGET_UNIT_CASTER
@ SPELL_EFFECT_KILL_CREDIT
@ SPELL_EFFECT_KILL_CREDIT2
@ 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_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_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_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_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_COMBAT_STOP
@ 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_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_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_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_AREATRIGGER_ONTRIGGER
@ SMART_EVENT_DISTANCE_GAMEOBJECT
@ SMART_EVENT_ON_SPELLCLICK
@ SMART_EVENT_MOVEMENTINFORM
@ SMART_EVENT_RANGE
@ SMART_EVENT_MANA_PCT
@ SMART_EVENT_PASSENGER_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_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_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
@ 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:33
@ SPAWN_TYPE_GAMEOBJECT
Definition: SpawnData.h:35
@ SPAWN_TYPE_CREATURE
Definition: SpawnData.h:34
#define sSpellMgr
Definition: SpellMgr.h:849
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition: Timer.h:57
uint32 getMSTime()
Definition: Timer.h:33
@ REACT_AGGRESSIVE
Definition: UnitDefines.h:508
#define MAX_MOVE_TYPE
Definition: UnitDefines.h:128
@ MAX_SHEATH_STATE
Definition: UnitDefines.h:86
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
#define sWaypointMgr
@ WORLD_SEL_SMART_SCRIPTS
Definition: WorldDatabase.h:35
Class used to access individual fields of database query result.
Definition: Field.h:90
uint8 GetUInt8() const
Definition: Field.cpp:30
std::string GetString() const
Definition: Field.cpp:118
int64 GetInt64() const
Definition: Field.cpp:86
uint16 GetUInt16() const
Definition: Field.cpp:46
float GetFloat() const
Definition: Field.cpp:94
uint32 GetUInt32() const
Definition: Field.cpp:62
std::vector< GameEventData > GameEventDataMap
Definition: GameEventMgr.h:103
ObjectVector _objectVector
void UpdateObjects(WorldObject const &ref) const
ObjectGuidVector(ObjectVector const &objectVector)
GuidVector _guidVector
uint64 LowType
Definition: ObjectGuid.h:278
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 IsAreaTriggerValid(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 SchoolMask
Definition: SpellInfo.h:413
std::vector< SpellEffectInfo > const & GetEffects() const
Definition: SpellInfo.h:576
void apply(T *val)
Definition: ByteConverter.h:41
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:56
uint16 ParentAreaID
Definition: DB2Structure.h:131
EnumFlag< AreaFlags > GetFlags() const
Definition: DB2Structure.h:153
std::string AIName
Definition: CreatureData.h:513
bool isValid() const
Definition: GameEventMgr.h:77
struct SmartAction::@66::@135 setRoot
struct SmartAction::@66::@166 addToStoredTargets
uint32 sounds[4]
uint32 targetParam2
struct SmartAction::@66::@143 randomSound
struct SmartAction::@66::@79 crossCast
struct SmartAction::@66::@95 callHelp
struct SmartAction::@66::@128 enableTempGO
struct SmartAction::@66::@85 setEventPhase
uint32 repeatMax
struct SmartAction::@66::@161 conversation
SAIBool transport
struct SmartAction::@66::@144 corpseDelay
struct SmartAction::@66::@160 setHealthPct
struct SmartAction::@66::@121 delunitByte
uint32 gameObjectAction
SAIBool disable
struct SmartAction::@66::@108 wpPause
struct SmartAction::@66::@92 setInstanceData
struct SmartAction::@66::@131 setGoLootState
struct SmartAction::@66::@130 sendGossipMenu
struct SmartAction::@66::@105 active
struct SmartAction::@66::@115 storeTargets
SAIBool regenHealth
uint32 wps[SMART_ACTION_PARAM_COUNT]
struct SmartAction::@66::@91 killedMonster
struct SmartAction::@66::@111 setRun
SAIBool allowOverride
struct SmartAction::@66::@107 wpStart
struct SmartAction::@66::@137 creatureGroup
struct SmartAction::@66::@102 moveRandom
struct SmartAction::@66::@120 setunitByte
struct SmartAction::@66::@142 moveOffset
struct SmartAction::@66::@104 summonGO
uint32 emotes[SMART_ACTION_PARAM_COUNT]
SAIBool withDelayed
struct SmartAction::@66::@106 taxi
struct SmartAction::@66::@146 groupSpawn
SAIBool withInstant
struct SmartAction::@66::@162 setImmunePC
struct SmartAction::@66::@81 threatPCT
uint32 targetParam1
struct SmartAction::@66::@118 equip
struct SmartAction::@66::@148 randomTimedEvent
struct SmartAction::@66::@134 setHealthRegen
struct SmartAction::@66::@96 setSheath
SAIBool toRespawnPosition
struct SmartAction::@66::@70 faction
struct SmartAction::@66::@129 moveToPos
SAIBool attackInvoker
struct SmartAction::@66::@69 simpleTalk
SAIBool useTalkTarget
uint32 areaLightId
struct SmartAction::@66::@88 follow
struct SmartAction::@66::@97 forceDespawn
SAIBool uninteractible
struct SmartAction::@66::@155 spellVisualKit
struct SmartAction::@66::@77 randomEmote
struct SmartAction::@66::@117 movie
struct SmartAction::@66::@140 gameEventStart
struct SmartAction::@66::@80 summonCreature
struct SmartAction::@66::@167 becomePersonalClone
struct SmartAction::@66::@109 wpStop
struct SmartAction::@66::@75 questOffer
uint32 spellVisualKitId
struct SmartAction::@66::@138 power
struct SmartAction::@66::@123 randTimedActionList
struct SmartAction::@66::@165 activateGameObject
struct SmartAction::@66::@122 timedActionList
struct SmartAction::@66::@101 setData
struct SmartAction::@66::@94 updateTemplate
struct SmartAction::@66::@141 closestWaypointFromList
struct SmartAction::@66::@103 visibility
struct SmartAction::@66::@152 scene
struct SmartAction::@66::@158 setHover
struct SmartAction::@66::@154 movementSpeed
SAIBool immunePC
struct SmartAction::@66::@159 evade
SAIBool updateLevel
uint32 actionLists[SMART_ACTION_PARAM_COUNT]
SMART_ACTION type
struct SmartAction::@66::@86 incEventPhase
struct SmartAction::@66::@125 interruptSpellCasting
uint32 targetType
struct SmartAction::@66::@93 setInstanceData64
uint32 phases[SMART_ACTION_PARAM_COUNT]
struct SmartAction::@66::@83 autoAttack
struct SmartAction::@66::@99 ingamePhaseId
struct SmartAction::@66::@113 teleport
struct SmartAction::@66::@153 cinematic
SAIBool onlySelf
struct SmartAction::@66::@112 setDisableGravity
SAIBool attack
uint32 repeatMin
struct SmartAction::@66::@87 removeAura
SAIBool onlyOwnedAuras
uint32 textGroupID
uint32 overrideLightId
struct SmartAction::@66::@145 disableEvade
struct SmartAction::@66::@98 invincHP
struct SmartAction::@66::@100 ingamePhaseGroup
struct SmartAction::@66::@124 randRangeTimedActionList
struct SmartAction::@66::@116 timeEvent
SAIBool repeat
SAIBool disablePathfinding
struct SmartAction::@66::@139 gameEventStop
struct SmartAction::@66::@156 overrideLight
struct SmartAction::@66::@168 triggerGameEvent
struct SmartAction::@66::@136 goState
SAIBool withEmote
SAIBool useSaiTargetAsGameEventSource
struct SmartAction::@66::@126 jump
struct SmartAction::@66::@133 setRangedMovement
uint32 speedFraction
struct SmartAction::@66::@164 setUninteractible
SAIBool directAdd
struct SmartAction::@66::@163 setImmuneNPC
struct SmartAction::@66::@76 react
struct SmartAction::@66::@78 cast
struct SmartAction::@66::@127 fleeAssist
struct SmartAction::@66::@84 combatMove
struct SmartAction::@66::@110 item
struct SmartAction::@66::@169 doAction
uint32 speedInteger
struct SmartAction::@66::@89 randomPhase
struct SmartAction::@66::@132 sendTargetToTarget
uint32 factionID
struct SmartAction::@66::@68 talk
SAIBool immuneNPC
struct SmartAction::@66::@149 pauseMovement
struct SmartAction::@66::@150 respawnData
uint32 movementType
struct SmartAction::@66::@157 overrideWeather
struct SmartAction::@66::@170 raw
struct SmartAction::@66::@82 threat
struct SmartAction::@66::@71 morphOrMount
struct SmartAction::@66::@90 randomPhaseRange
struct SmartAction::@66::@147 loadEquipment
struct SmartAction::@66::@114 setCounter
uint32 event_flags
struct SmartEvent::@29::@36 minMax
uint32 event_phase_mask
struct SmartEvent::@29::@65 raw
struct SmartEvent::@29::@47 dataSet
struct SmartEvent::@29::@46 movementInform
struct SmartEvent::@29::@32 kill
std::string param_string
struct SmartEvent::@29::@48 waypoint
uint32 cooldownMax
struct SmartEvent::@29::@40 summoned
struct SmartEvent::@29::@58 goLootStateChanged
struct SmartEvent::@29::@55 gossipHello
struct SmartEvent::@29::@37 targetCasting
struct SmartEvent::@29::@62 distance
struct SmartEvent::@29::@60 doAction
uint32 spellId
struct SmartEvent::@29::@59 eventInform
struct SmartEvent::@29::@39 missingBuff
uint32 hostilityMode
Hostility mode of the event. 0: hostile, 1: not hostile, 2: any
uint32 repeatMin
struct SmartEvent::@29::@63 counter
struct SmartEvent::@29::@38 friendlyCC
struct SmartEvent::@29::@34 los
uint32 event_chance
struct SmartEvent::@29::@35 respawn
struct SmartEvent::@29::@56 gossip
SAIBool playerOnly
struct SmartEvent::@29::@61 friendlyHealthPct
struct SmartEvent::@29::@45 charm
uint32 creatureEntry
struct SmartEvent::@29::@52 areatrigger
struct SmartEvent::@29::@33 spellHit
struct SmartEvent::@29::@42 questObjective
struct SmartEvent::@29::@50 transportRelocate
uint32 repeatMax
uint32 gameEventId
uint32 textGroupID
uint32 cooldownMin
struct SmartEvent::@29::@54 timedEvent
struct SmartEvent::@29::@64 spellCast
struct SmartEvent::@29::@49 transportAddCreature
uint32 minHpPct
struct SmartEvent::@29::@51 instancePlayerEnter
struct SmartEvent::@29::@57 gameEvent
struct SmartEvent::@29::@44 aura
SAIBool onRemove
uint32 maxHpPct
struct SmartEvent::@29::@31 minMaxRepeat
SMART_EVENT type
uint32 creature
struct SmartEvent::@29::@53 textOver
uint32 GetScriptType() const
uint32 GetEventType() const
uint32 GetTargetType() const
std::vector< Difficulty > Difficulties
SmartScriptType source_type
uint32 GetActionType() const
struct SmartTarget::@171::@178 playerDistance
struct SmartTarget::@171::@175 unitRange
struct SmartTarget::@171::@185 goClosest
struct SmartTarget::@171::@187 closestFriendly
SAIBool useCharmerOrOwner
SAIBool playerOnly
struct SmartTarget::@171::@184 unitClosest
struct SmartTarget::@171::@182 goGUID
struct SmartTarget::@171::@190 threatList
struct SmartTarget::@171::@183 goDistance
struct SmartTarget::@171::@191 raw
struct SmartTarget::@171::@186 closestAttackable
struct SmartTarget::@171::@189 vehicle
struct SmartTarget::@171::@177 unitDistance
struct SmartTarget::@171::@181 goRange
struct SmartTarget::@171::@173 hostilRandom
struct SmartTarget::@171::@176 unitGUID
struct SmartTarget::@171::@188 owner
struct SmartTarget::@171::@174 farthest
SMARTAI_TARGETS type
struct SmartTarget::@171::@179 playerRange
struct SmartTarget::@171::@180 stored
uint32 id
Definition: SpawnData.h:104
std::vector< WaypointNode > Nodes