/*
 * Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
 * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/>
 *
 * 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_Victor_Nefarius
SD%Complete: 75
SDComment: Missing some text, Vael beginning event, and spawns Nef in wrong place
SDCategory: Blackwing Lair
EndScriptData */

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

enum Says
{
    SAY_GAMESBEGIN_1        = 0,
    SAY_GAMESBEGIN_2        = 1,
  //SAY_VAEL_INTRO          = 2, Not used - when he corrupts Vaelastrasz
};

#define GOSSIP_ITEM_1           "I've made no mistakes."
#define GOSSIP_ITEM_2           "You have lost your mind, Nefarius. You speak in riddles."
#define GOSSIP_ITEM_3           "Please do."

enum Creatures
{
    CREATURE_BRONZE_DRAKANOID       = 14263,
    CREATURE_BLUE_DRAKANOID         = 14261,
    CREATURE_RED_DRAKANOID          = 14264,
    CREATURE_GREEN_DRAKANOID        = 14262,
    CREATURE_BLACK_DRAKANOID        = 14265,

    CREATURE_CHROMATIC_DRAKANOID    = 14302,
    CREATURE_NEFARIAN               = 11583
};

#define ADD_X1    -7591.151855f
#define ADD_X2    -7514.598633f
#define ADD_Y1    -1204.051880f
#define ADD_Y2    -1150.448853f
#define ADD_Z1    476.800476f
#define ADD_Z2    476.796570f

#define NEF_X     -7445
#define NEF_Y     -1332
#define NEF_Z     536

#define HIDE_X   -7592
#define HIDE_Y   -1264
#define HIDE_Z   481

enum Spells
{
   SPELL_SHADOWBOLT        = 21077,
   SPELL_FEAR              = 26070
};

