Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_teron_gorefiend.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6/* ScriptData
7SDName: Boss_Teron_Gorefiend
8SD%Complete: 60
9SDComment: Requires Mind Control support for Ghosts.
10SDCategory: Black Temple
11EndScriptData */
12
13#include "ScriptMgr.h"
14#include "ScriptedCreature.h"
15#include "black_temple.h"
16
18{
19 //Speech'n'sound
27
28 //Spells
35 SPELL_ATROPHY = 40327, // Shadowy Constructs use this when they get within melee range of a player
36
39};
40
42{
43public:
44 npc_doom_blossom() : CreatureScript("npc_doom_blossom") { }
45
47 {
48 return new npc_doom_blossomAI(creature);
49 }
50
52 {
53 npc_doom_blossomAI(Creature* creature) : ScriptedAI(creature) { }
54
58
60 {
61 CheckTeronTimer = 5000;
62 ShadowBoltTimer = 12000;
63 TeronGUID = 0;
64 }
65
66 void EnterCombat(Unit* /*who*/) OVERRIDE { }
67 void AttackStart(Unit* /*who*/) OVERRIDE { }
68 void MoveInLineOfSight(Unit* /*who*/) OVERRIDE { }
69
70
71 void Despawn()
72 {
73 me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
74 me->RemoveCorpse();
75 }
76
78 {
79 if (CheckTeronTimer <= diff)
80 {
81 if (TeronGUID)
82 {
84
85 Creature* Teron = (Unit::GetCreature((*me), TeronGUID));
86 if ((Teron) && (!Teron->IsAlive() || Teron->IsInEvadeMode()))
87 Despawn();
88 }
89 else
90 Despawn();
91
92 CheckTeronTimer = 5000;
93 } else CheckTeronTimer -= diff;
94
95 if (ShadowBoltTimer < diff && me->IsInCombat())
96 {
98 ShadowBoltTimer = 10000;
99 } else ShadowBoltTimer -= diff;
100 return;
101 }
102
104 {
105 TeronGUID = guid;
106 }
107 };
108};
109
111{
112public:
113 npc_shadowy_construct() : CreatureScript("npc_shadowy_construct") { }
114
116 {
117 return new npc_shadowy_constructAI(creature);
118 }
119
121 {
122 npc_shadowy_constructAI(Creature* creature) : ScriptedAI(creature) { }
123
126
129
131 {
132 GhostGUID = 0;
133 TeronGUID = 0;
134
135 CheckPlayerTimer = 2000;
136 CheckTeronTimer = 5000;
137 }
138
139 void EnterCombat(Unit* /*who*/) OVERRIDE { }
140
142
143 {
144 if (!who || (!who->IsAlive()) || (who->GetGUID() == GhostGUID))
145 return;
146
148 }
149
150 /* Comment it out for now. NOTE TO FUTURE DEV: UNCOMMENT THIS OUT ONLY AFTER MIND CONTROL IS IMPLEMENTED
151 void DamageTaken(Unit* done_by, uint32 &damage) OVERRIDE
152 {
153 if (done_by->GetGUID() != GhostGUID)
154 damage = 0; // Only the ghost can deal damage.
155 }
156 */
157
159 {
160 ThreatContainer::StorageType const &threatlist = me->getThreatManager().getThreatList();
161 if (threatlist.empty())
162 return; // No threat list. Don't continue.
163 ThreatContainer::StorageType::const_iterator itr = threatlist.begin();
164 std::list<Unit*> targets;
165 for (; itr != threatlist.end(); ++itr)
166 {
167 Unit* unit = Unit::GetUnit(*me, (*itr)->getUnitGuid());
168 if (unit && unit->IsAlive())
169 targets.push_back(unit);
170 }
172 Unit* target = targets.front();
173 if (target && me->IsWithinDistInMap(target, me->GetAttackDistance(target)))
174 {
175 DoCast(target, SPELL_ATROPHY);
176 me->AI()->AttackStart(target);
177 }
178 }
179
181 {
182 if (CheckPlayerTimer <= diff)
183 {
184 CheckPlayers();
185 CheckPlayerTimer = 3000;
186 } else CheckPlayerTimer -= diff;
187
188 if (CheckTeronTimer <= diff)
189 {
190 Creature* Teron = (Unit::GetCreature((*me), TeronGUID));
191 if (!Teron || !Teron->IsAlive() || Teron->IsInEvadeMode())
192 me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);
193
194 CheckTeronTimer = 5000;
195 } else CheckTeronTimer -= diff;
196 }
197 };
198};
199
201{
202public:
203 boss_teron_gorefiend() : CreatureScript("boss_teron_gorefiend") { }
204
206 {
207 return new boss_teron_gorefiendAI(creature);
208 }
209
211 {
213 {
214 instance = creature->GetInstanceScript();
215 }
216
218
227
229 uint64 GhostGUID; // Player that gets killed by Shadow of Death and gets turned into a ghost
230
231 bool Intro;
232 bool Done;
233
235 {
236 if (instance)
238
239 IncinerateTimer = std::rand() % 31000 + 20000;
241 EnrageTimer = 600000;
242 CrushingShadowsTimer = 22000;
243 SummonShadowsTimer = 60000;
244 RandomYellTimer = 50000;
245
247 // Start off unattackable so that the intro is done properly
249
250 AggroTimer = 20000;
251 AggroTargetGUID = 0;
252 Intro = false;
253 Done = false;
254 }
255
256 void EnterCombat(Unit* /*who*/) OVERRIDE { }
257
259
260 {
261 if (!Intro && who->GetTypeId() == TypeID::TYPEID_PLAYER && me->CanCreatureAttack(who))
262 {
263 if (me->IsWithinDistInMap(who, VISIBLE_RANGE) && me->IsWithinLOSInMap(who))
264 {
265 if (instance)
267
268 me->GetMotionMaster()->Clear(false);
272 AggroTargetGUID = who->GetGUID();
273 Intro = true;
274 }
275 }
276 if (Done)
278 }
279
280 void KilledUnit(Unit* /*victim*/) OVERRIDE
281 {
282 Talk(SAY_SLAY);
283 }
284
285 void JustDied(Unit* /*killer*/) OVERRIDE
286 {
287 if (instance)
288 instance->SetBossState(DATA_TERON_GOREFIEND, DONE);
289
291 }
292
293 float CalculateRandomLocation(float Loc, uint32 radius)
294 {
295 float coord = Loc;
296 switch (std::rand() % 1)
297 {
298 case 0:
299 coord += rand()%radius;
300 break;
301 case 1:
302 coord -= rand()%radius;
303 break;
304 }
305 return coord;
306 }
307
308 void SetThreatList(Creature* blossom)
309 {
310 if (!blossom)
311 return;
312
313 ThreatContainer::StorageType const &threatlist = me->getThreatManager().getThreatList();
314 ThreatContainer::StorageType::const_iterator i = threatlist.begin();
315 for (i = threatlist.begin(); i != threatlist.end(); ++i)
316 {
317 Unit* unit = Unit::GetUnit(*me, (*i)->getUnitGuid());
318 if (unit && unit->IsAlive())
319 {
320 float threat = DoGetThreat(unit);
321 blossom->AddThreat(unit, threat);
322 }
323 }
324 }
325
327 {
328 /************************************************************************/
333 /************************************************************************/
334
335 Unit* ghost = NULL;
336 if (GhostGUID)
337 ghost = Unit::GetUnit(*me, GhostGUID);
338 if (ghost && ghost->IsAlive() && ghost->HasAura(SPELL_SHADOW_OF_DEATH))
339 {
340 /*float x, y, z;
341 ghost->GetPosition(x, y, z);
342 if (Creature* control = me->SummonCreature(CREATURE_GHOST, x, y, z, 0, TEMPSUMMON_TIMED_DESAWN, 30000))
343 {
344 if (Player* player = ghost->ToPlayer())
345 player->Possess(control);
346 ghost->DealDamage(ghost, ghost->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL,
347 false);
348 }*/
349 for (uint8 i = 0; i < 4; ++i)
350 {
351 Creature* Construct = NULL;
352 float X = CalculateRandomLocation(ghost->GetPositionX(), 10);
353 float Y = CalculateRandomLocation(ghost->GetPositionY(), 10);
354 Construct = me->SummonCreature(CREATURE_SHADOWY_CONSTRUCT, X, Y, ghost->GetPositionZ(), 0, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000);
355 if (Construct)
356 {
357 Construct->CastSpell(Construct, SPELL_PASSIVE_SHADOWFORM, true);
358 SetThreatList(Construct); // Use same function as Doom Blossom to set Threat List.
361 if (!target) // someone's trying to solo.
362 target = me->GetVictim();
363
364 if (target)
365 Construct->GetMotionMaster()->MoveChase(target);
366 }
367 }
368 }
369 }
370
372 {
373 if (Intro && !Done)
374 {
375 if (AggroTimer <= diff)
376 {
381 Done = true;
382 if (AggroTargetGUID)
383 {
385 if (unit)
386 AttackStart(unit);
387
389 }
390 else
391 {
393 return;
394 }
395 } else AggroTimer -= diff;
396 }
397
398 if (!UpdateVictim() || !Done)
399 return;
400
401 if (SummonShadowsTimer <= diff)
402 {
403 //MindControlGhost();
404
405 for (uint8 i = 0; i < 2; ++i)
406 {
407 Creature* Shadow = NULL;
408 float X = CalculateRandomLocation(me->GetPositionX(), 10);
409 Shadow = me->SummonCreature(CREATURE_SHADOWY_CONSTRUCT, X, me->GetPositionY(), me->GetPositionZ(), 0, TempSummonType::TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 0);
410 if (Shadow)
411 {
413 if (!target)
414 target = me->GetVictim();
415
416 if (target)
417 Shadow->AI()->AttackStart(target);
418 }
419 }
420 SummonShadowsTimer = 60000;
421 } else SummonShadowsTimer -= diff;
422
423 if (SummonDoomBlossomTimer <= diff)
424 {
425 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
426 {
427 float X = CalculateRandomLocation(target->GetPositionX(), 20);
428 float Y = CalculateRandomLocation(target->GetPositionY(), 20);
429 float Z = target->GetPositionZ();
430 Z = me->GetMap()->GetHeight(me->GetPhaseMask(), X, Y, Z);
432 if (DoomBlossom)
433 {
435 DoomBlossom->setFaction(me->getFaction());
436 DoomBlossom->AddThreat(target, 1.0f);
437 CAST_AI(npc_doom_blossom::npc_doom_blossomAI, DoomBlossom->AI())->SetTeronGUID(me->GetGUID());
438 target->CombatStart(DoomBlossom);
441 }
442 }
443 } else SummonDoomBlossomTimer -= diff;
444
445 if (IncinerateTimer <= diff)
446 {
448 if (!target)
449 target = me->GetVictim();
450
451 if (target)
452 {
454 DoCast(target, SPELL_INCINERATE);
455 IncinerateTimer = std::rand() % (51 * IN_MILLISECONDS) + (20 * IN_MILLISECONDS);
456 }
457 } else IncinerateTimer -= diff;
458
459 if (CrushingShadowsTimer <= diff)
460 {
461 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
463 CrushingShadowsTimer = std::rand() % (26 * IN_MILLISECONDS) + (10 * IN_MILLISECONDS);
464 } else CrushingShadowsTimer -= diff;
465
466 /*** NOTE FOR FUTURE DEV: UNCOMMENT BELOW ONLY IF MIND CONTROL IS FULLY IMPLEMENTED **/
467 /*if (ShadowOfDeathTimer <= diff)
468 {
469 Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1);
470
471 if (!target)
472 target = me->GetVictim();
473
474 if (target && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
475 {
476 DoCast(target, SPELL_SHADOW_OF_DEATH);
477 GhostGUID = target->GetGUID();
478 ShadowOfDeathTimer = 30000;
479 SummonShadowsTimer = 53000; // Make it VERY close but slightly less so that we can check if the aura is still on the player
480 }
481 } else ShadowOfDeathTimer -= diff;*/
482
483 if (RandomYellTimer <= diff)
484 {
486 RandomYellTimer = std::rand() % (101 * IN_MILLISECONDS) + (50 * IN_MILLISECONDS);
487 } else RandomYellTimer -= diff;
488
489 if (!me->HasAura(SPELL_BERSERK))
490 {
491 if (EnrageTimer <= diff)
492 {
495 } else EnrageTimer -= diff;
496 }
497
499 }
500 };
501};
502
@ IN_MILLISECONDS
Definition Common.h:125
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
#define OVERRIDE
Definition Define.h:60
std::uint64_t uint64
Definition Define.h:76
@ IN_PROGRESS
@ DONE
@ NOT_STARTED
@ TYPEID_PLAYER
Definition Object.h:55
@ TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN
Definition Object.h:69
@ TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT
Definition Object.h:71
#define VISIBLE_RANGE
Definition ScriptMgr.h:56
#define CAST_AI(a, b)
@ EMOTE_STATE_TALK
@ EMOTE_STATE_NONE
@ SPELL_SCHOOL_MASK_NORMAL
@ UNIT_FLAG_NON_ATTACKABLE
Definition Unit.h:626
@ UNIT_FLAG_NOT_SELECTABLE
Definition Unit.h:650
@ DIRECT_DAMAGE
Definition Unit.h:614
@ SELECT_TARGET_RANDOM
Definition UnitAI.h:23
@ UNIT_FIELD_FLAGS
@ UNIT_FIELD_NPC_EMOTESTATE
@ DATA_TERON_GOREFIEND
@ SAY_SLAY
@ SAY_INTRO
@ SPELL_SHADOWBOLT
@ SPELL_INCINERATE
#define SAY_DEATH
#define SAY_AGGRO
@ SAY_ENRAGE
#define SPELL_BERSERK
@ SPELL_SHADOW_OF_DEATH
@ SPELL_PASSIVE_SHADOWFORM
@ CREATURE_DOOM_BLOSSOM
@ SPELL_CRUSHING_SHADOWS
@ SPELL_SHADOWBOLT
@ CREATURE_SHADOWY_CONSTRUCT
@ SPELL_INCINERATE
void AddSC_boss_teron_gorefiend()
virtual void MoveInLineOfSight(Unit *)
void DoZoneInCombat(Creature *creature=NULL, float maxRangeToNearestTarget=50.0f)
void Talk(uint8 id, WorldObject const *whisperTarget=NULL)
bool UpdateVictim()
virtual void EnterEvadeMode()
bool IsInEvadeMode() const
Definition Creature.h:478
CreatureAI * AI() const
Definition Creature.h:483
CreatureScript(const char *name)
void MoveChase(Unit *target, float dist=0.0f, float angle=0.0f)
std::list< HostileReference * > StorageType
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:28
void DoCast(uint32 spellId)
Definition UnitAI.cpp:110
Unit * SelectTarget(SelectAggroTarget targetType, uint32 position=0, float dist=0.0f, bool playerOnly=false, int32 aura=0)
Definition UnitAI.cpp:66
virtual void AttackStart(Unit *)
Definition UnitAI.cpp:16
Definition Unit.h:1367
void CastSpell(SpellCastTargets const &targets, SpellInfo const *spellInfo, CustomSpellValues const *value, TriggerCastFlags triggerFlags=TRIGGERED_NONE, Item *castItem=NULL, AuraEffect const *triggeredByAura=NULL, uint64 originalCaster=0)
void AddThreat(Unit *victim, float fThreat, SpellSchoolMask schoolMask=SPELL_SCHOOL_MASK_NORMAL, SpellInfo const *threatSpell=NULL)
Definition Unit.cpp:4463
MotionMaster * GetMotionMaster()
Definition Unit.h:2605
bool IsAlive() const
Definition Unit.h:2032
bool HasAura(uint32 spellId, uint64 casterGUID=0, uint64 itemCasterGUID=0, uint32 reqEffMask=0) const
static Creature * GetCreature(WorldObject &object, uint64 guid)
Definition Unit.cpp:4905
static Unit * GetUnit(WorldObject &object, uint64 guid)
Definition Unit.cpp:4895
InstanceScript * GetInstanceScript()
Definition Object.cpp:1612
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
@ SAY_SPELL
float GetPositionZ() const
Definition Object.h:330
float GetPositionX() const
Definition Object.h:328
float GetPositionY() const
Definition Object.h:329
Creature * me
float DoGetThreat(Unit *unit)
ScriptedAI(Creature *creature)
void AttackStart(Unit *) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
float CalculateRandomLocation(float Loc, uint32 radius)
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================