/*
 * Copyright (C) 
 * Copyright (C) 
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/* ScriptData
SDName: Boss_Nightbane
SD%Complete: 80
SDComment: SDComment: Timers may incorrect
SDCategory: Karazhan
EndScriptData */

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "karazhan.h"

enum Spells
{
    // phase 1
    SPELL_BELLOWING_ROAR        = 39427,
    SPELL_CHARRED_EARTH         = 30129,
    SPELL_DISTRACTING_ASH       = 30130,
    SPELL_SMOLDERING_BREATH     = 30210,
    SPELL_TAIL_SWEEP            = 25653,
    // phase 2
    SPELL_RAIN_OF_BONES         = 37098,
    SPELL_SMOKING_BLAST         = 37057,
    SPELL_FIREBALL_BARRAGE      = 30282,
    SPELL_SEARING_CINDERS       = 30127,
    SPELL_SUMMON_SKELETON       = 30170
};

enum Says
{
    EMOTE_SUMMON                = 0, // Not used in script
    YELL_AGGRO                  = 1,
    YELL_FLY_PHASE              = 2,
    YELL_LAND_PHASE             = 3,
    EMOTE_BREATH                = 4
};

float IntroWay[8][3] =
{
    {-11053.37f, -1794.48f, 149.00f},
    {-11141.07f, -1841.40f, 125.00f},
    {-11187.28f, -1890.23f, 125.00f},
    {-11189.20f, -1931.25f, 125.00f},
    {-11153.76f, -1948.93f, 125.00f},
    {-11128.73f, -1929.75f, 125.00f},
    {-11140.00f, -1915.00f, 122.00f},
    {-11163.00f, -1903.00f, 91.473f}
};

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

    CreatureAI* GetAI(Creature* creature) const
    {
        return new boss_nightbaneAI (creature);
    }

    struct boss_nightbaneAI : public ScriptedAI
    {
        boss_nightbaneAI(Creature* creature) : ScriptedAI(creature)
        {
            instance = creature->GetInstanceScript();
            Intro = true;
        }

        InstanceScript* instance;

        uint32 Phase;

        bool RainBones;
        bool Skeletons;

        uint32 BellowingRoarTimer;
        uint32 CharredEarthTimer;
        uint32 DistractingAshTimer;
        uint32 SmolderingBreathTimer;
        uint32 TailSweepTimer;
        uint32 RainofBonesTimer;
        uint32 SmokingBlastTimer;
        uint32 FireballBarrageTimer;
        uint32 SearingCindersTimer;

        uint32 FlyCount;
        uint32 FlyTimer;

        bool Intro;
        bool Flying;
        bool Movement;

        uint32 MovePhase;

        void Reset()
        {
            BellowingRoarTimer = 30000;
            CharredEarthTimer = 15000;
            DistractingAshTimer = 20000;
            SmolderingBreathTimer = 10000;
            TailSweepTimer = 12000;
            RainofBonesTimer = 10000;
            SmokingBlastTimer = 20000;
            FireballBarrageTimer = 13000;
            SearingCindersTimer = 14000;

            Phase = 1;
            FlyCount = 0;
            MovePhase = 0;

            me->SetSpeed(MOVE_RUN, 2.0f);
            me->SetDisableGravity(Intro);
            me->SetWalk(false);
            me->setActive(true);

            if (instance)
            {
                if (instance->GetData(TYPE_NIGHTBANE) == DONE)
                    me->DisappearAndDie();
                else
                    instance->SetData(TYPE_NIGHTBANE, NOT_STARTED);
            }

            HandleTerraceDoors(true);

            Flying = false;
            Movement = false;

            if (!Intro)
            {
                me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
                me->GetMotionMaster()->MoveTargetedHome();
            }
        }

        void HandleTerraceDoors(bool open)
        {
            if (instance)
            {
                instance->HandleGameObject(instance->GetData64(DATA_MASTERS_TERRACE_DOOR_1), open);
                instance->HandleGameObject(instance->GetData64(DATA_MASTERS_TERRACE_DOOR_2), open);
            }
        }

        void EnterCombat(Unit* /*who*/)
        {
            if (instance)
                instance->SetData(TYPE_NIGHTBANE, IN_PROGRESS);

            HandleTerraceDoors(false);
           Talk(YELL_AGGRO);
        }

        void AttackStart(Unit* who)
        {
            if (!Intro && !Flying)
                ScriptedAI::AttackStart(who);
        }

        void JustDied(Unit* /*killer*/)
        {
            if (instance)
                instance->SetData(TYPE_NIGHTBANE, DONE);

            HandleTerraceDoors(true);
        }

        void MoveInLineOfSight(Unit* who)
        {
            if (!Intro && !Flying)
                ScriptedAI::MoveInLineOfSight(who);
        }

        void MovementInform(uint32 type, uint32 id)
        {
            if (type != POINT_MOTION_TYPE)
                return;

            if (Intro)
            {
                if (id >= 8)
                {
                    Intro = false;
                    me->SetHomePosition(IntroWay[7][0], IntroWay[7][1], IntroWay[7][2], 0);
                    return;
                }

                MovePhase = id+1;
                return;
            }

            if (Flying)
            {
                if (id == 0)
                {
                    Talk(EMOTE_BREATH);
                    Flying = false;
                    Phase = 2;
                    return;
                }

                if (id < 8)
                    MovePhase = id+1;
                else
                {
                    Phase = 1;
                    Flying = false;
                    Movement = true;
                    return;
                }
            }
        }

        void JustSummoned(Creature* summoned)
        {
            summoned->AI()->AttackStart(me->GetVictim());
        }

        void TakeOff()
        {
            Talk(YELL_FLY_PHASE);

            me->InterruptSpell(CURRENT_GENERIC_SPELL);
            me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
            me->SetDisableGravity(true);
            me->GetMotionMaster()->Clear(false);
            me->GetMotionMaster()->MovePoint(0, IntroWay[2][0], IntroWay[2][1], IntroWay[2][2]);

            Flying = true;

            FlyTimer = urand(45000, 60000); //timer wrong between 45 and 60 seconds
            ++FlyCount;

            RainofBonesTimer = 5000; //timer wrong (maybe)
            RainBones = false;
            Skeletons = false;
         }

        void UpdateAI(uint32 diff)
        {
            if (Intro)
            {
                if (MovePhase)
                {
                    if (MovePhase >= 7)
                    {
                        me->SetDisableGravity(false);
                        me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
                        me->GetMotionMaster()->MovePoint(8, IntroWay[7][0], IntroWay[7][1], IntroWay[7][2]);
                    }
                    else
                    {
                        me->GetMotionMaster()->MovePoint(MovePhase, IntroWay[MovePhase][0], IntroWay[MovePhase][1], IntroWay[MovePhase][2]);
                    }
                    MovePhase = 0;
                }
                return;
            }

            if (Flying && MovePhase)
            {
                if (MovePhase >= 7)
                {
                    me->SetDisableGravity(false);
                    me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
                    me->GetMotionMaster()->MovePoint(8, IntroWay[7][0], IntroWay[7][1], IntroWay[7][2]);
                }
                else
                    me->GetMotionMaster()->MovePoint(MovePhase, IntroWay[MovePhase][0], IntroWay[MovePhase][1], IntroWay[MovePhase][2]);
                    
                MovePhase = 0;
            }

            if (!UpdateVictim())
                return;

            if (Flying)
                return;

            //  Phase 1 "GROUND FIGHT"
            if (Phase == 1)
            {
                if (Movement)
                {
                    DoStartMovement(me->GetVictim());
                    Movement = false;
                }

                if (BellowingRoarTimer <= diff)
                {
                    DoCastVictim(SPELL_BELLOWING_ROAR);
                    BellowingRoarTimer = urand(30000, 40000);
                } else BellowingRoarTimer -= diff;

                if (SmolderingBreathTimer <= diff)
                {
                    DoCastVictim(SPELL_SMOLDERING_BREATH);
                    SmolderingBreathTimer = 20000;
                } else SmolderingBreathTimer -= diff;

                if (CharredEarthTimer <= diff)
                {
                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        DoCast(target, SPELL_CHARRED_EARTH);
                    CharredEarthTimer = 20000;
                } else CharredEarthTimer -= diff;

                if (TailSweepTimer <= diff)
                {
                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        if (!me->HasInArc(M_PI, target))
                            DoCast(target, SPELL_TAIL_SWEEP);
                    TailSweepTimer = 15000;
                } else TailSweepTimer -= diff;

                if (SearingCindersTimer <= diff)
                {
                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        DoCast(target, SPELL_SEARING_CINDERS);
                    SearingCindersTimer = 10000;
                } else SearingCindersTimer -= diff;

                uint32 Prozent = uint32(me->GetHealthPct());

                if (Prozent < 75 && FlyCount == 0) // first take off 75%
                    TakeOff();

                if (Prozent < 50 && FlyCount == 1) // secound take off 50%
                    TakeOff();

                if (Prozent < 25 && FlyCount == 2) // third take off 25%
                    TakeOff();

                DoMeleeAttackIfReady();
            }

            //Phase 2 "FLYING FIGHT"
            if (Phase == 2)
            {
                if (!RainBones)
                {
                    if (!Skeletons)
                    {
                        for (uint8 i = 0; i <= 3; ++i)
                        {
                            DoCastVictim(SPELL_SUMMON_SKELETON);
                            Skeletons = true;
                        }
                    }

                    if (RainofBonesTimer < diff && !RainBones) // only once at the beginning of phase 2
                    {
                        DoCastVictim(SPELL_RAIN_OF_BONES);
                        RainBones = true;
                        SmokingBlastTimer = 20000;
                    } else RainofBonesTimer -= diff;

                    if (DistractingAshTimer <= diff)
                    {
                        if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                            DoCast(target, SPELL_DISTRACTING_ASH);
                        DistractingAshTimer = 2000; //timer wrong
                    } else DistractingAshTimer -= diff;
                }

                if (RainBones)
                {
                    if (SmokingBlastTimer <= diff)
                     {
                        DoCastVictim(SPELL_SMOKING_BLAST);
                        SmokingBlastTimer = 1500; //timer wrong
                     } else SmokingBlastTimer -= diff;
                }

                if (FireballBarrageTimer <= diff)
                {
                    if (Unit* target = SelectTarget(SELECT_TARGET_FARTHEST, 0))
                        DoCast(target, SPELL_FIREBALL_BARRAGE);
                    FireballBarrageTimer = 20000;
                } else FireballBarrageTimer -= diff;

                if (FlyTimer <= diff) //landing
                {
                    Talk(YELL_LAND_PHASE);

                    me->GetMotionMaster()->Clear(false);
                    me->GetMotionMaster()->MovePoint(3, IntroWay[3][0], IntroWay[3][1], IntroWay[3][2]);

                    Flying = true;
                } else FlyTimer -= diff;
            }
        }
    };

};

class go_blackened_urn : public GameObjectScript
{
public:
    go_blackened_urn() : GameObjectScript("go_blackened_urn") { }

    bool OnGossipHello(Player* pPlayer, GameObject *pGo)
    {
        if (InstanceScript* pInstance = pGo->GetInstanceScript())
        {
            if (pInstance->GetData(TYPE_NIGHTBANE) != DONE && !pGo->FindNearestCreature(17225, 40.0f))
                if (Creature *cr = ObjectAccessor::GetCreature(*pPlayer, pInstance->GetData64(DATA_NIGHTBANE)))
                    cr->GetMotionMaster()->MovePoint(0, IntroWay[0][0], IntroWay[0][1], IntroWay[0][2]);
        }        
        return false;
    }
};

void AddSC_boss_nightbane()
{
    new boss_nightbane();
    new go_blackened_urn();
}
