2 * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "Database/DatabaseEnv.h"
21 #include "Database/SQLStorage.h"
22 #include "CreatureEventAI.h"
23 #include "CreatureEventAIMgr.h"
24 #include "ObjectMgr.h"
25 #include "ProgressBar.h"
26 #include "Policies/SingletonImp.h"
27 #include "ObjectDefines.h"
28 #include "GridDefines.h"
30 INSTANTIATE_SINGLETON_1(CreatureEventAIMgr
);
32 // -------------------
33 void CreatureEventAIMgr::LoadCreatureEventAI_Texts()
35 // Drop Existing Text Map, only done once and we are ready to add data from multiple sources.
36 m_CreatureEventAI_TextMap
.clear();
39 LoadMangosStrings(WorldDatabase
,"creature_ai_texts",-1,1+(TEXT_SOURCE_RANGE
));
41 // Gather Additional data from EventAI Texts
42 QueryResult
*result
= WorldDatabase
.PQuery("SELECT entry, sound, type, language, emote FROM creature_ai_texts");
44 sLog
.outString("Loading EventAI Texts additional data...");
47 barGoLink
bar(result
->GetRowCount());
53 Field
* fields
= result
->Fetch();
56 int32 i
= fields
[0].GetInt32();
57 temp
.SoundId
= fields
[1].GetInt32();
58 temp
.Type
= fields
[2].GetInt32();
59 temp
.Language
= fields
[3].GetInt32();
60 temp
.Emote
= fields
[4].GetInt32();
64 sLog
.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` is not a negative value.",i
);
68 if (i
<= TEXT_SOURCE_RANGE
)
70 sLog
.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` is out of accepted entry range for table.",i
);
76 if (!sSoundEntriesStore
.LookupEntry(temp
.SoundId
))
77 sLog
.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` has Sound %u but sound does not exist.",i
,temp
.SoundId
);
80 if (!GetLanguageDescByID(temp
.Language
))
81 sLog
.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` using Language %u but Language does not exist.",i
,temp
.Language
);
83 if (temp
.Type
> CHAT_TYPE_ZONE_YELL
)
84 sLog
.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` has Type %u but this Chat Type does not exist.",i
,temp
.Type
);
88 if (!sEmotesStore
.LookupEntry(temp
.Emote
))
89 sLog
.outErrorDb("CreatureEventAI: Entry %i in table `creature_ai_texts` has Emote %u but emote does not exist.",i
,temp
.Emote
);
92 m_CreatureEventAI_TextMap
[i
] = temp
;
94 } while (result
->NextRow());
99 sLog
.outString(">> Loaded %u additional CreatureEventAI Texts data.", count
);
106 sLog
.outString(">> Loaded 0 additional CreatureEventAI Texts data. DB table `creature_ai_texts` is empty.");
111 // -------------------
112 void CreatureEventAIMgr::LoadCreatureEventAI_Summons()
115 //Drop Existing EventSummon Map
116 m_CreatureEventAI_Summon_Map
.clear();
118 //Gather additional data for EventAI
119 QueryResult
*result
= WorldDatabase
.PQuery("SELECT id, position_x, position_y, position_z, orientation, spawntimesecs FROM creature_ai_summons");
122 barGoLink
bar(result
->GetRowCount());
128 Field
*fields
= result
->Fetch();
130 CreatureEventAI_Summon temp
;
132 uint32 i
= fields
[0].GetUInt32();
133 temp
.position_x
= fields
[1].GetFloat();
134 temp
.position_y
= fields
[2].GetFloat();
135 temp
.position_z
= fields
[3].GetFloat();
136 temp
.orientation
= fields
[4].GetFloat();
137 temp
.SpawnTimeSecs
= fields
[5].GetUInt32();
139 if(!MaNGOS::IsValidMapCoord(temp
.position_x
,temp
.position_y
,temp
.position_z
,temp
.orientation
))
141 sLog
.outErrorDb("CreatureEventAI: Summon id %u have wrong coordinates (%f,%f,%f,%f), skipping.", i
,temp
.position_x
,temp
.position_y
,temp
.position_z
,temp
.orientation
);
146 m_CreatureEventAI_Summon_Map
[i
] = temp
;
148 }while (result
->NextRow());
153 sLog
.outString(">> Loaded %u CreatureEventAI summon definitions", Count
);
159 sLog
.outString(">> Loaded 0 CreatureEventAI Summon definitions. DB table `creature_ai_summons` is empty.");
164 // -------------------
165 void CreatureEventAIMgr::LoadCreatureEventAI_Scripts()
167 //Drop Existing EventAI List
168 m_CreatureEventAI_Event_Map
.clear();
171 QueryResult
*result
= WorldDatabase
.PQuery("SELECT id, creature_id, event_type, event_inverse_phase_mask, event_chance, event_flags, "
172 "event_param1, event_param2, event_param3, event_param4, "
173 "action1_type, action1_param1, action1_param2, action1_param3, "
174 "action2_type, action2_param1, action2_param2, action2_param3, "
175 "action3_type, action3_param1, action3_param2, action3_param3 "
176 "FROM creature_ai_scripts");
179 barGoLink
bar(result
->GetRowCount());
185 Field
*fields
= result
->Fetch();
187 CreatureEventAI_Event temp
;
188 temp
.event_id
= EventAI_Type(fields
[0].GetUInt32());
189 uint32 i
= temp
.event_id
;
191 temp
.creature_id
= fields
[1].GetUInt32();
192 uint32 creature_id
= temp
.creature_id
;
194 uint32 e_type
= fields
[2].GetUInt32();
195 //Report any errors in event
196 if (e_type
>= EVENT_T_END
)
198 sLog
.outErrorDb("CreatureEventAI: Event %u have wrong type (%u), skipping.", i
,e_type
);
201 temp
.event_type
= EventAI_Type(e_type
);
203 temp
.event_inverse_phase_mask
= fields
[3].GetUInt32();
204 temp
.event_chance
= fields
[4].GetUInt8();
205 temp
.event_flags
= fields
[5].GetUInt8();
206 temp
.event_param1
= fields
[6].GetUInt32();
207 temp
.event_param2
= fields
[7].GetUInt32();
208 temp
.event_param3
= fields
[8].GetUInt32();
209 temp
.event_param4
= fields
[9].GetUInt32();
211 //Creature does not exist in database
212 if (!sCreatureStorage
.LookupEntry
<CreatureInfo
>(temp
.creature_id
))
214 sLog
.outErrorDb("CreatureEventAI: Event %u has script for non-existing creature entry (%u), skipping.", i
, temp
.creature_id
);
218 //No chance of this event occuring
219 if (temp
.event_chance
== 0)
220 sLog
.outErrorDb("CreatureEventAI: Event %u has 0 percent chance. Event will never trigger!", i
);
221 //Chance above 100, force it to be 100
222 else if (temp
.event_chance
> 100)
224 sLog
.outErrorDb("CreatureEventAI: Creature %u are using event %u with more than 100 percent chance. Adjusting to 100 percent.", temp
.creature_id
, i
);
225 temp
.event_chance
= 100;
228 //Individual event checks
229 switch (temp
.event_type
)
232 case EVENT_T_TIMER_OOC
:
234 if (temp
.event_param2
< temp
.event_param1
)
235 sLog
.outErrorDb("CreatureEventAI: Creature %u are using timed event(%u) with param2 < param1 (InitialMax < InitialMin). Event will never repeat.", temp
.creature_id
, i
);
237 if (temp
.event_param4
< temp
.event_param3
)
238 sLog
.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp
.creature_id
, i
);
245 case EVENT_T_TARGET_HP
:
247 if (temp
.event_param2
> 100)
248 sLog
.outErrorDb("CreatureEventAI: Creature %u are using percentage event(%u) with param2 (MinPercent) > 100. Event will never trigger! ", temp
.creature_id
, i
);
250 if (temp
.event_param1
<= temp
.event_param2
)
251 sLog
.outErrorDb("CreatureEventAI: Creature %u are using percentage event(%u) with param1 <= param2 (MaxPercent <= MinPercent). Event will never trigger! ", temp
.creature_id
, i
);
253 if (temp
.event_flags
& EFLAG_REPEATABLE
&& !temp
.event_param3
&& !temp
.event_param4
)
255 sLog
.outErrorDb("CreatureEventAI: Creature %u has param3 and param4=0 (RepeatMin/RepeatMax) but cannot be repeatable without timers. Removing EFLAG_REPEATABLE for event %u.", temp
.creature_id
, i
);
256 temp
.event_flags
&= ~EFLAG_REPEATABLE
;
261 case EVENT_T_SPELLHIT
:
263 if (temp
.event_param1
)
265 SpellEntry
const* pSpell
= sSpellStore
.LookupEntry(temp
.event_param1
);
268 sLog
.outErrorDb("CreatureEventAI: Creature %u has non-existant SpellID(%u) defined in event %u.", temp
.creature_id
, temp
.event_param1
, i
);
272 if (temp
.event_param2_s
!= -1 && temp
.event_param2
!= pSpell
->SchoolMask
)
273 sLog
.outErrorDb("CreatureEventAI: Creature %u has param1(spellId %u) but param2 is not -1 and not equal to spell's school mask. Event %u can never trigger.", temp
.creature_id
, temp
.event_param1
, i
);
276 //TODO: fix this system with SPELL_SCHOOL_MASK. Current complicate things, using int32(-1) instead of just 0
277 //SPELL_SCHOOL_MASK_NONE = 0 and does not exist, thus it can not ever trigger or be used in SpellHit()
278 if (temp
.event_param2_s
!= -1 && temp
.event_param2_s
> SPELL_SCHOOL_MASK_ALL
)
279 sLog
.outErrorDb("CreatureEventAI: Creature %u is using invalid SpellSchoolMask(%u) defined in event %u.", temp
.creature_id
, temp
.event_param2
, i
);
281 if (temp
.event_param4
< temp
.event_param3
)
282 sLog
.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp
.creature_id
, i
);
287 case EVENT_T_OOC_LOS
:
288 case EVENT_T_FRIENDLY_HP
:
289 case EVENT_T_FRIENDLY_IS_CC
:
290 case EVENT_T_FRIENDLY_MISSING_BUFF
:
292 //Disabled check for now. Check code related to events and adjust accordingly before enable.
293 //Events should have min/max or alternative set to a static value.
294 /*if (!temp.event_param3 && !temp.event_param4)
296 sLog.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) without param3/param4 (RepeatMin/RepeatMax). Using minimum values.", temp.creature_id, i);
297 temp.event_param3 = 2500;
298 temp.event_param4 = 2500;
301 if (temp
.event_param4
< temp
.event_param3
)
302 sLog
.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param4 < param3 (RepeatMax < RepeatMin). Event will never repeat.", temp
.creature_id
, i
);
307 case EVENT_T_TARGET_CASTING
:
309 if (temp
.event_param2
< temp
.event_param1
)
310 sLog
.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with param2 < param1 (RepeatMax < RepeatMin). Event will never repeat.", temp
.creature_id
, i
);
318 case EVENT_T_SPAWNED
:
319 case EVENT_T_REACHED_HOME
:
321 if (temp
.event_flags
& EFLAG_REPEATABLE
)
323 sLog
.outErrorDb("CreatureEventAI: Creature %u has EFLAG_REPEATABLE set. Event can never be repeatable. Removing flag for event %u.", temp
.creature_id
, i
);
324 temp
.event_flags
&= ~EFLAG_REPEATABLE
;
330 case EVENT_T_RECEIVE_EMOTE
:
332 if (!sEmotesTextStore
.LookupEntry(temp
.event_param1
))
334 sLog
.outErrorDb("CreatureEventAI: Creature %u using event %u: param1 (EmoteTextId: %u) are not valid.",temp
.creature_id
, i
, temp
.event_param1
);
338 if (temp
.event_param2
== CONDITION_AD_COMMISSION_AURA
|| temp
.event_param2
== CONDITION_NO_AURA
)
340 sLog
.outErrorDb("CreatureEventAI: Creature %u using event %u: param2 (Condition: %u) are not implemented for EventAI.",temp
.creature_id
, i
, temp
.event_param2
);
344 if (!PlayerCondition::IsValid(ConditionType(temp
.event_param2
), temp
.event_param3
, temp
.event_param4
))
346 sLog
.outErrorDb("CreatureEventAI: Creature %u using event %u: param2 (Condition: %u) are not valid.",temp
.creature_id
, i
, temp
.event_param2
);
350 if (!(temp
.event_flags
& EFLAG_REPEATABLE
))
352 sLog
.outErrorDb("CreatureEventAI: Creature %u using event %u: EFLAG_REPEATABLE not set. Event must always be repeatable. Flag applied.", temp
.creature_id
, i
);
353 temp
.event_flags
|= EFLAG_REPEATABLE
;
359 case EVENT_T_SUMMONED_UNIT
:
361 if (!sCreatureStorage
.LookupEntry
<CreatureInfo
>(temp
.event_param1
))
362 sLog
.outErrorDb("CreatureEventAI: Creature %u are using event(%u) with not existed creature template id (%u) in param1, skipped.", temp
.creature_id
, i
, temp
.event_param1
);
364 if (temp
.event_param3
< temp
.event_param2
)
365 sLog
.outErrorDb("CreatureEventAI: Creature %u are using repeatable event(%u) with param3 < param2 (RepeatMax < RepeatMin). Event will never repeat.", temp
.creature_id
, i
);
370 case EVENT_T_QUEST_ACCEPT
:
371 case EVENT_T_QUEST_COMPLETE
:
372 sLog
.outErrorDb("CreatureEventAI: Creature %u using not implemented event (%u) in event %u.", temp
.creature_id
, temp
.event_id
, i
);
375 sLog
.outErrorDb("CreatureEventAI: Creature %u using not checked at load event (%u) in event %u. Need check code update?", temp
.creature_id
, temp
.event_id
, i
);
379 for (uint32 j
= 0; j
< MAX_ACTIONS
; j
++)
381 uint16 action_type
= fields
[10+(j
*4)].GetUInt16();
382 if (action_type
>= ACTION_T_END
)
384 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u has incorrect action type (%u), replace by ACTION_T_NONE.", i
, j
+1, action_type
);
385 temp
.action
[j
].type
= ACTION_T_NONE
;
389 temp
.action
[j
].type
= EventAI_ActionType(action_type
);
390 temp
.action
[j
].param1
= fields
[11+(j
*4)].GetUInt32();
391 temp
.action
[j
].param2
= fields
[12+(j
*4)].GetUInt32();
392 temp
.action
[j
].param3
= fields
[13+(j
*4)].GetUInt32();
394 //Report any errors in actions
395 switch (temp
.action
[j
].type
)
401 if (temp
.action
[j
].param1_s
< 0)
403 if (m_CreatureEventAI_TextMap
.find(temp
.action
[j
].param1_s
) == m_CreatureEventAI_TextMap
.end())
404 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u param1 refrences non-existing entry in texts table.", i
, j
+1);
406 if (temp
.action
[j
].param2_s
< 0)
408 if (m_CreatureEventAI_TextMap
.find(temp
.action
[j
].param2_s
) == m_CreatureEventAI_TextMap
.end())
409 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u param2 refrences non-existing entry in texts table.", i
, j
+1);
411 if (!temp
.action
[j
].param1_s
)
412 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u has param2, but param1 is not set. Required for randomized text.", i
, j
+1);
414 if (temp
.action
[j
].param3_s
< 0)
416 if (m_CreatureEventAI_TextMap
.find(temp
.action
[j
].param3_s
) == m_CreatureEventAI_TextMap
.end())
417 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u param3 refrences non-existing entry in texts table.", i
, j
+1);
419 if (!temp
.action
[j
].param1_s
|| !temp
.action
[j
].param2_s
)
420 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u has param3, but param1 and/or param2 is not set. Required for randomized text.", i
, j
+1);
424 case ACTION_T_SET_FACTION
:
425 if (temp
.action
[j
].param1
!=0 && !sFactionStore
.LookupEntry(temp
.action
[j
].param1
))
427 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant FactionId %u.", i
, j
+1, temp
.action
[j
].param1
);
428 temp
.action
[j
].param1
= 0;
431 case ACTION_T_MORPH_TO_ENTRY_OR_MODEL
:
432 if (temp
.action
[j
].param1
!=0 || temp
.action
[j
].param2
!=0)
434 if (temp
.action
[j
].param1
&& !sCreatureStorage
.LookupEntry
<CreatureInfo
>(temp
.action
[j
].param1
))
436 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Creature entry %u.", i
, j
+1, temp
.action
[j
].param1
);
437 temp
.action
[j
].param1
= 0;
440 if (temp
.action
[j
].param2
&& !sCreatureDisplayInfoStore
.LookupEntry(temp
.action
[j
].param2
))
442 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant ModelId %u.", i
, j
+1, temp
.action
[j
].param2
);
443 temp
.action
[j
].param2
= 0;
448 if (!sSoundEntriesStore
.LookupEntry(temp
.action
[j
].param1
))
449 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SoundID %u.", i
, j
+1, temp
.action
[j
].param1
);
451 case ACTION_T_RANDOM_SOUND
:
452 if (!sSoundEntriesStore
.LookupEntry(temp
.action
[j
].param1
))
453 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u param1 uses non-existant SoundID %u.", i
, j
+1, temp
.action
[j
].param1
);
454 if (temp
.action
[j
].param2_s
>= 0 && !sSoundEntriesStore
.LookupEntry(temp
.action
[j
].param2
))
455 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u param2 uses non-existant SoundID %u.", i
, j
+1, temp
.action
[j
].param2
);
456 if (temp
.action
[j
].param3_s
>= 0 && !sSoundEntriesStore
.LookupEntry(temp
.action
[j
].param3
))
457 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u param3 uses non-existant SoundID %u.", i
, j
+1, temp
.action
[j
].param3
);
460 if (!sEmotesStore
.LookupEntry(temp
.action
[j
].param1
))
461 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u param1 (EmoteId: %u) are not valid.", i
, j
+1, temp
.action
[j
].param1
);
463 case ACTION_T_RANDOM_EMOTE
:
464 if (!sEmotesStore
.LookupEntry(temp
.action
[j
].param1
))
465 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u param1 (EmoteId: %u) are not valid.", i
, j
+1, temp
.action
[j
].param1
);
466 if (temp
.action
[j
].param2_s
>= 0 && !sEmotesStore
.LookupEntry(temp
.action
[j
].param2
))
467 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u param2 (EmoteId: %u) are not valid.", i
, j
+1, temp
.action
[j
].param2
);
468 if (temp
.action
[j
].param3_s
>= 0 && !sEmotesStore
.LookupEntry(temp
.action
[j
].param3
))
469 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u param3 (EmoteId: %u) are not valid.", i
, j
+1, temp
.action
[j
].param3
);
473 const SpellEntry
*spell
= sSpellStore
.LookupEntry(temp
.action
[j
].param1
);
475 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i
, j
+1, temp
.action
[j
].param1
);
478 if (spell
->RecoveryTime
> 0 && temp
.event_flags
& EFLAG_REPEATABLE
)
480 //output as debug for now, also because there's no general rule all spells have RecoveryTime
481 if (temp
.event_param3
< spell
->RecoveryTime
)
482 sLog
.outDebug("CreatureEventAI: Event %u Action %u uses SpellID %u but cooldown is longer(%u) than minumum defined in event param3(%u).", i
, j
+1,temp
.action
[j
].param1
, spell
->RecoveryTime
, temp
.event_param3
);
486 if (temp
.action
[j
].param2
>= TARGET_T_END
)
487 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i
, j
+1);
490 case ACTION_T_REMOVEAURASFROMSPELL
:
492 if (!sSpellStore
.LookupEntry(temp
.action
[j
].param2
))
493 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i
, j
+1, temp
.action
[j
].param2
);
495 if (temp
.action
[j
].param1
>= TARGET_T_END
)
496 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i
, j
+1);
499 case ACTION_T_QUEST_EVENT
:
501 if (Quest
const* qid
= objmgr
.GetQuestTemplate(temp
.action
[j
].param1
))
503 if (!qid
->HasFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT
))
504 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i
, j
+1, temp
.action
[j
].param1
);
507 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i
, j
+1, temp
.action
[j
].param1
);
509 if (temp
.action
[j
].param2
>= TARGET_T_END
)
510 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i
, j
+1);
514 case ACTION_T_QUEST_EVENT_ALL
:
516 if (Quest
const* qid
= objmgr
.GetQuestTemplate(temp
.action
[j
].param1
))
518 if (!qid
->HasFlag(QUEST_MANGOS_FLAGS_EXPLORATION_OR_EVENT
))
519 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u. SpecialFlags for quest entry %u does not include |2, Action will not have any effect.", i
, j
+1, temp
.action
[j
].param1
);
522 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i
, j
+1, temp
.action
[j
].param1
);
525 case ACTION_T_CASTCREATUREGO
:
527 if (!sCreatureStorage
.LookupEntry
<CreatureInfo
>(temp
.action
[j
].param1
))
528 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i
, j
+1, temp
.action
[j
].param1
);
530 if (!sSpellStore
.LookupEntry(temp
.action
[j
].param2
))
531 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i
, j
+1, temp
.action
[j
].param2
);
533 if (temp
.action
[j
].param3
>= TARGET_T_END
)
534 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i
, j
+1);
537 case ACTION_T_CASTCREATUREGO_ALL
:
539 if (!objmgr
.GetQuestTemplate(temp
.action
[j
].param1
))
540 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant Quest entry %u.", i
, j
+1, temp
.action
[j
].param1
);
542 if (!sSpellStore
.LookupEntry(temp
.action
[j
].param2
))
543 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant SpellID %u.", i
, j
+1, temp
.action
[j
].param2
);
548 case ACTION_T_SUMMON_ID
:
550 if (!sCreatureStorage
.LookupEntry
<CreatureInfo
>(temp
.action
[j
].param1
))
551 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i
, j
+1, temp
.action
[j
].param1
);
553 if (m_CreatureEventAI_Summon_Map
.find(temp
.action
[j
].param3
) == m_CreatureEventAI_Summon_Map
.end())
554 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u summons missing CreatureEventAI_Summon %u", i
, j
+1, temp
.action
[j
].param3
);
556 if (temp
.action
[j
].param2
>= TARGET_T_END
)
557 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i
, j
+1);
560 case ACTION_T_KILLED_MONSTER
:
562 if (!sCreatureStorage
.LookupEntry
<CreatureInfo
>(temp
.action
[j
].param1
))
563 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i
, j
+1, temp
.action
[j
].param1
);
565 if (temp
.action
[j
].param2
>= TARGET_T_END
)
566 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i
, j
+1);
569 case ACTION_T_SUMMON
:
571 if (!sCreatureStorage
.LookupEntry
<CreatureInfo
>(temp
.action
[j
].param1
))
572 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i
, j
+1, temp
.action
[j
].param1
);
574 if (temp
.action
[j
].param2
>= TARGET_T_END
)
575 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i
, j
+1);
578 case ACTION_T_THREAT_SINGLE_PCT
:
579 case ACTION_T_SET_UNIT_FLAG
:
580 case ACTION_T_REMOVE_UNIT_FLAG
:
581 if (temp
.action
[j
].param2
>= TARGET_T_END
)
582 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i
, j
+1);
585 case ACTION_T_SET_UNIT_FIELD
:
586 if (temp
.action
[j
].param1
< OBJECT_END
|| temp
.action
[j
].param1
>= UNIT_END
)
587 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u param1 (UNIT_FIELD*). Index out of range for intended use.", i
, j
+1);
588 if (temp
.action
[j
].param3
>= TARGET_T_END
)
589 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i
, j
+1);
592 case ACTION_T_SET_PHASE
:
593 if (temp
.action
[j
].param1
> 31)
594 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set phase > 31. Phase mask cannot be used past phase 31.", i
, j
+1);
597 case ACTION_T_INC_PHASE
:
598 if (!temp
.action
[j
].param1
)
599 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u is incrementing phase by 0. Was this intended?", i
, j
+1);
602 case ACTION_T_SET_INST_DATA
:
604 if (!(temp
.event_flags
& EFLAG_NORMAL
) && !(temp
.event_flags
& EFLAG_HEROIC
))
605 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i
, j
+1);
607 if (temp
.action
[j
].param2
> 4/*SPECIAL*/)
608 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u attempts to set instance data above encounter state 4. Custom case?", i
, j
+1);
612 case ACTION_T_SET_INST_DATA64
:
614 if (!(temp
.event_flags
& EFLAG_NORMAL
) && !(temp
.event_flags
& EFLAG_HEROIC
))
615 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u. Cannot set instance data without event flags (normal/heroic).", i
, j
+1);
617 if (temp
.action
[j
].param2
>= TARGET_T_END
)
618 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses incorrect Target type", i
, j
+1);
622 case ACTION_T_UPDATE_TEMPLATE
:
624 if (!sCreatureStorage
.LookupEntry
<CreatureInfo
>(temp
.action
[j
].param1
))
625 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses non-existant creature entry %u.", i
, j
+1, temp
.action
[j
].param1
);
629 case ACTION_T_THREAT_ALL_PCT
:
630 if (abs(temp
.action
[j
].param1_s
) > 100)
631 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u uses invalid percent value %u.", i
, j
+1, temp
.action
[j
].param1
);
634 case ACTION_T_EVADE
: //No Params
635 case ACTION_T_FLEE
: //No Params
636 case ACTION_T_DIE
: //No Params
637 case ACTION_T_ZONE_COMBAT_PULSE
: //No Params
638 case ACTION_T_AUTO_ATTACK
: //AllowAttackState (0 = stop attack, anything else means continue attacking)
639 case ACTION_T_COMBAT_MOVEMENT
: //AllowCombatMovement (0 = stop combat based movement, anything else continue attacking)
640 case ACTION_T_RANGED_MOVEMENT
: //Distance, Angle
643 case ACTION_T_RANDOM_PHASE
: //PhaseId1, PhaseId2, PhaseId3
644 case ACTION_T_RANDOM_PHASE_RANGE
: //PhaseMin, PhaseMax
645 // check not implemented
648 case ACTION_T_RANDOM_SAY
:
649 case ACTION_T_RANDOM_YELL
:
650 case ACTION_T_RANDOM_TEXTEMOTE
:
651 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u currently unused ACTION type. Did you forget to update database?", i
, j
+1);
654 sLog
.outErrorDb("CreatureEventAI: Event %u Action %u have currently not checked at load action type (%u). Need check code update?", i
, j
+1, temp
.action
[j
].type
);
660 m_CreatureEventAI_Event_Map
[creature_id
].push_back(temp
);
662 } while (result
->NextRow());
667 sLog
.outString(">> Loaded %u CreatureEventAI scripts", Count
);
673 sLog
.outString(">> Loaded 0 CreatureEventAI scripts. DB table `creature_ai_scripts` is empty.");