aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/world/3.3.5/2016_11_26_04_world.sql39
-rw-r--r--src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp762
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();
}