 /*
REWRITTEN BY XINEF
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ScriptedGossip.h"
#include "ScriptedEscortAI.h"
#include "old_hillsbrad.h"
#include "Player.h"

/*enum Erozion
{
    QUEST_ENTRY_HILLSBRAD   = 10282,
    QUEST_ENTRY_DIVERSION   = 10283,
    QUEST_ENTRY_ESCAPE      = 10284,
    QUEST_ENTRY_RETURN      = 10285,
    ITEM_ENTRY_BOMBS        = 25853
};
*/
enum Says
{
    SAY_START_EVENT_PART1           = 0,
    SAY_ARMORY                      = 1,
    SAY_SKARLOC_MEET                = 2,
    SAY_SKARLOC_TAUNT               = 3,
    SAY_START_EVENT_PART2           = 4,
    SAY_MOUNTS_UP                   = 5,
    SAY_CHURCH_END                  = 6,
    SAY_MEET_TARETHA                = 7,
    SAY_EPOCH_WONDER                = 8,
    SAY_EPOCH_KILL_TARETHA          = 9,
    SAY_EVENT_COMPLETE              = 10,
    SAY_RANDOM_LOW_HP               = 11,
    SAY_RANDOM_DIE                  = 12,
    SAY_RANDOM_AGGRO                = 13,
    SAY_RANDOM_KILL                 = 14,
    SAY_LEAVE_COMBAT                = 15,
    SAY_KILL_ARMORER                = 16,
    SAY_GO_ARMORED                  = 17,
    SAY_ENTER_CHURCH                = 18,
    SAY_GREET_TARETHA               = 19,
    SAY_CHAT_TARETHA1               = 20,

    SAY_TARETHA_FREE                = 0,
    SAY_TARETHA_ESCAPED             = 1,
    SAY_TARETHA_TALK1               = 2,
    SAY_TARETHA_TALK2               = 3,

    SAY_ARMORER_THRALL              = 0,

    SAY_LOOKOUT_SAW                 = 0,
    SAY_LOOKOUT_GO                  = 1,
    SAY_LOOKOUT_CHURCH              = 2,
    SAY_LOOKOUT_INN                 = 3,

    SAY_EPOCH_ENTER1                = 0,
    SAY_EPOCH_ENTER2                = 1,
    SAY_EPOCH_ENTER3                = 2,

    SAY_EROZION_1                   = 0,
    SAY_EROZION_2                   = 1,
    SAY_EROZION_3                   = 2,
};

enum Spells
{
    SPELL_STRIKE                = 14516,
    SPELL_SHIELD_BLOCK          = 12169,
    SPELL_SUMMON_EROZION_IMAGE  = 33954,

    SPELL_SHADOW_PRISON         = 33071,
    SPELL_SHADOW_SPIKE          = 33125,

    SPELL_TELEPORT              = 34776,
    SPELL_MEMORY_WIPE           = 33336,
    SPELL_MEMORY_WIPE_RESUME    = 33337
};

enum Npcs
{
    NPC_TM_GUARDSMAN            = 18092,
    NPC_TM_PROTECTOR            = 18093,
    NPC_TM_LOOKOUT              = 18094,

    NPC_EPOCH_GUARDSMAN         = 23175,
    NPC_EPOCH_PROTECTOR         = 23179,
    NPC_EPOCH_LOOKOUT           = 23177,

    NPC_INFINITE_DEFILER        = 18171,
    NPC_INFINITE_SABOTEUR       = 18172,
    NPC_INFINITE_SLAYER         = 18170
};

enum Misc
{
    THRALL_WEAPON_ITEM          = 927,
    THRALL_SHIELD_ITEM          = 2129,
    THRALL_MODEL_UNEQUIPPED     = 17292,
    THRALL_MODEL_EQUIPPED       = 18165,

    ACTION_SET_IMMUNE_FLAG      = 1,
    ACTION_REMOVE_IMMUNE_FLAG   = 2,
    ACTION_TRANSFORM            = 3,
    ACTION_MOVE                 = 4,
    ACTION_START_COMBAT         = 5
};

#define SPEED_RUNNING           1.0f
#define SPEED_MOUNTED           1.6f

enum Events
{
    // Combat
    EVENT_CHECK_HEALTH          = 1,
    EVENT_SPELL_STRIKE          = 2,
    EVENT_SPELL_SHIELD_BLOCK    = 3,

    EVENT_OPEN_DOORS            = 6,
    EVENT_START_WP              = 7,

    EVENT_SET_FACING            = 9,
    EVENT_KILL_ARMORER          = 10,
    EVENT_TALK_KILL_ARMORER     = 11,
    
    EVENT_DRESSING_KNEEL        = 20,
    EVENT_DRESSING_ARMOR        = 21,
    EVENT_DRESSING_STAND        = 22,
    EVENT_DRESSING_AXE          = 23,
    EVENT_DRESSING_SHIELD       = 24,
    EVENT_DRESSING_TALK         = 25,

    EVENT_ENTER_MOUNT           = 30,
    EVENT_TALK_START_RIDE       = 31,

