OregonCore  revision fb2a440-git
Your Favourite TBC server
CreatureEventAI.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "Common.h"
19 #include "CreatureEventAI.h"
20 #include "CreatureEventAIMgr.h"
21 #include "ObjectMgr.h"
22 #include "Spell.h"
23 #include "World.h"
24 #include "Cell.h"
25 #include "CellImpl.h"
26 #include "GameEventMgr.h"
27 #include "GridNotifiers.h"
28 #include "GridNotifiersImpl.h"
29 #include "InstanceData.h"
30 #include "Spell.h"
31 #include "SpellMgr.h"
32 #include "CreatureAIImpl.h"
33 #include "ConditionMgr.h"
34 
35 bool CreatureEventAIHolder::UpdateRepeatTimer(Creature* creature, uint32 repeatMin, uint32 repeatMax)
36 {
37  if (repeatMin == repeatMax)
38  Time = repeatMin;
39  else if (repeatMax > repeatMin)
40  Time = urand(repeatMin, repeatMax);
41  else
42  {
43  sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u (Type = %u) has RandomMax < RandomMin. Event repeating disabled.", creature->GetEntry(), Event.event_id, Event.event_type);
44  Enabled = false;
45  return false;
46  }
47 
48  return true;
49 }
50 
52 {
53  if (creature->GetAIName() == "EventAI")
54  return PERMIT_BASE_SPECIAL;
55  return PERMIT_BASE_NO;
56 }
57 
59 {
60  hasLosEvents = false;
61 
62  // Need make copy for filter unneeded steps and safe in case table reload
63  CreatureEventAI_Event_Map::const_iterator CreatureEvents = CreatureEAI_Mgr.GetCreatureEventAIMap().find(me->GetEntry());
64  if (CreatureEvents != CreatureEAI_Mgr.GetCreatureEventAIMap().end())
65  {
66  std::vector<CreatureEventAI_Event>::const_iterator i;
67  for (i = (*CreatureEvents).second.begin(); i != (*CreatureEvents).second.end(); ++i)
68  {
69 
70  //Debug check
71  #ifndef OREGON_DEBUG
72  if ((*i).event_flags & EFLAG_DEBUG_ONLY)
73  continue;
74  #endif
75  if (((*i).event_flags & (EFLAG_HEROIC | EFLAG_NORMAL)) && me->GetMap()->IsDungeon())
76  {
77  if ((me->GetMap()->IsHeroic() && (*i).event_flags & EFLAG_HEROIC) ||
78  (!me->GetMap()->IsHeroic() && (*i).event_flags & EFLAG_NORMAL))
79  {
80  //event flagged for instance mode
82 
83  if ((*i).event_type == EVENT_T_OOC_LOS)
84  hasLosEvents = true;
85  }
86  continue;
87  }
89 
90  if ((*i).event_type == EVENT_T_OOC_LOS)
91  hasLosEvents = true;
92  }
93  //EventMap had events but they were not added because they must be for instance
94  if (CreatureEventAIList.empty())
95  sLog.outError("CreatureEventAI: Creature %u has events but no events added to list because of instance flags.", me->GetEntry());
96  }
97  else
98  sLog.outError("CreatureEventAI: EventMap for Creature %u is empty but creature is using CreatureEventAI.", me->GetEntry());
99 
101  Phase = 0;
102  MeleeEnabled = true;
103 
105 
106  //Handle Spawned Events
107  if (!bEmptyList)
108  {
109  for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
110  if (SpawnedEventConditionsCheck((*i).Event))
111  ProcessEvent(*i);
112  }
113 }
114 
116 {
117  if (!pHolder.Enabled || pHolder.Time)
118  return false;
119 
120  //Check the inverse phase mask (event doesn't trigger if current phase bit is set in mask)
121  if (pHolder.Event.event_inverse_phase_mask & (1 << Phase))
122  return false;
123 
124  CreatureEventAI_Event const& event = pHolder.Event;
125 
126  //Check event conditions based on the event type, also reset events
127  switch (event.event_type)
128  {
129  case EVENT_T_TIMER:
130  if (!me->IsInCombat())
131  return false;
132 
133  //Repeat Timers
134  pHolder.UpdateRepeatTimer(me, event.timer.repeatMin, event.timer.repeatMax);
135  break;
136  case EVENT_T_TIMER_OOC:
137  if (me->IsInCombat() || me->IsInEvadeMode())
138  return false;
139 
140  //Repeat Timers
141  pHolder.UpdateRepeatTimer(me, event.timer.repeatMin, event.timer.repeatMax);
142  break;
143  case EVENT_T_HP:
144  {
145  if (!me->IsInCombat() || !me->GetMaxHealth())
146  return false;
147 
148  uint32 perc = (me->GetHealth() * 100) / me->GetMaxHealth();
149 
150  if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
151  return false;
152 
153  //Repeat Timers
154  pHolder.UpdateRepeatTimer(me, event.percent_range.repeatMin, event.percent_range.repeatMax);
155  break;
156  }
157  case EVENT_T_MANA:
158  {
159  if (!me->IsInCombat() || !me->GetMaxPower(POWER_MANA))
160  return false;
161 
162  uint32 perc = (me->GetPower(POWER_MANA) * 100) / me->GetMaxPower(POWER_MANA);
163 
164  if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
165  return false;
166 
167  //Repeat Timers
168  pHolder.UpdateRepeatTimer(me, event.percent_range.repeatMin, event.percent_range.repeatMax);
169  break;
170  }
171  case EVENT_T_AGGRO:
172  break;
173  case EVENT_T_KILL:
174  //Repeat Timers
175  pHolder.UpdateRepeatTimer(me, event.kill.repeatMin, event.kill.repeatMax);
176  break;
177  case EVENT_T_DEATH:
178  case EVENT_T_EVADE:
179  break;
180  case EVENT_T_SPELLHIT:
181  //Spell hit is special case, param1 and param2 handled within CreatureEventAI::SpellHit
182 
183  //Repeat Timers
184  pHolder.UpdateRepeatTimer(me, event.spell_hit.repeatMin, event.spell_hit.repeatMax);
185  break;
186  case EVENT_T_RANGE:
187  //Repeat Timers
188  pHolder.UpdateRepeatTimer(me, event.range.repeatMin, event.range.repeatMax);
189  break;
190  case EVENT_T_OOC_LOS:
191  //Repeat Timers
192  pHolder.UpdateRepeatTimer(me, event.ooc_los.repeatMin, event.ooc_los.repeatMax);
193  break;
194  case EVENT_T_SPAWNED:
195  break;
196  case EVENT_T_TARGET_HP:
197  {
198  if (!me->IsInCombat() || !me->GetVictim() || !me->GetVictim()->GetMaxHealth())
199  return false;
200 
201  uint32 perc = (me->GetVictim()->GetHealth() * 100) / me->GetVictim()->GetMaxHealth();
202 
203  if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
204  return false;
205 
206  //Repeat Timers
207  pHolder.UpdateRepeatTimer(me, event.percent_range.repeatMin, event.percent_range.repeatMax);
208  break;
209  }
211  if (!me->IsInCombat() || !me->GetVictim() || !me->GetVictim()->IsNonMeleeSpellCast(false, false, true))
212  return false;
213 
214  //Repeat Timers
215  pHolder.UpdateRepeatTimer(me, event.target_casting.repeatMin, event.target_casting.repeatMax);
216  break;
217  case EVENT_T_FRIENDLY_HP:
218  {
219  if (!me->IsInCombat())
220  return false;
221 
222  Unit* pUnit = DoSelectLowestHpFriendly(event.friendly_hp.radius, event.friendly_hp.hpDeficit);
223  if (!pUnit)
224  return false;
225 
226  pActionInvoker = pUnit;
227 
228  //Repeat Timers
229  pHolder.UpdateRepeatTimer(me, event.friendly_hp.repeatMin, event.friendly_hp.repeatMax);
230  break;
231  }
233  {
234  if (!me->IsInCombat())
235  return false;
236 
237  std::list<Creature*> pList;
238  DoFindFriendlyCC(pList, event.friendly_is_cc.radius);
239 
240  //List is empty
241  if (pList.empty())
242  return false;
243 
244  //We don't really care about the whole list, just return first available
245  pActionInvoker = *(pList.begin());
246 
247  //Repeat Timers
248  pHolder.UpdateRepeatTimer(me, event.friendly_is_cc.repeatMin, event.friendly_is_cc.repeatMax);
249  break;
250  }
252  {
253  std::list<Creature*> pList;
254  DoFindFriendlyMissingBuff(pList, event.friendly_buff.radius, event.friendly_buff.spellId);
255 
256  //List is empty
257  if (pList.empty())
258  return false;
259 
260  //We don't really care about the whole list, just return first available
261  pActionInvoker = *(pList.begin());
262 
263  //Repeat Timers
264  pHolder.UpdateRepeatTimer(me, event.friendly_buff.repeatMin, event.friendly_buff.repeatMax);
265  break;
266  }
270  {
271  //Prevent event from occuring on no unit or non creatures
272  if (!pActionInvoker || pActionInvoker->GetTypeId() != TYPEID_UNIT)
273  return false;
274 
275  //Creature id doesn't match up
276  if (pActionInvoker->ToCreature()->GetEntry() != event.summon_unit.creatureId)
277  return false;
278 
279  //Repeat Timers
280  pHolder.UpdateRepeatTimer(me, event.summon_unit.repeatMin, event.summon_unit.repeatMax);
281  break;
282  }
283  case EVENT_T_TARGET_MANA:
284  {
285  if (!me->IsInCombat() || !me->GetVictim() || !me->GetVictim()->GetMaxPower(POWER_MANA))
286  return false;
287 
289 
290  if (perc > event.percent_range.percentMax || perc < event.percent_range.percentMin)
291  return false;
292 
293  //Repeat Timers
294  pHolder.UpdateRepeatTimer(me, event.percent_range.repeatMin, event.percent_range.repeatMax);
295  break;
296  }
299  break;
300  case EVENT_T_BUFFED:
301  {
302  //Note: checked only aura for effect 0, if need check aura for effect 1/2 then
303  // possible way: pack in event.buffed.amount 2 uint16 (ammount+effectIdx)
304  Aura* aura = me->GetAura(event.buffed.spellId, 0);
305  if (!aura || uint32(aura->GetStackAmount()) < event.buffed.amount)
306  return false;
307 
308  //Repeat Timers
309  pHolder.UpdateRepeatTimer(me, event.buffed.repeatMin, event.buffed.repeatMax);
310  break;
311  }
313  {
314  //Prevent event from occuring on no unit
315  if (!pActionInvoker)
316  return false;
317 
318  //Note: checked only aura for effect 0, if need check aura for effect 1/2 then
319  // possible way: pack in event.buffed.amount 2 uint16 (ammount+effectIdx)
320  Aura* aura = pActionInvoker->GetAura(event.buffed.spellId, 0);
321  if (!aura || uint32(aura->GetStackAmount()) < event.buffed.amount)
322  return false;
323 
324  //Repeat Timers
325  pHolder.UpdateRepeatTimer(me, event.buffed.repeatMin, event.buffed.repeatMax);
326  break;
327  }
329  {
330  //Note: checked only aura for effect 0, if need check aura for effect 1/2 then
331  // possible way: pack in event.buffed.amount 2 uint16 (ammount+effectIdx)
332  Aura* aura = me->GetAura(event.buffed.spellId, 0);
333  if (aura && uint32(aura->GetStackAmount()) >= event.buffed.amount)
334  return false;
335 
336  //Repeat Timers
337  pHolder.UpdateRepeatTimer(me, event.buffed.repeatMin, event.buffed.repeatMax);
338  break;
339  }
341  {
342  if (!me->IsInCombat() || !me->GetVictim())
343  return false;
344 
345  Aura* aura = me->GetVictim()->GetAura(event.buffed.spellId, 0);
346  if (aura && uint32(aura->GetStackAmount()) >= event.buffed.amount)
347  return false;
348 
349  //Repeat Timers
350  pHolder.UpdateRepeatTimer(me, event.buffed.repeatMin, event.buffed.repeatMax);
351  break;
352  }
353  default:
354  sLog.outErrorDb("CreatureEventAI: Creature %u using Event %u has invalid Event Type(%u), missing from ProcessEvent() Switch.", me->GetEntry(), pHolder.Event.event_id, pHolder.Event.event_type);
355  break;
356  }
357 
358  //Disable non-repeatable events
359  if (!(pHolder.Event.event_flags & EFLAG_REPEATABLE))
360  pHolder.Enabled = false;
361 
362  //Store random here so that all random actions match up
363  uint32 rnd = rand();
364 
365  //Return if chance for event is not met
366  if (pHolder.Event.event_chance <= rnd % 100)
367  return false;
368 
369  //Process actions
370  for (uint8 j = 0; j < MAX_ACTIONS; ++j)
371  ProcessAction(pHolder.Event.action[j], rnd, pHolder.Event.event_id, pActionInvoker);
372 
373  return true;
374 }
375 
377 {
378  switch (action.type)
379  {
380  case ACTION_T_TEXT:
382  {
383  if (!action.text.TextId[0])
384  return;
385 
386  int32 temp = 0;
387 
388  if (action.type == ACTION_T_TEXT)
389  {
390  if (action.text.TextId[1] && action.text.TextId[2])
391  temp = action.text.TextId[urand(0, 2)];
392  else if (action.text.TextId[1] && urand(0, 1))
393  temp = action.text.TextId[1];
394  else
395  temp = action.text.TextId[0];
396  }
397  // ACTION_T_CHANCED_TEXT, chance hits
398  else if (urand(0, 99) < action.chanced_text.chance)
399  {
400  if (action.chanced_text.TextId[0] && action.chanced_text.TextId[1])
401  temp = action.chanced_text.TextId[urand(0, 1)];
402  else
403  temp = action.chanced_text.TextId[0];
404  }
405 
406  if (temp)
407  {
408  Unit* target = NULL;
409 
410  if (pActionInvoker)
411  {
412  if (pActionInvoker->GetTypeId() == TYPEID_PLAYER)
413  target = pActionInvoker;
414  else if (Unit* owner = pActionInvoker->GetOwner())
415  {
416  if (owner->GetTypeId() == TYPEID_PLAYER)
417  target = owner;
418  }
419  }
420  else
421  {
422  target = me->GetVictim();
423  if (target && target->GetTypeId() != TYPEID_PLAYER)
424  if (Unit* owner = target->GetOwner())
425  if (owner->GetTypeId() == TYPEID_PLAYER)
426  target = owner;
427  }
428 
429  DoScriptText(temp, me, target);
430  }
431  break;
432  }
434  {
435  if (action.set_faction.factionId)
436  me->SetFaction(action.set_faction.factionId);
437  else
438  {
439  if (CreatureInfo const* ci = GetCreatureTemplateStore(me->GetEntry()))
440  {
441  //if no id provided, assume reset and then use default
442  if (me->GetFaction() != ci->faction)
443  me->SetFaction(ci->faction);
444  }
445  }
446  break;
447  }
449  {
450  if (action.morph.creatureId || action.morph.modelId)
451  {
452  //set model based on entry from creature_template
453  if (action.morph.creatureId)
454  {
455  if (CreatureInfo const* ci = GetCreatureTemplateStore(action.morph.creatureId))
456  {
457  uint32 display_id = sObjectMgr.ChooseDisplayId(0, ci);
458  me->SetDisplayId(display_id);
459  }
460  }
461  //if no param1, then use value from param2 (modelId)
462  else
463  me->SetDisplayId(action.morph.modelId);
464  }
465  else
466  me->DeMorph();
467  break;
468  }
469  case ACTION_T_SOUND:
470  me->SendPlaySound(action.sound.soundId, false);
471  break;
472  case ACTION_T_EMOTE:
473  me->HandleEmoteCommand(action.emote.emoteId);
474  break;
476  {
477  int32 temp = GetRandActionParam(rnd, action.random_sound.soundId1, action.random_sound.soundId2, action.random_sound.soundId3);
478  if (temp >= 0)
479  me->SendPlaySound(temp, false);
480  break;
481  }
483  {
484  int32 temp = GetRandActionParam(rnd, action.random_emote.emoteId1, action.random_emote.emoteId2, action.random_emote.emoteId3);
485  if (temp >= 0)
486  me->HandleEmoteCommand(temp);
487  break;
488  }
489  case ACTION_T_CAST:
490  {
491  Unit* target = GetTargetByType(action.cast.target, pActionInvoker);
492  const SpellEntry* spell = sSpellStore.LookupEntry(action.cast.spellId);
493 
494  SpellCastResult castResult = CanCast(target, spell, action.cast.castFlags);
495 
496  switch (castResult)
497  {
501  {
502  // Melee current victim if flag not set
503  if (!(action.cast.castFlags & CAST_NO_MELEE_IF_OOM))
504  {
506  {
507  case CHASE_MOTION_TYPE:
508  case FOLLOW_MOTION_TYPE:
510  case IDLE_MOTION_TYPE:
511  SetCombatMovement(true);
512  break;
513  default:
514  break;
515  }
516  }
517  break;
518  }
519  case SPELL_CAST_OK:
520  /* @TODO: Correctly switch between melee/ranged states.
521  SetCombatMovement(false);*/
522  default:
523  break;
524  }
525 
526  break;
527  }
528  case ACTION_T_SUMMON:
529  {
530  Unit* target = GetTargetByType(action.summon.target, pActionInvoker);
531 
532  Creature* pCreature = NULL;
533 
534  if (action.summon.duration)
535  pCreature = me->SummonCreature(action.summon.creatureId, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, action.summon.duration);
536  else
537  pCreature = me->SummonCreature(action.summon.creatureId, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
538 
539  if (!pCreature)
540  sLog.outErrorDb("CreatureEventAI: failed to spawn creature %u. Spawn event %d is on creature %d", action.summon.creatureId, EventId, me->GetEntry());
541  else if (action.summon.target != TARGET_T_SELF && target)
542  pCreature->AI()->AttackStart(target);
543  break;
544  }
546  if (Unit* target = GetTargetByType(action.threat_single_pct.target, pActionInvoker))
547  me->getThreatManager().modifyThreatPercent(target, action.threat_single_pct.percent);
548  break;
550  {
552  for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i)
553  if (Unit* unit = Unit::GetUnit(*me, (*i)->getUnitGuid()))
554  me->getThreatManager().modifyThreatPercent(unit, action.threat_all_pct.percent);
555  break;
556  }
558  if (Unit* target = GetTargetByType(action.quest_event.target, pActionInvoker))
559  if (target->GetTypeId() == TYPEID_PLAYER)
560  target->ToPlayer()->AreaExploredOrEventHappens(action.quest_event.questId);
561  break;
562  case ACTION_T_CAST_EVENT:
563  if (Unit* target = GetTargetByType(action.cast_event.target, pActionInvoker))
564  if (target->GetTypeId() == TYPEID_PLAYER)
565  target->ToPlayer()->CastedCreatureOrGO(action.cast_event.creatureId, me->GetGUID(), action.cast_event.spellId);
566  break;
568  {
569  Unit* target = GetTargetByType(action.set_unit_field.target, pActionInvoker);
570 
571  // not allow modify important for integrity object fields
572  if (action.set_unit_field.field < OBJECT_END || action.set_unit_field.field >= UNIT_END)
573  return;
574 
575  if (target)
576  target->SetUInt32Value(action.set_unit_field.field, action.set_unit_field.value);
577 
578  break;
579  }
581  if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker))
582  target->SetFlag(UNIT_FIELD_FLAGS, action.unit_flag.value);
583  break;
585  if (Unit* target = GetTargetByType(action.unit_flag.target, pActionInvoker))
586  target->RemoveFlag(UNIT_FIELD_FLAGS, action.unit_flag.value);
587  break;
589  MeleeEnabled = action.auto_attack.state != 0;
590  break;
592  // ignore no affect case
593  if (CombatMovementEnabled == (action.combat_movement.state != 0) || me->IsNonMeleeSpellCast(false))
594  return;
595 
596  SetCombatMovement(action.combat_movement.state != 0);
597 
598  if (CombatMovementEnabled && action.combat_movement.melee && me->IsInCombat() && me->GetVictim())
600  else if (action.combat_movement.melee && me->IsInCombat() && me->GetVictim())
602  break;
603  case ACTION_T_SET_PHASE:
604  Phase = action.set_phase.phase;
605  break;
606  case ACTION_T_INC_PHASE:
607  {
608  int32 new_phase = int32(Phase) + action.set_inc_phase.step;
609  if (new_phase < 0)
610  {
611  sLog.outErrorDb("CreatureEventAI: Event %d decrease Phase under 0. CreatureEntry = %d", EventId, me->GetEntry());
612  Phase = 0;
613  }
614  else if (new_phase >= MAX_PHASE)
615  {
616  sLog.outErrorDb("CreatureEventAI: Event %d incremented Phase above %u. Phase mask cannot be used with phases past %u. CreatureEntry = %d", EventId, MAX_PHASE - 1, MAX_PHASE - 1, me->GetEntry());
617  Phase = MAX_PHASE - 1;
618  }
619  else
620  Phase = new_phase;
621 
622  break;
623  }
624  case ACTION_T_EVADE:
625  EnterEvadeMode();
626  break;
629  break;
631  if (pActionInvoker && pActionInvoker->GetTypeId() == TYPEID_PLAYER)
632  {
633  if (Unit* Temp = Unit::GetUnit(*me, pActionInvoker->GetGUID()))
634  if (Temp->GetTypeId() == TYPEID_PLAYER)
635  Temp->ToPlayer()->GroupEventHappens(action.quest_event_all.questId, me);
636  }
637  break;
639  {
641  for (ThreatContainer::StorageType::const_iterator i = threatList.begin(); i != threatList.end(); ++i)
642  if (Unit* unit = Unit::GetUnit(*me, (*i)->getUnitGuid()))
643  if (unit->GetTypeId() == TYPEID_PLAYER)
644  unit->ToPlayer()->CastedCreatureOrGO(action.cast_event_all.creatureId, me->GetGUID(), action.cast_event_all.spellId);
645  break;
646  }
648  if (Unit* target = GetTargetByType(action.remove_aura.target, pActionInvoker))
649  target->RemoveAurasDueToSpell(action.remove_aura.spellId);
650  break;
652  AttackDistance = (float)action.ranged_movement.distance;
653  AttackAngle = action.ranged_movement.angle / 180.0f * M_PI;
654 
656  {
658  {
659  me->GetMotionMaster()->Clear(false);
661  }
662  }
663  break;
665  Phase = GetRandActionParam(rnd, action.random_phase.phase1, action.random_phase.phase2, action.random_phase.phase3);
666  break;
668  if (action.random_phase_range.phaseMin <= action.random_phase_range.phaseMax)
669  Phase = urand(action.random_phase_range.phaseMin, action.random_phase_range.phaseMax);
670  else
671  sLog.outErrorDb("CreatureEventAI: ACTION_T_RANDOM_PHASE_RANGE cannot have Param2 < Param1. Event = %d. CreatureEntry = %d", EventId, me->GetEntry());
672  break;
673  case ACTION_T_SUMMON_ID:
674  {
675  Unit* target = GetTargetByType(action.summon_id.target, pActionInvoker);
676 
677  CreatureEventAI_Summon_Map::const_iterator i = CreatureEAI_Mgr.GetCreatureEventAISummonMap().find(action.summon_id.spawnId);
678  if (i == CreatureEAI_Mgr.GetCreatureEventAISummonMap().end())
679  {
680  sLog.outErrorDb("CreatureEventAI: failed to spawn creature %u. Summon map index %u does not exist. EventID %d. CreatureID %d", action.summon_id.creatureId, action.summon_id.spawnId, EventId, me->GetEntry());
681  return;
682  }
683 
684  Creature* pCreature = NULL;
685  if ((*i).second.SpawnTimeSecs)
686  pCreature = me->SummonCreature(action.summon_id.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, (*i).second.SpawnTimeSecs);
687  else
688  pCreature = me->SummonCreature(action.summon_id.creatureId, (*i).second.position_x, (*i).second.position_y, (*i).second.position_z, (*i).second.orientation, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 0);
689 
690  if (!pCreature)
691  sLog.outErrorDb("CreatureEventAI: failed to spawn creature %u. EventId %d.Creature %d", action.summon_id.creatureId, EventId, me->GetEntry());
692  else if (action.summon_id.target != TARGET_T_SELF && target)
693  pCreature->AI()->AttackStart(target);
694 
695  break;
696  }
698  //first attempt player who tapped creature
699  if (Player* pPlayer = me->GetLootRecipient())
700  pPlayer->RewardPlayerAndGroupAtEvent(action.killed_monster.creatureId, pPlayer); // pPlayer as param is a hacky solution not to use GUID
701  else
702  {
703  //if not available, use pActionInvoker
704  if (Unit* pTarget = GetTargetByType(action.killed_monster.target, pActionInvoker))
705  if (Player* pPlayer2 = pTarget->GetCharmerOrOwnerPlayerOrPlayerItself())
706  pPlayer2->RewardPlayerAndGroupAtEvent(action.killed_monster.creatureId, pPlayer2);
707  }
708  break;
710  {
712  if (!pInst)
713  {
714  sLog.outErrorDb("CreatureEventAI: Event %d attempt to set instance data without instance script. Creature %d", EventId, me->GetEntry());
715  return;
716  }
717 
718  pInst->SetData(action.set_inst_data.field, action.set_inst_data.value);
719  break;
720  }
722  {
723  Unit* target = GetTargetByType(action.set_inst_data64.target, pActionInvoker);
724  if (!target)
725  {
726  sLog.outErrorDb("CreatureEventAI: Event %d attempt to set instance data64 but Target == NULL. Creature %d", EventId, me->GetEntry());
727  return;
728  }
729 
731  if (!pInst)
732  {
733  sLog.outErrorDb("CreatureEventAI: Event %d attempt to set instance data64 without instance script. Creature %d", EventId, me->GetEntry());
734  return;
735  }
736 
737  pInst->SetData(action.set_inst_data64.field, target->GetGUID());
738  break;
739  }
741  if (me->GetEntry() == action.update_template.creatureId)
742  {
743 
744  sLog.outErrorDb("CreatureEventAI: Event %d ACTION_T_UPDATE_TEMPLATE call with param1 == current entry. Creature %d", EventId, me->GetEntry());
745  return;
746  }
747 
748  me->UpdateEntry(action.update_template.creatureId, action.update_template.team ? HORDE : ALLIANCE);
749  break;
750  case ACTION_T_DIE:
751  if (me->isDead())
752  {
753 
754  sLog.outErrorDb("CreatureEventAI: Event %d ACTION_T_DIE on dead creature. Creature %d", EventId, me->GetEntry());
755  return;
756  }
758  break;
760  {
762  break;
763  }
765  {
766  me->CallForHelp(action.call_for_help.radius);
767  break;
768  }
769  break;
770 
771  // Oregon ONLY
773  me->SetReactState(ReactStates(action.raw.param1));
774  break;
776  AttackStart(me->SelectNearestTarget((float)action.raw.param1));
777  break;
778  case ACTION_T_SUMMON_GO:
779  {
780  GameObject* pObject = NULL;
781 
782  float x, y, z;
783  me->GetPosition(x, y, z);
784  pObject = me->SummonGameObject(action.raw.param1, x, y, z, 0, 0, 0, 0, 0, action.raw.param2);
785  if (!pObject)
786  sLog.outErrorDb("OSCR: EventAI failed to spawn object %u. Spawn event %d is on creature %d", action.raw.param1, EventId, me->GetEntry());
787  break;
788  }
789 
790  case ACTION_T_SET_SHEATH:
791  {
792  me->SetSheath(SheathState(action.set_sheath.sheath));
793  break;
794  }
796  {
797  me->ForcedDespawn();
798  break;
799  }
801  {
802  if (action.invincibility_hp_level.is_percent)
803  InvinceabilityHpLevel = me->GetMaxHealth() * action.invincibility_hp_level.hp_level / 100;
804  else
806  break;
807  }
809  {
810  if (action.mount.creatureId || action.mount.modelId)
811  {
812  // set model based on entry from creature_template
813  if (action.mount.creatureId)
814  {
815  if (CreatureInfo const* cInfo = GetCreatureTemplateStore(action.mount.creatureId))
816  {
817  uint32 display_id = sObjectMgr.ChooseDisplayId(0, cInfo);
818  me->Mount(display_id);
819  }
820  }
821  //if no param1, then use value from param2 (modelId)
822  else
823  me->Mount(action.mount.modelId);
824  }
825  else
826  me->Dismount();
827 
828  break;
829  }
830  }
831 }
832 
834 {
835  Reset();
836 
837  if (bEmptyList)
838  return;
839 
840  //Handle Spawned Events
841  for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
842  if (SpawnedEventConditionsCheck((*i).Event))
843  ProcessEvent(*i);
844 }
845 
847 {
849  EventDiff = 0;
850 
851  if (bEmptyList)
852  return;
853 
854  //Reset all events to enabled
855  for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
856  {
857  CreatureEventAI_Event const& event = (*i).Event;
858  switch (event.event_type)
859  {
860  //Reset all out of combat timers
861  case EVENT_T_TIMER_OOC:
862  {
863  if ((*i).UpdateRepeatTimer(me, event.timer.initialMin, event.timer.initialMax))
864  (*i).Enabled = true;
865  break;
866  }
867  //default:
868  //@todo enable below code line / verify this is correct to enable events previously disabled (ex. aggro yell), instead of enable this in void EnterCombat()
869  //(*i).Enabled = true;
870  //(*i).Time = 0;
871  //break;
872  }
873  }
874 }
875 
877 {
878  if (!bEmptyList)
879  {
880  for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
881  {
882  if ((*i).Event.event_type == EVENT_T_REACHED_HOME)
883  ProcessEvent(*i);
884  }
885  }
886 
887  Reset();
888 }
889 
891 {
893 
894  if (bEmptyList)
895  return;
896 
897  //Handle Evade events
898  for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
899  {
900  if ((*i).Event.event_type == EVENT_T_EVADE)
901  ProcessEvent(*i);
902  }
903 }
904 
906 {
907  Reset();
908 
909  if (bEmptyList)
910  return;
911 
912  //Handle Evade events
913  for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
914  {
915  if ((*i).Event.event_type == EVENT_T_DEATH)
916  ProcessEvent(*i, killer);
917  }
918 
919  // reset phase after any death state events
920  Phase = 0;
921 }
922 
924 {
925  if (bEmptyList || victim->GetTypeId() != TYPEID_PLAYER)
926  return;
927 
928  for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
929  {
930  if ((*i).Event.event_type == EVENT_T_KILL)
931  ProcessEvent(*i, victim);
932  }
933 }
934 
936 {
937  if (bEmptyList || !pUnit)
938  return;
939 
940  for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
941  {
942  if ((*i).Event.event_type == EVENT_T_SUMMONED_UNIT)
943  ProcessEvent(*i, pUnit);
944  }
945 }
946 
948 {
949  me->InterruptNonMeleeSpells(false);
950  //Check for on combat start events
951  if (!bEmptyList)
952  {
953  for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
954  {
955  CreatureEventAI_Event const& event = (*i).Event;
956  switch (event.event_type)
957  {
958  case EVENT_T_AGGRO:
959  (*i).Enabled = true;
960  ProcessEvent(*i, enemy);
961  break;
962  //Reset all in combat timers
963  case EVENT_T_TIMER:
964  if ((*i).UpdateRepeatTimer(me, event.timer.initialMin, event.timer.initialMax))
965  (*i).Enabled = true;
966  break;
967  //All normal events need to be re-enabled and their time set to 0
968  default:
969  (*i).Enabled = true;
970  (*i).Time = 0;
971  break;
972  }
973  }
974  }
975 
977  EventDiff = 0;
978 }
979 
981 {
982  if (!who)
983  return;
984 
985  if (me->Attack(who, MeleeEnabled))
986  {
989  else
990  {
992  me->StopMoving();
993  }
994  }
995 }
996 
998 {
999  //Check for OOC LOS Event
1000  if (hasLosEvents)
1001  {
1002  //those checks are done in CreatureAI::MoveInLineOfSight as well,
1003  //for this reason moved into this if
1004 
1005  if (!who)
1006  return;
1007 
1008  if (me->GetVictim())
1009  return;
1010 
1011  for (std::list<CreatureEventAIHolder>::iterator itr = CreatureEventAIList.begin(); itr != CreatureEventAIList.end(); ++itr)
1012  {
1013  CreatureEventAI_Event aiEvent = (*itr).Event;
1014 
1015  if (aiEvent.event_type == EVENT_T_OOC_LOS)
1016  {
1017  bool isHostile = me->IsHostileTo(who);
1018 
1019  //if friendly event && who is not hostile OR hostile event && who is hostile
1020  if ((aiEvent.ooc_los.noHostile && !isHostile) ||
1021  (!aiEvent.ooc_los.noHostile && isHostile))
1022  {
1023  //can trigger if closer than fMaxAllowedRange
1024  float fMaxAllowedRange = aiEvent.ooc_los.maxRange;
1025 
1026  //if range is ok and we are actually in LOS
1027  if (me->IsWithinDistInMap(who, fMaxAllowedRange) && me->IsWithinLOSInMap(who))
1028  {
1029  ProcessEvent(*itr, who);
1030  }
1031  }
1032  }
1033  }
1034  }
1035 
1037 }
1038 
1039 void CreatureEventAI::SpellHit(Unit* pUnit, const SpellEntry* pSpell)
1040 {
1041 
1042  if (bEmptyList)
1043  return;
1044 
1045  for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
1046  if ((*i).Event.event_type == EVENT_T_SPELLHIT)
1047  //If spell id matches (or no spell id) & if spell school matches (or no spell school)
1048  if (!(*i).Event.spell_hit.spellId || pSpell->Id == (*i).Event.spell_hit.spellId)
1049  if (pSpell->SchoolMask & (*i).Event.spell_hit.schoolMask)
1050  ProcessEvent(*i, pUnit);
1051 }
1052 
1054 {
1055  //Check if we are in combat (also updates calls threat update code)
1056  bool Combat = UpdateVictim();
1057 
1058  if (!bEmptyList)
1059  {
1060  //Events are only updated once every EVENT_UPDATE_TIME ms to prevent lag with large amount of events
1061  if (EventUpdateTime <= diff)
1062  {
1063  EventDiff += diff;
1064 
1065  //Check for time based events
1066  for (std::list<CreatureEventAIHolder>::iterator i = CreatureEventAIList.begin(); i != CreatureEventAIList.end(); ++i)
1067  {
1068  //Decrement Timers
1069  if ((*i).Time)
1070  {
1071  if (EventDiff <= (*i).Time)
1072  {
1073  //Do not decrement timers if event cannot trigger in this phase
1074  if (!((*i).Event.event_inverse_phase_mask & (1 << Phase)))
1075  (*i).Time -= EventDiff;
1076 
1077  //Skip processing of events that have time remaining
1078  continue;
1079  }
1080  else (*i).Time = 0;
1081  }
1082 
1083  //Events that are updated every EVENT_UPDATE_TIME
1084  switch ((*i).Event.event_type)
1085  {
1086  case EVENT_T_TIMER_OOC:
1087  ProcessEvent(*i);
1088  break;
1089  case EVENT_T_TIMER:
1090  case EVENT_T_MANA:
1091  case EVENT_T_HP:
1092  case EVENT_T_TARGET_HP:
1094  case EVENT_T_FRIENDLY_HP:
1095  if (me->GetVictim())
1096  ProcessEvent(*i);
1097  break;
1098  case EVENT_T_RANGE:
1099  if (me->GetVictim())
1100  if (me->IsInMap(me->GetVictim()))
1101  if (me->IsInRange(me->GetVictim(), (float)(*i).Event.range.minDist, (float)(*i).Event.range.maxDist))
1102  ProcessEvent(*i);
1103  break;
1104  }
1105  }
1106 
1107  EventDiff = 0;
1109  }
1110  else
1111  {
1112  EventDiff += diff;
1113  EventUpdateTime -= diff;
1114  }
1115  }
1116 
1117  //Melee Auto-Attack
1118  if (Combat && MeleeEnabled)
1120 }
1121 
1123 {
1124  switch (rnd % 3)
1125  {
1126  case 0:
1127  return param1;
1128  case 1:
1129  return param2;
1130  case 2:
1131  return param3;
1132  }
1133  return 0;
1134 }
1135 
1137 {
1138  switch (rnd % 3)
1139  {
1140  case 0:
1141  return param1;
1142  case 1:
1143  return param2;
1144  case 2:
1145  return param3;
1146  }
1147  return 0;
1148 }
1149 
1151 {
1152  switch (Target)
1153  {
1154  case TARGET_T_SELF:
1155  return me;
1156  case TARGET_T_HOSTILE:
1157  return me->GetVictim();
1167  return pActionInvoker;
1168  default:
1169  return NULL;
1170  };
1171 }
1172 
1174 {
1176  Cell cell(p);
1177  cell.SetNoCreate();
1178 
1179  Unit* pUnit = NULL;
1180 
1181  Oregon::MostHPMissingInRange u_check(me, range, MinHPDiff);
1183 
1185 
1186  cell.Visit(p, grid_unit_searcher, *me->GetMap(), *me, range);
1187  return pUnit;
1188 }
1189 
1190 void CreatureEventAI::DoFindFriendlyCC(std::list<Creature*>& _list, float range)
1191 {
1193  Cell cell(p);
1194  cell.SetNoCreate();
1195 
1196  Oregon::FriendlyCCedInRange u_check(me, range);
1198 
1200 
1201  cell.Visit(p, grid_creature_searcher, *me->GetMap(), *me, range);
1202 }
1203 
1204 void CreatureEventAI::DoFindFriendlyMissingBuff(std::list<Creature*>& _list, float range, uint32 spellid)
1205 {
1207  Cell cell(p);
1208  cell.SetNoCreate();
1209 
1210  Oregon::FriendlyMissingBuffInRange u_check(me, range, spellid);
1212 
1214 
1215  cell.Visit(p, grid_creature_searcher, *me->GetMap(), *me, range);
1216 }
1217 
1218 //*********************************
1219 //*** Functions used globally ***
1220 
1221 void CreatureEventAI::DoScriptText(int32 textEntry, WorldObject* pSource, Unit* target)
1222 {
1223  if (!pSource)
1224  {
1225  sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i, invalid Source pointer.", textEntry);
1226  return;
1227  }
1228 
1229  if (textEntry >= 0)
1230  {
1231  sLog.outErrorDb("CreatureEventAI: DoScriptText with source entry %u (TypeId=%u, guid=%u) attempts to process text entry %i, but text entry must be negative.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), textEntry);
1232  return;
1233  }
1234 
1235  CreatureEventAI_TextMap::const_iterator i = CreatureEAI_Mgr.GetCreatureEventAITextMap().find(textEntry);
1236 
1237  if (i == CreatureEAI_Mgr.GetCreatureEventAITextMap().end())
1238  {
1239  sLog.outErrorDb("CreatureEventAI: DoScriptText with source entry %u (TypeId=%u, guid=%u) could not find text entry %i.", pSource->GetEntry(), pSource->GetTypeId(), pSource->GetGUIDLow(), textEntry);
1240  return;
1241  }
1242 
1243  sLog.outDebug("CreatureEventAI: DoScriptText: text entry=%i, Sound=%u, Type=%u, Language=%u, Emote=%u", textEntry, (*i).second.SoundId, (*i).second.Type, (*i).second.Language, (*i).second.Emote);
1244 
1245  if ((*i).second.SoundId)
1246  {
1247  if (GetSoundEntriesStore()->LookupEntry((*i).second.SoundId))
1248  pSource->SendPlaySound((*i).second.SoundId, false);
1249  else
1250  sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i tried to process invalid sound id %u.", textEntry, (*i).second.SoundId);
1251  }
1252 
1253  if ((*i).second.Emote)
1254  {
1255  if (pSource->GetTypeId() == TYPEID_UNIT || pSource->GetTypeId() == TYPEID_PLAYER)
1256  ((Unit*)pSource)->HandleEmoteCommand((*i).second.Emote);
1257  else
1258  sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i tried to process emote for invalid TypeId (%u).", textEntry, pSource->GetTypeId());
1259  }
1260 
1261  switch ((*i).second.Type)
1262  {
1263  case CHAT_TYPE_SAY:
1264  pSource->MonsterSay(textEntry, (*i).second.Language, target ? target->GetGUID() : 0);
1265  break;
1266  case CHAT_TYPE_YELL:
1267  pSource->MonsterYell(textEntry, (*i).second.Language, target ? target->GetGUID() : 0);
1268  break;
1269  case CHAT_TYPE_TEXT_EMOTE:
1270  pSource->MonsterTextEmote(textEntry, target ? target->GetGUID() : 0);
1271  break;
1272  case CHAT_TYPE_BOSS_EMOTE:
1273  pSource->MonsterTextEmote(textEntry, target ? target->GetGUID() : 0, true);
1274  break;
1275  case CHAT_TYPE_WHISPER:
1276  {
1277  if (target && target->GetTypeId() == TYPEID_PLAYER)
1278  pSource->MonsterWhisper(textEntry, target->GetGUID());
1279  else sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry);
1280  }
1281  break;
1283  {
1284  if (target && target->GetTypeId() == TYPEID_PLAYER)
1285  pSource->MonsterWhisper(textEntry, target->GetGUID(), true);
1286  else sLog.outErrorDb("CreatureEventAI: DoScriptText entry %i cannot whisper without target unit (TYPEID_PLAYER).", textEntry);
1287  }
1288  break;
1289  case CHAT_TYPE_ZONE_YELL:
1290  pSource->MonsterYellToZone(textEntry, (*i).second.Language, target ? target->GetGUID() : 0);
1291  break;
1292  }
1293 }
1294 
1296 {
1297  Unit* caster = me;
1298 
1299  if (flags & CAST_FORCE_TARGET_SELF)
1300  caster = target;
1301 
1302  if (!spell)
1303  {
1304  sLog.outErrorDb("CreatureEventAI::CanCast by creature entry %u attempt to cast spell but spell does not exist.", me->GetEntry());
1305  return SPELL_FAILED_UNKNOWN;
1306  }
1307 
1308  // Allowed to cast only if not casting (unless we interrupt ourself) or if spell is triggered
1309  if (!caster->IsNonMeleeSpellCast(false) || (flags & (CAST_TRIGGERED | CAST_INTURRUPT_PREVIOUS)))
1310  {
1311  // No target so we can't cast
1312  if (!target)
1313  return SPELL_FAILED_BAD_TARGETS;
1314 
1315  // If cast flag CAST_AURA_NOT_PRESENT is active, check if target already has aura on them
1316  if (flags & CAST_AURA_NOT_PRESENT)
1317  {
1318  if (target->HasAura(spell->Id))
1320  }
1321 
1322  // Silenced so we can't cast
1324  return SPELL_FAILED_SILENCED;
1325 
1326  // Target is not within LoS
1327  if (!caster->IsWithinLOSInMap(target) && !caster->IsWithinLOS(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()))
1329 
1330  // Check for power
1331  if (!(flags & CAST_TRIGGERED) && me->GetPower((Powers)spell->powerType) < CalculatePowerCost(spell, me, GetSpellSchoolMask(spell)))
1332  return SPELL_FAILED_NO_POWER;
1333 
1334  SpellRangeEntry const* TempRange = NULL;
1335  TempRange = GetSpellRangeStore()->LookupEntry(spell->rangeIndex);
1336 
1337  //Unit is out of range of this spell
1338  if (!me->IsInRange(target, TempRange->minRange, TempRange->maxRange))
1340 
1341  // Interrupt any previous spell
1342  if (flags & CAST_INTURRUPT_PREVIOUS && caster->IsNonMeleeSpellCast(false))
1343  caster->InterruptNonMeleeSpells(false);
1344 
1345  caster->CastSpell(target, spell, flags & CAST_TRIGGERED, NULL, NULL);
1346  return SPELL_CAST_OK;
1347  }
1348  else
1350 }
1351 
1352 void CreatureEventAI::ReceiveEmote(Player* pPlayer, uint32 text_emote)
1353 {
1354  if (bEmptyList)
1355  return;
1356 
1357  for (std::list<CreatureEventAIHolder>::iterator itr = CreatureEventAIList.begin(); itr != CreatureEventAIList.end(); ++itr)
1358  {
1359  if ((*itr).Event.event_type == EVENT_T_RECEIVE_EMOTE)
1360  {
1361  if ((*itr).Event.receive_emote.emoteId != text_emote)
1362  return;
1363 
1364  Condition* cond = new Condition();
1365  cond->Type = ConditionType((*itr).Event.receive_emote.condition);
1366  cond->ConditionValue1 = (*itr).Event.receive_emote.conditionValue1;
1367  cond->ConditionValue2 = (*itr).Event.receive_emote.conditionValue2;
1368 
1369  ConditionSourceInfo info(pPlayer);
1370  if (cond->Meets(info))
1371  {
1372  sLog.outDebug("CreatureEventAI: ReceiveEmote CreatureEventAI: Condition ok, processing");
1373  ProcessEvent(*itr, pPlayer);
1374  }
1375  }
1376  }
1377 }
1378 
1379 void CreatureEventAI::DamageTaken(Unit* /*done_by*/, uint32& damage)
1380 {
1381  if (InvinceabilityHpLevel > 0 && me->GetHealth() < InvinceabilityHpLevel + damage)
1382  {
1384  damage = 0;
1385  else
1386  damage = me->GetHealth() - InvinceabilityHpLevel;
1387  }
1388 }
1389 
1391 {
1392  if (event.event_type != EVENT_T_SPAWNED)
1393  return false;
1394 
1395  switch (event.spawned.condition)
1396  {
1397  case SPAWNED_EVENT_ALWAY:
1398  // always
1399  return true;
1400  case SPAWNED_EVENT_MAP:
1401  // map ID check
1402  return me->GetMapId() == event.spawned.conditionValue1;
1403  case SPAWNED_EVENT_ZONE:
1404  // zone ID check
1405  return me->GetZoneId() == event.spawned.conditionValue1 || me->GetAreaId() == event.spawned.conditionValue1;
1406  default:
1407  break;
1408  }
1409 
1410  return false;
1411 }
1412 
bool UpdateRepeatTimer(Creature *creature, uint32 repeatMin, uint32 repeatMax)
void KilledUnit(Unit *victim)
virtual void EnterEvadeMode()
Definition: CreatureAI.cpp:219
Unit * GetTargetByType(uint32 Target, Unit *pActionInvoker)
GameObject * SummonGameObject(uint32 entry, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime)
Definition: Object.cpp:2225
void SendPlaySound(uint32 Sound, bool OnlySelf)
Definition: Object.cpp:1790
struct CreatureEventAI_Action::@3::@34 update_template
ConditionType Type
Definition: ConditionMgr.h:186
struct CreatureEventAI_Action::@3::@12 cast
Unit * DoSelectLowestHpFriendly(float range, uint32 MinHPDiff)
bool Attack(Unit *victim, bool meleeAttack)
Definition: Unit.cpp:7390
uint32 CalculatePowerCost(SpellEntry const *spellInfo, Unit const *caster, SpellSchoolMask schoolMask)
Definition: SpellMgr.cpp:303
struct CreatureEventAI_Action::@3::@27 ranged_movement
#define CreatureEAI_Mgr
void DamageTaken(Unit *done_by, uint32 &damage)
void Mount(uint32 mount, uint32 spellId=0)
Definition: Unit.cpp:9270
struct CreatureEventAI_Action::@3::@17 cast_event
void MoveIdle(MovementSlot slot=MOTION_SLOT_ACTIVE)
uint32 GetMaxHealth() const
Definition: Unit.h:1075
struct CreatureEventAI_Action::@3::@31 killed_monster
float AttackAngle
Definition: CreatureAI.h:212
bool UpdateVictim()
Definition: CreatureAI.cpp:276
DBCStorage< SpellRangeEntry > const * GetSpellRangeStore()
Definition: DBCStores.cpp:780
void modifyThreatPercent(Unit *victim, int32 percent)
Map * GetMap() const
Definition: Object.h:841
uint32 GetFaction() const
Definition: Unit.h:1116
struct CreatureEventAI_Action::@3::@37 invincibility_hp_level
void Clear(bool reset=true)
Definition: MotionMaster.h:145
bool ProcessEvent(CreatureEventAIHolder &pHolder, Unit *pActionInvoker=NULL)
void ProcessAction(CreatureEventAI_Action const &action, uint32 rnd, uint32 EventId, Unit *pActionInvoker)
void SendMeleeAttackStop(Unit *victim=NULL)
Definition: Unit.cpp:2642
void MonsterTextEmote(const char *text, uint64 TargetGuid, bool IsBossEmote=false)
Definition: Object.cpp:1504
void MonsterSay(const char *text, uint32 language, uint64 TargetGuid)
Definition: Object.cpp:1490
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false) const
Definition: Unit.cpp:3547
void MoveChase(Unit *target, float dist=0.0f, float angle=0.0f)
struct CreatureEventAI_Action::@3::@23 set_inc_phase
static int Permissible(const Creature *)
Unit * SelectNearestTarget(float dist=0, bool playerOnly=false) const
Definition: Creature.cpp:1864
void Dismount()
Definition: Unit.cpp:9303
void SetCombatMovement(bool enable)
Set combat movement (on/off)
Definition: CreatureAI.cpp:317
MotionMaster * GetMotionMaster()
Definition: Unit.h:1890
uint32 GetZoneId() const
Definition: Object.cpp:1179
struct CreatureEventAI_Action::@3::@22 set_phase
TempSummon * SummonCreature(uint32 id, const Position &pos, TempSummonType spwtype=TEMPSUMMON_MANUAL_DESPAWN, uint32 despwtime=0)
Definition: Object.cpp:2091
bool IsInCombat() const
Definition: Unit.h:1243
EventAI_ActionType type
#define MAX_ACTIONS
#define sLog
Log class singleton.
Definition: Log.h:187
MovementGeneratorType GetCurrentMovementGeneratorType() const
ThreatContainer::StorageType const & getThreatList() const
void SetUInt32Value(uint16 index, uint32 value)
Definition: Object.cpp:779
ACE_INT32 int32
Definition: Define.h:67
bool IsWithinLOSInMap(const WorldObject *obj) const
Definition: Object.cpp:1229
struct CreatureEventAI_Action::@3::@13 summon
void JustSummoned(Creature *pUnit)
bool IsInEvadeMode() const
Definition: Creature.cpp:2298
uint32 powerType
Definition: DBCStructure.h:709
void ReceiveEmote(Player *pPlayer, uint32 text_emote)
bool IsDungeon() const
Definition: Map.h:427
bool IsWithinLOS(float x, float y, float z) const
Definition: Object.cpp:1243
void SetNoCreate()
Definition: Cell.h:76
struct CreatureEventAI_Action::@3::@7 morph
uint32 GetGUIDLow() const
Definition: Object.h:166
void MonsterYell(const char *text, uint32 language, uint64 TargetGuid)
Definition: Object.cpp:1497
uint32 DealDamage(Unit *victim, uint32 damage, CleanDamage const *cleanDamage=NULL, DamageEffectType damagetype=DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *spellProto=NULL, bool durabilityLoss=true)
Definition: Unit.cpp:910
Aura * GetAura(uint32 spellId, uint32 effindex)
Definition: Unit.cpp:4641
#define sObjectMgr
Definition: ObjectMgr.h:1285
ConditionType
Definition: ConditionMgr.h:29
DBCStorage< SpellEntry > sSpellStore(SpellEntryfmt)
void ForcedDespawn(uint32 timeMSToDespawn=0)
Definition: Creature.cpp:1702
uint32 rangeIndex
Definition: DBCStructure.h:714
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true) const
Definition: Object.h:774
uint32 GetPower(Powers power) const
Definition: Unit.h:1096
#define EVENT_UPDATE_TIME
void MonsterWhisper(const char *text, uint64 receiver, bool IsBossWhisper=false)
Definition: Object.cpp:1511
struct CreatureEventAI_Action::@3::@30 summon_id
SpellSchoolMask GetSpellSchoolMask(SpellEntry const *spellInfo)
Definition: SpellMgr.h:481
SheathState
Definition: Unit.h:220
struct CreatureEventAI_Action::@3::@40 raw
Creature *const me
Definition: CreatureAI.h:68
void DoFleeToGetAssistance()
Definition: Creature.cpp:712
uint8 GetTypeId() const
Definition: Object.h:210
struct CreatureEventAI_Action::@3::@11 random_emote
CreatureEventAI_Action action[MAX_ACTIONS]
struct CreatureEventAI_Action::@3::@38 mount
ACE_UINT8 uint8
Definition: Define.h:73
Powers
uint32 GetMaxPower(Powers power) const
Definition: Unit.h:1097
DBCStorage< SoundEntriesEntry > const * GetSoundEntriesStore()
Definition: DBCStores.cpp:772
struct CreatureEventAI_Action::@3::@35 call_for_help
bool IsHeroic() const
Definition: Map.h:435
void SetDisplayId(uint32 modelId)
Definition: Unit.cpp:11975
struct CreatureEventAI_Action::@3::@5 text
struct CreatureEventAI_Event::@41::@48 ooc_los
void DoScriptText(int32 textEntry, WorldObject *pSource, Unit *target)
Unit * GetVictim() const
Definition: Unit.h:1013
uint32 InvinceabilityHpLevel
float GetPositionY() const
Definition: Position.h:98
void DeMorph()
Definition: Unit.cpp:3664
SpellCastResult CanCast(Unit *target, SpellEntry const *spell, uint32 flags)
virtual void SetData(uint32, uint32)
Definition: ZoneScript.h:61
void CastSpell(Unit *Victim, uint32 spellId, bool triggered, Item *castItem=NULL, Aura *triggeredByAura=NULL, uint64 originalCaster=0)
Definition: Unit.cpp:1223
CreatureAI * AI() const
Definition: Creature.h:517
void GetPosition(float &x, float &y) const
Definition: Position.h:102
void UpdateAI(const uint32 diff)
float GetPositionZ() const
Definition: Position.h:99
void CallForHelp(float fRadius)
Definition: Creature.cpp:1965
void SendMeleeAttackStart(Unit *victim)
Definition: Unit.cpp:2633
void SpellHit(Unit *pUnit, const SpellEntry *pSpell)
std::list< CreatureEventAIHolder > CreatureEventAIList
uint32 GetMapId() const
Definition: Object.h:591
bool CombatMovementEnabled
Combat movement currently enabled.
Definition: CreatureAI.h:209
uint32 SchoolMask
Definition: DBCStructure.h:772
bool IsInMap(const WorldObject *obj) const
Definition: Object.h:745
uint32 GetAreaId() const
Definition: Object.cpp:1184
struct CreatureEventAI_Action::@3::@9 emote
struct CreatureEventAI_Action::@3::@16 quest_event
void MoveInLineOfSight(Unit *who)
despawns after a specified time after the creature is out of combat
CreatureEventAI(Creature *c)
virtual void SetSheath(SheathState sheathed)
Definition: Unit.h:1113
EventId
bool SpawnedEventConditionsCheck(CreatureEventAI_Event const &event)
CreatureEventAI_Event Event
struct CreatureEventAI_Event::@41::@49 spawned
void DoFindFriendlyCC(std::list< Creature * > &_list, float range)
ReactStates
Pet&#39;s behavior.
Definition: Unit.h:758
struct CreatureEventAI_Action::@3::@19 unit_flag
CellCoord ComputeCellCoord(float x, float y)
Definition: GridDefines.h:167
void MonsterYellToZone(int32 textId, uint32 language, uint64 TargetGuid)
Definition: Object.cpp:1865
void DoFindFriendlyMissingBuff(std::list< Creature * > &_list, float range, uint32 spellid)
struct CreatureEventAI_Action::@3::@21 combat_movement
struct CreatureEventAI_Action::@3::@6 set_faction
uint32 ConditionValue2
Definition: ConditionMgr.h:188
struct CreatureEventAI_Action::@3::@14 threat_single_pct
Definition: Cell.h:46
despawns after a specified time OR when the creature disappears
Player * GetLootRecipient() const
Definition: Creature.cpp:998
bool IsInRange(WorldObject const *obj, float minRange, float maxRange, bool is3D=true) const
Definition: Object.cpp:1299
struct CreatureEventAI_Action::@3::@32 set_inst_data
struct CreatureEventAI_Action::@3::@25 cast_event_all
int32 GetStackAmount()
Definition: SpellAuras.h:443
Target
uint32 GetRandActionParam(uint32 rnd, uint32 param1, uint32 param2, uint32 param3)
bool isDead() const
Definition: Unit.h:1338
struct CreatureEventAI_Action::@3::@15 threat_all_pct
struct CreatureEventAI_Action::@3::@26 remove_aura
CreatureInfo const * GetCreatureTemplateStore(uint32 entry)
Definition: ObjectMgr.cpp:7668
bool Meets(ConditionSourceInfo &sourceInfo)
bool UpdateEntry(uint32 entry, uint32 team=ALLIANCE, const CreatureData *data=NULL)
Definition: Creature.cpp:353
std::list< HostileReference * > StorageType
uint32 ConditionValue1
Definition: ConditionMgr.h:187
Unit * GetOwner() const
Definition: Unit.cpp:7625
Creature * ToCreature()
Definition: Object.h:395
void SetFaction(uint32 faction)
Definition: Unit.h:1117
struct CreatureEventAI_Action::@3::@10 random_sound
void EnterCombat(Unit *enemy)
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition: Unit.cpp:3576
ThreatManager & getThreatManager()
Definition: Unit.h:1721
struct CreatureEventAI_Action::@3::@18 set_unit_field
bool IsHostileTo(Unit const *unit) const
Definition: Unit.cpp:7334
void DoMeleeAttackIfReady()
Definition: UnitAI.cpp:45
struct CreatureEventAI_Action::@3::@39 chanced_text
void SetInCombatWithZone()
Definition: Creature.cpp:2200
virtual void MoveInLineOfSight(Unit *)
Definition: CreatureAI.cpp:159
void HandleEmoteCommand(uint32 anim_id)
Definition: Unit.cpp:1970
static Unit * GetUnit(WorldObject &object, uint64 guid)
Definition: Unit.cpp:10671
SpellCastResult
uint32 GetEntry() const
Definition: Object.h:192
#define MAX_PHASE
bool HasFlag(uint16 index, uint32 flag) const
Definition: Object.h:305
ACE_UINT32 uint32
Definition: Define.h:71
float GetPositionX() const
Definition: Position.h:97
struct CreatureEventAI_Action::@3::@24 quest_event_all
uint32 GetHealth() const
Definition: Unit.h:1074
std::string GetAIName() const
Definition: Creature.cpp:2383
Definition: Unit.h:908
Unit * SelectTarget(SelectAggroTarget target, uint32 position=0, float dist=0, bool playerOnly=false, int32 aura=0)
Definition: UnitAI.cpp:126
void StopMoving()
Definition: Unit.cpp:11917
void SetReactState(ReactStates st)
Definition: Creature.h:495
Definition: Player.h:922
virtual void AttackStart(Unit *)
Definition: UnitAI.cpp:25
float AttackDistance
How should an enemy be chased.
Definition: CreatureAI.h:211
void Visit(CellCoord const &, TypeContainerVisitor< T, CONTAINER > &visitor, Map &, WorldObject const &, float) const
Definition: CellImpl.h:121
struct CreatureEventAI_Action::@3::@33 set_inst_data64
struct CreatureEventAI_Action::@3::@20 auto_attack
void JustDied(Unit *)
struct CreatureEventAI_Action::@3::@28 random_phase
struct CreatureEventAI_Action::@3::@8 sound
struct CreatureEventAI_Action::@3::@29 random_phase_range
uint32 urand(uint32 min, uint32 max)
Definition: Util.cpp:33
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition: Unit.cpp:7641
struct CreatureEventAI_Action::@3::@36 set_sheath
const uint64 & GetGUID() const
Definition: Object.h:162
bool HasAura(uint32 spellId, uint8 effIndex=0) const
Definition: Unit.h:1262
InstanceData * GetInstanceData()
Definition: Object.cpp:1189
void AttackStart(Unit *who)