Example #1
0
//perception and AI
void ADA2UE4Creature::OnSeePlayer(APawn* Pawn)
{
	ADA2UE4CreatureController* AIController = Cast<ADA2UE4CreatureController>(GetController());

	ADA2UE4Creature* SensedPawn = Cast<ADA2UE4Creature>(Pawn);
	if (AIController)// && SensedPawn->IsAlive())
	{
		//have I seen this pawn before?
		//if yes, did the hostility changed?

		Cast<ADA2UE4Creature>(SensedPawn)->LastSensedTime = GetWorld()->GetTimeSeconds();
		//TODO handle bStealth, and event integer 1 = ability
		int32 bStealth = TRUE_;
		if (!SensedPawns.Contains(SensedPawn))
		{
#ifdef DEBUG
			LogWarning(GetName() + " | OnSee " + SensedPawn->GetName() + " by " + GetName());
#endif // DEBUG
			int32 bHostile = IsObjectHostile(this, Cast<ADA2UE4Creature>(SensedPawn));
			if (bHostile) AddThreat(SensedPawn, 10.f); //default threat

			SensedPawns.Add(SensedPawn);
		}
		else if (bHostilityChanged)
		{
#ifdef DEBUG
			LogWarning(GetName() + " | OnSee Hostility changed " + SensedPawn->GetName() + " by " + GetName());
#endif // DEBUG
			bHostilityChanged = FALSE_;
			int32 bHostile = IsObjectHostile(this, Cast<ADA2UE4Creature>(SensedPawn));
			if (bHostile) AddThreat(SensedPawn, 10.f); //default threat
		}
	}
}
Example #2
0
        void UpdateAI(uint32 diff) override
        {
            if (!UpdateVictim())
                return;

            DoMeleeAttackIfReady();

            if (ChaseTimer <= diff)
            {
                if (!IsChasing)
                {
                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                    {
                        Talk(SAY_WOLF_HOOD);
                        DoCast(target, SPELL_LITTLE_RED_RIDING_HOOD, true);
                        TempThreat = GetThreat(target);
                        if (TempThreat)
                            ModifyThreatByPercent(target, -100);
                        HoodGUID = target->GetGUID();
                        AddThreat(target, 1000000.0f);
                        ChaseTimer = 20000;
                        IsChasing = true;
                    }
                }
                else
                {
                    IsChasing = false;

                    if (Unit* target = ObjectAccessor::GetUnit(*me, HoodGUID))
                    {
                        HoodGUID.Clear();
                        if (GetThreat(target))
                            ModifyThreatByPercent(target, -100);
                        AddThreat(target, TempThreat);
                        TempThreat = 0;
                    }

                    ChaseTimer = 40000;
                }
            } else ChaseTimer -= diff;

            if (IsChasing)
                return;

            if (FearTimer <= diff)
            {
                DoCastVictim(SPELL_TERRIFYING_HOWL);
                FearTimer = urand(25000, 35000);
            } else FearTimer -= diff;

            if (SwipeTimer <= diff)
            {
                DoCastVictim(SPELL_WIDE_SWIPE);
                SwipeTimer = urand(25000, 30000);
            } else SwipeTimer -= diff;
        }
Example #3
0
 void IsSummonedBy(Unit* summoner) override
 {
     targetGUID = summoner->GetGUID();
     summoner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED);
     summoner->SetControlled(true, UNIT_STATE_ROOT);
     me->SetInCombatWith(summoner);
     AddThreat(summoner, 250.0f);
     AddThreat(me, 250.0f, summoner);
     if (Creature* target = ObjectAccessor::GetCreature(*me, targetGUID))
     {
         DoCast(target, SPELL_FLASH_FREEZE_HELPER, true);
         // Prevents to have Ice Block on other place than target is
         me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation());
     }
 }
 void WaypointReached(uint32 waypointId, uint32 /*pathId*/) override
 {
     if (waypointId == 7 && instance)
     {
         Creature* target = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THRALL));
         if (target && target->IsAlive())
             AddThreat(target, 0.0f);
     }
 }
 void StartChase(Unit* who)
 {
     DoCast(who, SPELL_MARK);
     me->SetSpeedRate(MOVE_RUN, 0.5f);
     // make sure the Spine will really follow the one he should
     me->GetThreatManager().ResetAllThreat();
     DoZoneInCombat();
     AddThreat(who, 1000000.0f);
     me->GetMotionMaster()->Clear(true);
     me->GetMotionMaster()->MoveChase(who);
 }
Example #6
0
        void AttackStart(Unit* who) override
        {
            if (me->Attack(who, true))
            {
                AddThreat(who, 0.0f);
                me->SetInCombatWith(who);
                who->SetInCombatWith(me);

                if (!m_bIsFrozen)
                    me->GetMotionMaster()->MoveChase(who);
            }
        }
Example #7
0
            void IsSummonedBy(Unit* summoner) override
            {
                if (summoner->GetTypeId() != TYPEID_PLAYER || !summoner->GetVehicle())
                    return;

                _tigerGuid = summoner->GetVehicle()->GetBase()->GetGUID();
                if (Unit* tiger = ObjectAccessor::GetUnit(*me, _tigerGuid))
                {
                    AddThreat(tiger, 500000.0f);
                    DoCast(me, SPELL_FURIOUS_BITE);
                }
            }
            void IsSummonedBy(WorldObject* summonerWO) override
            {
                Player* summoner = summonerWO->ToPlayer();
                if (!summoner || !summoner->GetVehicle())
                    return;

                _tigerGuid = summoner->GetVehicle()->GetBase()->GetGUID();
                if (Unit* tiger = ObjectAccessor::GetUnit(*me, _tigerGuid))
                {
                    AddThreat(tiger, 500000.0f);
                    DoCast(me, SPELL_FURIOUS_BITE);
                }
            }
