Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_magtheridon.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_Magtheridon
8SD%Complete: 60
9SDComment: In Development
10SDCategory: Hellfire Citadel, Magtheridon's lair
11EndScriptData */
12
13#include "ScriptMgr.h"
14#include "ScriptedCreature.h"
15#include "magtheridons_lair.h"
16#include "Player.h"
17#include "SpellInfo.h"
18
29
36
38{
40 NPC_ROOM = 17516,
42 NPC_ABYSSAL = 17454,
43};
44
46{
48 SPELL_CLEAVE = 30619,
49 SPELL_QUAKE_TRIGGER = 30657, //must be cast with 30561 as the proc spell
55 SPELL_DEBRIS_DAMAGE = 30631, //core bug, does not support target 8
61 SPELL_MIND_EXHAUSTION = 44032, //Casted by the cubes when channeling ends
66 SPELL_FEAR = 30530, //39176
68 SPELL_SOUL_TRANSFER = 30531, //core bug, does not support target 7
70};
71
72//count of clickers needed to interrupt blast nova
73#define CLICKERS_COUNT 5
74
75typedef std::map<uint64, uint64> CubeMap;
76
78{
79 public:
80 npc_abyssal() : CreatureScript("npc_abyssal") { }
81
82 struct npc_abyssalAI : public ScriptedAI
83 {
84 npc_abyssalAI(Creature* creature) : ScriptedAI(creature)
85 {
86 trigger = 0;
87 Despawn_Timer = 60000;
88 }
89
93
95 {
96 FireBlast_Timer = 6000;
97 }
98
99 void SpellHit(Unit*, const SpellInfo* spell) OVERRIDE
100 {
101 if (trigger == 2 && spell->Id == SPELL_BLAZE_TARGET)
102 {
103 DoCast(me, SPELL_BLAZE_TRAP, true);
104 me->SetVisible(false);
105 Despawn_Timer = 130000;
106 }
107 }
108
109 void SetTrigger(uint32 _trigger)
110 {
111 trigger = _trigger;
112 me->SetDisplayId(11686);
113 if (trigger == 1) //debris
114 {
117 FireBlast_Timer = 5000;
118 Despawn_Timer = 10000;
119 }
120 }
121
122 void EnterCombat(Unit* /*who*/) OVERRIDE
123 {
125 }
127 {
128 if (!trigger)
130 }
132
133 {
134 if (!trigger)
136 }
137
139 {
140 if (trigger)
141 {
142 if (trigger == 1)
143 {
144 if (FireBlast_Timer <= diff)
145 {
147 trigger = 3;
148 }
149 else FireBlast_Timer -= diff;
150 }
151 return;
152 }
153
154 if (Despawn_Timer <= diff)
155 {
156 me->DespawnOrUnsummon();
157 }
158 else Despawn_Timer -= diff;
159
160 if (!UpdateVictim())
161 return;
162
163 if (FireBlast_Timer <= diff)
164 {
166 FireBlast_Timer = 5000+rand()%10000;
167 }
168 else FireBlast_Timer -= diff;
169
171 }
172 };
173
175 {
176 return new npc_abyssalAI(creature);
177 }
178};
179
181{
182 public:
183 boss_magtheridon() : CreatureScript("boss_magtheridon") { }
184
186 {
188 {
189 instance = creature->GetInstanceScript();
190 me->SetFloatValue(UNIT_FIELD_BOUNDING_RADIUS, 10);
191 me->SetFloatValue(UNIT_FIELD_COMBAT_REACH, 10);
192 }
193
195
197
205
206 bool Phase3;
208
210 {
211 Berserk_Timer = 1320000;
212 Quake_Timer = 40000;
213 Debris_Timer = 10000;
214 Blaze_Timer = 10000+rand()%20000;
215 BlastNova_Timer = 60000;
216 Cleave_Timer = 15000;
217 RandChat_Timer = 90000;
218
219 Phase3 = false;
220 NeedCheckCube = false;
221
225 me->AddUnitState(UNIT_STATE_STUNNED);
227 }
228
230 {
231 if (instance)
232 {
234 instance->SetData(DATA_COLLAPSE, false);
235 }
236 }
237
238 void SetClicker(uint64 cubeGUID, uint64 clickerGUID)
239 {
240 // to avoid multiclicks from 1 cube
241 if (uint64 guid = Cube[cubeGUID])
243 Cube[cubeGUID] = clickerGUID;
244 NeedCheckCube = true;
245 }
246
247 //function to interrupt channeling and debuff clicker with mind exh(used if second person clicks with same cube or after dispeling/ending shadow grasp DoT)
248 void DebuffClicker(Unit* clicker)
249 {
250 if (!clicker || !clicker->IsAlive())
251 return;
252
253 clicker->RemoveAurasDueToSpell(SPELL_SHADOW_GRASP); // cannot interrupt triggered spells
254 clicker->InterruptNonMeleeSpells(false);
255 clicker->CastSpell(clicker, SPELL_MIND_EXHAUSTION, true);
256 }
257
259 {
260 uint32 ClickerNum = 0;
261 // now checking if every clicker has debuff from manticron(it is dispelable atm rev 6110 : S)
262 // if not - apply mind exhaustion and delete from clicker's list
263 for (CubeMap::iterator i = Cube.begin(); i != Cube.end(); ++i)
264 {
265 Unit* clicker = Unit::GetUnit(*me, (*i).second);
266 if (!clicker || !clicker->HasAura(SPELL_SHADOW_GRASP))
267 {
268 DebuffClicker(clicker);
269 (*i).second = 0;
270 }
271 else
272 ++ClickerNum;
273 }
274
275 // if 5 clickers from other cubes apply shadow cage
276 if (ClickerNum >= CLICKERS_COUNT && !me->HasAura(SPELL_SHADOW_CAGE))
277 {
280 }
281 else
282 if (ClickerNum < CLICKERS_COUNT && me->HasAura(SPELL_SHADOW_CAGE))
283 me->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE);
284
285 if (!ClickerNum)
286 NeedCheckCube = false;
287 }
288
289 void KilledUnit(Unit* /*victim*/) OVERRIDE
290 {
292 }
293
294 void JustDied(Unit* /*killer*/) OVERRIDE
295 {
296 if (instance)
298
300 }
301
302 void MoveInLineOfSight(Unit* /*who*/) OVERRIDE { }
303
304
306 {
307 if (!me->HasUnitState(UNIT_STATE_STUNNED))
309 }
310
311 void EnterCombat(Unit* /*who*/) OVERRIDE
312 {
313 if (instance)
316
318 me->RemoveAurasDueToSpell(SPELL_SHADOW_CAGE_C);
319
321 }
322
324 {
325 if (!me->IsInCombat())
326 {
327 if (RandChat_Timer <= diff)
328 {
330 RandChat_Timer = 90000;
331 }
332 else
333 RandChat_Timer -= diff;
334 }
335
336 if (!UpdateVictim())
337 return;
338
340
341 if (Berserk_Timer <= diff)
342 {
343 DoCast(me, SPELL_BERSERK, true);
345 Berserk_Timer = 60000;
346 }
347 else
348 Berserk_Timer -= diff;
349
350 if (Cleave_Timer <= diff)
351 {
353 Cleave_Timer = 10000;
354 }
355 else
356 Cleave_Timer -= diff;
357
358 if (BlastNova_Timer <= diff)
359 {
360 // to avoid earthquake interruption
361 if (!me->HasUnitState(UNIT_STATE_STUNNED))
362 {
365 BlastNova_Timer = 60000;
366 }
367 }
368 else
369 BlastNova_Timer -= diff;
370
371 if (Quake_Timer <= diff)
372 {
373 // to avoid blastnova interruption
374 if (!me->IsNonMeleeSpellCasted(false))
375 {
377 Quake_Timer = 50000;
378 }
379 }
380 else
381 Quake_Timer -= diff;
382
383 if (Blaze_Timer <= diff)
384 {
385 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
386 {
387 float x, y, z;
388 target->GetPosition(x, y, z);
389 Creature* summon = me->SummonCreature(NPC_ABYSSAL, x, y, z, 0, TempSummonType::TEMPSUMMON_CORPSE_DESPAWN, 0);
390 if (summon)
391 {
392 CAST_AI(npc_abyssal::npc_abyssalAI, summon->AI())->SetTrigger(2);
393 DoCast(summon, SPELL_BLAZE_TARGET, true);
395 }
396 }
397 Blaze_Timer = std::rand() % 40000 + 20000;
398 }
399 else
400 Blaze_Timer -= diff;
401
402 if (!Phase3 && HealthBelowPct(30)
403 && !me->IsNonMeleeSpellCasted(false) // blast nova
404 && !me->HasUnitState(UNIT_STATE_STUNNED)) // shadow cage and earthquake
405 {
406 Phase3 = true;
410
411 if (instance)
412 instance->SetData(DATA_COLLAPSE, true);
413 }
414
415 if (Phase3)
416 {
417 if (Debris_Timer <= diff)
418 {
419 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
420 {
421 float x, y, z;
422 target->GetPosition(x, y, z);
423 Creature* summon = me->SummonCreature(NPC_ABYSSAL, x, y, z, 0, TempSummonType::TEMPSUMMON_CORPSE_DESPAWN, 0);
424 if (summon)
425 CAST_AI(npc_abyssal::npc_abyssalAI, summon->AI())->SetTrigger(1);
426 }
427 Debris_Timer = 10000;
428 }
429 else
430 Debris_Timer -= diff;
431 }
432
434 }
435 };
436
438 {
439 return new boss_magtheridonAI(creature);
440 }
441};
442
444{
445 public:
446 npc_hellfire_channeler() : CreatureScript("npc_hellfire_channeler") { }
447
449 {
451 {
452 instance = creature->GetInstanceScript();
453 }
454
456
461
463
465 {
466 ShadowBoltVolley_Timer = std::rand() % 10000 + 8000;
467 DarkMending_Timer = 10000;
468 Fear_Timer = std::rand() % 20000 + 15000;
469 Infernal_Timer = std::rand() % 50000 + 10000;
470
471 Check_Timer = 5000;
472 }
473
474 void EnterCombat(Unit* /*who*/) OVERRIDE
475 {
476 if (instance)
478
479 me->InterruptNonMeleeSpells(false);
481 }
482
484 {
485 if (instance)
487
489 }
490
492 {
493 summon->AI()->AttackStart(me->GetVictim());
494 }
495
497 {
498 if (damage >= me->GetHealth())
500 }
501
502 void JustDied(Unit* /*killer*/) OVERRIDE
503 {
504 if (instance)
506 }
507
509 {
510 if (!UpdateVictim())
511 return;
512
513 if (ShadowBoltVolley_Timer <= diff)
514 {
516 ShadowBoltVolley_Timer = std::rand() % 20000 + 10000;
517 }
518 else
520
521 if (DarkMending_Timer <= diff)
522 {
523 if (HealthBelowPct(50))
525 DarkMending_Timer = 10000 +(rand() % 10000);
526 }
527 else
528 DarkMending_Timer -= diff;
529
530 if (Fear_Timer <= diff)
531 {
532 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1))
533 DoCast(target, SPELL_FEAR);
534 Fear_Timer = std::rand() % 40000 + 25000;
535 }
536 else
537 Fear_Timer -= diff;
538
539 if (Infernal_Timer <= diff)
540 {
541 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
542 DoCast(target, SPELL_BURNING_ABYSSAL, true);
543 Infernal_Timer = std::rand() % 40000 + 30000;
544 }
545 else
546 Infernal_Timer -= diff;
547
549 }
550 };
551
553 {
554 return new npc_hellfire_channelerAI(creature);
555 }
556};
557
558//Manticron Cube
560{
561public:
562 go_manticron_cube() : GameObjectScript("go_manticron_cube")
563 {
564 }
565
567 {
568 InstanceScript* instance = go->GetInstanceScript();
569
570 if (!instance)
571 return true;
572
574 return true;
575 Creature* Magtheridon =Unit::GetCreature(*go, instance->GetData64(DATA_MAGTHERIDON));
576 if (!Magtheridon || !Magtheridon->IsAlive())
577 return true;
578
579 // if exhausted or already channeling return
580 if (player->HasAura(SPELL_MIND_EXHAUSTION) || player->HasAura(SPELL_SHADOW_GRASP))
581 return true;
582
583 player->InterruptNonMeleeSpells(false);
584 player->CastSpell(player, SPELL_SHADOW_GRASP, true);
585 player->CastSpell(player, SPELL_SHADOW_GRASP_VISUAL, false);
586 CAST_AI(boss_magtheridon::boss_magtheridonAI, Magtheridon->AI())->SetClicker(go->GetGUID(), player->GetGUID());
587 return true;
588 }
589};
590
592{
593 new boss_magtheridon();
595 new npc_abyssal();
596 new go_manticron_cube();
597}
598
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
@ TEMPSUMMON_CORPSE_DESPAWN
Definition Object.h:72
#define CAST_AI(a, b)
@ UNIT_STATE_STUNNED
Definition Unit.h:515
@ UNIT_FLAG_NON_ATTACKABLE
Definition Unit.h:626
@ UNIT_FLAG_NOT_SELECTABLE
Definition Unit.h:650
@ UNIT_FLAG_IMMUNE_TO_PC
Definition Unit.h:633
@ SELECT_TARGET_RANDOM
Definition UnitAI.h:23
@ UNIT_FIELD_BOUNDING_RADIUS
@ UNIT_FIELD_FLAGS
@ UNIT_FIELD_COMBAT_REACH
Creatures
@ SPELL_CLEAVE
@ SAY_BANISH
#define SAY_DEATH
#define SAY_AGGRO
#define SPELL_BERSERK
@ EMOTE_BERSERK
@ SPELL_SHADOW_BOLT_VOLLEY
std::map< uint64, uint64 > CubeMap
@ NPC_CHANNELLER
@ NPC_MAGTHERIDON
@ NPC_ABYSSAL
@ NPC_ROOM
@ EMOTE_BLASTNOVA
@ EMOTE_BERSERK
@ EMOTE_BEGIN
@ SAY_DEATH
@ SAY_BANISH
@ SAY_CHAMBER_DESTROY
@ SAY_FREED
@ SAY_TAUNT
@ SAY_PLAYER_KILLED
@ SPELL_SHADOW_BOLT_VOLLEY
@ SPELL_DEBRIS_KNOCKDOWN
@ SPELL_CLEAVE
@ SPELL_SHADOW_CAGE
@ SPELL_QUAKE_KNOCKBACK
@ SPELL_SHADOW_GRASP
@ SPELL_SHADOW_GRASP_C
@ SPELL_DARK_MENDING
@ SPELL_SOUL_TRANSFER
@ SPELL_FEAR
@ SPELL_BLAZE_TARGET
@ SPELL_DEBRIS_DAMAGE
@ SPELL_SHADOW_GRASP_VISUAL
@ SPELL_CAMERA_SHAKE
@ SPELL_SHADOW_CAGE_C
@ SPELL_BLAZE_TRAP
@ SPELL_BLASTNOVA
@ SPELL_BURNING_ABYSSAL
@ SPELL_MIND_EXHAUSTION
@ SPELL_DEBRIS_VISUAL
@ SPELL_BERSERK
@ SPELL_QUAKE_TRIGGER
@ SPELL_FIRE_BLAST
#define CLICKERS_COUNT
void AddSC_boss_magtheridon()
@ SPELL_FEAR
virtual void MoveInLineOfSight(Unit *)
void DoZoneInCombat(Creature *creature=NULL, float maxRangeToNearestTarget=50.0f)
void Talk(uint8 id, WorldObject const *whisperTarget=NULL)
bool UpdateVictim()
CreatureAI * AI() const
Definition Creature.h:483
CreatureScript(const char *name)
GameObjectScript(const char *name)
void SetFlag(uint16 index, uint32 newFlag)
Definition Object.cpp:1261
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
void DoCastVictim(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:168
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 RemoveAurasDueToSpell(uint32 spellId, uint64 casterGUID=0, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:1433
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
virtual uint32 GetData(uint32) const
Definition ZoneScript.h:36
virtual uint64 GetData64(uint32) const
Definition ZoneScript.h:32
CreatureAI * GetAI(Creature *creature) const OVERRIDE
bool OnGossipHello(Player *player, GameObject *go) OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
@ SPELL_DARK_MENDING
@ DATA_CHANNELER_EVENT
@ DATA_COLLAPSE
@ DATA_MAGTHERIDON
@ DATA_MAGTHERIDON_EVENT
Creature * me
bool HealthBelowPct(uint32 pct) const
ScriptedAI(Creature *creature)
void AttackStart(Unit *) OVERRIDE
void SetClicker(uint64 cubeGUID, uint64 clickerGUID)
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void EnterCombat(Unit *) OVERRIDE
void MoveInLineOfSight(Unit *who) OVERRIDE
void SetTrigger(uint32 _trigger)
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void SpellHit(Unit *, const SpellInfo *spell) OVERRIDE
void AttackStart(Unit *who) OVERRIDE
npc_abyssalAI(Creature *creature)
void DamageTaken(Unit *, uint32 &damage) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
@ SPELL_CAMERA_SHAKE