diff options
| -rw-r--r-- | sql/updates/world/3.3.5/2016_11_26_04_world.sql | 39 | ||||
| -rw-r--r-- | src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp | 762 | 
2 files changed, 409 insertions, 392 deletions
diff --git a/sql/updates/world/3.3.5/2016_11_26_04_world.sql b/sql/updates/world/3.3.5/2016_11_26_04_world.sql new file mode 100644 index 00000000000..bac834aa589 --- /dev/null +++ b/sql/updates/world/3.3.5/2016_11_26_04_world.sql @@ -0,0 +1,39 @@ +-- Add Flying InhabitType for Doom Blossom. +UPDATE `creature_template` SET `InhabitType`=`InhabitType`|4 WHERE `entry`= 23123; +-- Add missing spells to Ghost (Vengeful Spirit) +UPDATE `creature_template` SET `spell1`=40325, `spell3`=40157, `spell4`=40175, `spell5`=40314, `spell7`=40322 WHERE `entry`=23109; +-- Add missing auras in Shadowy Construct +DELETE FROM `creature_template_addon` WHERE `entry`=23111; +INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES +(23111, 0, 0, 0, 0, 0, '40326 40334'); + +-- Teron Gorefiend texts +DELETE FROM `creature_text` where `entry`= 22871; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`language`,`probability`,`emote`,`duration`,`sound`,`BroadcastTextId`,`TextRange`,`comment`) VALUES +(22871, 0, 0, 'I was the first you know. For me the wheel of death has spun many times. So much time has passed... I have a lot of catching up to do.' , 14, 0, 100, 0, 0, 11512, 21098, 0, 'Teron Gorefiend SAY_INTRO'), +(22871, 1, 0, 'Vengeance is mine!', 14, 0, 100, 0, 0, 11513, 21097, 0, 'Teron Gorefiend SAY_AGGRO'), +(22871, 2, 0, 'I have use for you...', 14, 0, 100, 0, 0, 11514, 21099, 0, 'Teron Gorefiend SAY_SLAY1'), +(22871, 2, 1, 'It gets worse.', 14, 0, 100, 0, 0, 11515, 21100, 0, 'Teron Gorefiend SAY_SLAY2'), +(22871, 3, 0, 'What are you afraid of?', 14, 0, 100, 0, 0, 11517, 21102, 0, 'Teron Gorefiend SAY_INCINERATE1'), +(22871, 3, 1, 'You will show the proper respect!', 14, 0, 100, 0, 0, 11520, 21105, 0, 'Teron Gorefiend SAY_INCINERATE2'), +(22871, 4, 0, "Death really isn't so bad.", 14, 0, 100, 0, 0, 11516, 21101, 0, 'Teron Gorefiend SAY_DOOM_BLOSSOM1'), +(22871, 4, 1, 'I have something for you...', 14, 0, 100, 0, 0, 11519, 21104, 0, 'Teron Gorefiend SAY_DOOM_BLOSSOM2'), +(22871, 5, 0, 'Give in.', 14, 0, 100, 0, 0, 11518, 21103, 0, 'Teron Gorefiend SPELL_CRUSHING_SHADOWS'), +(22871, 6, 0, 'The wheel... spins... again.', 14, 0, 100, 0, 0, 11521, 21106, 0, 'Teron Gorefiend SAY_DEATH'); + +-- Area Trigger +DELETE FROM `areatrigger_scripts` WHERE `entry`=4665; +INSERT INTO `areatrigger_scripts` (`entry`, `ScriptName`) VALUES +(4665,'at_teron_gorefiend_entrance'); + +-- Spell scripts +DELETE FROM `spell_script_names` WHERE `ScriptName` IN('spell_teron_gorefiend_spiritual_vengeance','spell_teron_gorefiend_shadow_of_death','spell_teron_gorefiend_shadow_of_death_remove'); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(40268,'spell_teron_gorefiend_spiritual_vengeance'), +(40251,'spell_teron_gorefiend_shadow_of_death'), +(41999,'spell_teron_gorefiend_shadow_of_death_remove'); + +-- Conditions +DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=13 AND `SourceEntry`=40268; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES +(13,3,40268,0,0,31,0,3,23109,0,0,0,0,'','Effect_0 and Effect_1 hits Vengeful Spirit'); diff --git a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp index 699dd578b8d..bee9fe1532b 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp @@ -1,6 +1,5 @@  /*   * Copyright (C) 2008-2016 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 @@ -16,515 +15,494 @@   * with this program. If not, see <http://www.gnu.org/licenses/>.   */ -/* ScriptData -SDName: Boss_Teron_Gorefiend -SD%Complete: 60 -SDComment: Requires Mind Control support for Ghosts. -SDCategory: Black Temple -EndScriptData */ -  #include "ScriptMgr.h"  #include "ScriptedCreature.h"  #include "black_temple.h" +#include "PassiveAI.h" +#include "Player.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" -enum DoomBlossom +enum Says  { -    //Speech'n'sound -    SAY_INTRO                       = 0, -    SAY_AGGRO                       = 1, -    SAY_SLAY                        = 2, -    SAY_SPELL                       = 3, -    SAY_SPECIAL                     = 4, -    SAY_ENRAGE                      = 5, -    SAY_DEATH                       = 6, - -    //Spells -    SPELL_INCINERATE                = 40239, -    SPELL_CRUSHING_SHADOWS          = 40243, -    SPELL_SHADOWBOLT                = 40185, -    SPELL_PASSIVE_SHADOWFORM        = 40326, -    SPELL_SHADOW_OF_DEATH           = 40251, -    SPELL_BERSERK                   = 45078, -    SPELL_ATROPHY                   = 40327,               // Shadowy Constructs use this when they get within melee range of a player - -    CREATURE_DOOM_BLOSSOM           = 23123, -    CREATURE_SHADOWY_CONSTRUCT      = 23111 +    SAY_INTRO      = 0, +    SAY_AGGRO      = 1, +    SAY_SLAY       = 2, +    SAY_INCINERATE = 3, +    SAY_BLOSSOM    = 4, +    SAY_CRUSHING   = 5, +    SAY_DEATH      = 6  }; -class npc_doom_blossom : public CreatureScript +enum Spells  { -public: -    npc_doom_blossom() : CreatureScript("npc_doom_blossom") { } +    //Teron +    SPELL_INCINERATE                 = 40239, +    SPELL_CRUSHING_SHADOWS           = 40243, +    SPELL_SHADOW_OF_DEATH            = 40251, +    SPELL_SHADOW_OF_DEATH_REMOVE     = 41999, +    SPELL_BERSERK                    = 45078, +    SPELL_SUMMON_DOOM_BLOSSOM        = 40188, + +    //Doom Blossom +    SPELL_SUMMON_BLOSSOM_MOVE_TARGET = 40186, +    SPELL_SHADOWBOLT                 = 40185, + +    //Shadow Construct +    SPELL_ATROPHY                    = 40327, + +    //Player +    SPELL_SUMMON_SPIRIT              = 40266, +    SPELL_SPIRITUAL_VENGEANCE        = 40268, +    SPELL_POSSESS_SPIRIT_IMMUNE      = 40282, +    SPELL_SUMMON_SKELETRON_1         = 40270, +    SPELL_SUMMON_SKELETRON_2         = 41948, +    SPELL_SUMMON_SKELETRON_3         = 41949, +    SPELL_SUMMON_SKELETRON_4         = 41950, + +    //Vengeful Spirit +    SPELL_SPIRIT_STRIKE              = 40325, +    SPELL_SPIRIT_CHAINS              = 40175, +    SPELL_SPIRIT_VOLLEY              = 40314, +    SPELL_SPIRIT_SHIELD              = 40322, +    SPELL_SPIRIT_LANCE               = 40157 -    CreatureAI* GetAI(Creature* creature) const override -    { -        return new npc_doom_blossomAI(creature); -    } +}; + +enum Npcs +{ +    NPC_DOOM_BLOSSOM                 = 23123, +    NPC_SHADOWY_CONSTRUCT            = 23111, +    NPC_VENGEFUL_SPIRIT              = 23109 //Npc controlled by player +}; + +enum Events +{ +    EVENT_ENRAGE = 1, +    EVENT_INCINERATE, +    EVENT_SUMMON_DOOM_BLOSSOM, +    EVENT_SHADOW_DEATH, +    EVENT_CRUSHING_SHADOWS, +    EVENT_FINISH_INTRO +}; -    struct npc_doom_blossomAI : public ScriptedAI +enum Actions +{ +    ACTION_START_INTRO = 1 +}; + +uint32 const SkeletronSpells[4] = +{ +    SPELL_SUMMON_SKELETRON_1, +    SPELL_SUMMON_SKELETRON_2, +    SPELL_SUMMON_SKELETRON_3, +    SPELL_SUMMON_SKELETRON_4 +}; + +class boss_teron_gorefiend : public CreatureScript +{ +public: +    boss_teron_gorefiend() : CreatureScript("boss_teron_gorefiend") { } + +    struct boss_teron_gorefiendAI : public BossAI      { -        npc_doom_blossomAI(Creature* creature) : ScriptedAI(creature) +        boss_teron_gorefiendAI(Creature* creature) : BossAI(creature, DATA_TERON_GOREFIEND), _intro(false)          { -            Initialize(); +            me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); +            me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +            me->SetReactState(REACT_PASSIVE);          } -        void Initialize() +        void EnterCombat(Unit* /*who*/) override          { -            CheckTeronTimer = 5000; -            ShadowBoltTimer = 12000; -            TeronGUID.Clear(); +            _EnterCombat(); +            Talk(SAY_AGGRO); +            events.ScheduleEvent(EVENT_ENRAGE, Minutes(10)); +            events.ScheduleEvent(EVENT_INCINERATE, Seconds(12)); +            events.ScheduleEvent(EVENT_SUMMON_DOOM_BLOSSOM, Seconds(8)); +            events.ScheduleEvent(EVENT_SHADOW_DEATH, Seconds(8)); +            events.ScheduleEvent(EVENT_CRUSHING_SHADOWS, Seconds(18));          } -        uint32 CheckTeronTimer; -        uint32 ShadowBoltTimer; -        ObjectGuid TeronGUID; - -        void Reset() override +        void EnterEvadeMode(EvadeReason /*why*/) override          { -            Initialize(); +            DoCast(SPELL_SHADOW_OF_DEATH_REMOVE); +            summons.DespawnAll(); +            _DespawnAtEvade();          } -        void EnterCombat(Unit* /*who*/) override { } -        void AttackStart(Unit* /*who*/) override { } -        void MoveInLineOfSight(Unit* /*who*/) override { } +        void DoAction(int32 action) override +        { +            if (action == ACTION_START_INTRO && !_intro && me->IsAlive()) +            { +                _intro = true; +                Talk(SAY_INTRO); +                events.ScheduleEvent(EVENT_FINISH_INTRO, Seconds(20)); +            } +        } +        void KilledUnit(Unit* victim) override +        { +            if (victim->GetTypeId() == TYPEID_PLAYER) +                Talk(SAY_SLAY); +        } -        void Despawn() +        void JustDied(Unit* /*killer*/) override          { -            me->DealDamage(me, me->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); -            me->RemoveCorpse(); +            Talk(SAY_DEATH); +            DoCast(SPELL_SHADOW_OF_DEATH_REMOVE); +            _JustDied();          }          void UpdateAI(uint32 diff) override          { -            if (CheckTeronTimer <= diff) +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; + +            events.Update(diff); + +            while (uint32 eventId = events.ExecuteEvent())              { -                if (TeronGUID) +                switch (eventId)                  { -                    DoZoneInCombat(); - -                    Creature* Teron = (ObjectAccessor::GetCreature((*me), TeronGUID)); -                    if ((Teron) && (!Teron->IsAlive() || Teron->IsInEvadeMode())) -                        Despawn(); +                case EVENT_ENRAGE: +                    DoCast(SPELL_BERSERK); +                    break; +                case EVENT_INCINERATE: +                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) +                        DoCast(target, SPELL_INCINERATE); +                    Talk(SAY_INCINERATE); +                    events.Repeat(Seconds(12), Seconds(20)); +                    break; +                case EVENT_SUMMON_DOOM_BLOSSOM: +                    DoCastSelf(SPELL_SUMMON_DOOM_BLOSSOM, true); +                    Talk(SAY_BLOSSOM); +                    events.Repeat(Seconds(30), Seconds(40)); +                    break; +                case EVENT_SHADOW_DEATH: +                    if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 100.0f, true, -SPELL_SPIRITUAL_VENGEANCE)) +                        DoCast(target, SPELL_SHADOW_OF_DEATH); +                    events.Repeat(Seconds(30), Seconds(35)); +                    break; +                case EVENT_CRUSHING_SHADOWS: +                    me->CastCustomSpell(SPELL_CRUSHING_SHADOWS, SPELLVALUE_MAX_TARGETS, 5, me); +                    Talk(SAY_CRUSHING); +                    events.Repeat(Seconds(18), Seconds(30)); +                    break; +                case EVENT_FINISH_INTRO: +                    me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); +                    me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); +                    me->SetReactState(REACT_AGGRESSIVE); +                    break; +                default: +                    break;                  } -                else -                    Despawn(); -                CheckTeronTimer = 5000; -            } else CheckTeronTimer -= diff; +                if (me->HasUnitState(UNIT_STATE_CASTING)) +                    return; +            } -            if (ShadowBoltTimer < diff && me->IsInCombat()) -            { -                DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0), SPELL_SHADOWBOLT); -                ShadowBoltTimer = 10000; -            } else ShadowBoltTimer -= diff; -            return; -        } +            if (!UpdateVictim()) +                return; -        void SetTeronGUID(ObjectGuid guid) -        { -            TeronGUID = guid; +            DoMeleeAttackIfReady();          } +            private: +                bool _intro;      }; -}; - -class npc_shadowy_construct : public CreatureScript -{ -public: -    npc_shadowy_construct() : CreatureScript("npc_shadowy_construct") { }      CreatureAI* GetAI(Creature* creature) const override      { -        return new npc_shadowy_constructAI(creature); +        return GetInstanceAI<boss_teron_gorefiendAI>(creature);      } +}; -    struct npc_shadowy_constructAI : public ScriptedAI +class npc_doom_blossom : public CreatureScript +{ +public: +    npc_doom_blossom() : CreatureScript("npc_doom_blossom") { } +    struct npc_doom_blossomAI : public NullCreatureAI      { -        npc_shadowy_constructAI(Creature* creature) : ScriptedAI(creature) +        npc_doom_blossomAI(Creature* creature) : NullCreatureAI(creature), _instance(me->GetInstanceScript())          { -            Initialize(); -        } - -        void Initialize() -        { -            GhostGUID.Clear(); -            TeronGUID.Clear(); - -            CheckPlayerTimer = 2000; -            CheckTeronTimer = 5000; +            /* Workaround - Until SMSG_SET_PLAY_HOVER_ANIM be implemented */ +            me->SetDisableGravity(true); +            Position pos; +            pos.Relocate(me); +            pos.m_positionZ += 8.0f; +            me->GetMotionMaster()->MoveTakeoff(0, pos);          } -        ObjectGuid GhostGUID; -        ObjectGuid TeronGUID; - -        uint32 CheckPlayerTimer; -        uint32 CheckTeronTimer; -          void Reset() override          { -            Initialize(); -        } - -        void EnterCombat(Unit* /*who*/) override { } - -        void MoveInLineOfSight(Unit* who) override - -        { -            if (!who || (!who->IsAlive()) || (who->GetGUID() == GhostGUID)) -                return; - -            ScriptedAI::MoveInLineOfSight(who); -        } - -    /* Comment it out for now. NOTE TO FUTURE DEV: UNCOMMENT THIS OUT ONLY AFTER MIND CONTROL IS IMPLEMENTED -        void DamageTaken(Unit* done_by, uint32 &damage) override -        { -            if (done_by->GetGUID() != GhostGUID) -            damage = 0;                                         // Only the ghost can deal damage. -        } -     */ - -        void CheckPlayers() -        { -            ThreatContainer::StorageType const &threatlist = me->getThreatManager().getThreatList(); -            if (threatlist.empty()) -                return;                                         // No threat list. Don't continue. -            ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); -            std::list<Unit*> targets; -            for (; itr != threatlist.end(); ++itr) -            { -                Unit* unit = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()); -                if (unit && unit->IsAlive()) -                    targets.push_back(unit); -            } -            targets.sort(Trinity::ObjectDistanceOrderPred(me)); -            Unit* target = targets.front(); -            if (target && me->IsWithinDistInMap(target, me->GetAttackDistance(target))) +            DoCast(SPELL_SUMMON_BLOSSOM_MOVE_TARGET); +            _scheduler.CancelAll(); +            me->SetInCombatWithZone(); +            _scheduler.Schedule(Seconds(12), [this](TaskContext shadowBolt)              { -                DoCast(target, SPELL_ATROPHY); -                AttackStart(target); -            } +                if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) +                    DoCast(target, SPELL_SHADOWBOLT); + +                shadowBolt.Repeat(Seconds(2)); +            });          }          void UpdateAI(uint32 diff) override          { -            if (CheckPlayerTimer <= diff) -            { -                CheckPlayers(); -                CheckPlayerTimer = 3000; -            } else CheckPlayerTimer -= diff; - -            if (CheckTeronTimer <= diff) -            { -                Creature* Teron = (ObjectAccessor::GetCreature((*me), TeronGUID)); -                if (!Teron || !Teron->IsAlive() || Teron->IsInEvadeMode()) -                    me->DealDamage(me, me->GetHealth(), nullptr, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); +            if (me->HasUnitState(UNIT_STATE_CASTING)) +                return; -                CheckTeronTimer = 5000; -            } else CheckTeronTimer -= diff; +            _scheduler.Update(diff);          } -    }; -}; -class boss_teron_gorefiend : public CreatureScript -{ -public: -    boss_teron_gorefiend() : CreatureScript("boss_teron_gorefiend") { } +    private: +        TaskScheduler _scheduler; +        InstanceScript* _instance; +    };      CreatureAI* GetAI(Creature* creature) const override      { -        return GetInstanceAI<boss_teron_gorefiendAI>(creature); +        return  GetInstanceAI<npc_doom_blossomAI>(creature);      } +}; -    struct boss_teron_gorefiendAI : public BossAI +class npc_shadowy_construct : public CreatureScript +{ +public: +    npc_shadowy_construct() : CreatureScript("npc_shadowy_construct") { } +    struct npc_shadowy_constructAI : public ScriptedAI      { -        boss_teron_gorefiendAI(Creature* creature) : BossAI(creature, DATA_TERON_GOREFIEND) +        npc_shadowy_constructAI(Creature* creature) : ScriptedAI(creature), _instance(me->GetInstanceScript())          { -            Initialize(); +            //This creature must be immune everything, except spells of Vengeful Spirit. +            me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true); +            me->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_MAGIC, true);          } -        void Initialize() -        { -            IncinerateTimer = urand(20000, 31000); -            SummonDoomBlossomTimer = 12000; -            EnrageTimer = 600000; -            CrushingShadowsTimer = 22000; -            SummonShadowsTimer = 60000; -            RandomYellTimer = 50000; - -            AggroTimer = 20000; -            AggroTargetGUID.Clear(); -            Intro = false; -            Done = false; -        } - -        uint32 IncinerateTimer; -        uint32 SummonDoomBlossomTimer; -        uint32 EnrageTimer; -        uint32 CrushingShadowsTimer; -        uint32 SummonShadowsTimer; -        uint32 RandomYellTimer; -        uint32 AggroTimer; - -        ObjectGuid AggroTargetGUID; -        ObjectGuid GhostGUID;                                       // Player that gets killed by Shadow of Death and gets turned into a ghost - -        bool Intro; -        bool Done; -          void Reset() override          { -            _Reset(); -            Initialize(); - -            me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -            // Start off unattackable so that the intro is done properly -            me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); -        } - -        void EnterCombat(Unit* /*who*/) override { } - -        void MoveInLineOfSight(Unit* who) override +            if (_instance->GetBossState(DATA_TERON_GOREFIEND) != IN_PROGRESS) +            { +                me->DespawnOrUnsummon(); +                return; +            } -        { -            if (!Intro && who->GetTypeId() == TYPEID_PLAYER && me->CanCreatureAttack(who)) +            targetGUID.Clear(); +            _scheduler.CancelAll(); +            _scheduler.Schedule(Seconds(12), [this](TaskContext atrophy) +            { +                DoCastVictim(SPELL_ATROPHY); +                atrophy.Repeat(Seconds(10), Seconds(12)); +            }); +            _scheduler.Schedule(Milliseconds(200), [this](TaskContext checkPlayer)              { -                if (me->IsWithinDistInMap(who, VISIBLE_RANGE) && me->IsWithinLOSInMap(who)) +                if (Unit* target = ObjectAccessor::GetUnit(*me, targetGUID))                  { -                    instance->SetBossState(DATA_TERON_GOREFIEND, IN_PROGRESS); - -                    me->GetMotionMaster()->Clear(false); -                    me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                    Talk(SAY_INTRO); -                    me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_TALK); -                    AggroTargetGUID = who->GetGUID(); -                    Intro = true; +                    if (!target->IsAlive() || !me->CanCreatureAttack(target)) +                        SelectNewTarget();                  } -            } -            if (Done) -                ScriptedAI::MoveInLineOfSight(who); -        } +                else +                    SelectNewTarget(); -        void KilledUnit(Unit* /*victim*/) override -        { -            Talk(SAY_SLAY); -        } +                checkPlayer.Repeat(Seconds(1)); +            }); -        void JustDied(Unit* /*killer*/) override -        { -            Talk(SAY_DEATH); -            _JustDied(); -        } +            if (Creature* teron = _instance->GetCreature(DATA_TERON_GOREFIEND)) +                teron->AI()->JustSummoned(me); -        float CalculateRandomLocation(float Loc, uint32 radius) -        { -            float coord = Loc; -            switch (urand(0, 1)) -            { -                case 0: -                    coord += rand32() % radius; -                    break; -                case 1: -                    coord -= rand32() % radius; -                    break; -            } -            return coord; +            SelectNewTarget();          } -        void SetThreatList(Creature* blossom) +        void UpdateAI(uint32 diff) override          { -            if (!blossom) +            if (me->HasUnitState(UNIT_STATE_CASTING))                  return; -            ThreatContainer::StorageType const &threatlist = me->getThreatManager().getThreatList(); -            ThreatContainer::StorageType::const_iterator i = threatlist.begin(); -            for (i = threatlist.begin(); i != threatlist.end(); ++i) +            _scheduler.Update(diff, [this]              { -                Unit* unit = ObjectAccessor::GetUnit(*me, (*i)->getUnitGuid()); -                if (unit && unit->IsAlive()) -                { -                    float threat = DoGetThreat(unit); -                    blossom->AddThreat(unit, threat); -                } -            } +                DoMeleeAttackIfReady(); +            });          } -        void MindControlGhost() +        void SelectNewTarget()          { -            /************************************************************************/ -            /** NOTE FOR FUTURE DEVELOPER: PROPERLY IMPLEMENT THE GHOST PORTION *****/ -            /**  ONLY AFTER TrinIty FULLY IMPLEMENTS MIND CONTROL ABILITIES      *****/ -            /**   THE CURRENT CODE IN THIS FUNCTION IS ONLY THE BEGINNING OF    *****/ -            /**    WHAT IS FULLY NECESSARY FOR GOREFIEND TO BE 100% COMPLETE    *****/ -            /************************************************************************/ - -            Unit* ghost = nullptr; -            if (GhostGUID) -                ghost = ObjectAccessor::GetUnit(*me, GhostGUID); -            if (ghost && ghost->IsAlive() && ghost->HasAura(SPELL_SHADOW_OF_DEATH)) +            if (Creature* teron = _instance->GetCreature(DATA_TERON_GOREFIEND))              { -                /*float x, y, z; -                ghost->GetPosition(x, y, z); -                if (Creature* control = me->SummonCreature(CREATURE_GHOST, x, y, z, 0, TEMPSUMMON_TIMED_DESAWN, 30000)) +                if (Unit* target = teron->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, -SPELL_SPIRITUAL_VENGEANCE))                  { -                    if (Player* player = ghost->ToPlayer()) -                        player->Possess(control); -                    ghost->DealDamage(ghost, ghost->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, -                false); -                }*/ -                for (uint8 i = 0; i < 4; ++i) +                    DoResetThreat(); +                    AttackStart(target); +                    me->AddThreat(target, 1000000.0f); +                    targetGUID = target->GetGUID(); +                } +                //He only should target Vengeful Spirits if has no other player available +                else if (Unit* target = teron->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0))                  { -                    Creature* Construct = nullptr; -                    float X = CalculateRandomLocation(ghost->GetPositionX(), 10); -                    float Y = CalculateRandomLocation(ghost->GetPositionY(), 10); -                    Construct = me->SummonCreature(CREATURE_SHADOWY_CONSTRUCT, X, Y, ghost->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); -                    if (Construct) -                    { -                        Construct->CastSpell(Construct, SPELL_PASSIVE_SHADOWFORM, true); -                        SetThreatList(Construct);               // Use same function as Doom Blossom to set Threat List. -                        ENSURE_AI(npc_shadowy_construct::npc_shadowy_constructAI, Construct->AI())->GhostGUID = GhostGUID; -                        Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1); -                        if (!target)                             // someone's trying to solo. -                            target = me->GetVictim(); - -                        if (target) -                            Construct->GetMotionMaster()->MoveChase(target); -                    } +                    DoResetThreat(); +                    AttackStart(target); +                    me->AddThreat(target, 1000000.0f); +                    targetGUID = target->GetGUID();                  }              }          } -        void UpdateAI(uint32 diff) override +    private: +        TaskScheduler _scheduler; +        InstanceScript* _instance; +        ObjectGuid targetGUID; + +    }; + +    CreatureAI* GetAI(Creature* creature) const override +    { +        return  GetInstanceAI<npc_shadowy_constructAI>(creature); +    } +}; + +class at_teron_gorefiend_entrance : public AreaTriggerScript +{ +public: +    at_teron_gorefiend_entrance() : AreaTriggerScript("at_teron_gorefiend_entrance") { } + +    bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override +    { +        if (InstanceScript* instance = player->GetInstanceScript()) +            if (Creature* teron = instance->GetCreature(DATA_TERON_GOREFIEND)) +                teron->AI()->DoAction(ACTION_START_INTRO); + +        return true; +    } +}; + +class spell_teron_gorefiend_shadow_of_death : public SpellScriptLoader +{ +    public: +        spell_teron_gorefiend_shadow_of_death() : SpellScriptLoader("spell_teron_gorefiend_shadow_of_death") { } + +        class spell_teron_gorefiend_shadow_of_death_AuraScript : public AuraScript          { -            if (Intro && !Done) +            PrepareAuraScript(spell_teron_gorefiend_shadow_of_death_AuraScript); + +            bool Validate(SpellInfo const* /*spell*/) override              { -                if (AggroTimer <= diff) -                { -                    me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                    me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); -                    Talk(SAY_AGGRO); -                    me->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_NONE); -                    Done = true; -                    if (AggroTargetGUID) -                    { -                        Unit* unit = ObjectAccessor::GetUnit(*me, AggroTargetGUID); -                        if (unit) -                            AttackStart(unit); - -                        DoZoneInCombat(); -                    } -                    else -                    { -                        EnterEvadeMode(); -                        return; -                    } -                } else AggroTimer -= diff; +                if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_SPIRIT) +                    || !sSpellMgr->GetSpellInfo(SPELL_POSSESS_SPIRIT_IMMUNE) +                    || !sSpellMgr->GetSpellInfo(SPELL_SPIRITUAL_VENGEANCE) +                    || !sSpellMgr->GetSpellInfo(SPELL_SUMMON_SKELETRON_1) +                    || !sSpellMgr->GetSpellInfo(SPELL_SUMMON_SKELETRON_2) +                    || !sSpellMgr->GetSpellInfo(SPELL_SUMMON_SKELETRON_3) +                    || !sSpellMgr->GetSpellInfo(SPELL_SUMMON_SKELETRON_4)) +                    return false; +                return true;              } -            if (!UpdateVictim() || !Done) -                return; - -            if (SummonShadowsTimer <= diff) +            void Absorb(AuraEffect* /*aurEff*/, DamageInfo& /*dmgInfo*/, uint32& /*absorbAmount*/)              { -                //MindControlGhost(); - -                for (uint8 i = 0; i < 2; ++i) -                { -                    float X = CalculateRandomLocation(me->GetPositionX(), 10); -                    if (Creature* shadow = me->SummonCreature(CREATURE_SHADOWY_CONSTRUCT, X, me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 0)) -                    { -                        if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) -                            shadow->AI()->AttackStart(target); -                        else if (Unit* victim = me->GetVictim()) -                            shadow->AI()->AttackStart(victim); -                    } -                } -                SummonShadowsTimer = 60000; -            } else SummonShadowsTimer -= diff; +                PreventDefaultAction(); +            } -            if (SummonDoomBlossomTimer <= diff) +            void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)              { -                if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) +                if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)                  { -                    float X = CalculateRandomLocation(target->GetPositionX(), 20); -                    float Y = CalculateRandomLocation(target->GetPositionY(), 20); -                    float Z = target->GetPositionZ(); -                    Z = me->GetMap()->GetHeight(me->GetPhaseMask(), X, Y, Z); -                    Creature* DoomBlossom = me->SummonCreature(CREATURE_DOOM_BLOSSOM, X, Y, Z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 20000); -                    if (DoomBlossom) -                    { -                        DoomBlossom->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); -                        DoomBlossom->setFaction(me->getFaction()); -                        DoomBlossom->AddThreat(target, 1.0f); -                        ENSURE_AI(npc_doom_blossom::npc_doom_blossomAI, DoomBlossom->AI())->SetTeronGUID(me->GetGUID()); -                        target->CombatStart(DoomBlossom); -                        SetThreatList(DoomBlossom); -                        SummonDoomBlossomTimer = 35000; -                    } +                    Unit* target = GetTarget(); +                    target->CastSpell(target, SPELL_SUMMON_SPIRIT, true); + +                    for (uint8 i = 0; i < 4; ++i) +                        target->CastSpell(target, SkeletronSpells[i], true); + +                    target->CastSpell(target, SPELL_POSSESS_SPIRIT_IMMUNE, true); +                    target->CastSpell(target, SPELL_SPIRITUAL_VENGEANCE, true);                  } -            } else SummonDoomBlossomTimer -= diff; +            } -            if (IncinerateTimer <= diff) +            void Register() override              { -                Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1); -                if (!target) -                    target = me->GetVictim(); +                OnEffectAbsorb += AuraEffectAbsorbFn(spell_teron_gorefiend_shadow_of_death_AuraScript::Absorb, EFFECT_0); +                AfterEffectRemove += AuraEffectRemoveFn(spell_teron_gorefiend_shadow_of_death_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_OVERRIDE_CLASS_SCRIPTS, AURA_EFFECT_HANDLE_REAL); +            } +        }; -                if (target) -                { -                    Talk(SAY_SPECIAL); -                    DoCast(target, SPELL_INCINERATE); -                    IncinerateTimer = urand(20, 51) * 1000; -                } -            } else IncinerateTimer -= diff; +        AuraScript* GetAuraScript() const override +        { +            return new spell_teron_gorefiend_shadow_of_death_AuraScript(); +        } +}; + +class spell_teron_gorefiend_spiritual_vengeance : public SpellScriptLoader +{ +    public: +        spell_teron_gorefiend_spiritual_vengeance() : SpellScriptLoader("spell_teron_gorefiend_spiritual_vengeance") { } -            if (CrushingShadowsTimer <= diff) +        class spell_teron_gorefiend_spiritual_vengeance_AuraScript : public AuraScript +        { +            PrepareAuraScript(spell_teron_gorefiend_spiritual_vengeance_AuraScript); + +            void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)              { -                if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) -                    DoCast(target, SPELL_CRUSHING_SHADOWS); -                CrushingShadowsTimer = urand(10, 26) * 1000; -            } else CrushingShadowsTimer -= diff; +                GetTarget()->KillSelf(); +            } -            /*** NOTE FOR FUTURE DEV: UNCOMMENT BELOW ONLY IF MIND CONTROL IS FULLY IMPLEMENTED **/ -            /*if (ShadowOfDeathTimer <= diff) +            void Register() override              { -                Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); +            AfterEffectRemove += AuraEffectRemoveFn(spell_teron_gorefiend_spiritual_vengeance_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_MOD_POSSESS, AURA_EFFECT_HANDLE_REAL); +            AfterEffectRemove += AuraEffectRemoveFn(spell_teron_gorefiend_spiritual_vengeance_AuraScript::OnRemove, EFFECT_2, SPELL_AURA_MOD_PACIFY_SILENCE, AURA_EFFECT_HANDLE_REAL); +            } +        }; -                if (!target) -                   target = me->GetVictim(); +        AuraScript* GetAuraScript() const override +        { +            return new spell_teron_gorefiend_spiritual_vengeance_AuraScript(); +        } +}; -                if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER) -                { -                    DoCast(target, SPELL_SHADOW_OF_DEATH); -                    GhostGUID = target->GetGUID(); -                    ShadowOfDeathTimer = 30000; -                    SummonShadowsTimer = 53000; // Make it VERY close but slightly less so that we can check if the aura is still on the player -                } -            } else ShadowOfDeathTimer -= diff;*/ +class spell_teron_gorefiend_shadow_of_death_remove : public SpellScriptLoader +{ +    public: +        spell_teron_gorefiend_shadow_of_death_remove() : SpellScriptLoader("spell_teron_gorefiend_shadow_of_death_remove") { } + +        class spell_teron_gorefiend_shadow_of_death_remove_SpellScript : public SpellScript +        { +            PrepareSpellScript(spell_teron_gorefiend_shadow_of_death_remove_SpellScript); -            if (RandomYellTimer <= diff) +            bool Validate(SpellInfo const* /*spell*/) override              { -                Talk(SAY_SPELL); -                RandomYellTimer = urand(50, 101) * 1000; -            } else RandomYellTimer -= diff; +                if (!sSpellMgr->GetSpellInfo(SPELL_SHADOW_OF_DEATH) +                    || !sSpellMgr->GetSpellInfo(SPELL_POSSESS_SPIRIT_IMMUNE) +                    || !sSpellMgr->GetSpellInfo(SPELL_SPIRITUAL_VENGEANCE)) +                    return false; +                return true; +            } -            if (!me->HasAura(SPELL_BERSERK)) +            void RemoveAuras()              { -                if (EnrageTimer <= diff) +                Unit* target = GetHitUnit(); + +                target->RemoveAurasDueToSpell(SPELL_POSSESS_SPIRIT_IMMUNE); +                target->RemoveAurasDueToSpell(SPELL_SPIRITUAL_VENGEANCE); +                target->RemoveAurasDueToSpell(SPELL_SHADOW_OF_DEATH); +            } + +            void Register() override              { -                DoCast(me, SPELL_BERSERK); -                Talk(SAY_ENRAGE); -            } else EnrageTimer -= diff; +                OnHit += SpellHitFn(spell_teron_gorefiend_shadow_of_death_remove_SpellScript::RemoveAuras);              } -            DoMeleeAttackIfReady(); +        }; + +        SpellScript* GetSpellScript() const override +        { +            return new spell_teron_gorefiend_shadow_of_death_remove_SpellScript();          } -    };  };  void AddSC_boss_teron_gorefiend()  { +    new boss_teron_gorefiend();      new npc_doom_blossom();      new npc_shadowy_construct(); -    new boss_teron_gorefiend(); +    new at_teron_gorefiend_entrance(); +    new spell_teron_gorefiend_shadow_of_death(); +    new spell_teron_gorefiend_spiritual_vengeance(); +    new spell_teron_gorefiend_shadow_of_death_remove();  }  | 