Example #9
0
 void JustEngagedWith(Unit* /*who*/) override
 {
     Talk(SAY_ROMULO_AGGRO);
     if (JulianneGUID)
     {
         Creature* Julianne = (ObjectAccessor::GetCreature((*me), JulianneGUID));
         if (Julianne && Julianne->GetVictim())
         {
             AddThreat(Julianne->GetVictim(), 1.0f);
             AttackStart(Julianne->GetVictim());
         }
     }
 }
Example #10
0
 void IsSummonedBy(Unit* summoner) override
 {
     targetGUID = summoner->GetGUID();
     me->SetInCombatWith(summoner);
     AddThreat(summoner, 250.0f);
     if (Unit* target = ObjectAccessor::GetUnit(*me, targetGUID))
     {
         DoCast(target, SPELL_BLOCK_OF_ICE, true);
         // Prevents to have Ice Block on other place than target is
         me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation());
         if (target->GetTypeId() == TYPEID_PLAYER)
             if (Creature* hodir = instance->GetCreature(BOSS_HODIR))
                 hodir->AI()->DoAction(ACTION_CHEESE_THE_FREEZE);
     }
 }
        void SetThreatList(Creature* summonedUnit)
        {
            if (!summonedUnit)
                return;

            ThreatContainer::StorageType const& threatlist = me->GetThreatManager().getThreatList();
            ThreatContainer::StorageType::const_iterator i = threatlist.begin();
            for (i = threatlist.begin(); i != threatlist.end(); ++i)
            {
                Unit* unit = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid());
                if (unit && unit->IsAlive())
                {
                    float threat = me->GetThreatManager().getThreat(unit);
                    AddThreat(unit, threat, summonedUnit);
                }
            }
        }
    bool TryActivateAfterTTelep(uint32 diff)
    {
        if (AfterTeleport)
        {
            if (!tspellcast)
            {
                me->ClearUnitState(UNIT_STATE_STUNNED);
                DoCast(me, SPELL_TWIN_TELEPORT);
                me->AddUnitState(UNIT_STATE_STUNNED);
            }

            tspellcast = true;

            if (AfterTeleportTimer <= diff)
            {
                AfterTeleport = false;
                me->ClearUnitState(UNIT_STATE_STUNNED);
                if (Unit* nearu = me->SelectNearestTarget(100))
                {
                    //DoYell(nearu->GetName(), LANG_UNIVERSAL, 0);
                    AttackStart(nearu);
                    AddThreat(nearu, 10000);
                }
                return true;
            }
            else
            {
                AfterTeleportTimer -= diff;
                // update important timers which would otherwise get skipped
                if (EnrageTimer > diff)
                    EnrageTimer -= diff;
                else
                    EnrageTimer = 0;
                if (Teleport_Timer > diff)
                    Teleport_Timer -= diff;
                else
                    Teleport_Timer = 0;
                return false;
            }
        }
        else
        {
            return true;
        }
    }
        void SummonCreatureWithRandomTarget(uint32 creatureId, int position)
        {
            if (Creature* summoned = me->SummonCreature(creatureId, PyrewoodSpawnPoints[position][0], PyrewoodSpawnPoints[position][1], PyrewoodSpawnPoints[position][2], PyrewoodSpawnPoints[position][3], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 15000))
            {
                Unit* target = nullptr;
                if (PlayerGUID)
                    if (Player* player = ObjectAccessor::GetPlayer(*me, PlayerGUID))
                        if (player->IsAlive() && RAND(0, 1))
                            target = player;

                if (!target)
                    target = me;

                summoned->SetFaction(FACTION_ENEMY);
                AddThreat(target, 32.0f, summoned);
                summoned->AI()->AttackStart(target);
            }
        }
    void SelectNewTarget()
    {
        if (Creature* teron = _instance->GetCreature(DATA_TERON_GOREFIEND))
        {
            Unit* target = teron->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, true, -SPELL_SPIRITUAL_VENGEANCE);
            // He should target Vengeful Spirits only if has no other player available
            if (!target)
                target = teron->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0);

            if (target)
            {
                ResetThreatList();
                AttackStart(target);
                AddThreat(target, 1000000.0f);
                targetGUID = target->GetGUID();
            }
        }
    }
Example #15
0
    void MovementInform(uint32 type, uint32 pointId) override
    {
        if (!instance || type != POINT_MOTION_TYPE)
            return;

        // debug_log("dummy_dragonAI: %s reached point %u", me->GetName(), uiPointId);

        // if healers messed up the raid and we was already initialized
        if (instance->GetBossState(DATA_SARTHARION) != IN_PROGRESS)
        {
            EnterEvadeMode();
            return;
        }

        // this is end, if we reach this, don't do much
        if (pointId == POINT_ID_LAND)
        {
            me->GetMotionMaster()->Clear();
            DoZoneInCombat();
            if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0, true))
            {
                AddThreat(target, 1.0f);
                me->Attack(target, true);
                me->GetMotionMaster()->MoveChase(target);
            }

            _canMoveFree = false;
            return;
        }

        // increase
        waypointId = pointId + 1;

        // if we have reached a point bigger or equal to count, it mean we must reset to point 0
        if (waypointId >= MAX_WAYPOINT)
        {
            if (!_canMoveFree)
                _canMoveFree = true;

            waypointId = 0;
        }

        events.ScheduleEvent(EVENT_FREE_MOVEMENT, 500);
    }
        void DoSummonAtRift(uint32 creature_entry)
        {
            if (!creature_entry)
                return;

            if (instance->GetData(TYPE_MEDIVH) != IN_PROGRESS)
            {
                me->InterruptNonMeleeSpells(true);
                me->RemoveAllAuras();
                return;
            }

            Position pos = me->GetRandomNearPosition(10.0f);

            //normalize Z-level if we can, if rift is not at ground level.
            pos.m_positionZ = std::max(me->GetMap()->GetHeight(pos.m_positionX, pos.m_positionY, MAX_HEIGHT), me->GetMap()->GetWaterLevel(pos.m_positionX, pos.m_positionY));

            if (Unit* Summon = DoSummon(creature_entry, pos, 30000, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT))
                if (Unit* temp = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_MEDIVH)))
                    AddThreat(temp, 0.0f, Summon);
        }
