Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_svala.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#include "ScriptMgr.h"
7#include "ScriptedCreature.h"
8#include "SpellScript.h"
9#include "SpellAuraEffects.h"
10#include "utgarde_pinnacle.h"
11
13{
17
18 SPELL_CALL_FLAMES = 48258, // caster effect only, triggers event 17841
21
24 SPELL_RITUAL_STRIKE_TRIGGER = 48331, // triggers 48277 & 59930, needs NPC_RITUAL_TARGET as spell_script_target
28
33
34 // Ritual Channeler spells
37
38 // Scourge Hulk spells
42};
43
45{
46 // Svala
48
49 // Svala Sorrowgrave
56
57 // Image of Arthas
60};
61
63{
64 NPC_ARTHAS = 29280, // Image of Arthas
65 NPC_SVALA_SORROWGRAVE = 26668, // Svala after transformation
71};
72
74{
76};
77
86
87enum Misc
88{
90};
91
92static const float spectatorWP[2][3] =
93{
94 {296.95f, -312.76f, 86.36f},
95 {297.69f, -275.81f, 86.36f}
96};
97
98static Position ArthasPos = { 295.81f, -366.16f, 92.57f, 1.58f };
99
101{
102public:
103 boss_svala() : CreatureScript("boss_svala") { }
104
106 {
107 return new boss_svalaAI(creature);
108 }
109
110 struct boss_svalaAI : public ScriptedAI
111 {
112 boss_svalaAI(Creature* creature) : ScriptedAI(creature), summons(creature)
113 {
114 instance = creature->GetInstanceScript();
115 Phase = IDLE;
116
117 me->ApplySpellImmune(0, IMMUNITY_ID, SPELL_RITUAL_STRIKE_EFF_1, true);
118 me->ApplySpellImmune(0, IMMUNITY_ID, SPELL_RITUAL_STRIKE_EFF_2, true);
119 }
120
124
126 float x, y, z;
127
131
134
138
140
142 {
143 sacrificed = false;
144 SetCombatMovement(true);
145
146 summons.DespawnAll();
147 me->RemoveAllAuras();
148
149 if (Phase > NORMAL)
150 Phase = NORMAL;
151
152 me->SetDisableGravity(Phase == NORMAL);
153
155 introPhase = 0;
156 arthasGUID = 0;
157
158 if (instance)
159 {
161 instance->SetData64(DATA_SACRIFICED_PLAYER, 0);
162 }
163 }
164
165 void EnterCombat(Unit* /*who*/) OVERRIDE
166 {
168
170 callFlamesTimer = std::rand() % (20 * IN_MILLISECONDS) + (10 * IN_MILLISECONDS);
171
172 if (instance)
174 }
175
177 {
178 if (summon->GetEntry() == NPC_RITUAL_CHANNELER)
179 summon->CastSpell(summon, SPELL_SUMMONED_VIS, true);
180
181 summons.Summon(summon);
182 }
183
185 {
186 summons.Despawn(summon);
187 }
188
190
191 {
192 if (!who)
193 return;
194
195 if (Phase == IDLE && me->IsValidAttackTarget(who) && me->IsWithinDistInMap(who, 40))
196 {
197 Phase = INTRO;
199
201 mirror->SetGoState(GOState::GO_STATE_READY);
202
204 {
206 arthasGUID = arthas->GetGUID();
207 }
208 }
209 }
210
212 {
213 if (victim != me)
214 Talk(SAY_SLAY);
215 }
216
217 void JustDied(Unit* /*killer*/) OVERRIDE
218 {
219 if (Phase == SACRIFICING)
221
222 me->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH);
223
224 summons.DespawnAll();
225
226 if (instance)
228
230 }
231
232 void SpellHitTarget(Unit* /*target*/, const SpellInfo* spell) OVERRIDE
233 {
234 if (spell->Id == SPELL_RITUAL_STRIKE_EFF_1 && Phase != NORMAL && Phase != SVALADEAD)
235 {
236 Phase = NORMAL;
237 SetCombatMovement(true);
238
239 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 300.0f, true))
240 me->GetMotionMaster()->MoveChase(target);
241 }
242 }
243
245 {
246 if (Phase == IDLE)
247 return;
248
249 if (Phase == INTRO)
250 {
251 if (introTimer <= diff)
252 {
254 if (!arthas)
255 return;
256
257 switch (introPhase)
258 {
259 case 0:
261 ++introPhase;
262 introTimer = 8100;
263 break;
264 case 1:
265 arthas->AI()->Talk(SAY_DIALOG_OF_ARTHAS_1);
266 ++introPhase;
267 introTimer = 10000;
268 break;
269 case 2:
270 arthas->CastSpell(me, SPELL_TRANSFORMING_CHANNEL, false);
271 pos.Relocate(me);
272 pos.m_positionZ += 8.0f;
273 me->GetMotionMaster()->MoveTakeoff(0, pos);
274 // spectators flee event
275 if (instance)
276 {
277 std::list<Creature*> lspectatorList;
278 GetCreatureListWithEntryInGrid(lspectatorList, me, NPC_SPECTATOR, 100.0f);
279 for (std::list<Creature*>::iterator itr = lspectatorList.begin(); itr != lspectatorList.end(); ++itr)
280 {
281 if ((*itr)->IsAlive())
282 {
283 (*itr)->SetStandState(UNIT_STAND_STATE_STAND);
284 (*itr)->SetWalk(false);
285 (*itr)->GetMotionMaster()->MovePoint(1, spectatorWP[0][0], spectatorWP[0][1], spectatorWP[0][2]);
286 }
287 }
288 }
289 ++introPhase;
290 introTimer = 4200;
291 break;
292 case 3:
293 me->CastSpell(me, SPELL_SVALA_TRANSFORMING1, false);
294 ++introPhase;
295 introTimer = 6200;
296 break;
297 case 4:
298 me->CastSpell(me, SPELL_SVALA_TRANSFORMING2, false);
299 arthas->InterruptNonMeleeSpells(true);
300 me->RemoveAllAuras();
301 me->UpdateEntry(NPC_SVALA_SORROWGRAVE);
302 me->SetFacingToObject(arthas);
304 ++introPhase;
305 introTimer = 3200;
306 break;
307 case 5:
309 ++introPhase;
310 introTimer = 10000;
311 break;
312 case 6:
313 arthas->AI()->Talk(SAY_DIALOG_OF_ARTHAS_2);
314 ++introPhase;
315 introTimer = 7200;
316 break;
317 case 7:
319 me->SetFacingTo(1.58f);
320 arthas->SetVisible(false);
321 ++introPhase;
322 introTimer = 13800;
323 break;
324 case 8:
325 pos.Relocate(me);
326 pos.m_positionX = me->GetHomePosition().GetPositionX();
327 pos.m_positionY = me->GetHomePosition().GetPositionY();
328 pos.m_positionZ = 90.6065f;
329 me->GetMotionMaster()->MoveLand(0, pos);
330 me->SetDisableGravity(false, true);
331 me->SetHover(true);
332 ++introPhase;
333 introTimer = 3000;
334 break;
335 case 9:
337 mirror->SetGoState(GOState::GO_STATE_ACTIVE);
339 arthas->DespawnOrUnsummon();
340 arthasGUID = 0;
341 Phase = NORMAL;
342 break;
343 }
344 }
345 else
346 introTimer -= diff;
347
348 return;
349 }
350
351 if (Phase == NORMAL)
352 {
353 //Return since we have no target
354 if (!UpdateVictim())
355 return;
356
357 if (sinsterStrikeTimer <= diff)
358 {
360 sinsterStrikeTimer = std::rand() % (9 * IN_MILLISECONDS) + (5 * IN_MILLISECONDS);
361 }
362 else
363 sinsterStrikeTimer -= diff;
364
365 if (callFlamesTimer <= diff)
366 {
367 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
368 {
369 DoCast(target, SPELL_CALL_FLAMES);
370 callFlamesTimer = std::rand() % (20 * IN_MILLISECONDS) + (10 * IN_MILLISECONDS);
371 }
372 }
373 else callFlamesTimer -= diff;
374
375 if (!sacrificed)
376 {
377 if (HealthBelowPct(50))
378 {
379 if (Unit* sacrificeTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 80.0f, true))
380 {
381 if (instance)
382 instance->SetData64(DATA_SACRIFICED_PLAYER, sacrificeTarget->GetGUID());
383
385
386 DoCast(sacrificeTarget, SPELL_RITUAL_PREPARATION);
387
388 SetCombatMovement(false);
389
391 sacrePhase = 0;
393
395 sacrificed = true;
396 }
397 }
398 }
399
401 }
402 else //SACRIFICING
403 {
404 if (sacrificeTimer <= diff)
405 {
406 switch (sacrePhase)
407 {
408 case 0:
409 // spawn ritual channelers
410 if (instance)
411 {
415 }
416 ++sacrePhase;
418 break;
419 case 1:
420 me->StopMoving();
421 me->GetMotionMaster()->MoveIdle();
422 me->InterruptNonMeleeSpells(true);
424 ++sacrePhase;
425 sacrificeTimer = 200;
426 break;
427 case 2:
429 ++sacrePhase;
430 break;
431 case 3:
432 break;
433 }
434 }
435 else sacrificeTimer -= diff;
436 }
437 }
438 };
439};
440
442{
443public:
444 npc_ritual_channeler() : CreatureScript("npc_ritual_channeler") { }
445
447 {
448 return new npc_ritual_channelerAI(creature);
449 }
450
452 {
454 {
455 instance = creature->GetInstanceScript();
456
457 SetCombatMovement(false);
458 }
459
462
464 {
465 paralyzeTimer = 1600;
466 if (instance)
467 if (IsHeroic())
469 }
470
472 {
473 if (me->HasUnitState(UNIT_STATE_CASTING))
474 return;
475
476 if (paralyzeTimer <= diff)
477 {
478 if (instance)
479 if (Unit* victim = me->GetUnit(*me, instance->GetData64(DATA_SACRIFICED_PLAYER)))
480 DoCast(victim, SPELL_PARALYZE, false);
481
482 paralyzeTimer = 200;
483 }
484 else
485 paralyzeTimer -= diff;
486 }
487 };
488};
489
491{
492public:
493 npc_spectator() : CreatureScript("npc_spectator") { }
494
496 {
497 return new npc_spectatorAI(creature);
498 }
499
501 {
502 npc_spectatorAI(Creature* creature) : ScriptedAI(creature) { }
503
504 void Reset() OVERRIDE { }
505
506 void MovementInform(uint32 motionType, uint32 pointId) OVERRIDE
507 {
508 if (motionType == POINT_MOTION_TYPE)
509 {
510 if (pointId == 1)
511 me->GetMotionMaster()->MovePoint(2, spectatorWP[1][0], spectatorWP[1][1], spectatorWP[1][2]);
512 else if (pointId == 2)
513 me->DespawnOrUnsummon(1000);
514 }
515 }
516 };
517};
518
520{
521 public:
522 explicit RitualTargetCheck(Unit* _caster) : caster(_caster) { }
523
524 bool operator() (WorldObject* unit) const
525 {
526 if (InstanceScript* instance = caster->GetInstanceScript())
527 if (instance->GetData64(DATA_SACRIFICED_PLAYER) == unit->GetGUID())
528 return false;
529
530 return true;
531 }
532
533 private:
535};
536
562
564{
565 public:
566 npc_scourge_hulk() : CreatureScript("npc_scourge_hulk") { }
567
569 {
570 npc_scourge_hulkAI(Creature* creature) : ScriptedAI(creature) { }
571
574
576 {
577 mightyBlow = std::rand() % 9000 + 4000;
578 volatileInfection = std::rand() % 14000 + 10000;
579 killedByRitualStrike = false;
580 }
581
583 {
584 return type == DATA_INCREDIBLE_HULK ? killedByRitualStrike : 0;
585 }
586
587 void DamageTaken(Unit* attacker, uint32 &damage) OVERRIDE
588 {
589 if (damage >= me->GetHealth() && attacker->GetEntry() == NPC_SVALA_SORROWGRAVE)
591 }
592
594 {
595 if (!UpdateVictim())
596 return;
597
598 if (mightyBlow <= diff)
599 {
600 if (Unit* victim = me->GetVictim())
601 if (!victim->HasUnitState(UNIT_STATE_STUNNED)) // Prevent knocking back a ritual player
602 DoCast(victim, SPELL_MIGHTY_BLOW);
603 mightyBlow = std::rand() % 17000 + 12000;
604 }
605 else
606 mightyBlow -= diff;
607
608 if (volatileInfection <= diff)
609 {
611 volatileInfection = std::rand() % 17000 + 13000;
612 }
613 else
614 volatileInfection -= diff;
615
617 }
618
619 private:
621 };
622
624 {
625 return new npc_scourge_hulkAI(creature);
626 }
627};
628
630{
631 public:
632 achievement_incredible_hulk() : AchievementCriteriaScript("achievement_incredible_hulk") { }
633
634 bool OnCheck(Player* /*player*/, Unit* target) OVERRIDE
635 {
636 return target && target->IsAIEnabled && target->GetAI()->GetData(DATA_INCREDIBLE_HULK);
637 }
638};
639
641{
642 new boss_svala();
644 new npc_spectator();
646 new npc_scourge_hulk();
648}
@ IN_MILLISECONDS
Definition Common.h:125
@ EQUIP_UNEQUIP
Definition CreatureAI.h:50
@ EQUIP_NO_CHANGE
Definition CreatureAI.h:49
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
@ GO_STATE_ACTIVE
Definition GameObject.h:576
@ GO_STATE_READY
Definition GameObject.h:577
@ IN_PROGRESS
@ DONE
@ NOT_STARTED
@ POINT_MOTION_TYPE
@ TEMPSUMMON_MANUAL_DESPAWN
Definition Object.h:75
GameObject * GetClosestGameObjectWithEntry(WorldObject *source, uint32 entry, float maxSearchRange)
void GetCreatureListWithEntryInGrid(std::list< Creature * > &list, WorldObject *source, uint32 entry, float maxSearchRange)
@ EFFECT_0
@ EMOTE_ONESHOT_FLYDEATH
@ TARGET_UNIT_SRC_AREA_ENEMY
@ IMMUNITY_ID
#define SpellObjectAreaTargetSelectFn(F, I, N)
@ UNIT_STAND_STATE_STAND
Definition Unit.h:162
@ UNIT_STATE_CASTING
Definition Unit.h:527
@ 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
Creatures
@ SAY_SLAY
@ SPELL_PARALYZE
#define SAY_DEATH
#define SAY_AGGRO
@ GO_UTGARDE_MIRROR
void AddSC_boss_svala()
@ NPC_RITUAL_TARGET
@ NPC_FLAME_BRAZIER
@ NPC_SVALA_SORROWGRAVE
@ NPC_SCOURGE_HULK
@ NPC_ARTHAS
@ NPC_SPECTATOR
@ NPC_RITUAL_CHANNELER
static const float spectatorWP[2][3]
@ DATA_INCREDIBLE_HULK
@ SAY_DEATH
@ SAY_SACRIFICE_PLAYER
@ SAY_SVALA_INTRO_0
@ SAY_AGGRO
@ SAY_SVALA_INTRO_2
@ SAY_SLAY
@ SAY_SVALA_INTRO_1
@ SAY_DIALOG_OF_ARTHAS_2
@ SAY_DIALOG_OF_ARTHAS_1
static Position ArthasPos
@ SPELL_RITUAL_STRIKE_TRIGGER
@ SPELL_RITUAL_PREPARATION
@ SPELL_TRANSFORMING_CHANNEL
@ H_SPELL_SINSTER_STRIKE
@ SPELL_SINSTER_STRIKE
@ H_SPELL_VOLATILE_INFECTION
@ SPELL_SUMMONED_VIS
@ SPELL_SHADOWS_IN_THE_DARK
@ SPELL_RITUAL_CHANNELER_1
@ SPELL_SVALA_TRANSFORMING1
@ SPELL_CALL_FLAMES
@ SPELL_RITUAL_DISARM
@ SPELL_RITUAL_CHANNELER_3
@ SPELL_SVALA_TRANSFORMING2
@ SPELL_RITUAL_OF_THE_SWORD
@ SPELL_PARALYZE
@ SPELL_RITUAL_STRIKE_EFF_1
@ SPELL_MIGHTY_BLOW
@ SPELL_VOLATILE_INFECTION
@ SPELL_RITUAL_STRIKE_EFF_2
@ SPELL_RITUAL_CHANNELER_2
SvalaPhase
@ SACRIFICING
@ INTRO
@ NORMAL
@ SVALADEAD
@ IDLE
AchievementCriteriaScript(const char *name)
void Talk(uint8 id, WorldObject const *whisperTarget=NULL)
bool UpdateVictim()
CreatureScript(const char *name)
uint64 GetGUID() const
Definition Object.h:119
RitualTargetCheck(Unit *_caster)
bool operator()(WorldObject *unit) const
Unit * GetCaster()
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
SpellScriptLoader(const char *name)
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
static Creature * GetCreature(WorldObject &object, uint64 guid)
Definition Unit.cpp:4905
InstanceScript * GetInstanceScript()
Definition Object.cpp:1612
bool OnCheck(Player *, Unit *target) 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 FilterTargets(std::list< WorldObject * > &unitList)
PrepareSpellScript(spell_paralyze_pinnacle_SpellScript)
SpellScript * GetSpellScript() const OVERRIDE
bool IsHeroic() const
void SetEquipmentSlots(bool loadDefault, int32 mainHand=EQUIP_NO_CHANGE, int32 offHand=EQUIP_NO_CHANGE, int32 ranged=EQUIP_NO_CHANGE)
void SetCombatMovement(bool allowMovement)
Creature * me
bool HealthBelowPct(uint32 pct) const
ScriptedAI(Creature *creature)
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void JustDied(Unit *) OVERRIDE
void KilledUnit(Unit *victim) OVERRIDE
void JustSummoned(Creature *summon) OVERRIDE
void EnterCombat(Unit *) OVERRIDE
boss_svalaAI(Creature *creature)
InstanceScript * instance
void MoveInLineOfSight(Unit *who) OVERRIDE
void SpellHitTarget(Unit *, const SpellInfo *spell) OVERRIDE
void SummonedCreatureDespawn(Creature *summon) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
uint32 GetData(uint32 type) const OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void DamageTaken(Unit *attacker, uint32 &damage) OVERRIDE
void MovementInform(uint32 motionType, uint32 pointId) OVERRIDE
npc_spectatorAI(Creature *creature)
@ DATA_SACRIFICED_PLAYER
@ DATA_SVALA_SORROWGRAVE_EVENT