    EVENT_LOOK_1                = 40,
    EVENT_MOVE_AROUND           = 41,
    EVENT_LOOK_2                = 42,
    EVENT_LOOK_3                = 43,
    EVENT_SUMMON_GUARDS         = 44,
    EVENT_SUMMON_TALK1          = 45,
    EVENT_SUMMON_TALK2          = 46,

    EVENT_LOOK_4                = 50,
    EVENT_SUMMON_GUARDS_2       = 51,
    EVENT_SUMMON_TALK3          = 52,

    EVENT_THRALL_TALK           = 60,
    EVENT_SUMMON_CHRONO         = 61,
    EVENT_THRALL_TALK_2         = 62,
    EVENT_TARETHA_FALL          = 63,
    EVENT_THRALL_TALK_3         = 64,
    EVENT_THRALL_MOVE_DOWN      = 65,

    EVENT_EPOCH_INTRO           = 70,
    EVENT_SUMMON_INFINITES      = 71,
    EVENT_TRANSFORM             = 72,
    EVENT_START_WAVE_1          = 73,
    EVENT_CHECK_WAVE_1          = 74,
    EVENT_CHECK_WAVE_2          = 75,
    EVENT_CHECK_WAVE_3          = 76,
    EVENT_CALL_EPOCH            = 77,

    EVENT_THRALL_FACE_TARETHA   = 80,
    EVENT_THRALL_TALK_4         = 81,
    EVENT_TARETHA_TALK_1        = 82,
    EVENT_THRALL_TALK_5         = 83,
    EVENT_SUMMON_EROZION        = 84,
    EVENT_EROZION_TALK_1        = 85,
    EVENT_EROZION_ACTION_1      = 86,
    EVENT_EROZION_TALK_2        = 87,
    EVENT_EROZION_ACTION_2      = 88,
    EVENT_EROZION_TALK_3        = 89,
    EVENT_THRALL_TALK_6         = 90,
    EVENT_THRALL_RUN_AWAY       = 91,
    EVENT_TARETHA_TALK_2        = 92

};

class npc_thrall_old_hillsbrad : public CreatureScript
{
public:
    npc_thrall_old_hillsbrad() : CreatureScript("npc_thrall_old_hillsbrad") { }

    CreatureAI* GetAI(Creature* creature) const
    {
        return GetInstanceAI<npc_thrall_old_hillsbradAI>(creature);
    }

    bool OnGossipHello(Player* player, Creature* creature)
    {
        InstanceScript* instance = creature->GetInstanceScript();
        if (!instance)
            return true;

        uint32 menuId = creature->GetCreatureTemplate()->GossipMenuId;
        if (instance->GetData(DATA_ESCORT_PROGRESS) == ENCOUNTER_PROGRESS_SKARLOC_KILLED)
            menuId = 7830;
        else if (instance->GetData(DATA_ESCORT_PROGRESS) == ENCOUNTER_PROGRESS_TARREN_MILL)
            menuId = 7840;
        else if (instance->GetData(DATA_ESCORT_PROGRESS) == ENCOUNTER_PROGRESS_TARETHA_MEET)
            menuId = 7853;

        player->PrepareGossipMenu(creature, menuId, true);
        player->SendPreparedGossip(creature);
        return true;
    }

    bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action)
    {
        GossipMenuItemData const* gossipMenuItemData = player->PlayerTalkClass->GetGossipMenu().GetItemData(0);
        InstanceScript* instance = creature->GetInstanceScript();
        if (!instance || (gossipMenuItemData && gossipMenuItemData->GossipActionMenuId != 0))
            return false;

        player->PlayerTalkClass->ClearMenus();
        player->CLOSE_GOSSIP_MENU();

        creature->AI()->DoAction(instance->GetData(DATA_ESCORT_PROGRESS));
        creature->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER);
        return true;
    }

    struct npc_thrall_old_hillsbradAI : public npc_escortAI
    {
        npc_thrall_old_hillsbradAI(Creature* creature) : npc_escortAI(creature), summons(me)
        {
            instance = creature->GetInstanceScript();
        }

        void DoAction(int32 param)
        {
            switch (param)
            {
                case ENCOUNTER_PROGRESS_DRAKE_KILLED:
                    events.ScheduleEvent(EVENT_OPEN_DOORS, 0);
                    events.ScheduleEvent(EVENT_START_WP, 3000);
                    break;
                case ENCOUNTER_PROGRESS_THRALL_ARMORED:
                case ENCOUNTER_PROGRESS_AMBUSHES_1:
                case ENCOUNTER_PROGRESS_SKARLOC_KILLED:
                case ENCOUNTER_PROGRESS_TARREN_MILL:
                    SetEscortPaused(false);
                    break;
                case ENCOUNTER_PROGRESS_TARETHA_MEET:
                    events.ScheduleEvent(EVENT_SUMMON_CHRONO, 0);
                    events.ScheduleEvent(EVENT_THRALL_TALK_2, 6000);
                    events.ScheduleEvent(EVENT_TARETHA_FALL, 11000);
                    events.ScheduleEvent(EVENT_THRALL_TALK_3, 14000);
                    events.ScheduleEvent(EVENT_THRALL_MOVE_DOWN, 17000);
                    break;
                case NPC_TARETHA:
                    events.ScheduleEvent(EVENT_THRALL_FACE_TARETHA, 0);
                    events.ScheduleEvent(EVENT_THRALL_TALK_4, 4000);
                    events.ScheduleEvent(EVENT_TARETHA_TALK_1, 13000);
                    events.ScheduleEvent(EVENT_THRALL_TALK_5, 17000);
                    events.ScheduleEvent(EVENT_SUMMON_EROZION, 17500);
                    events.ScheduleEvent(EVENT_EROZION_TALK_1, 18000);
                    events.ScheduleEvent(EVENT_EROZION_ACTION_1, 26000);
                    events.ScheduleEvent(EVENT_EROZION_TALK_2, 29000);
                    events.ScheduleEvent(EVENT_EROZION_TALK_3, 42000);
                    events.ScheduleEvent(EVENT_EROZION_ACTION_2, 47000);
                    events.ScheduleEvent(EVENT_THRALL_TALK_6, 48000);
                    events.ScheduleEvent(EVENT_THRALL_RUN_AWAY, 51000);
                    events.ScheduleEvent(EVENT_TARETHA_TALK_2, 53000);
                    break;
            }
        }

        void WaypointStart(uint32 waypointId)
        {
            switch (waypointId)
            {
                case 30:
                    Talk(SAY_START_EVENT_PART2);
                    break;
            }
        }

        void WaypointReached(uint32 waypointId)
        {
            switch (waypointId)
            {
                case 0:
                    Talk(SAY_START_EVENT_PART1);
                    break;
                case 8:
                    events.ScheduleEvent(EVENT_SET_FACING, 500);
                    break;
                case 9:
                    SetRun(false);
                    events.ScheduleEvent(EVENT_KILL_ARMORER, 500);
                    events.ScheduleEvent(EVENT_TALK_KILL_ARMORER, 4000);
                    break;
                case 10:
                    SetRun(true);
                    events.ScheduleEvent(EVENT_DRESSING_KNEEL, 500);
                    events.ScheduleEvent(EVENT_DRESSING_ARMOR, 3000);
                    events.ScheduleEvent(EVENT_DRESSING_STAND, 4000);
                    events.ScheduleEvent(EVENT_DRESSING_AXE, 7000);
                    events.ScheduleEvent(EVENT_DRESSING_SHIELD, 9000);
                    events.ScheduleEvent(EVENT_DRESSING_TALK, 12000);
                    break;
                case 13:
                    me->SummonCreature(NPC_DURNHOLDE_SENTRY, 2200.28f, 137.37f, 87.93f, 5.07f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_SENTRY, 2197.44f, 131.83f, 87.93f, 0.78f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_MAGE, 2203.62f, 135.40f, 87.93f, 3.70f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_VETERAN, 2200.75f, 130.13f, 87.93f, 1.48f, TEMPSUMMON_MANUAL_DESPAWN);
                    break;
                case 16:
                    me->SummonCreature(NPC_DURNHOLDE_SENTRY, 2147.43f, 122.194f, 76.422f, 0.67f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_SENTRY, 2146.27f, 126.13f, 76.241f, 0.60f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_MAGE, 2142.62f, 120.38f, 75.862f, 0.48f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_VETERAN, 2141.74f, 123.95f, 75.732f, 0.24f, TEMPSUMMON_MANUAL_DESPAWN);
                    break;
                case 18:
                    me->SummonCreature(NPC_DURNHOLDE_SENTRY, 2138.37f, 167.98f, 66.23f, 2.59f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_WARDEN, 2142.76f, 173.62f, 66.23f, 2.59f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_MAGE, 2140.96f, 168.64f, 66.23f, 2.59f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_VETERAN, 2142.53f, 171.03f, 66.23f, 2.59f, TEMPSUMMON_MANUAL_DESPAWN);
                    break;
                case 22:
                    me->SummonCreature(NPC_DURNHOLDE_SENTRY, 2108.73f, 190.43f, 66.23f, 5.56f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_MAGE, 2109.74f, 195.29f, 66.23f, 5.56f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_MAGE, 2107.74f, 192.59f, 66.23f, 5.56f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_DURNHOLDE_SENTRY, 2112.26f, 195.13f, 66.23f, 5.56f, TEMPSUMMON_MANUAL_DESPAWN);
                    break;
                case 27:
                    instance->SetData(DATA_ESCORT_PROGRESS, ENCOUNTER_PROGRESS_AMBUSHES_1);
                    break;
                case 28:
                    me->SummonCreature(NPC_CAPTAIN_SKARLOC, 1995.78f, 277.46f, 66.64f, 0.74f, TEMPSUMMON_MANUAL_DESPAWN);
                    break;
                case 29:
                    SetEscortPaused(true);
                    Talk(SAY_SKARLOC_MEET);
                    break;
                case 30:
                    events.ScheduleEvent(EVENT_ENTER_MOUNT, 3000);
                    events.ScheduleEvent(EVENT_TALK_START_RIDE, 7000);
                    break;
                case 59:
                    instance->SetData(DATA_ESCORT_PROGRESS, ENCOUNTER_PROGRESS_TARREN_MILL);
                    me->SummonCreature(NPC_SKARLOC_MOUNT, 2488.64f, 625.77f, 58.26f, 4.71f, TEMPSUMMON_TIMED_DESPAWN, 7000);
                    UnMountSelf();
                    _mounted = false;
                    SetRun(false);
                    break;
                case 60:
                    me->HandleEmoteCommand(EMOTE_ONESHOT_EXCLAMATION);
                    if (Creature* horse = me->FindNearestCreature(NPC_SKARLOC_MOUNT, 10.0f))
                        horse->GetMotionMaster()->MovePoint(0, 2501.15f, 572.14f, 54.13f);

                    SetEscortPaused(true);
                    SetRun(true);
                    me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
                    break;
                case 64:
                    SetRun(false);
                    break;
                case 67:
                    events.ScheduleEvent(EVENT_LOOK_1, 500);
                    events.ScheduleEvent(EVENT_MOVE_AROUND, 3500);
                    events.ScheduleEvent(EVENT_LOOK_2, 5000);
                    events.ScheduleEvent(EVENT_LOOK_3, 6700);
                    events.ScheduleEvent(EVENT_SUMMON_GUARDS, 6000);
                    events.ScheduleEvent(EVENT_SUMMON_TALK1, 6500);
                    events.ScheduleEvent(EVENT_SUMMON_TALK2, 12000);
                    break;
                case 82:
                    events.ScheduleEvent(EVENT_LOOK_4, 500);
                    events.ScheduleEvent(EVENT_SUMMON_GUARDS_2, 1000);
                    events.ScheduleEvent(EVENT_SUMMON_TALK3, 1500);
                    break;
                case 91:
                    me->SummonCreature(NPC_TM_PROTECTOR, 2652.71f, 660.31f, 61.93f, 1.67f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_TM_LOOKOUT, 2648.96f, 662.59f, 61.93f, 0.79f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_TM_GUARDSMAN, 2657.36f, 662.34f, 61.93f, 2.68f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_TM_GUARDSMAN, 2656.39f, 659.77f, 61.93f, 2.61f, TEMPSUMMON_MANUAL_DESPAWN);
                    if (Creature* summon = summons.GetCreatureWithEntry(NPC_TM_LOOKOUT))
                        summon->AI()->Talk(SAY_LOOKOUT_INN);
                    break;
                case 92:
                    SetRun(false);
                    break;
                case 94:
                    summons.DespawnAll();
                    SetEscortPaused(true);
                    SetRun(true);
                    instance->SetData(DATA_ESCORT_PROGRESS, ENCOUNTER_PROGRESS_TARETHA_MEET);
                    if (Creature* Taretha = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_TARETHA_GUID)))
                        Taretha->AI()->Talk(SAY_TARETHA_ESCAPED);
                    events.ScheduleEvent(EVENT_THRALL_TALK, 2000);
                    break;
                case 101:
                    SetEscortPaused(true);
                    events.ScheduleEvent(EVENT_EPOCH_INTRO, 500);
                    events.ScheduleEvent(EVENT_SUMMON_INFINITES, 1500);
                    events.ScheduleEvent(EVENT_TRANSFORM, 8000);
                    events.ScheduleEvent(EVENT_START_WAVE_1, 25000);
                    break;
                case 103:
                    if (Creature* erozion = summons.GetCreatureWithEntry(NPC_EROZION))
                        erozion->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER);
                    instance->SetData(DATA_ESCORT_PROGRESS, ENCOUNTER_PROGRESS_FINISHED);
                    me->SetVisible(false);
                    break;
            }
        }

        void MountSelf()
        {
            me->Mount(SKARLOC_MOUNT_MODEL);
            me->SetSpeed(MOVE_RUN, SPEED_MOUNTED);
        }

        void UnMountSelf()
        {
            me->Dismount();
            me->SetSpeed(MOVE_RUN, SPEED_RUNNING);
        }

        void MovementInform(uint32 type, uint32 point)
        {
            npc_escortAI::MovementInform(type, point);
            if (type == POINT_MOTION_TYPE && point == 0xFFFFFF /*POINT_LAST_POINT*/)
            {
                if (roll_chance_i(30))
                    Talk(SAY_LEAVE_COMBAT);
                if (_mounted)
                    MountSelf();
            }
        }

        void EnterCombat(Unit*)
        {
            combatEvents.Reset();
            combatEvents.ScheduleEvent(EVENT_CHECK_HEALTH, 500);
            combatEvents.ScheduleEvent(EVENT_SPELL_SHIELD_BLOCK, 8000);
            combatEvents.ScheduleEvent(EVENT_SPELL_STRIKE, 2000);

            if (roll_chance_i(50))
                Talk(SAY_RANDOM_AGGRO);

            if (me->IsMounted())
            {
                _mounted = true;
                UnMountSelf();
            }
        }

        void Reset()
        {
            _mounted = false;
            events.Reset();
            combatEvents.Reset();
            summons.DespawnAll();

            me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER);
            instance->SetData(DATA_THRALL_REPOSITION, 1);
                
            uint32 data = instance->GetData(DATA_ESCORT_PROGRESS);
            if (data >= ENCOUNTER_PROGRESS_THRALL_ARMORED)
                ReorderInstance(data);
        }

        void KilledUnit(Unit*)
        {
            Talk(SAY_RANDOM_KILL);
        }

        void JustSummoned(Creature* summon)
        {
            if (summon->GetEntry() == NPC_INFINITE_SLAYER || summon->GetEntry() == NPC_INFINITE_SABOTEUR || summon->GetEntry() == NPC_INFINITE_DEFILER)
                summon->GetMotionMaster()->MovePoint(10, 2634.25f, 672.01f, 54.445f);

            summons.Summon(summon);
        }
        void SummonedCreatureDespawn(Creature* summon) { summons.Despawn(summon); }
        void SummonedCreatureDies(Creature* summon, Unit*) { summons.Despawn(summon); }

        void JustDied(Unit* killer)
        {
            if (killer == me)
                return;

            summons.DespawnAll();
            Talk(SAY_RANDOM_DIE);
            RemoveEscortState(STATE_ESCORT_ESCORTING);
            instance->SetData(DATA_THRALL_REPOSITION, 3);
            if (instance->GetData(DATA_ATTEMPTS_COUNT) < 20)
                me->CastSpell(me, SPELL_SUMMON_EROZION_IMAGE, true);
            else
                me->SetRespawnTime(DAY);
        }

        void UpdateAI(uint32 diff)
        {
            npc_escortAI::UpdateAI(diff);

            events.Update(diff);
            switch (events.ExecuteEvent())
            {
                case EVENT_OPEN_DOORS:
                    if (GameObject* doors = me->FindNearestGameObject(GO_PRISON_DOOR, 10.0f))
                        doors->SetGoState(GO_STATE_ACTIVE);
                    break;
                case EVENT_START_WP:
                    Start(true, true);
                    SetDespawnAtEnd(false);
                    break;
                case EVENT_SET_FACING:
                    if (Creature* armorer = me->FindNearestCreature(NPC_DURNHOLDE_ARMORER, 30.0f))
                    {
                        armorer->AI()->Talk(SAY_ARMORER_THRALL);
                        armorer->SetFacingToObject(me);
                        me->SetFacingToObject(armorer);
                    }
                    break;
                case EVENT_KILL_ARMORER:
                    me->HandleEmoteCommand(EMOTE_ONESHOT_ATTACK_UNARMED);
                    if (Creature* armorer = me->FindNearestCreature(NPC_DURNHOLDE_ARMORER, 30.0f))
                        armorer->SetStandState(UNIT_STAND_STATE_DEAD);
                    break;
                case EVENT_TALK_KILL_ARMORER:
                    Talk(SAY_KILL_ARMORER);
                    break;
                case EVENT_DRESSING_KNEEL:
                    me->SetFacingTo(2.61f);
                    Talk(SAY_ARMORY);
                    me->SetStandState(UNIT_STAND_STATE_KNEEL);
                    break;
                case EVENT_DRESSING_ARMOR:
                    me->SetDisplayId(THRALL_MODEL_EQUIPPED);
                    break;
                case EVENT_DRESSING_STAND:
                    me->SetStandState(UNIT_STAND_STATE_STAND);
                    break;
                case EVENT_DRESSING_AXE:
                    me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, THRALL_WEAPON_ITEM);
                    break;
                case EVENT_DRESSING_SHIELD:
                    me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID+1, THRALL_SHIELD_ITEM);
                    break;
                case EVENT_DRESSING_TALK:
                    instance->SetData(DATA_ESCORT_PROGRESS, ENCOUNTER_PROGRESS_THRALL_ARMORED);
                    Talk(SAY_GO_ARMORED);
                    break;
                case EVENT_ENTER_MOUNT:
                    MountSelf();
                    if (Creature* mount = me->FindNearestCreature(NPC_SKARLOC_MOUNT, 10.0f))
                    {
                        me->SetFacingTo(mount->GetOrientation());
                        mount->DespawnOrUnsummon();
                    }
                    break;
                case EVENT_TALK_START_RIDE:
                    Talk(SAY_MOUNTS_UP);
                    break;
                case EVENT_LOOK_1:
                    me->SetFacingTo(5.058f);
                    break;
                case EVENT_MOVE_AROUND:
                    me->GetMotionMaster()->MovePoint(0, 2477.146f, 695.041f, 55.801f);
                    break;
                case EVENT_LOOK_2:
                    me->SetFacingTo(2.297f);
                    break;
                case EVENT_LOOK_3:
                    me->SetFacingTo(0.64f);
                    break;
                case EVENT_SUMMON_GUARDS:
                    SetRun(true);
                    me->SummonCreature(NPC_TM_PROTECTOR, 2501.34f, 700.80f, 55.573f, 3.92f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_TM_LOOKOUT, 2503.02f, 699.11f, 55.57f, 3.92f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_TM_GUARDSMAN, 2503.04f, 702.495f, 50.63f, 3.92f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_TM_GUARDSMAN, 2504.72f, 700.806f, 55.62f, 3.92f, TEMPSUMMON_MANUAL_DESPAWN);
                    summons.DoAction(ACTION_SET_IMMUNE_FLAG);
                    break;
                case EVENT_SUMMON_TALK1:
                    if (Creature* summon = summons.GetCreatureWithEntry(NPC_TM_LOOKOUT))
                        summon->AI()->Talk(SAY_LOOKOUT_SAW);
                    break;
                case EVENT_SUMMON_TALK2:
                    if (Creature* summon = summons.GetCreatureWithEntry(NPC_TM_LOOKOUT))
                        summon->AI()->Talk(SAY_LOOKOUT_GO);
                    summons.DoAction(ACTION_REMOVE_IMMUNE_FLAG);
                    break;
                case EVENT_LOOK_4:
                    me->SetFacingTo(0.41f);
                    Talk(SAY_ENTER_CHURCH);
                    break;
                case EVENT_SUMMON_GUARDS_2:
                    me->SummonCreature(NPC_TM_PROTECTOR, 2630.75f, 664.80f, 54.28f, 4.37f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_TM_LOOKOUT, 2632.20f, 661.98f, 54.30f, 4.37f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_TM_GUARDSMAN, 2630.02f, 662.75f, 54.28f, 4.37f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_TM_GUARDSMAN, 2632.86f, 664.05f, 54.31f, 4.37f, TEMPSUMMON_MANUAL_DESPAWN);
                    break;
                case EVENT_SUMMON_TALK3:
                    if (Creature* summon = summons.GetCreatureWithEntry(NPC_TM_LOOKOUT))
                        summon->AI()->Talk(SAY_LOOKOUT_CHURCH);
                    break;
                case EVENT_THRALL_TALK:
                    Talk(SAY_MEET_TARETHA);
                    me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP);
                    break;
                case EVENT_SUMMON_CHRONO:
                    if (Creature* epoch = me->SummonCreature(NPC_EPOCH_HUNTER, 2640.49f, 696.15f, 64.31f, 4.51f, TEMPSUMMON_MANUAL_DESPAWN))
                    {
                        epoch->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC);
                        epoch->AI()->Talk(SAY_EPOCH_ENTER1);
                    }
                    break;
                case EVENT_THRALL_TALK_2:
                    me->SetFacingTo(2.67f);
                    Talk(SAY_EPOCH_WONDER);
                    break;
                case EVENT_TARETHA_FALL:
                    if (Creature* epoch = summons.GetCreatureWithEntry(NPC_EPOCH_HUNTER))
                        epoch->AI()->Talk(SAY_EPOCH_ENTER2);
                    if (Creature* Taretha = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_TARETHA_GUID)))
                    {
                        Taretha->CastSpell(Taretha, SPELL_SHADOW_SPIKE);
                        Taretha->SetStandState(UNIT_STAND_STATE_DEAD);
                    }
                    break;
                case EVENT_THRALL_TALK_3:
                    me->SetFacingTo(5.78f);
                    Talk(SAY_EPOCH_KILL_TARETHA);
                    break;
                case EVENT_THRALL_MOVE_DOWN:
                    SetEscortPaused(false);
                    break;
                case EVENT_EPOCH_INTRO:
                    me->SetFacingTo(1.33f);
                    if (Creature* epoch = summons.GetCreatureWithEntry(NPC_EPOCH_HUNTER))
                        epoch->AI()->Talk(SAY_EPOCH_ENTER3);
                    break;
                case EVENT_SUMMON_INFINITES:
                    me->SummonCreature(NPC_EPOCH_LOOKOUT, 2647.57f, 701.17f, 56.215f, 4.3f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_EPOCH_GUARDSMAN, 2629.46f, 704.76f, 56.286f, 4.98f, TEMPSUMMON_MANUAL_DESPAWN);
                    me->SummonCreature(NPC_EPOCH_PROTECTOR, 2640.14f, 709.44f, 56.135f, 4.70f, TEMPSUMMON_MANUAL_DESPAWN);
                    summons.DoAction(ACTION_SET_IMMUNE_FLAG);
                    summons.DoAction(ACTION_MOVE);
                    break;
                case EVENT_TRANSFORM:
                    summons.DoAction(ACTION_TRANSFORM);
                    summons.DoAction(ACTION_SET_IMMUNE_FLAG);
                    break;
                case EVENT_START_WAVE_1:
                    events.ScheduleEvent(EVENT_CHECK_WAVE_1, 500);
                    summons.DoAction(ACTION_REMOVE_IMMUNE_FLAG);
                    summons.DoAction(ACTION_START_COMBAT);
                    break;
                case EVENT_CHECK_WAVE_1:
                    if (summons.size() == 1)
                    {
                        me->SummonCreature(NPC_INFINITE_SABOTEUR, 2599.57f, 683.72f, 55.975f, 0.05f, TEMPSUMMON_MANUAL_DESPAWN);
                        me->SummonCreature(NPC_INFINITE_SLAYER, 2599.57f, 677.0f, 55.975f, 0.05f, TEMPSUMMON_MANUAL_DESPAWN);
                        me->SummonCreature(NPC_INFINITE_DEFILER, 2592.57f, 680.0f, 55.975f, 0.05f, TEMPSUMMON_MANUAL_DESPAWN);
                        summons.DoAction(ACTION_START_COMBAT);
                        events.ScheduleEvent(EVENT_CHECK_WAVE_2, 500);
                        break;
                    }
                    events.ScheduleEvent(EVENT_CHECK_WAVE_1, 500);
                    break;
                case EVENT_CHECK_WAVE_2:
                    if (summons.size() == 1)
                    {
                        me->SummonCreature(NPC_INFINITE_SLAYER, 2642.62f, 701.43f, 55.965f, 4.46f, TEMPSUMMON_MANUAL_DESPAWN);
                        me->SummonCreature(NPC_INFINITE_SLAYER, 2638.62f, 701.43f, 55.965f, 4.46f, TEMPSUMMON_MANUAL_DESPAWN);
                        me->SummonCreature(NPC_INFINITE_SABOTEUR, 2638.62f, 705.43f, 55.965f, 4.46f, TEMPSUMMON_MANUAL_DESPAWN);
                        me->SummonCreature(NPC_INFINITE_DEFILER, 2642.62f, 705.43f, 55.965f, 4.46f, TEMPSUMMON_MANUAL_DESPAWN);
                        summons.DoAction(ACTION_START_COMBAT);
                        events.ScheduleEvent(EVENT_CHECK_WAVE_3, 500);
                        break;
                    }
                    events.ScheduleEvent(EVENT_CHECK_WAVE_2, 500);
                    break;
                case EVENT_CHECK_WAVE_3:
                    if (summons.size() == 1)
                    {
                        me->SetHomePosition(2634.79f, 672.964f, 54.8577f, 1.33f);
                        me->GetMotionMaster()->MoveTargetedHome();
                        events.ScheduleEvent(EVENT_CALL_EPOCH, 8000);
                        break;
                    }
                    events.ScheduleEvent(EVENT_CHECK_WAVE_3, 500);
                    break;
                case EVENT_CALL_EPOCH:
                    if (Creature* epoch = summons.GetCreatureWithEntry(NPC_EPOCH_HUNTER))
                    {
                        epoch->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC);
                        epoch->GetMotionMaster()->MovePoint(0, *me, false, true);
                    }
                    break;
                case EVENT_THRALL_FACE_TARETHA:
                {
                    Map::PlayerList const& players = me->GetMap()->GetPlayers();
                    if (!players.isEmpty())
                        for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
                            if (Player* player = itr->GetSource())
                                player->KilledMonsterCredit(20156, 0);

                    me->SetFacingTo(5.76f);
                    break;
                }
                case EVENT_THRALL_TALK_4:
                    Talk(SAY_GREET_TARETHA);
                    break;
                case EVENT_TARETHA_TALK_1:
                    if (Creature* Taretha = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_TARETHA_GUID)))
                        Taretha->AI()->Talk(SAY_TARETHA_TALK1);
                    break;
                case EVENT_THRALL_TALK_5:
                    Talk(SAY_CHAT_TARETHA1);
                    break;
                case EVENT_SUMMON_EROZION:
                    if (Creature* erozion = me->SummonCreature(NPC_EROZION, 2646.31f, 680.01f, 55.36f, 3.76f, TEMPSUMMON_MANUAL_DESPAWN))
                        erozion->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
                    break;
                case EVENT_EROZION_TALK_1:
                    if (Creature* erozion = summons.GetCreatureWithEntry(NPC_EROZION))
                    {
                        erozion->CastSpell(erozion, SPELL_TELEPORT, true);
                        erozion->AI()->Talk(SAY_EROZION_1);
                    }
                    break;
                case EVENT_EROZION_ACTION_1:
                    if (Creature* erozion = summons.GetCreatureWithEntry(NPC_EROZION))
                        erozion->CastSpell(erozion, SPELL_MEMORY_WIPE, false);
                    break;
                case EVENT_EROZION_TALK_2:
                    if (Creature* erozion = summons.GetCreatureWithEntry(NPC_EROZION))
                        erozion->AI()->Talk(SAY_EROZION_2);
                    break;
                case EVENT_EROZION_TALK_3:
                    if (Creature* erozion = summons.GetCreatureWithEntry(NPC_EROZION))
                        erozion->AI()->Talk(SAY_EROZION_3);
                    break;
                case EVENT_EROZION_ACTION_2:
                    if (Creature* erozion = summons.GetCreatureWithEntry(NPC_EROZION))
                        erozion->CastSpell(erozion, SPELL_MEMORY_WIPE_RESUME, false);
                    break;
                case EVENT_THRALL_TALK_6:
                    Talk(SAY_EVENT_COMPLETE);
                    break;
                case EVENT_THRALL_RUN_AWAY:
                    me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_IMMUNE_TO_NPC);
                    me->SetReactState(REACT_PASSIVE);
                    SetEscortPaused(false);
                    break;
                case EVENT_TARETHA_TALK_2:
                    if (Creature* Taretha = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_TARETHA_GUID)))
                    {
                        Taretha->SetFacingTo(4.233f);
                        Taretha->AI()->Talk(SAY_TARETHA_TALK2);
                    }
                    break;
            }
        }

        void UpdateEscortAI(uint32 diff)
        {
            if (!UpdateVictim())
                return;

            combatEvents.Update(diff);
            switch (combatEvents.ExecuteEvent())
            {
                case EVENT_CHECK_HEALTH:
                    if (me->HealthBelowPct(20))
                    {
                        Talk(SAY_RANDOM_LOW_HP);
                        break;
                    }
                    events.ScheduleEvent(EVENT_CHECK_HEALTH, 500);
                    break;
                case EVENT_SPELL_STRIKE:
                    me->CastSpell(me->GetVictim(), SPELL_STRIKE, false);
                    events.ScheduleEvent(EVENT_SPELL_STRIKE, 6000);
                    break;
                case EVENT_SPELL_SHIELD_BLOCK:
                    me->CastSpell(me, SPELL_SHIELD_BLOCK, false);
                    events.ScheduleEvent(EVENT_SPELL_SHIELD_BLOCK, 6000);
                    break;
            }

            DoMeleeAttackIfReady();
        }

        void ReorderInstance(uint32 data)
        {
            Start(true, true);
            SetEscortPaused(true);
            SetDespawnAtEnd(false);
            
            me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP|UNIT_NPC_FLAG_QUESTGIVER);

            if (data < ENCOUNTER_PROGRESS_THRALL_ARMORED)
            {
                me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, 0);
                me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID+1, 0);
                me->SetDisplayId(THRALL_MODEL_UNEQUIPPED);
            }
            else
            {
                me->SetDisplayId(THRALL_MODEL_EQUIPPED);
                me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, THRALL_WEAPON_ITEM);
                me->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID+1, THRALL_SHIELD_ITEM);
            }

            switch (data)
            {
                case ENCOUNTER_PROGRESS_THRALL_ARMORED:
                    SetNextWaypoint(11, false);
                    break;
                case ENCOUNTER_PROGRESS_AMBUSHES_1:
                    SetNextWaypoint(27, false);
                    break;
                case ENCOUNTER_PROGRESS_SKARLOC_KILLED:
                    me->SummonCreature(NPC_SKARLOC_MOUNT, 2049.12f, 252.31f, 62.855f, me->GetOrientation(), TEMPSUMMON_MANUAL_DESPAWN);
                    SetNextWaypoint(30, false);
                    break;
                case ENCOUNTER_PROGRESS_TARREN_MILL:
                    SetNextWaypoint(61, false);
                    break;
                case ENCOUNTER_PROGRESS_TARETHA_MEET:
                    SetNextWaypoint(95, false);                    
                    if (Creature* Taretha = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_TARETHA_GUID)))
                        Taretha->SetStandState(UNIT_STAND_STATE_STAND);
                    break;
            }
        }

        private:
            InstanceScript* instance;
            EventMap events;
            EventMap combatEvents;
            SummonList summons;

            bool _mounted;
    };
};

