Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_kiljaeden.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_Kiljaeden
8SD%Complete: 80
9SDComment: Sinister Reflection Model, Armageddon Visual, SAY_KJ_SHADOWSPIKE3, Emote, End Sequence
10SDCategory: Sunwell_Plateau
11EndScriptData */
12
14
15#include "ScriptMgr.h"
16#include "ScriptedCreature.h"
17#include "sunwell_plateau.h"
18#include <math.h>
19#include "Player.h"
20
21/*** Speech and sounds***/
53
54/*** Spells used during the encounter ***/
56{
57 /* Hand of the Deceiver's spells and cosmetics */
58 SPELL_SHADOW_BOLT_VOLLEY = 45770, // ~30 yard range Shadow Bolt Volley for ~2k(?) damage
59 SPELL_SHADOW_INFUSION = 45772, // They gain this at 20% - Immunity to Stun/Silence and makes them look angry!
60 SPELL_FELFIRE_PORTAL = 46875, // Creates a portal that spawns Felfire Fiends (LIVE FOR THE SWARM!1 FOR THE OVERMIND!)
61 SPELL_SHADOW_CHANNELING = 46757, // Channeling animation out of combat
62
63 /* Volatile Felfire Fiend's spells */
64 SPELL_FELFIRE_FISSION = 45779, // Felfire Fiends explode when they die or get close to target.
65
66 /* Kil'Jaeden's spells and cosmetics */
67 SPELL_TRANS = 23188, // Surprisingly, this seems to be the right spell.. (Where is it used?)
68 SPELL_REBIRTH = 44200, // Emerge from the Sunwell
69 SPELL_SOUL_FLAY = 45442, // 9k Shadow damage over 3 seconds. Spammed throughout all the fight.
71 SPELL_LEGION_LIGHTNING = 45664, // Chain Lightning, 4 targets, ~3k Shadow damage, 1.5fk mana burn
72 SPELL_FIRE_BLOOM = 45641, // Places a debuff on 5 raid members, which causes them to deal 2k Fire damage to nearby allies and selves. MIGHT NOT WORK
73 SPELL_DESTROY_ALL_DRAKES = 46707, // when he use it?
74
75 SPELL_SINISTER_REFLECTION = 45785, // Summon shadow copies of 5 raid members that fight against KJ's enemies//dont work
76 // 45892 // right one for SPELL_SINISTER_REFLECTION but no EffectScriptEffect
77 SPELL_COPY_WEAPON = 41055, // }
78 SPELL_COPY_WEAPON2 = 41054, // }
79 SPELL_COPY_OFFHAND = 45206, // }- Spells used in Sinister Reflection creation
81
82 SPELL_SHADOW_SPIKE = 46680, // Bombard random raid members with Shadow Spikes (Very similar to Void Reaver orbs)
83 SPELL_FLAME_DART = 45737, // Bombards the raid with flames every 3(?) seconds
84 SPELL_DARKNESS_OF_A_THOUSAND_SOULS = 46605, // Begins a 8-second channeling, after which he will deal 50'000 damage to the raid
86
87 /* Armageddon spells wrong visual */
88 SPELL_ARMAGEDDON_TRIGGER = 45909, // Meteor spell trigger missile should cast Creature on himself
89 SPELL_ARMAGEDDON_VISUAL = 45911, // Does the hellfire visual to indicate where the meteor missle lands
90 SPELL_ARMAGEDDON_VISUAL2 = 45914, // Does the light visual to indicate where the meteor missle lands
91 SPELL_ARMAGEDDON_VISUAL3 = 24207, // This shouldn't correct but same as seen on the movie
92 SPELL_ARMAGEDDON_SUMMON_TRIGGER = 45921, // Summons the triggers that cast the spells on himself need random target select
93 SPELL_ARMAGEDDON_DAMAGE = 45915, // This does the area damage
94
95 /* Shield Orb Spells*/
96 SPELL_SHADOW_BOLT = 45680, //45679 would be correct but triggers to often /// @todo fix console error
97
98 /* Anveena's spells and cosmetics (Or, generally, everything that has "Anveena" in name) */
99 SPELL_ANVEENA_PRISON = 46367, // She hovers locked within a bubble
100 SPELL_ANVEENA_ENERGY_DRAIN = 46410, // Sunwell energy glow animation (Control mob uses this)
101 SPELL_SACRIFICE_OF_ANVEENA = 46474, // This is cast on Kil'Jaeden when Anveena sacrifices herself into the Sunwell
102
103 /* Sinister Reflection Spells */
106
108
110
112
115
118
122
124
126 //SPELL_SR_PLAGU STRIKE = 58843, Dk Spell!
127
128 /*** Other Spells (used by players, etc) ***/
129 SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT = 45839, // Possess the blue dragon from the orb to help the raid.
130 SPELL_ENTROPIUS_BODY = 46819, // Visual for Entropius at the Epilogue
131 SPELL_RING_OF_BLUE_FLAMES = 45825 //Cast this spell when the go is activated
132};
133
134/*** Error messages ***/
135#define ERROR_KJ_NOT_SUMMONED "TSCR ERROR: Unable to summon Kil'Jaeden for some reason"
136
137/*** Others ***/
138#define FLOOR_Z 28.050388f
139#define SHIELD_ORB_Z 45.000f
140
142{
143 PHASE_DECEIVERS = 1, // Fight 3 adds
144 PHASE_NORMAL = 2, // Kil'Jaeden emerges from the sunwell
145 PHASE_DARKNESS = 3, // At 85%, he gains few abilities; Kalecgos joins the fight
146 PHASE_ARMAGEDDON = 4, // At 55%, he gains even more abilities
147 PHASE_SACRIFICE = 5, // At 25%, Anveena sacrifices herself into the Sunwell; at this point he becomes enraged and has *significally* shorter cooldowns.
148};
149
150//Timers
170
171// Locations of the Hand of Deceiver adds
173{
174 {1682.045f, 631.299f, 5.936f, 0.0f},
175 {1684.099f, 618.848f, 0.589f, 0.0f},
176 {1694.170f, 612.272f, 1.416f, 0.0f},
177};
178
179// Locations, where Shield Orbs will spawn
181{
182 {1698.900f, 627.870f}, // middle pont of Sunwell
183 {12, 3.14f}, // First one spawns northeast of KJ
184 {12, 3.14f/0.7f}, // Second one spawns southeast
185 {12, 3.14f*3.8f} // Third one spawns (?)
186};
187
188struct Speech
189{
192};
193
194// Timers
196{
197 //Kil Phase 1 -> Phase 2
200 //Kil Phase 2 -> Phase 3
204 //Kil Phase 3 -> Phase 4
208 //Kil Phase 4 -> Phase 5
214
215 // use in End sequence?
217};
218
219//AI for Kalecgos
221{
222public:
223 boss_kalecgos_kj() : CreatureScript("boss_kalecgos_kj") { }
224
226 {
227 return new boss_kalecgos_kjAI(creature);
228 }
229
231 {
233 {
234 instance = creature->GetInstanceScript();
235 }
236
240
242 {
243 OrbsEmpowered = 0;
244 EmpowerCount = 0;
245 me->SetDisableGravity(true);
247 me->setActive(true);
248
249 for (uint8 i = 0; i < 4; ++i)
250 if (GameObject* pOrb = GetOrb(i))
251 pOrb->SetGoType(GAMEOBJECT_TYPE_BUTTON);
252 }
253
255 {
256 if (!instance)
257 return NULL;
258
259 switch (index)
260 {
261 case 0:
262 return instance->instance->GetGameObject(instance->GetData64(DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1));
263 case 1:
264 return instance->instance->GetGameObject(instance->GetData64(DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_2));
265 case 2:
266 return instance->instance->GetGameObject(instance->GetData64(DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_3));
267 case 3:
268 return instance->instance->GetGameObject(instance->GetData64(DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_4));
269 }
270
271 return NULL;
272 }
273
275 {
276 me->RemoveDynObject(SPELL_RING_OF_BLUE_FLAMES);
277 for (uint8 i = 0; i < 4; ++i)
278 if (GameObject* pOrb = GetOrb(i))
279 pOrb->SetUInt32Value(GAMEOBJECT_FIELD_FACTION_TEMPLATE, 0);
280 }
281
282 void EmpowerOrb(bool all)
283 {
284 GameObject* pOrbEmpowered = GetOrb(OrbsEmpowered);
285 if (!pOrbEmpowered)
286 return;
287
288 if (all)
289 {
290 me->RemoveDynObject(SPELL_RING_OF_BLUE_FLAMES);
291 for (uint8 i = 0; i < 4; ++i)
292 {
293 if (GameObject* pOrb = GetOrb(i))
294 {
295 pOrb->CastSpell(me, SPELL_RING_OF_BLUE_FLAMES);
296 pOrb->SetUInt32Value(GAMEOBJECT_FIELD_FACTION_TEMPLATE, 35);
297 pOrb->setActive(true);
298 pOrb->Refresh();
299 }
300 }
302 }
303 else
304 {
305 if (GameObject* pOrb = GetOrb(std::rand() % 3))
306 {
307 pOrb->CastSpell(me, SPELL_RING_OF_BLUE_FLAMES);
308 pOrb->SetUInt32Value(GAMEOBJECT_FIELD_FACTION_TEMPLATE, 35);
309 pOrb->setActive(true);
310 pOrb->Refresh();
311
313
314 ++EmpowerCount;
315 switch (EmpowerCount)
316 {
317 case 1: Talk(SAY_KALECGOS_READY1); break;
318 case 2: Talk(SAY_KALECGOS_READY2); break;
319 case 3: Talk(SAY_KALECGOS_READY3); break;
320 case 4: Talk(SAY_KALECGOS_READY4); break;
321 }
322 }
323 }
324 }
325
326 void UpdateAI(uint32 /*diff*/) OVERRIDE
327 {
328 }
329
331 {
332 me->RemoveDynObject(SPELL_RING_OF_BLUE_FLAMES);
333 for (uint8 i = 0; i < 4; ++i)
334 {
335 if (GameObject* pOrb = GetOrb(i))
336 {
337 if (pOrb->GetUInt32Value(GAMEOBJECT_FIELD_FACTION_TEMPLATE) == 35)
338 {
339 pOrb->CastSpell(me, SPELL_RING_OF_BLUE_FLAMES);
340 pOrb->setActive(true);
341 pOrb->Refresh();
342 }
343 }
344 }
345 }
346 };
347};
348
350{
351public:
352 go_orb_of_the_blue_flight() : GameObjectScript("go_orb_of_the_blue_flight") { }
353
355 {
356 if (go->GetUInt32Value(GAMEOBJECT_FIELD_FACTION_TEMPLATE) == 35)
357 {
358 InstanceScript* instance = go->GetInstanceScript();
359 player->SummonCreature(CREATURE_POWER_OF_THE_BLUE_DRAGONFLIGHT, player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), 0.0f, TempSummonType::TEMPSUMMON_TIMED_DESPAWN, 121000);
360 player->CastSpell(player, SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT, false);
361 go->SetUInt32Value(GAMEOBJECT_FIELD_FACTION_TEMPLATE, 0);
362
363 if (Creature* pKalec = Unit::GetCreature(*player, instance->GetData64(DATA_KALECGOS_KJ)))
364 CAST_AI(boss_kalecgos_kj::boss_kalecgos_kjAI, pKalec->AI())->SetRingOfBlueFlames();
365
366 go->Refresh();
367 }
368 return true;
369 }
370};
371
372//AI for Kil'jaeden Event Controller
374{
375public:
376 npc_kiljaeden_controller() : CreatureScript("npc_kiljaeden_controller") { }
377
379 {
380 return new npc_kiljaeden_controllerAI(creature);
381 }
382
384 {
386 {
387 instance = creature->GetInstanceScript();
388
389 SetCombatMovement(false);
390 }
391
394
397
401
410
412 {
414
415 if (instance)
416 if (Creature* pKalecKJ = Unit::GetCreature((*me), instance->GetData64(DATA_KALECGOS_KJ)))
417 CAST_AI(boss_kalecgos_kj::boss_kalecgos_kjAI, pKalecKJ->AI())->ResetOrbs();
419 bSummonedDeceivers = false;
420 bKiljaedenDeath = false;
421 uiRandomSayTimer = 30000;
422 summons.DespawnAll();
423 }
424
426 {
427 switch (summoned->GetEntry())
428 {
430 summoned->CastSpell(summoned, SPELL_SHADOW_CHANNELING, false);
431 break;
432 case CREATURE_ANVEENA:
433 summoned->SetDisableGravity(true);
434 summoned->CastSpell(summoned, SPELL_ANVEENA_PRISON, true);
435 summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
436 break;
438 summoned->CastSpell(summoned, SPELL_REBIRTH, false);
439 summoned->AddThreat(me->GetVictim(), 1.0f);
440 break;
441 }
442 summons.Summon(summoned);
443 }
444
446 {
447 if (uiRandomSayTimer < diff)
448 {
451 uiRandomSayTimer = 30000;
452 } else uiRandomSayTimer -= diff;
453
455 {
456 for (uint8 i = 0; i < 3; ++i)
458
461 bSummonedDeceivers = true;
462 }
463
465 {
466 me->RemoveAurasDueToSpell(SPELL_ANVEENA_ENERGY_DRAIN);
469 }
470 }
471 };
472};
473
474//AI for Kil'jaeden
476{
477public:
478 boss_kiljaeden() : CreatureScript("boss_kiljaeden") { }
479
481 {
482 return new boss_kiljaedenAI(creature);
483 }
484
486 {
488 {
489 instance = creature->GetInstanceScript();
490
491 SetCombatMovement(false);
492 }
493
496
500
505
506 /* Boolean */
512
514 {
515 // Scripted_NoMovementAI::InitializeAI();
516 }
517
519 {
521 Timer[TIMER_SPEECH] = 0;
522
523 //Phase 2 Timer
524 Timer[TIMER_SOUL_FLAY] = 11000;
526 Timer[TIMER_FIRE_BLOOM] = 20000;
528
529 //Phase 3 Timer
531 Timer[TIMER_FLAME_DART] = 3000;
532 Timer[TIMER_DARKNESS] = 45000;
533 Timer[TIMER_ORBS_EMPOWER] = 35000;
534
535 //Phase 4 Timer
536 Timer[TIMER_ARMAGEDDON] = 2000;
537
538 ActiveTimers = 5;
539 WaitTimer = 0;
540 speechCount = 0;
541 SpeechTimer = 0;
542
544
545 IsInDarkness = false;
546 IsWaiting = false;
547 OrbActivated = false;
548 SpeechBegins = true;
549
550 if (instance)
551 {
552 if (Creature* pKalec = Unit::GetCreature(*me, instance->GetData64(DATA_KALECGOS_KJ)))
553 pKalec->RemoveDynObject(SPELL_RING_OF_BLUE_FLAMES);
554 }
555 me->SetFloatValue(UNIT_FIELD_COMBAT_REACH, 12);
556 ChangeTimers(false, 0);
557 summons.DespawnAll();
558 }
559
560 void ChangeTimers(bool status, uint32 WTimer)
561 {
562 for (uint8 i = 1; i < ActiveTimers; ++i)
563 TimerIsDeactivated[i] = status;
564
565 if (WTimer > 0)
566 {
567 IsWaiting = true;
568 WaitTimer = WTimer;
569 }
570
571 if (OrbActivated)
573 if (Timer[TIMER_SHADOW_SPIKE] == 0)
575 if (Phase == PHASE_SACRIFICE)
577 }
578
580 {
581 if (summoned->GetEntry() == CREATURE_ARMAGEDDON_TARGET)
582 {
583 summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
584 summoned->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
585 // summoned->SetVisibility(VISIBILITY_OFF); //with this we cant see the armageddon visuals
586 }
587 else
588 summoned->SetLevel(me->getLevel());
589
590 summoned->setFaction(me->getFaction());
591 summons.Summon(summoned);
592 }
593
594 void JustDied(Unit* /*killer*/) OVERRIDE
595 {
597 summons.DespawnAll();
598
599 if (instance)
601 }
602
603 void KilledUnit(Unit* /*victim*/) OVERRIDE
604 {
606 }
607
609 {
611
612 summons.DespawnAll();
613
614 // Reset the controller
615 if (instance)
616 {
617 if (Creature* pControl = Unit::GetCreature(*me, instance->GetData64(DATA_KILJAEDEN_CONTROLLER)))
619 }
620 }
621
622 void EnterCombat(Unit* /*who*/) OVERRIDE
623 {
625 }
626
628 {
629 SpeechBegins = true;
630 OrbActivated = false;
631 ChangeTimers(true, 0);//stop every cast Shadow spike will reactivate em all
634 // empowered orbs before darkness
635 Timer[TIMER_DARKNESS] = (Phase == PHASE_SACRIFICE) ? 15000 : std::rand() % 40000 + 10000;
636 Timer[TIMER_ORBS_EMPOWER] = (Phase == PHASE_SACRIFICE) ? 10000 : 5000;
637 }
638
640 {
642 for (uint8 i = 0; i < 4; ++i)
643 {
645 {
646 float x, y, z;
647 target->GetPosition(x, y, z);
648 if (Creature* pSinisterReflection = me->SummonCreature(CREATURE_SINISTER_REFLECTION, x, y, z, 0, TempSummonType::TEMPSUMMON_CORPSE_DESPAWN, 0))
649 {
650 pSinisterReflection->SetDisplayId(target->GetDisplayId());
651 pSinisterReflection->AI()->AttackStart(target);
652 }
653 }
654 }
655 }
656
658 {
659 if (!UpdateVictim() || Phase < PHASE_NORMAL)
660 return;
661
662 if (IsWaiting)
663 {
664 if (WaitTimer <= diff)
665 {
666 IsWaiting = false;
667 ChangeTimers(false, 0);
668 } else WaitTimer -= diff;
669 }
670
671 for (uint8 t = 0; t < ActiveTimers; ++t)
672 {
673 if (Timer[t] < diff && !TimerIsDeactivated[t])
674 {
675 switch (t)
676 {
677 case TIMER_SPEECH:
678 if (SpeechBegins)
679 {
680 SpeechBegins=false;
681 switch (Phase)
682 {
683 case PHASE_NORMAL:
685 break;
686 case PHASE_DARKNESS:
688 break;
689 case PHASE_ARMAGEDDON:
691 break;
692 case PHASE_SACRIFICE:
694 break;
695 }
696 }
697 if (Speeches[speechCount].timer < SpeechTimer)
698 {
699 SpeechTimer = 0;
700 if (instance)
701 {
702 if (Creature* speechCreature = Unit::GetCreature(*me, instance->GetData64(Speeches[speechCount].creature)))
703 speechCreature->AI()->Talk(Speeches[speechCount].textid);
704 if (speechCount == 12)
705 if (Creature* pAnveena = Unit::GetCreature(*me, instance->GetData64(DATA_ANVEENA)))
706 pAnveena->CastSpell(me, SPELL_SACRIFICE_OF_ANVEENA, false);
707 // ChangeTimers(true, 10000); // Kil should do an emote while screaming without attacking for 10 seconds
708 }
711 speechCount++;
712 }
713 SpeechTimer += diff;
714 break;
715 case TIMER_SOUL_FLAY:
716 if (!me->IsNonMeleeSpellCasted(false))
717 {
720 Timer[TIMER_SOUL_FLAY] = 3500;
721 }
722 break;
724 if (!me->IsNonMeleeSpellCasted(false))
725 {
726 Unit* pRandomPlayer = NULL;
727
728 me->RemoveAurasDueToSpell(SPELL_SOUL_FLAY);
729 for (uint8 z = 0; z < 6; ++z)
730 {
731 pRandomPlayer = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
732 if (!pRandomPlayer || !pRandomPlayer->HasAura(SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT, 0))
733 break;
734 }
735
736 if (pRandomPlayer)
737 DoCast(pRandomPlayer, SPELL_LEGION_LIGHTNING, false);
738 else
739 SF_LOG_ERROR("scripts", "try to cast SPELL_LEGION_LIGHTNING on invalid target");
740
741 Timer[TIMER_LEGION_LIGHTNING] = (Phase == PHASE_SACRIFICE) ? 18000 : 30000; // 18 seconds in PHASE_SACRIFICE
742 Timer[TIMER_SOUL_FLAY] = 2500;
743 }
744 break;
745 case TIMER_FIRE_BLOOM:
746 if (!me->IsNonMeleeSpellCasted(false))
747 {
748 me->RemoveAurasDueToSpell(SPELL_SOUL_FLAY);
750 Timer[TIMER_FIRE_BLOOM] = (Phase == PHASE_SACRIFICE) ? 25000 : 40000; // 25 seconds in PHASE_SACRIFICE
751 Timer[TIMER_SOUL_FLAY] = 1000;
752 }
753 break;
755 for (uint8 i = 1; i < Phase; ++i)
756 {
757 float sx, sy;
758 sx = ShieldOrbLocations[0][0] + std::sin(ShieldOrbLocations[i][0]);
759 sy = ShieldOrbLocations[0][1] + std::sin(ShieldOrbLocations[i][1]);
761 }
762 Timer[TIMER_SUMMON_SHILEDORB] = std::rand() % 60000 + 30000; // 30-60seconds cooldown
763 Timer[TIMER_SOUL_FLAY] = 2000;
764 break;
765 case TIMER_SHADOW_SPIKE: //Phase 3
766 if (!me->IsNonMeleeSpellCasted(false))
767 {
770 ChangeTimers(true, 30000);
773 }
774 break;
775 case TIMER_FLAME_DART: //Phase 3
777 Timer[TIMER_FLAME_DART] = 3000;
778 break;
779 case TIMER_DARKNESS: //Phase 3
780 if (!me->IsNonMeleeSpellCasted(false))
781 {
782 // Begins to channel for 8 seconds, then deals 50'000 damage to all raid members.
783 if (!IsInDarkness)
784 {
787 ChangeTimers(true, 9000);
788 Timer[TIMER_DARKNESS] = 8750;
790 if (Phase == PHASE_SACRIFICE)
792 IsInDarkness = true;
793 }
794 else
795 {
796 Timer[TIMER_DARKNESS] = (Phase == PHASE_SACRIFICE) ? 15000 : std::rand() % 70000 + 40000;
797 IsInDarkness = false;
800 }
801 Timer[TIMER_SOUL_FLAY] = 9000;
802 }
803 break;
804 case TIMER_ORBS_EMPOWER: //Phase 3
805 if (instance)
806 if (Creature* pKalec = Unit::GetCreature(*me, instance->GetData64(DATA_KALECGOS_KJ)))
807 {
808 switch (Phase)
809 {
810 case PHASE_SACRIFICE:
811 CAST_AI(boss_kalecgos_kj::boss_kalecgos_kjAI, pKalec->AI())->EmpowerOrb(true);
812 break;
813 default:
814 CAST_AI(boss_kalecgos_kj::boss_kalecgos_kjAI, pKalec->AI())->EmpowerOrb(false);
815 break;
816 }
817 }
818 OrbActivated = true;
820 break;
821 case TIMER_ARMAGEDDON: //Phase 4
822 Unit* target = NULL;
823 for (uint8 z = 0; z < 6; ++z)
824 {
825 target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
826 if (!target || !target->HasAura(SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT, 0)) break;
827 }
828 if (target)
829 {
830 float x, y, z;
831 target->GetPosition(x, y, z);
833 }
834 Timer[TIMER_ARMAGEDDON] = 2000; // No, I'm not kidding
835 break;
836 }
837 }
838 }
840 //Time runs over!
841 for (uint8 i = 0; i < ActiveTimers; ++i)
842 if (!TimerIsDeactivated[i])
843 {
844 Timer[i] -= diff;
845 if (((int32)Timer[i]) < 0) Timer[i] = 0;
846 }
847
848 //Phase 3
850 {
851 if (Phase == PHASE_NORMAL && HealthBelowPct(85))
852 {
854 ActiveTimers = 9;
856 }
857 else return;
858 }
859
860 //Phase 4
862 {
863 if (Phase == PHASE_DARKNESS && HealthBelowPct(55))
864 {
866 ActiveTimers = 10;
868 }
869 else return;
870 }
871
872 //Phase 5 specific spells all we can
874 {
876 {
879 }
880 else return;
881 }
882 }
883 };
884};
885
886//AI for Hand of the Deceiver
888{
889public:
890 npc_hand_of_the_deceiver() : CreatureScript("npc_hand_of_the_deceiver") { }
891
893 {
894 return new npc_hand_of_the_deceiverAI(creature);
895 }
896
898 {
900 {
901 instance = creature->GetInstanceScript();
902 }
903
905
908
910 {
912 ShadowBoltVolleyTimer = std::rand() % 14000 + 8000; // So they don't all cast it in the same moment.
913 FelfirePortalTimer = 20000;
914 if (instance)
916 }
917
919 {
920 summoned->setFaction(me->getFaction());
921 summoned->SetLevel(me->getLevel());
922 }
923
925 {
926 if (instance)
927 {
929 if (Creature* pControl = Unit::GetCreature(*me, instance->GetData64(DATA_KILJAEDEN_CONTROLLER)))
930 pControl->AddThreat(who, 1.0f);
931 }
932 me->InterruptNonMeleeSpells(true);
933 }
934
935 void JustDied(Unit* /*killer*/) OVERRIDE
936 {
937 if (!instance)
938 return;
939
940 if (Creature* pControl = Unit::GetCreature(*me, instance->GetData64(DATA_KILJAEDEN_CONTROLLER)))
941 ++(CAST_AI(npc_kiljaeden_controller::npc_kiljaeden_controllerAI, pControl->AI())->deceiverDeathCount);
942 }
943
945 {
946 if (!me->IsInCombat())
948
949 if (!UpdateVictim())
950 return;
951
952 // Gain Shadow Infusion at 20% health
953 if (HealthBelowPct(20) && !me->HasAura(SPELL_SHADOW_INFUSION, 0))
955
956 // Shadow Bolt Volley - Shoots Shadow Bolts at all enemies within 30 yards, for ~2k Shadow damage.
957 if (ShadowBoltVolleyTimer <= diff)
958 {
960 ShadowBoltVolleyTimer = 12000;
961 }
962 else
963 ShadowBoltVolleyTimer -= diff;
964
965 // Felfire Portal - Creatres a portal, that spawns Volatile Felfire Fiends, which do suicide bombing.
966 if (FelfirePortalTimer <= diff)
967 {
969 {
970 ThreatContainer::StorageType const &threatlist = me->getThreatManager().getThreatList();
971 for (ThreatContainer::StorageType::const_iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
972 {
973 Unit* unit = Unit::GetUnit(*me, (*itr)->getUnitGuid());
974 if (unit)
975 pPortal->AddThreat(unit, 1.0f);
976 }
977 }
978 FelfirePortalTimer = 20000;
979 } else FelfirePortalTimer -= diff;
980
982 }
983 };
984};
985
986//AI for Felfire Portal
988{
989public:
990 npc_felfire_portal() : CreatureScript("npc_felfire_portal") { }
991
993 {
994 return new npc_felfire_portalAI(creature);
995 }
996
998 {
1000 {
1001 SetCombatMovement(false);
1002 }
1003
1005
1011
1013 {
1014 summoned->setFaction(me->getFaction());
1015 summoned->SetLevel(me->getLevel());
1016 }
1017
1019 {
1020 if (!UpdateVictim())
1021 return;
1022
1023 if (uiSpawnFiendTimer <= diff)
1024 {
1026 pFiend->AddThreat(SelectTarget(SELECT_TARGET_RANDOM, 0), 100000.0f);
1027 uiSpawnFiendTimer = std::rand() % 8000 + 4000;
1028 } else uiSpawnFiendTimer -= diff;
1029 }
1030 };
1031};
1032
1033//AI for Felfire Fiend
1035{
1036public:
1037 npc_volatile_felfire_fiend() : CreatureScript("npc_volatile_felfire_fiend") { }
1038
1040 {
1041 return new npc_volatile_felfire_fiendAI(creature);
1042 }
1043
1045 {
1047
1049
1051
1053 {
1054 uiExplodeTimer = 2000;
1055 bLockedTarget = false;
1056 }
1057
1058 void DamageTaken(Unit* /*done_by*/, uint32 &damage) OVERRIDE
1059 {
1060 if (damage > me->GetHealth())
1062 }
1063
1065 {
1066 if (!UpdateVictim())
1067 return;
1068
1069 if (!bLockedTarget)
1070 {
1071 me->AddThreat(me->GetVictim(), 10000000.0f);
1072 bLockedTarget = true;
1073 }
1074
1075 if (uiExplodeTimer)
1076 {
1077 if (uiExplodeTimer <= diff)
1078 uiExplodeTimer = 0;
1079 else uiExplodeTimer -= diff;
1080 }
1081 else if (me->IsWithinDistInMap(me->GetVictim(), 3)) // Explode if it's close enough to it's target
1082 {
1084 me->Kill(me);
1085 }
1086 }
1087 };
1088};
1089
1090//AI for Armageddon target
1092{
1093public:
1094 npc_armageddon() : CreatureScript("npc_armageddon") { }
1095
1097 {
1098 return new npc_armageddonAI(creature);
1099 }
1100
1102 {
1103 npc_armageddonAI(Creature* creature) : ScriptedAI(creature)
1104 {
1105 SetCombatMovement(false);
1106 }
1107
1110
1112 {
1113 spell = 0;
1114 uiTimer = 0;
1115 }
1116
1118 {
1119 if (uiTimer <= diff)
1120 {
1121 switch (spell)
1122 {
1123 case 0:
1125 ++spell;
1126 break;
1127 case 1:
1129 uiTimer = 9000;
1130 ++spell;
1131 break;
1132 case 2:
1134 ++spell;
1135 uiTimer = 5000;
1136 break;
1137 case 3:
1138 me->Kill(me);
1139 me->RemoveCorpse();
1140 break;
1141 }
1142 } else uiTimer -=diff;
1143 }
1144 };
1145};
1146
1147//AI for Shield Orbs
1149{
1150public:
1151 npc_shield_orb() : CreatureScript("npc_shield_orb") { }
1152
1154 {
1155 return new npc_shield_orbAI(creature);
1156 }
1157
1159 {
1160 npc_shield_orbAI(Creature* creature) : ScriptedAI(creature)
1161 {
1162 instance = creature->GetInstanceScript();
1163 }
1164
1166
1171 float x, y, r, c, mx, my;
1172
1174 {
1175 me->SetDisableGravity(true);
1176 bPointReached = true;
1177 uiTimer = std::rand() % 1000 + 500;
1178 uiCheckTimer = 1000;
1179 r = 17;
1180 c = 0;
1181 mx = ShieldOrbLocations[0][0];
1182 my = ShieldOrbLocations[0][1];
1183 bClockwise = std::rand() % 1;
1184 }
1185
1187 {
1188 if (bPointReached)
1189 {
1190 if (bClockwise)
1191 {
1192 y = my - r * std::sin(c);
1193 x = mx - r * std::cos(c);
1194 }
1195 else
1196 {
1197 y = my + r * std::sin(c);
1198 x = mx + r * std::cos(c);
1199 }
1200 bPointReached = false;
1201 uiCheckTimer = 1000;
1202 me->GetMotionMaster()->MovePoint(1, x, y, SHIELD_ORB_Z);
1203 c += M_PI/32;
1204 if (c >= 2*M_PI) c = 0;
1205 }
1206 else
1207 {
1208 if (uiCheckTimer <= diff)
1209 {
1211 bPointReached = true;
1212 }
1213 else uiCheckTimer -= diff;
1214 }
1215
1216 if (uiTimer <= diff)
1217 {
1218 if (Unit* random = Unit::GetUnit(*me, instance ? instance->GetData64(DATA_PLAYER_GUID) : 0))
1219 DoCast(random, SPELL_SHADOW_BOLT, false);
1220 uiTimer = std::rand() % 1000 + 500;
1221 } else uiTimer -= diff;
1222 }
1223
1225 {
1226 if (type != POINT_MOTION_TYPE)
1227 return;
1228
1229 bPointReached = true;
1230 }
1231 };
1232};
1233
1234//AI for Sinister Reflection
1236{
1237public:
1238 npc_sinster_reflection() : CreatureScript("npc_sinster_reflection") { }
1239
1241 {
1242 return new npc_sinster_reflectionAI(creature);
1243 }
1244
1246 {
1248
1251
1253 {
1254 uiTimer[0] = 0;
1255 uiTimer[1] = 0;
1256 uiTimer[2] = 0;
1257 victimClass = 0;
1258 }
1259
1261 {
1262 if (!UpdateVictim())
1263 return;
1264
1265 if ((victimClass == 0) && me->GetVictim())
1266 {
1267 victimClass = me->GetVictim()->getClass();
1268 switch (victimClass)
1269 {
1270 case CLASS_DRUID:
1271 break;
1272 case CLASS_HUNTER:
1273 break;
1274 case CLASS_MAGE:
1275 break;
1276 case CLASS_WARLOCK:
1277 break;
1278 case CLASS_WARRIOR:
1279 me->SetCanDualWield(true);
1280 break;
1281 case CLASS_PALADIN:
1282 break;
1283 case CLASS_PRIEST:
1284 break;
1285 case CLASS_SHAMAN:
1286 me->SetCanDualWield(true);
1287 break;
1288 case CLASS_ROGUE:
1289 me->SetCanDualWield(true);
1290 break;
1291 }
1292 }
1293
1294 switch (victimClass)
1295 {
1296 case CLASS_DRUID:
1297 if (uiTimer[1] <= diff)
1298 {
1300 uiTimer[1] = std::rand() % 4000 + 2000;
1301 }
1303 break;
1304 case CLASS_HUNTER:
1305 if (uiTimer[1] <= diff)
1306 {
1308 uiTimer[1] = std::rand() % 10000 + 8000;
1309 }
1310 if (uiTimer[2] <= diff)
1311 {
1313 uiTimer[2] = std::rand() % 6000 + 4000;
1314 }
1315 if (me->IsWithinMeleeRange(me->GetVictim(), 6))
1316 {
1317 if (uiTimer[0] <= diff)
1318 {
1320 uiTimer[0] = std::rand() % 8000 + 6000;
1321 }
1323 }
1324 break;
1325 case CLASS_MAGE:
1326 if (uiTimer[1] <= diff)
1327 {
1329 uiTimer[1] = std::rand() % 4000 + 2000;
1330 }
1332 break;
1333 case CLASS_WARLOCK:
1334 if (uiTimer[1] <= diff)
1335 {
1337 uiTimer[1] = std::rand() % 5000 + 3000;
1338 }
1339 if (uiTimer[2] <= diff)
1340 {
1342 uiTimer[2] = std::rand() % 4000 + 2000;
1343 }
1345 break;
1346 case CLASS_WARRIOR:
1347 if (uiTimer[1] <= diff)
1348 {
1350 uiTimer[1] = std::rand() % 11000 + 9000;
1351 }
1353 break;
1354 case CLASS_PALADIN:
1355 if (uiTimer[1] <= diff)
1356 {
1358 uiTimer[1] = std::rand() % 8000 + 6000;
1359 }
1360 if (uiTimer[2] <= diff)
1361 {
1363 uiTimer[2] = std::rand() % 4000 + 2000;
1364 }
1366 break;
1367 case CLASS_PRIEST:
1368 if (uiTimer[1] <= diff)
1369 {
1371 uiTimer[1] = std::rand() % 6000 + 4000;
1372 }
1373 if (uiTimer[2] <= diff)
1374 {
1375 DoCast(me, SPELL_SR_RENEW, false);
1376 uiTimer[2] = std::rand() % 8000 + 6000;
1377 }
1379 break;
1380 case CLASS_SHAMAN:
1381 if (uiTimer[1] <= diff)
1382 {
1384 uiTimer[1] = std::rand() % 6000 + 4000;
1385 }
1387 break;
1388 case CLASS_ROGUE:
1389 if (uiTimer[1] <= diff)
1390 {
1392 uiTimer[1] = std::rand() % 6000 + 4000;
1393 }
1395 break;
1396 }
1397 SF_LOG_DEBUG("scripts", "Sinister-Timer");
1398 for (uint8 i = 0; i < 3; ++i)
1399 uiTimer[i] -= diff;
1400 }
1401 };
1402};
1403
1405{
1407 new boss_kalecgos_kj();
1408 new boss_kiljaeden();
1411 new npc_felfire_portal();
1413 new npc_armageddon();
1414 new npc_shield_orb();
1416}
#define M_PI
Definition Common.h:192
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
#define OVERRIDE
Definition Define.h:60
@ IN_PROGRESS
@ DONE
@ NOT_STARTED
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
@ POINT_MOTION_TYPE
@ TEMPSUMMON_MANUAL_DESPAWN
Definition Object.h:75
@ TEMPSUMMON_CORPSE_DESPAWN
Definition Object.h:72
@ TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN
Definition Object.h:69
@ TEMPSUMMON_TIMED_DESPAWN
Definition Object.h:70
@ TEMPSUMMON_DEAD_DESPAWN
Definition Object.h:74
#define CAST_AI(a, b)
@ GAMEOBJECT_TYPE_BUTTON
@ CLASS_HUNTER
@ CLASS_DRUID
@ CLASS_SHAMAN
@ CLASS_PRIEST
@ CLASS_WARRIOR
@ CLASS_WARLOCK
@ CLASS_MAGE
@ CLASS_PALADIN
@ CLASS_ROGUE
@ UNIT_STATE_STUNNED
Definition Unit.h:515
@ UNIT_FLAG_NON_ATTACKABLE
Definition Unit.h:626
@ UNIT_FLAG_NOT_SELECTABLE
Definition Unit.h:650
@ SELECT_TARGET_RANDOM
Definition UnitAI.h:23
@ UNIT_FIELD_FLAGS
@ UNIT_FIELD_COMBAT_REACH
@ GAMEOBJECT_FIELD_FACTION_TEMPLATE
@ SPELL_SHADOW_BOLT
@ SAY_KJ_PHASE3
@ SAY_ANVEENA_GOODBYE
@ SAY_KALECGOS_READY1
@ SAY_KJ_DARKNESS
@ SAY_KJ_PHASE5
@ SAY_KALECGOS_FOCUS
@ SAY_KJ_EMERGE
@ SAY_KJ_SLAY
@ SAY_KJ_REFLECTION
@ SAY_KALECGOS_READY2
@ SAY_ANVEENA_LOST
@ SAY_KALECGOS_JOIN
@ SAY_KJ_DEATH
@ SAY_KJ_PHASE4
@ SAY_KALECGOS_LETGO
@ SAY_KALECGOS_GOODBYE
@ SAY_ANVEENA_IMPRISONED
@ SAY_ANVEENA_KALEC
@ SAY_KJ_OFFCOMBAT
@ SAY_KALECGOS_READY4
@ SAY_KALECGOS_AWAKEN
@ EMOTE_KJ_DARKNESS
@ SAY_KALECGOS_READY3
@ SAY_KALECGOS_ENCOURAGE
@ SAY_KALECGOS_FATE
void AddSC_boss_kiljaeden()
float ShieldOrbLocations[4][2]
@ SPELL_SHADOW_BOLT_VOLLEY
@ SPELL_SR_WING_CLIP
@ SPELL_SHADOW_SPIKE
@ SPELL_SR_MULTI_SHOT
@ SPELL_ENTROPIUS_BODY
@ SPELL_ARMAGEDDON_VISUAL3
@ SPELL_SR_HOLY_SHOCK
@ SPELL_DARKNESS_OF_A_THOUSAND_SOULS
@ SPELL_ARMAGEDDON_DAMAGE
@ SPELL_ARMAGEDDON_SUMMON_TRIGGER
@ SPELL_COPY_WEAPON
@ SPELL_COPY_WEAPON2
@ SPELL_DARKNESS_OF_A_THOUSAND_SOULS_DAMAGE
@ SPELL_FELFIRE_PORTAL
@ SPELL_SR_MOONFIRE
@ SPELL_ARMAGEDDON_VISUAL
@ SPELL_REBIRTH
@ SPELL_ANVEENA_PRISON
@ SPELL_TRANS
@ SPELL_RING_OF_BLUE_FLAMES
@ SPELL_SINISTER_REFLECTION
@ SPELL_DESTROY_ALL_DRAKES
@ SPELL_FIRE_BLOOM
@ SPELL_SR_HEMORRHAGE
@ SPELL_SHADOW_BOLT
@ SPELL_LEGION_LIGHTNING
@ SPELL_SR_WHIRLWIND
@ SPELL_SOUL_FLAY_SLOW
@ SPELL_SHADOW_INFUSION
@ SPELL_ARMAGEDDON_TRIGGER
@ SPELL_SR_HAMMER_OF_JUSTICE
@ SPELL_SR_RENEW
@ SPELL_SACRIFICE_OF_ANVEENA
@ SPELL_SR_HOLY_SMITE
@ SPELL_SR_EARTH_SHOCK
@ SPELL_SR_CURSE_OF_AGONY
@ SPELL_ARMAGEDDON_VISUAL2
@ SPELL_FLAME_DART
@ SPELL_SR_FIREBALL
@ SPELL_FELFIRE_FISSION
@ SPELL_SR_SHADOW_BOLT
@ SPELL_SOUL_FLAY
@ SPELL_ANVEENA_ENERGY_DRAIN
@ SPELL_SHADOW_CHANNELING
@ SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT
@ SPELL_SR_SHOOT
@ SPELL_COPY_OFFHAND
@ SPELL_COPY_OFFHAND_WEAPON
static Speech Speeches[]
Position DeceiverLocations[3]
#define SHIELD_ORB_Z
@ PHASE_SACRIFICE
@ PHASE_ARMAGEDDON
@ PHASE_DARKNESS
@ PHASE_DECEIVERS
@ PHASE_NORMAL
KilJaedenTimers
@ TIMER_ORBS_EMPOWER
@ TIMER_SPEECH
@ TIMER_ARMAGEDDON
@ TIMER_DARKNESS
@ TIMER_LEGION_LIGHTNING
@ TIMER_FLAME_DART
@ TIMER_FIRE_BLOOM
@ TIMER_SUMMON_SHILEDORB
@ TIMER_SOUL_FLAY
@ TIMER_SHADOW_SPIKE
@ SPELL_SHADOW_BOLT_VOLLEY
void DoZoneInCombat(Creature *creature=NULL, float maxRangeToNearestTarget=50.0f)
void Talk(uint8 id, WorldObject const *whisperTarget=NULL)
bool UpdateVictim()
virtual void EnterEvadeMode()
CreatureScript(const char *name)
GameObjectScript(const char *name)
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 InitializeAI()
Definition UnitAI.h:118
void DoCastVictim(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:168
void DoCastAOE(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:176
Definition Unit.h:1367
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 uint64 GetData64(uint32) const
Definition ZoneScript.h:32
CreatureAI * GetAI(Creature *creature) const OVERRIDE
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
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
void GetPosition(float &x, float &y) const
Definition Object.h:333
void SetCombatMovement(bool allowMovement)
Creature * me
void DoTeleportTo(float x, float y, float z, uint32 time=0)
bool HealthBelowPct(uint32 pct) const
Creature * DoSpawnCreature(uint32 entry, float offsetX, float offsetY, float offsetZ, float angle, TempSummonType type, uint32 despawntime)
ScriptedAI(Creature *creature)
uint32 creature
void UpdateAI(uint32) OVERRIDE
== Triggered Actions Requested ==================
void JustSummoned(Creature *summoned) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void ChangeTimers(bool status, uint32 WTimer)
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void JustSummoned(Creature *summoned) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void MovementInform(uint32 type, uint32) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
@ CREATURE_SINISTER_REFLECTION
@ CREATURE_KILJAEDEN
@ CREATURE_POWER_OF_THE_BLUE_DRAGONFLIGHT
@ CREATURE_SHIELD_ORB
@ CREATURE_ARMAGEDDON_TARGET
@ CREATURE_FELFIRE_PORTAL
@ CREATURE_VOLATILE_FELFIRE_FIEND
@ CREATURE_ANVEENA
@ CREATURE_HAND_OF_THE_DECEIVER
@ DATA_KILJAEDEN_CONTROLLER
@ DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_4
@ DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_1
@ DATA_KILJAEDEN
@ DATA_ANVEENA
@ DATA_PLAYER_GUID
@ DATA_KALECGOS_KJ
@ DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_2
@ DATA_ORB_OF_THE_BLUE_DRAGONFLIGHT_3
@ DATA_MURU_EVENT
@ DATA_KILJAEDEN_EVENT