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(); } |