class npc_taretha : public CreatureScript
{
public:
    npc_taretha() : CreatureScript("npc_taretha") { }

    CreatureAI* GetAI(Creature* creature) const
    {
        return GetInstanceAI<npc_tarethaAI>(creature);
    }

    bool OnGossipHello(Player* player, Creature* creature)
    {
        return true;
    }

    struct npc_tarethaAI : public npc_escortAI
    {
        npc_tarethaAI(Creature* creature) : npc_escortAI(creature)
        {
            instance = creature->GetInstanceScript();
        }

        InstanceScript* instance;

        void DoAction(int32 param)
        {
            me->SetStandState(UNIT_STAND_STATE_STAND);
            me->RemoveAllAuras();
            Start(false, true);
        }

        void WaypointReached(uint32 waypointId)
        {
            if (waypointId == 7)
            {
                SetRun(false);
                Talk(SAY_TARETHA_FREE);
                me->HandleEmoteCommand(EMOTE_ONESHOT_CHEER);
                if (Creature* thrall = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_THRALL_GUID)))
                    thrall->AI()->DoAction(me->GetEntry());
            }
            else if (waypointId == 9)
                me->SetVisible(false);
        }

        void Reset()
        {
            me->SetUInt32Value(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_NONE);
            me->CastSpell(me, SPELL_SHADOW_PRISON, true);
        }

        void AttackStart(Unit*) { }
        void MoveInLineOfSight(Unit*) { }
    };

};

void AddSC_old_hillsbrad()
{
    new npc_thrall_old_hillsbrad();
    new npc_taretha();
}