Example #17
0
        void JustSummoned(Creature* summon) override
        {
            switch (summon->GetEntry())
            {
                case NPC_SPIRIT_FOUNT:
                    summon->CastSpell(summon, SPELL_SPIRIT_FOUNT, true);
                    summon->SetDisplayId(11686);
                    SpiritFountGUID = summon->GetGUID();
                    break;
                case NPC_AVENGING_SPIRIT:
                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
                    {
                        AddThreat(target, 0.0f, summon);
                        summon->AI()->AttackStart(target);
                    }
                    break;
                default:
                    break;
            }

            summons.Summon(summon);
        }
        void UpdateAI(uint32 diff) override
        {
            if (DespawnTimer <= diff)
                me->KillSelf();
            else
                DespawnTimer -= diff;

            //Return since we have no target
            if (!UpdateVictim())
                return;

            if (ChangeTargetTimer <= diff)
            {
                if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                {
                    AddThreat(target, 1.0f);
                    me->TauntApply(target);
                    AttackStart(target);
                }

                ChangeTargetTimer = urand(5000, 15000);
            } else ChangeTargetTimer -= diff;
        }
            void DoAction(int32 actionId) override
            {
                if (actionId == ACTION_STORE_OLD_TARGET)
                {
                    if (Unit* victim = me->GetVictim())
                    {
                        _oldTargetGUID = victim->GetGUID();
                        _tempThreat = GetThreat(victim);
                    }
                }
                else if (actionId == ACTION_RESET_THREAT)
                {
                    if (Unit* oldTarget = ObjectAccessor::GetUnit(*me, _oldTargetGUID))
                    {
                        if (Unit* current = me->GetVictim())
                            ModifyThreatByPercent(current, -100);

                        AddThreat(oldTarget, _tempThreat);
                        AttackStart(oldTarget);
                        _oldTargetGUID.Clear();
                        _tempThreat = 0.0f;
                    }
                }
            }
        void UpdateAI(uint32 diff) override
        {
            //Return since we have no target
            if (!UpdateVictim())
                return;

            if (!WhirlWind && WhirlWind_Timer <= diff)
            {
                DoCast(me, SPELL_WHIRLWINDADD);
                WhirlWind = true;
                WhirlWind_Timer = urand(25000, 40000);
                WhirlWindEnd_Timer = 15000;
            } else WhirlWind_Timer -= diff;

            if (WhirlWind)
            {
                if (WhirlWindRandom_Timer <= diff)
                {
                    //Attack random Gamers
                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100.0f, true))
                    {
                        AddThreat(target, 1.0f);
                        AttackStart(target);
                    }

                    WhirlWindRandom_Timer = urand(3000, 7000);
                } else WhirlWindRandom_Timer -= diff;

                if (WhirlWindEnd_Timer <= diff)
                {
                    WhirlWind = false;
                } else WhirlWindEnd_Timer -= diff;
            }

            if (!WhirlWind)
            {
                if (AggroReset_Timer <= diff)
                {
                    //Attack random Gamers
                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100.0f, true))
                    {
                        AddThreat(target, 1.0f);
                        AttackStart(target);
                    }

                    AggroReset = true;
                    AggroReset_Timer = urand(2000, 5000);
                } else AggroReset_Timer -= diff;

                if (KnockBack_Timer <= diff)
                {
                    DoCast(me, SPELL_WHIRLWINDADD);
                    KnockBack_Timer = urand(10000, 20000);
                } else KnockBack_Timer -= diff;
            }

            if (AggroReset)
            {
                if (AggroResetEnd_Timer <= diff)
                {
                    AggroReset = false;
                    AggroResetEnd_Timer = 5000;
                    AggroReset_Timer = urand(30000, 40000);
                } else AggroResetEnd_Timer -= diff;
            }

            DoMeleeAttackIfReady();
        }
        void UpdateAI(uint32 diff) override
        {
            //Return since we have no target
            if (!UpdateVictim())
                return;

            if (WhirlWind)
            {
                if (WhirlWindRandom_Timer <= diff)
                {
                    //Attack random Gamers
                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100.0f, true))
                    {
                        AddThreat(target, 1.0f);
                        AttackStart(target);
                    }
                    WhirlWindRandom_Timer = urand(3000, 7000);
                } else WhirlWindRandom_Timer -= diff;

                if (WhirlWindEnd_Timer <= diff)
                {
                    WhirlWind = false;
                    WhirlWind_Timer = urand(25000, 40000);
                } else WhirlWindEnd_Timer -= diff;
            }

            if (!WhirlWind)
            {
                if (WhirlWind_Timer <= diff)
                {
                    DoCast(me, SPELL_WHIRLWIND);
                    WhirlWind = true;
                    WhirlWindEnd_Timer = 15000;
                } else WhirlWind_Timer -= diff;

                if (AggroReset_Timer <= diff)
                {
                    //Attack random Gamers
                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100.0f, true))
                    {
                        AddThreat(target, 1.0f);
                        AttackStart(target);
                    }
                    AggroReset = true;
                    AggroReset_Timer = urand(2000, 5000);
                } else AggroReset_Timer -= diff;

                if (AggroReset)
                {
                    if (AggroResetEnd_Timer <= diff)
                    {
                        AggroReset = false;
                        AggroResetEnd_Timer = 5000;
                        AggroReset_Timer = urand(35000, 45000);
                    } else AggroResetEnd_Timer -= diff;
                }

                //If she is 20% enrage
                if (!Enraged)
                {
                    if (!HealthAbovePct(20) && !me->IsNonMeleeSpellCast(false))
                    {
                        DoCast(me, SPELL_ENRAGE);
                        Enraged = true;
                    }
                }

                //After 10 minutes hard enrage
                if (!EnragedHard)
                {
                    if (EnrageHard_Timer <= diff)
                    {
                        DoCast(me, SPELL_ENRAGEHARD);
                        EnragedHard = true;
                    } else EnrageHard_Timer -= diff;
                }

                DoMeleeAttackIfReady();
            }
        }
 void JustEngagedWith(Unit* who) override
 {
     AddThreat(who, 0.1f);
 }
            void UpdateAI(uint32 diff) override
            {
                if (!UpdateVictim())
                    return;

                events.Update(diff);

                while (uint32 eventId = events.ExecuteEvent())
                {
                    switch (eventId)
                    {
                        case EVENT_STATIC_DISRUPTION:
                            {
                            Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1);
                            if (!target)
                                target = me->GetVictim();
                            if (target)
                            {
                                TargetGUID = target->GetGUID();
                                DoCast(target, SPELL_STATIC_DISRUPTION, false);
                            }
                            /*if (float dist = me->IsWithinDist3d(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 5.0f) dist = 5.0f;
                            SDisruptAOEVisual_Timer = 1000 + floor(dist / 30 * 1000.0f);*/
                            events.ScheduleEvent(EVENT_STATIC_DISRUPTION, 10s, 18s);
                            break;
                            }
                        case EVENT_GUST_OF_WIND:
                            {
                                Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1);
                                if (!target)
                                    target = me->GetVictim();
                                if (target)
                                    DoCast(target, SPELL_GUST_OF_WIND);
                                events.ScheduleEvent(EVENT_GUST_OF_WIND, 20s, 30s);
                                break;
                            }
                        case EVENT_CALL_LIGHTNING:
                            DoCastVictim(SPELL_CALL_LIGHTNING);
                            events.ScheduleEvent(EVENT_CALL_LIGHTNING, 12s, 17s); // totaly random timer. can't find any info on this
                            break;
                        case EVENT_ELECTRICAL_STORM:
                            {
                                Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50, true);
                                if (!target)
                                {
                                    EnterEvadeMode();
                                    return;
                                }
                                target->CastSpell(target, 44007, true); // cloud visual
                                DoCast(target, SPELL_ELECTRICAL_STORM, false); // storm cyclon + visual
                                float x, y, z;
                                target->GetPosition(x, y, z);
                                /// @todo: fix it in correct way, that causes player to can fly until logout
                                /*
                                if (target)
                                {
                                    target->SetDisableGravity(true);
                                    target->MonsterMoveWithSpeed(x, y, me->GetPositionZ()+15, 0);
                                }
                                */

                                Unit* Cloud = me->SummonTrigger(x, y, me->GetPositionZ()+16, 0, 15000);
                                if (Cloud)
                                    {
                                        CloudGUID = Cloud->GetGUID();
                                        Cloud->SetDisableGravity(true);
                                        Cloud->StopMoving();
                                        Cloud->SetObjectScale(1.0f);
                                        Cloud->SetFaction(FACTION_FRIENDLY);
                                        Cloud->SetMaxHealth(9999999);
                                        Cloud->SetHealth(9999999);
                                        Cloud->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
                                    }
                                StormCount = 1;
                                events.ScheduleEvent(EVENT_ELECTRICAL_STORM, 1min); // 60 seconds(bosskillers)
                                events.ScheduleEvent(EVENT_RAIN, 47s, 52s);
                                break;
                            }
                        case EVENT_RAIN:
                            if (!isRaining)
                            {
                                SetWeather(WEATHER_STATE_HEAVY_RAIN, 0.9999f);
                                isRaining = true;
                            }
                            else
                                events.ScheduleEvent(EVENT_RAIN, 1s);
                            break;
                        case EVENT_STORM_SEQUENCE:
                            {
                                Unit* target = ObjectAccessor::GetUnit(*me, CloudGUID);
                                if (!target || !target->IsAlive())
                                {
                                    EnterEvadeMode();
                                    return;
                                }
                                else if (Unit* Cyclone = ObjectAccessor::GetUnit(*me, CycloneGUID))
                                    Cyclone->CastSpell(target, SPELL_SAND_STORM, true); // keep casting or...
                                HandleStormSequence(target);
                                break;
                            }
                        case EVENT_SUMMON_EAGLES:
                            Talk(SAY_SUMMON);

                            float x, y, z;
                            me->GetPosition(x, y, z);

                            for (uint8 i = 0; i < 8; ++i)
                            {
                                Unit* bird = ObjectAccessor::GetUnit(*me, BirdGUIDs[i]);
                                if (!bird) //they despawned on die
                                {
                                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
                                    {
                                        x = target->GetPositionX() + irand(-10, 10);
                                        y = target->GetPositionY() + irand(-10, 10);
                                        z = target->GetPositionZ() + urand(16, 20);
                                        if (z > 95)
                                            z = 95.0f - urand(0, 5);
                                    }
                                    Creature* creature = me->SummonCreature(NPC_SOARING_EAGLE, x, y, z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0);
                                    if (creature)
                                    {
                                        AddThreat(me->GetVictim(), 1.0f, creature);
                                        creature->AI()->AttackStart(me->GetVictim());
                                        BirdGUIDs[i] = creature->GetGUID();
                                    }
                                }
                            }
                            break;
                        case EVENT_ENRAGE:
                             Talk(SAY_ENRAGE);
                             DoCast(me, SPELL_BERSERK, true);
                            events.ScheduleEvent(EVENT_ENRAGE, 10min);
                            break;
                        default:
                            break;
                    }
                }

                DoMeleeAttackIfReady();
            }
        void UpdateAI(uint32 diff) override
        {
            _events.Update(diff);

            if (UpdateVictim())
            {
                while (uint32 eventId = _events.ExecuteEvent())
                {
                    switch (eventId)
                    {
                        case EVENT_FROST_SHOCK:
                            DoCastVictim(SPELL_FROST_SHOCK);
                            _events.DelayEvents(1 * IN_MILLISECONDS);
                            _events.ScheduleEvent(EVENT_FROST_SHOCK, 10s, 15s);
                            break;
                        case EVENT_SEARING_TOTEM:
                            DoCast(me, SPELL_SEARING_TOTEM);
                            _events.DelayEvents(1 * IN_MILLISECONDS);
                            _events.ScheduleEvent(EVENT_SEARING_TOTEM, urand(110, 130) * IN_MILLISECONDS);
                            break;
                        case EVENT_STRENGTH_OF_EARTH_TOTEM:
                            DoCast(me, SPELL_STRENGTH_OF_EARTH_TOTEM);
                            _events.DelayEvents(1 * IN_MILLISECONDS);
                            _events.ScheduleEvent(EVENT_STRENGTH_OF_EARTH_TOTEM, urand(110, 130) * IN_MILLISECONDS);
                            break;
                        case EVENT_HEALING_SURGE:
                        {
                            Unit* target = nullptr;
                            if (me->GetHealthPct() < 85)
                                target = me;
                            else if (Player* player = GetPlayerForEscort())
                                if (player->GetHealthPct() < 85)
                                    target = player;
                            if (target)
                            {
                                DoCast(target, SPELL_HEALING_SURGE);
                                _events.ScheduleEvent(EVENT_HEALING_SURGE, 10s);
                            }
                            else
                                _events.ScheduleEvent(EVENT_HEALING_SURGE, 2s);
                            break;
                        }
                        default:
                            break;
                    }
                }

                DoMeleeAttackIfReady();
            }

            if (HasEscortState(STATE_ESCORT_NONE))
                return;

            EscortAI::UpdateAI(diff);

            if (_phase)
            {
                if (_moveTimer <= diff)
                {
                    switch (_phase)
                    {
                        case PHASE_WP_26: //debug skip path to point 26, buggy path calculation
                            me->GetMotionMaster()->MovePoint(WP_DEBUG_2, -2021.77f, -10648.8f, 129.903f, false);
                            _moveTimer = 2 * IN_MILLISECONDS;
                            _phase = PHASE_CONTINUE;
                            break;
                        case PHASE_CONTINUE: // continue escort
                            SetEscortPaused(false);
                            _moveTimer = 0 * IN_MILLISECONDS;
                            _phase = PHASE_NONE;
                            break;
                        case PHASE_WP_22: //debug skip path to point 22, buggy path calculation
                            me->GetMotionMaster()->MovePoint(WP_EXPLOSIVES_FIRST_PLANT, -1958.026f, -10660.465f, 111.547f, false);
                            Talk(SAY_LEGOSO_3);
                            _moveTimer = 2 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_FIRST_KNEEL;
                            break;
                        case PHASE_PLANT_FIRST_KNEEL: // plant first explosives stage 1 kneel
                            me->SetStandState(UNIT_STAND_STATE_KNEEL);
                            _moveTimer = 10 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_FIRST_STAND;
                            break;
                        case PHASE_PLANT_FIRST_STAND: // plant first explosives stage 1 stand
                            me->SetStandState(UNIT_STAND_STATE_STAND);
                            _moveTimer = 0.5* IN_MILLISECONDS;
                            _phase = PHASE_PLANT_FIRST_WORK;
                            break;
                        case PHASE_PLANT_FIRST_WORK: // plant first explosives stage 2 work
                            Talk(SAY_LEGOSO_4);
                            _moveTimer = 17.5 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_FIRST_FINISH;
                            break;
                        case PHASE_PLANT_FIRST_FINISH: // plant first explosives finish
                            _explosivesGuids.clear();
                            for (uint8 i = 0; i != MAX_EXPLOSIVES; ++i)
                            {
                                if (GameObject* explosive = me->SummonGameObject(GO_DRAENEI_EXPLOSIVES_1, ExplosivesPos[0][i], QuaternionData(), 0))
                                    _explosivesGuids.push_back(explosive->GetGUID());
                            }
                            me->HandleEmoteCommand(EMOTE_ONESHOT_NONE); // reset anim state
                            // force runoff movement so he will not screw up next waypoint
                            me->GetMotionMaster()->MovePoint(WP_EXPLOSIVES_FIRST_RUNOFF, -1955.6f, -10669.8f, 110.65f, false);
                            Talk(SAY_LEGOSO_5);
                            _moveTimer = 1.5 * IN_MILLISECONDS;
                            _phase = PHASE_CONTINUE;
                            break;
                        case PHASE_PLANT_FIRST_TIMER_1: // first explosives detonate timer 1
                            Talk(SAY_LEGOSO_6);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_FIRST_TIMER_2;
                            break;
                        case PHASE_PLANT_FIRST_TIMER_2: // first explosives detonate timer 2
                            Talk(SAY_LEGOSO_7);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_FIRST_TIMER_3;
                            break;
                        case PHASE_PLANT_FIRST_TIMER_3: // first explosives detonate timer 3
                            Talk(SAY_LEGOSO_8);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_FIRST_DETONATE;
                            break;
                        case PHASE_PLANT_FIRST_DETONATE: // first explosives detonate finish
                            for (GuidList::iterator itr = _explosivesGuids.begin(); itr != _explosivesGuids.end(); ++itr)
                            {
                                if (GameObject* explosive = ObjectAccessor::GetGameObject(*me, *itr))
                                    me->RemoveGameObject(explosive, true);
                            }
                            _explosivesGuids.clear();
                            me->HandleEmoteCommand(EMOTE_ONESHOT_CHEER);
                            _moveTimer = 2 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_FIRST_SPEECH;
                            break;
                        case PHASE_PLANT_FIRST_SPEECH: // after detonation 1 speech
                            Talk(SAY_LEGOSO_9);
                            _moveTimer = 4 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_FIRST_ROTATE;
                            break;
                        case PHASE_PLANT_FIRST_ROTATE: // after detonation 1 rotate to next point
                            me->SetFacingTo(2.272f);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_FIRST_POINT;
                            break;
                        case PHASE_PLANT_FIRST_POINT: // after detonation 1 send point anim and go on to next point
                            me->HandleEmoteCommand(EMOTE_ONESHOT_POINT);
                            _moveTimer = 2 * IN_MILLISECONDS;
                            _phase = PHASE_CONTINUE;
                            break;
                        case PHASE_FEEL_SIRONAS_1: // legoso exclamation before sironas 1.1
                            Talk(SAY_LEGOSO_10);
                            _moveTimer = 4 * IN_MILLISECONDS;
                            _phase = PHASE_FEEL_SIRONAS_2;
                            break;
                        case PHASE_FEEL_SIRONAS_2: // legoso exclamation before sironas 1.2
                            Talk(SAY_LEGOSO_11);
                            _moveTimer = 4 * IN_MILLISECONDS;
                            _phase = PHASE_CONTINUE;
                            break;
                        case PHASE_MEET_SIRONAS_ROAR: // legoso exclamation before sironas 2.1
                            Talk(SAY_LEGOSO_12);
                            _moveTimer = 4 * IN_MILLISECONDS;
                            _phase = PHASE_MEET_SIRONAS_TURN;
                            break;
                        case PHASE_MEET_SIRONAS_TURN: // legoso exclamation before sironas 2.2
                            if (Player* player = GetPlayerForEscort())
                                me->SetFacingToObject(player);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_MEET_SIRONAS_SPEECH;
                            break;
                        case PHASE_MEET_SIRONAS_SPEECH: // legoso exclamation before sironas 2.3
                            Talk(SAY_LEGOSO_13);
                            _moveTimer = 7 * IN_MILLISECONDS;
                            _phase = PHASE_CONTINUE;
                            break;
                        case PHASE_PLANT_SECOND_KNEEL: // plant second explosives stage 1 kneel
                            me->SetStandState(UNIT_STAND_STATE_KNEEL);
                            _moveTimer = 11 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_SECOND_SPEECH;
                            break;
                        case PHASE_PLANT_SECOND_SPEECH: // plant second explosives stage 2 kneel
                            Talk(SAY_LEGOSO_14);
                            _moveTimer = 13 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_SECOND_STAND;
                            break;
                        case PHASE_PLANT_SECOND_STAND: // plant second explosives finish
                            me->SetStandState(UNIT_STAND_STATE_STAND);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_SECOND_FINISH;
                            break;
                        case PHASE_PLANT_SECOND_FINISH: // plant second explosives finish - create explosives
                            _explosivesGuids.clear();
                            for (uint8 i = 0; i != MAX_EXPLOSIVES; ++i)
                            {
                                if (GameObject* explosive = me->SummonGameObject(GO_DRAENEI_EXPLOSIVES_2, ExplosivesPos[1][i], QuaternionData(), 0))
                                    _explosivesGuids.push_back(explosive->GetGUID());
                            }
                            Talk(SAY_LEGOSO_15);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_SECOND_WAIT;
                            break;
                        case PHASE_PLANT_SECOND_WAIT: // plant second explosives finish - proceed to next point
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_CONTINUE;
                            break;
                        case PHASE_PLANT_SECOND_TIMER_1: // second explosives detonate timer 1
                            Talk(SAY_LEGOSO_16);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_SECOND_TIMER_2;
                            break;
                        case PHASE_PLANT_SECOND_TIMER_2: // second explosives detonate timer 2
                            Talk(SAY_LEGOSO_17);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_SECOND_TIMER_3;
                            break;
                        case PHASE_PLANT_SECOND_TIMER_3: // second explosives detonate timer 3
                            Talk(SAY_LEGOSO_18);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_PLANT_SECOND_DETONATE;
                            break;
                        case PHASE_PLANT_SECOND_DETONATE: // second explosives detonate finish
                            for (GuidList::iterator itr = _explosivesGuids.begin(); itr != _explosivesGuids.end(); ++itr)
                            {
                                if (GameObject* explosive = ObjectAccessor::GetGameObject(*me, *itr))
                                    me->RemoveGameObject(explosive, true);
                            }
                            _explosivesGuids.clear();
                            if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS))
                            {
                                sironas->SetImmuneToAll(false);
                                me->SetFacingToObject(sironas);
                            }
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_FIGHT_SIRONAS_STOP;
                            break;
                        case PHASE_FIGHT_SIRONAS_STOP: // sironas channel stop
                            if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS))
                                sironas->AI()->DoAction(ACTION_SIRONAS_CHANNEL_STOP);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_FIGHT_SIRONAS_SPEECH_1;
                            break;
                        case PHASE_FIGHT_SIRONAS_SPEECH_1: // sironas exclamation before aggro
                            if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS))
                                sironas->AI()->Talk(SAY_SIRONAS_1);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_FIGHT_SIRONAS_SPEECH_2;
                            break;
                        case PHASE_FIGHT_SIRONAS_SPEECH_2: // legoso exclamation before aggro
                            if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS))
                                sironas->SetObjectScale(3.0f);
                            Talk(SAY_LEGOSO_19);
                            _moveTimer = 1 * IN_MILLISECONDS;
                            _phase = PHASE_FIGHT_SIRONAS_START;
                            break;
                        case PHASE_FIGHT_SIRONAS_START: // legoso exclamation at aggro
                            if (Creature* sironas = me->FindNearestCreature(NPC_SIRONAS, SIZE_OF_GRIDS))
                            {
                                Unit* target = GetPlayerForEscort();
                                if (!target)
                                    target = me;

                                AddThreat(sironas, 0.001f, target);
                                sironas->Attack(target, true);
                                sironas->GetMotionMaster()->MoveChase(target);
                            }
                            _moveTimer = 10 * IN_MILLISECONDS;
                            _phase = PHASE_CONTINUE;
                            break;
                        case PHASE_SIRONAS_SLAIN_SPEECH_1: // legoso exclamation after battle - stage 1.1
                            Talk(SAY_LEGOSO_20);
                            _moveTimer = 2 * IN_MILLISECONDS;
                            _phase = PHASE_SIRONAS_SLAIN_EMOTE_1;
                            break;
                        case PHASE_SIRONAS_SLAIN_EMOTE_1: // legoso exclamation after battle - stage 1.2
                            me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION);
                            _moveTimer = 2 * IN_MILLISECONDS;
                            _phase = PHASE_SIRONAS_SLAIN_EMOTE_2;
                            break;
                        case PHASE_SIRONAS_SLAIN_EMOTE_2: // legoso exclamation after battle - stage 1.3
                            if (Player* player = GetPlayerForEscort())
                                player->GroupEventHappens(QUEST_ENDING_THEIR_WORLD, me);
                            me->HandleEmoteCommand(EMOTE_ONESHOT_CHEER);
                            _moveTimer = 5 * IN_MILLISECONDS;
                            _phase = PHASE_SIRONAS_SLAIN_SPEECH_2;
                            break;
                        case PHASE_SIRONAS_SLAIN_SPEECH_2: // legoso exclamation after battle - stage 2
                            Talk(SAY_LEGOSO_21);
                            _moveTimer = 30 * IN_MILLISECONDS;
                            _phase = PHASE_CONTINUE;
                            break;
                        default:
                            break;
                    }
               }
                else if (!me->IsInCombat())
                    _moveTimer -= diff;
            }
        }
        void UpdateAI(uint32 diff) override
        {
            if (!UpdateVictim())
                return;

            events.Update(diff);

            while (uint32 eventId = events.ExecuteEvent())
            {
                switch (eventId)
                {
                    case EVENT_HATEFUL:
                    {
                        // Hateful Strike targets the highest non-MT threat in melee range on 10man
                        // and the higher HP target out of the two highest non-MT threats in melee range on 25man
                        ThreatReference* secondThreat = nullptr;
                        ThreatReference* thirdThreat = nullptr;

                        ThreatManager const& mgr = me->GetThreatManager();
                        Unit* currentVictim = mgr.GetCurrentVictim();
                        auto list = mgr.GetModifiableThreatList();
                        auto it = list.begin(), end = list.end();
                        if (it == end)
                        {
                            EnterEvadeMode(EVADE_REASON_NO_HOSTILES);
                            return;
                        }

                        if ((*it)->GetVictim() != currentVictim)
                            secondThreat = *it;
                        if ((!secondThreat || Is25ManRaid()) && (++it != end && (*it)->IsAvailable()))
                        {
                            if ((*it)->GetVictim() != currentVictim)
                                (secondThreat ? thirdThreat : secondThreat) = *it;
                            if (!thirdThreat && Is25ManRaid() && (++it != end && (*it)->IsAvailable()))
                                thirdThreat = *it;
                        }

                        Unit* pHatefulTarget = nullptr;
                        if (!secondThreat)
                            pHatefulTarget = currentVictim;
                        else if (!thirdThreat)
                            pHatefulTarget = secondThreat->GetVictim();
                        else
                            pHatefulTarget = (secondThreat->GetVictim()->GetHealth() < thirdThreat->GetVictim()->GetHealth()) ? thirdThreat->GetVictim() : secondThreat->GetVictim();

                        // add threat to highest threat targets
                        AddThreat(currentVictim, HATEFUL_THREAT_AMT);
                        if (secondThreat)
                            secondThreat->AddThreat(HATEFUL_THREAT_AMT);
                        if (thirdThreat)
                            thirdThreat->AddThreat(HATEFUL_THREAT_AMT);

                        DoCast(pHatefulTarget, SPELL_HATEFUL_STRIKE, true);

                        events.Repeat(Seconds(1));
                        break;
                    }
                    case EVENT_BERSERK:
                        DoCast(me, SPELL_BERSERK, true);
                        Talk(EMOTE_BERSERK);
                        events.ScheduleEvent(EVENT_SLIME, Seconds(2));
                        break;
                    case EVENT_SLIME:
                        DoCastAOE(SPELL_SLIME_BOLT, true);
                        events.Repeat(Seconds(2));
                        break;
                }
            }

            if (!Enraged && HealthBelowPct(5))
            {
                DoCast(me, SPELL_FRENZY, true);
                Talk(EMOTE_FRENZY);
                Enraged = true;
            }

            DoMeleeAttackIfReady();
        }
        void UpdateAI(uint32 diff) override
        {
            //Return since we have no target
            if (!UpdateVictim())
                return;

            switch (Phase)
            {
                case 0:
                {
                    // *Heroic mode only:
                    if (IsHeroic())
                    {
                        if (PyroblastTimer <= diff)
                        {
                            me->InterruptSpell(CURRENT_CHANNELED_SPELL);
                            me->InterruptSpell(CURRENT_GENERIC_SPELL);
                            DoCast(me, SPELL_SHOCK_BARRIER, true);
                            DoCastVictim(SPELL_PYROBLAST);
                            PyroblastTimer = 60000;
                        } else PyroblastTimer -= diff;
                    }

                    if (FireballTimer <= diff)
                    {
                        DoCastVictim(SPELL_FIREBALL_NORMAL);
                        FireballTimer = urand(2000, 6000);
                    } else FireballTimer -= diff;

                    if (PhoenixTimer <= diff)
                    {
                        Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1);

                        uint8 random = urand(1, 2);
                        float x = KaelLocations[random][0];
                        float y = KaelLocations[random][1];

                        Creature* Phoenix = me->SummonCreature(CREATURE_PHOENIX, x, y, LOCATION_Z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 60000);
                        if (Phoenix)
                        {
                            Phoenix->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE + UNIT_FLAG_NON_ATTACKABLE);
                            SetThreatList(Phoenix);
                            Phoenix->AI()->AttackStart(target);
                        }

                        Talk(SAY_PHOENIX);

                        PhoenixTimer = 60000;
                    } else PhoenixTimer -= diff;

                    if (FlameStrikeTimer <= diff)
                    {
                        if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        {
                            me->InterruptSpell(CURRENT_CHANNELED_SPELL);
                            me->InterruptSpell(CURRENT_GENERIC_SPELL);
                            DoCast(target, SPELL_FLAMESTRIKE3, true);
                            Talk(SAY_FLAMESTRIKE);
                        }
                        FlameStrikeTimer = urand(15000, 25000);
                    } else FlameStrikeTimer -= diff;

                    // Below 50%
                    if (HealthBelowPct(50))
                    {
                        me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_INTERRUPT_CAST, true);
                        me->StopMoving();
                        me->GetMotionMaster()->Clear();
                        me->GetMotionMaster()->MoveIdle();
                        GravityLapseTimer = 0;
                        GravityLapsePhase = 0;
                        Phase = 1;
                    }

                    DoMeleeAttackIfReady();
                }
                break;

                case 1:
                {
                    if (GravityLapseTimer <= diff)
                    {
                        switch (GravityLapsePhase)
                        {
                            case 0:
                                if (FirstGravityLapse)          // Different yells at 50%, and at every following Gravity Lapse
                                {
                                    Talk(SAY_GRAVITY_LAPSE);
                                    FirstGravityLapse = false;

                                    instance->SetData(DATA_KAELTHAS_STATUES, 1);
                                }
                                else
                                    Talk(SAY_RECAST_GRAVITY);

                                DoCast(me, SPELL_GRAVITY_LAPSE_INITIAL);
                                GravityLapseTimer = 2000 + diff;// Don't interrupt the visual spell
                                GravityLapsePhase = 1;
                                break;

                            case 1:
                                TeleportPlayersToSelf();
                                GravityLapseTimer = 1000;
                                GravityLapsePhase = 2;
                                break;

                            case 2:
                                CastGravityLapseKnockUp();
                                GravityLapseTimer = 1000;
                                GravityLapsePhase = 3;
                                break;

                            case 3:
                                CastGravityLapseFly();
                                GravityLapseTimer = 30000;
                                GravityLapsePhase = 4;

                                for (uint8 i = 0; i < 3; ++i)
                                {
                                    Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0);

                                    Creature* Orb = DoSpawnCreature(CREATURE_ARCANE_SPHERE, 5, 5, 0, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000);
                                    if (Orb && target)
                                    {
                                        Orb->SetSpeedRate(MOVE_RUN, 0.5f);
                                        AddThreat(target, 1000000.0f, Orb);
                                        Orb->AI()->AttackStart(target);
                                    }
                                }

                                DoCast(me, SPELL_GRAVITY_LAPSE_CHANNEL);
                                break;

                            case 4:
                                me->InterruptNonMeleeSpells(false);
                                Talk(SAY_TIRED);
                                DoCast(me, SPELL_POWER_FEEDBACK);
                                RemoveGravityLapse();
                                GravityLapseTimer = 10000;
                                GravityLapsePhase = 0;
                                break;
                        }
                    } else GravityLapseTimer -= diff;
                }
                break;
            }
        }