//This script is complicated
//Instead of morphing Victor Nefarius we will have him control phase 1
//And then have him spawn "Nefarian" for phase 2
//When phase 2 starts Victor Nefarius will go into hiding and stop attacking
//If Nefarian despawns because he killed the players then this guy will EnterEvadeMode
//and allow players to start the event over
//If nefarian dies then he will kill himself then he will kill himself in his hiding place
//To prevent players from doing the event twice

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

    bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action)
    {
        player->PlayerTalkClass->ClearMenus();
        switch (action)
        {
            case GOSSIP_ACTION_INFO_DEF+1:
                player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_2, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+2);
                player->SEND_GOSSIP_MENU(7198, creature->GetGUID());
                break;
            case GOSSIP_ACTION_INFO_DEF+2:
                player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_3, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+3);
                player->SEND_GOSSIP_MENU(7199, creature->GetGUID());
                break;
            case GOSSIP_ACTION_INFO_DEF+3:
                player->CLOSE_GOSSIP_MENU();
                creature->AI()->Talk(SAY_GAMESBEGIN_1);
                CAST_AI(boss_victor_nefarius::boss_victor_nefariusAI, creature->AI())->BeginEvent(player);
                break;
        }
        return true;
    }

    bool OnGossipHello(Player* player, Creature* creature)
    {
        player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM_1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1);
        player->SEND_GOSSIP_MENU(7134, creature->GetGUID());
        return true;
    }

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

    struct boss_victor_nefariusAI : public ScriptedAI
    {
        boss_victor_nefariusAI(Creature* creature) : ScriptedAI(creature)
        {
            NefarianGUID = 0;
            switch (urand(0, 19))
            {
                case 0:
                    DrakType1 = CREATURE_BRONZE_DRAKANOID;
                    DrakType2 = CREATURE_BLUE_DRAKANOID;
                    break;
                case 1:
                    DrakType1 = CREATURE_BRONZE_DRAKANOID;
                    DrakType2 = CREATURE_RED_DRAKANOID;
                    break;
                case 2:
                    DrakType1 = CREATURE_BRONZE_DRAKANOID;
                    DrakType2 = CREATURE_GREEN_DRAKANOID;
                    break;
                case 3:
                    DrakType1 = CREATURE_BRONZE_DRAKANOID;
                    DrakType2 = CREATURE_BLACK_DRAKANOID;
                    break;
                case 4:
                    DrakType1 = CREATURE_BLUE_DRAKANOID;
                    DrakType2 = CREATURE_BRONZE_DRAKANOID;
                    break;
                case 5:
                    DrakType1 = CREATURE_BLUE_DRAKANOID;
                    DrakType2 = CREATURE_RED_DRAKANOID;
                    break;
                case 6:
                    DrakType1 = CREATURE_BLUE_DRAKANOID;
                    DrakType2 = CREATURE_GREEN_DRAKANOID;
                    break;
                case 7:
                    DrakType1 = CREATURE_BLUE_DRAKANOID;
                    DrakType2 = CREATURE_BLACK_DRAKANOID;
                    break;
                case 8:
                    DrakType1 = CREATURE_RED_DRAKANOID;
                    DrakType2 = CREATURE_BRONZE_DRAKANOID;
                    break;
                case 9:
                    DrakType1 = CREATURE_RED_DRAKANOID;
                    DrakType2 = CREATURE_BLUE_DRAKANOID;
                    break;
                case 10:
                    DrakType1 = CREATURE_RED_DRAKANOID;
                    DrakType2 = CREATURE_GREEN_DRAKANOID;
                    break;
                case 11:
                    DrakType1 = CREATURE_RED_DRAKANOID;
                    DrakType2 = CREATURE_BLACK_DRAKANOID;
                    break;
                case 12:
                    DrakType1 = CREATURE_GREEN_DRAKANOID;
                    DrakType2 = CREATURE_BRONZE_DRAKANOID;
                    break;
                case 13:
                    DrakType1 = CREATURE_GREEN_DRAKANOID;
                    DrakType2 = CREATURE_BLUE_DRAKANOID;
                    break;
                case 14:
                    DrakType1 = CREATURE_GREEN_DRAKANOID;
                    DrakType2 = CREATURE_RED_DRAKANOID;
                    break;
                case 15:
                    DrakType1 = CREATURE_GREEN_DRAKANOID;
                    DrakType2 = CREATURE_BLACK_DRAKANOID;
                    break;
                case 16:
                    DrakType1 = CREATURE_BLACK_DRAKANOID;
                    DrakType2 = CREATURE_BRONZE_DRAKANOID;
                    break;
                case 17:
                    DrakType1 = CREATURE_BLACK_DRAKANOID;
                    DrakType2 = CREATURE_BLUE_DRAKANOID;
                    break;
                case 18:
                    DrakType1 = CREATURE_BLACK_DRAKANOID;
                    DrakType2 = CREATURE_GREEN_DRAKANOID;
                    break;
                case 19:
                    DrakType1 = CREATURE_BLACK_DRAKANOID;
                    DrakType2 = CREATURE_RED_DRAKANOID;
                    break;
            }
        }

        uint32 SpawnedAdds;
        uint32 AddSpawnTimer;
        uint32 ShadowBoltTimer;
        uint32 FearTimer;
        uint32 MindControlTimer;
        uint32 ResetTimer;
        uint32 DrakType1;
        uint32 DrakType2;
        uint64 NefarianGUID;
        uint32 NefCheckTime;

        void Reset()
        {
            SpawnedAdds = 0;
            AddSpawnTimer = 10000;
            ShadowBoltTimer = 5000;
            FearTimer = 8000;
            ResetTimer = 900000;                                // On official it takes him 15 minutes(900 seconds) to reset. We are only doing 1 minute to make testing easier
            NefarianGUID = 0;
            NefCheckTime = 2000;

            me->SetUInt32Value(UNIT_NPC_FLAGS, 1);
            me->setFaction(35);
            me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
        }

        void BeginEvent(Player* target)
        {
            Talk(SAY_GAMESBEGIN_2);

            //Trinity::Singleton<MapManager>::Instance().GetMap(me->GetMapId(), me)->GetPlayers().begin();
            /*
            list <Player*>::const_iterator i = sMapMgr->GetMap(me->GetMapId(), me)->GetPlayers().begin();

            for (i = sMapMgr->GetMap(me->GetMapId(), me)->GetPlayers().begin(); i != sMapMgr->GetMap(me->GetMapId(), me)->GetPlayers().end(); ++i)
            {
            AttackStart((*i));
            }
            */
            me->SetUInt32Value(UNIT_NPC_FLAGS, 0);
            me->setFaction(103);
            me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
            AttackStart(target);
        }

        void EnterCombat(Unit* /*who*/)
        {
        }

        void MoveInLineOfSight(Unit* who)
        {
            //We simply use this function to find players until we can use map->GetPlayers()

            if (who && who->GetTypeId() == TYPEID_PLAYER && me->IsHostileTo(who))
            {
                //Add them to our threat list
                me->AddThreat(who, 0.0f);
            }
        }

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

            //Only do this if we haven't spawned nef yet
            if (SpawnedAdds < 42)
            {
                //ShadowBoltTimer
                if (ShadowBoltTimer <= diff)
                {
                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        DoCast(target, SPELL_SHADOWBOLT);

                    ShadowBoltTimer = urand(3000, 10000);
                } else ShadowBoltTimer -= diff;

                //FearTimer
                if (FearTimer <= diff)
                {
                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
                        DoCast(target, SPELL_FEAR);

                    FearTimer = 10000 + (rand()%10000);
                } else FearTimer -= diff;

                //Add spawning mechanism
                if (AddSpawnTimer <= diff)
                {
                    //Spawn 2 random types of creatures at the 2 locations
                    uint32 CreatureID;
                    Creature* Spawned = NULL;
                    Unit* target = NULL;

                    //1 in 3 chance it will be a chromatic
                    if (urand(0, 2) == 0)
                        CreatureID = CREATURE_CHROMATIC_DRAKANOID;
                    else
                        CreatureID = DrakType1;

                    ++SpawnedAdds;

                    //Spawn Creature and force it to start attacking a random target
                    Spawned = me->SummonCreature(CreatureID, ADD_X1, ADD_Y1, ADD_Z1, 5.000f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000);
                    target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
                    if (target && Spawned)
                    {
                        Spawned->AI()->AttackStart(target);
                        Spawned->setFaction(103);
                    }

                    //1 in 3 chance it will be a chromatic
                    if (urand(0, 2) == 0)
                        CreatureID = CREATURE_CHROMATIC_DRAKANOID;
                    else
                        CreatureID = DrakType2;

                    ++SpawnedAdds;

                    Spawned = me->SummonCreature(CreatureID, ADD_X2, ADD_Y2, ADD_Z2, 5.000f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000);
                    target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
                    if (target && Spawned)
                    {
                        Spawned->AI()->AttackStart(target);
                        Spawned->setFaction(103);
                    }

                    //Begin phase 2 by spawning Nefarian and what not
                    if (SpawnedAdds >= 42)
                    {
                        //Teleport Victor Nefarius way out of the map
                        //sMapMgr->GetMap(me->GetMapId(), me)->CreatureRelocation(me, 0, 0, -5000, 0);

                        //Interrupt any spell casting
                        me->InterruptNonMeleeSpells(false);

                        //Root self
                        DoCast(me, 33356);

                        //Make super invis
                        DoCast(me, 8149);

                        //Teleport self to a hiding spot (this causes errors in the Trinity log but no real issues)
                        DoTeleportTo(HIDE_X, HIDE_Y, HIDE_Z);
                        me->AddUnitState(UNIT_STATE_FLEEING);

                        //Spawn nef and have him attack a random target
                        Creature* Nefarian = me->SummonCreature(CREATURE_NEFARIAN, NEF_X, NEF_Y, NEF_Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 120000);
                        target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
                        if (target && Nefarian)
                        {
                            Nefarian->AI()->AttackStart(target);
                            Nefarian->setFaction(103);
                            NefarianGUID = Nefarian->GetGUID();
                        }
                        else sLog->outError(LOG_FILTER_TSCR, "Blackwing Lair: Unable to spawn nefarian properly.");
                    }

                    AddSpawnTimer = 4000;
                } else AddSpawnTimer -= diff;
            }
            else if (NefarianGUID)
            {
                if (NefCheckTime <= diff)
                {
                    Unit* Nefarian = Unit::GetCreature((*me), NefarianGUID);

                    //If nef is dead then we die to so the players get out of combat
                    //and cannot repeat the event
                    if (!Nefarian || !Nefarian->isAlive())
                    {
                        NefarianGUID = 0;
                        me->DespawnOrUnsummon();
                    }

                    NefCheckTime = 2000;
                } else NefCheckTime -= diff;
            }
        }
    };
};

void AddSC_boss_victor_nefarius()
{
    new boss_victor_nefarius();
}
