Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_skadi.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/* Script Data Start
7SDName: Boss_Skadi
8SDAuthor: LordVanMartin, JohnHoliver
9SD%Complete: 90%
10SDComment: <Known Bugs>
11 After Unmount() he appears to still be flying even with SetFlying(false)
12 </Known Bugs>
13SDCategory: Utgarde Pinnacle
14Script Data End */
15
16#include "ScriptMgr.h"
17#include "ScriptedCreature.h"
18#include "utgarde_pinnacle.h"
19#include "Player.h"
20#include "SpellInfo.h"
21
32
33static Position SpawnLoc = {468.931f, -513.555f, 104.723f, 0};
35{
36 // Boss
37 {341.740997f, -516.955017f, 104.66900f, 0}, // 0
38 {293.299f, -505.95f, 142.03f, 0}, // 1
39 {301.664f, -535.164f, 146.097f, 0}, // 2
40 {521.031006f, -544.667847f, 128.80064f, 0}, // 3
41 {477.311981f, -509.296814f, 104.72308f, 0}, // 4
42 {341.740997f, -516.955017f, 104.66900f, 0}, // 5
43 {341.740997f, -516.955017f, 104.66900f, 0}, // 6
44 {341.740997f, -516.955017f, 104.66900f, 0}, // 7
45 // Triggers Left
46 {469.661f, -484.546f, 104.712f, 0}, // 8
47 {483.315f, -485.028f, 104.718f, 0}, // 9
48 {476.87f, -487.994f, 104.735f, 0}, //10
49 {477.512f, -497.772f, 104.728f, 0}, //11
50 {486.287f, -500.759f, 104.722f, 0}, //12
51 {480.1f, -503.895f, 104.722f, 0}, //13
52 {472.391f, -505.103f, 104.723f, 0}, //14
53 {478.885f, -510.803f, 104.723f, 0}, //15
54 {489.529f, -508.615f, 104.723f, 0}, //16
55 {484.272f, -508.589f, 104.723f, 0}, //17
56 {465.328f, -506.495f, 104.427f, 0}, //18
57 {456.885f, -508.104f, 104.447f, 0}, //19
58 {450.177f, -507.989f, 105.247f, 0}, //20
59 {442.273f, -508.029f, 104.813f, 0}, //21
60 {434.225f, -508.19f, 104.787f, 0}, //22
61 {423.902f, -508.525f, 104.274f, 0}, //23
62 {414.551f, -508.645f, 105.136f, 0}, //24
63 {405.787f, -508.755f, 104.988f, 0}, //25
64 {398.812f, -507.224f, 104.82f, 0}, //26
65 {389.702f, -506.846f, 104.729f, 0}, //27
66 {381.856f, -506.76f, 104.756f, 0}, //28
67 {372.881f, -507.254f, 104.779f, 0}, //29
68 {364.978f, -508.182f, 104.673f, 0}, //30
69 {357.633f, -508.075f, 104.647f, 0}, //31
70 {350.008f, -506.826f, 104.588f, 0}, //32
71 {341.69f, -506.77f, 104.499f, 0}, //33
72 {335.31f, -505.745f, 105.18f, 0}, //34
73 {471.178f, -510.74f, 104.723f, 0}, //35
74 {461.759f, -510.365f, 104.199f, 0}, //36
75 {424.07287f, -510.082916f, 104.711082f, 0}, //37
76 // Triggers Right
77 {489.46f, -513.297f, 105.413f, 0}, //38
78 {485.706f, -517.175f, 104.724f, 0}, //39
79 {480.98f, -519.313f, 104.724f, 0}, //40
80 {475.05f, -520.52f, 104.724f, 0}, //41
81 {482.97f, -512.099f, 104.724f, 0}, //42
82 {477.082f, -514.172f, 104.724f, 0}, //43
83 {468.991f, -516.691f, 104.724f, 0}, //44
84 {461.722f, -517.063f, 104.627f, 0}, //45
85 {455.88f, -517.681f, 104.707f, 0}, //46
86 {450.499f, -519.099f, 104.701f, 0}, //47
87 {444.889f, -518.963f, 104.82f, 0}, //48
88 {440.181f, -518.893f, 104.861f, 0}, //49
89 {434.393f, -518.758f, 104.891f, 0}, //50
90 {429.328f, -518.583f, 104.904f, 0}, //51
91 {423.844f, -518.394f, 105.004f, 0}, //52
92 {418.707f, -518.266f, 105.135f, 0}, //53
93 {413.377f, -518.085f, 105.153f, 0}, //54
94 {407.277f, -517.844f, 104.893f, 0}, //55
95 {401.082f, -517.443f, 104.723f, 0}, //56
96 {394.933f, -514.64f, 104.724f, 0}, //57
97 {388.917f, -514.688f, 104.734f, 0}, //58
98 {383.814f, -515.834f, 104.73f, 0}, //59
99 {377.887f, -518.653f, 104.777f, 0}, //60
100 {371.376f, -518.289f, 104.781f, 0}, //61
101 {365.669f, -517.822f, 104.758f, 0}, //62
102 {359.572f, -517.314f, 104.706f, 0}, //63
103 {353.632f, -517.146f, 104.647f, 0}, //64
104 {347.998f, -517.038f, 104.538f, 0}, //65
105 {341.803f, -516.98f, 104.584f, 0}, //66
106 {335.879f, -516.674f, 104.628f, 0}, //67
107 {329.871f, -515.92f, 104.711f, 0}, //68
108 // Breach Zone
109 {485.4577f, -511.2515f, 115.3011f, 0}, //69
110 {435.1892f, -514.5232f, 118.6719f, 0}, //70
111 {413.9327f, -540.9407f, 138.2614f, 0}, //71
112};
113
119
121{
122 // Skadi Spells
123 SPELL_CRUSH = 50234,
124 SPELL_POISONED_SPEAR = 50225, //isn't being casted =/
125 SPELL_WHIRLWIND = 50228, //random target, but not the tank approx. every 20s
129};
130
140
145
147{
148public:
149 boss_skadi() : CreatureScript("boss_skadi") { }
150
152 {
153 return new boss_skadiAI(creature);
154 }
155
156 struct boss_skadiAI : public ScriptedAI
157 {
158 boss_skadiAI(Creature* creature) : ScriptedAI(creature), Summons(me)
159 {
160 instance = creature->GetInstanceScript();
161 m_uiGraufGUID = 0;
162 }
163
167 std::vector<uint64> triggersGUID;
168
178
180
182 {
183 triggersGUID.clear();
184
185 m_uiCrushTimer = 8000;
187 m_uiWhirlwindTimer = 20000;
188 m_uiMountTimer = 3000;
189 m_uiWaypointId = 0;
190 m_bSaidEmote = false;
192
193 Phase = SKADI;
194
195 Summons.DespawnAll();
196 me->SetSpeed(MOVE_FLIGHT, 3.0f);
197 if ((Unit::GetCreature(*me, m_uiGraufGUID) == NULL) && !me->IsMounted())
198 me->SummonCreature(NPC_GRAUF, Location[0].GetPositionX(), Location[0].GetPositionY(), Location[0].GetPositionZ(), 3.0f);
199 if (instance)
200 {
203 }
204 }
205
207 {
208 me->SetCanFly(false);
209 me->Dismount();
212 me->SummonCreature(NPC_GRAUF, Location[0].GetPositionX(), Location[0].GetPositionY(), Location[0].GetPositionZ(), 3.0f);
213 }
214
215 void EnterCombat(Unit* /*who*/) OVERRIDE
216 {
218
220
221 Phase = FLYING;
222
223 m_uiMovementTimer = 1000;
224 m_uiSummonTimer = 10000;
225 me->SetInCombatWithZone();
226 if (instance)
227 {
230 me->GetMotionMaster()->MoveJump(Location[0].GetPositionX(), Location[0].GetPositionY(), Location[0].GetPositionZ(), 5.0f, 10.0f);
231 me->SetWalk(false);
232 m_uiMountTimer = 1000;
233 Summons.DespawnEntry(NPC_GRAUF);
234 }
235 }
236
238 {
239 switch (summoned->GetEntry())
240 {
241 case NPC_GRAUF:
242 m_uiGraufGUID = summoned->GetGUID();
243 break;
247 summoned->setActive(true);
248 summoned->SetInCombatWithZone();
249 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
250 summoned->AI()->AttackStart(target);
251 break;
252 case NPC_TRIGGER:
253 summoned->CastSpell((Unit*)NULL, SPELL_FREEZING_CLOUD, true);
254 summoned->DespawnOrUnsummon(10*IN_MILLISECONDS);
255 break;
256 }
257 Summons.Summon(summoned);
258 }
259
261 {
262 if (summoned->GetEntry() == NPC_GRAUF)
263 m_uiGraufGUID = 0;
264 Summons.Despawn(summoned);
265 }
266
267 void SpellHit(Unit* /*caster*/, const SpellInfo* spell) OVERRIDE
268 {
269 if (spell->Id == SPELL_HARPOON_DAMAGE)
270 {
272 if (m_uiSpellHitCount >= 3)
273 {
274 Phase = SKADI;
275 me->SetCanFly(false);
276 me->Dismount();
277 if (Creature* pGrauf = me->SummonCreature(NPC_GRAUF, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TempSummonType::TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3*IN_MILLISECONDS))
278 {
279 pGrauf->GetMotionMaster()->MoveFall();
280 pGrauf->HandleEmoteCommand(EMOTE_ONESHOT_FLYDEATH);
281 }
282 me->GetMotionMaster()->MoveJump(Location[4].GetPositionX(), Location[4].GetPositionY(), Location[4].GetPositionZ(), 5.0f, 10.0f);
285 m_uiCrushTimer = 8000;
287 m_uiWhirlwindTimer = 20000;
288 me->AI()->AttackStart(SelectTarget(SELECT_TARGET_RANDOM));
289 }
290 }
291 }
292
294 {
295 switch (Phase)
296 {
297 case FLYING:
298 if (!UpdateVictim())
299 return;
300
301 if (me->GetPositionX() >= 519)
302 {
304 if (!m_bSaidEmote)
305 {
307 m_bSaidEmote = true;
308 }
309 }
310 else
311 {
313 m_bSaidEmote = false;
314 }
315
316 if (m_uiMountTimer && m_uiMountTimer <= diff)
317 {
318 me->Mount(DATA_MOUNT);
319 me->SetCanFly(true);
320 m_uiMountTimer = 0;
321 } else m_uiMountTimer -= diff;
322
323 if (m_uiSummonTimer <= diff)
324 {
325 SpawnMobs();
326 m_uiSummonTimer = 25000;
327 } else m_uiSummonTimer -= diff;
328
329 if (m_uiMovementTimer <= diff)
330 {
331 switch (m_uiWaypointId)
332 {
333 case 0:
334 me->GetMotionMaster()->MovePoint(0, Location[1].GetPositionX(), Location[1].GetPositionY(), Location[1].GetPositionZ());
335 m_uiMovementTimer = 5000;
336 break;
337 case 1:
338 me->GetMotionMaster()->MovePoint(0, Location[2].GetPositionX(), Location[2].GetPositionY(), Location[2].GetPositionZ());
339 m_uiMovementTimer = 2000;
340 break;
341 case 2:
342 me->GetMotionMaster()->MovePoint(0, Location[3].GetPositionX(), Location[3].GetPositionY(), Location[3].GetPositionZ());
343 m_uiMovementTimer = 15000;
344 break;
345 case 3:
346 me->GetMotionMaster()->MovePoint(0, Location[69].GetPositionX(), Location[69].GetPositionY(), Location[69].GetPositionZ());
349 m_uiMovementTimer = 2500;
350 break;
351 case 4:
352 me->GetMotionMaster()->MovePoint(0, Location[70].GetPositionX(), Location[70].GetPositionY(), Location[70].GetPositionZ());
353 m_uiMovementTimer = 2000;
354 SpawnTrigger();
355 break;
356 case 5:
357 me->GetMotionMaster()->MovePoint(0, Location[71].GetPositionX(), Location[71].GetPositionY(), Location[71].GetPositionZ());
358 m_uiMovementTimer = 3000;
359 break;
360 case 6:
361 me->GetMotionMaster()->MovePoint(0, Location[3].GetPositionX(), Location[3].GetPositionY(), Location[3].GetPositionZ());
362 m_uiWaypointId = 2;
363 m_uiMovementTimer = 15000;
364 break;
365 }
367 } else m_uiMovementTimer -= diff;
368 break;
369 case SKADI:
370 //Return since we have no target
371 if (!UpdateVictim())
372 return;
373
374 if (m_uiCrushTimer <= diff)
375 {
377 m_uiCrushTimer = 8000;
378 } else m_uiCrushTimer -= diff;
379
380 if (m_uiPoisonedSpearTimer <= diff)
381 {
385 } else m_uiPoisonedSpearTimer -= diff;
386
387 if (m_uiWhirlwindTimer <= diff)
388 {
390 m_uiWhirlwindTimer = 20000;
391 } else m_uiWhirlwindTimer -= diff;
392
394 break;
395 }
396 }
397
398 void JustDied(Unit* /*killer*/) OVERRIDE
399 {
401 Summons.DespawnAll();
402 if (instance)
404 }
405
406 void KilledUnit(Unit* /*victim*/) OVERRIDE
407 {
408 Talk(SAY_KILL);
409 }
410
412 {
413 for (uint8 i = 0; i < DUNGEON_MODE(5, 6); ++i)
414 {
415 switch (std::rand() % 2)
416 {
417 case 0:
418 me->SummonCreature(NPC_YMIRJAR_WARRIOR, SpawnLoc.GetPositionX()+rand()%5, SpawnLoc.GetPositionY()+rand()%5, SpawnLoc.GetPositionZ(), 0, TempSummonType::TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
419 break;
420
421 case 1:
422 me->SummonCreature(NPC_YMIRJAR_WITCH_DOCTOR, SpawnLoc.GetPositionX()+rand()%5, SpawnLoc.GetPositionY()+rand()%5, SpawnLoc.GetPositionZ(), 0, TempSummonType::TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
423 break;
424
425 case 2:
426 me->SummonCreature(NPC_YMIRJAR_HARPOONER, SpawnLoc.GetPositionX()+rand()%5, SpawnLoc.GetPositionY()+rand()%5, SpawnLoc.GetPositionZ(), 0, TempSummonType::TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000);
427 break;
428 }
429 }
430 }
431
433 {
434 uint8 iStart = 0, iEnd = 0;
435 switch (std::rand() % 1)
436 {
437 case 0:
438 iStart = 8;
439 iEnd = 37;
440 break;
441 case 1:
442 iStart = 38;
443 iEnd = 68;
444 break;
445 default:
446 break;
447 }
448 for (uint32 i = iStart; i < iEnd; ++i)
449 me->SummonCreature(NPC_TRIGGER, Location[i]);
450 }
451 };
452};
453
455{
456public:
457 go_harpoon_launcher() : GameObjectScript("go_harpoon_launcher") { }
458
460 {
461 InstanceScript* instance = go->GetInstanceScript();
462 if (!instance)
463 return false;
464
465 if (Creature* pSkadi = Unit::GetCreature(*go, instance->GetData64(DATA_SKADI_THE_RUTHLESS)))
466 player->CastSpell(pSkadi, SPELL_RAPID_FIRE, true);
467
468 return false;
469 }
470};
471
473{
474 new boss_skadi();
476}
@ IN_MILLISECONDS
Definition Common.h:125
@ ACHIEVEMENT_TIMED_TYPE_EVENT
Definition DBCEnums.h:158
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
@ TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT
Definition Object.h:71
@ TEMPSUMMON_CORPSE_TIMED_DESPAWN
Definition Object.h:73
@ EMOTE_ONESHOT_FLYDEATH
@ MOVE_FLIGHT
Definition Unit.h:561
@ 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
@ SPELL_WHIRLWIND
#define SAY_DEATH
#define SAY_AGGRO
#define SAY_KILL
CombatPhase
@ EMOTE_BREATH
@ NPC_YMIRJAR_WITCH_DOCTOR
@ NPC_YMIRJAR_WARRIOR
@ DATA_MOUNT
@ NPC_GRAUF
@ NPC_YMIRJAR_HARPOONER
@ NPC_TRIGGER
@ SAY_DEATH
@ EMOTE_RANGE
@ SAY_DRAKE_DEATH
@ SAY_AGGRO
@ EMOTE_BREATH
@ SAY_KILL
@ SAY_DRAKE_BREATH
Achievments
@ ACHIEV_TIMED_START_EVENT
@ SPELL_HARPOON_DAMAGE
@ SPELL_RAPID_FIRE
@ SPELL_POISONED_SPEAR
@ SPELL_WHIRLWIND
@ SPELL_FREEZING_CLOUD
@ SPELL_CRUSH
static Position SpawnLoc
void AddSC_boss_skadi()
CombatPhase
@ SKADI
@ FLYING
static Position Location[]
static Position SpawnLoc[]
@ SPELL_CRUSH
void Talk(uint8 id, WorldObject const *whisperTarget=NULL)
bool UpdateVictim()
CreatureScript(const char *name)
GameObjectScript(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
void DoCastAOE(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:176
Definition Unit.h:1367
static Creature * GetCreature(WorldObject &object, uint64 guid)
Definition Unit.cpp:4905
InstanceScript * GetInstanceScript()
Definition Object.cpp:1612
virtual uint64 GetData64(uint32) const
Definition ZoneScript.h:32
CreatureAI * GetAI(Creature *creature) const OVERRIDE
bool OnGossipHello(Player *player, GameObject *go) OVERRIDE
@ NPC_TRIGGER
@ ACHIEV_TIMED_START_EVENT
Creature * me
ScriptedAI(Creature *creature)
const T & DUNGEON_MODE(const T &normal5, const T &heroic5) const
void EnterCombat(Unit *) OVERRIDE
void JustDied(Unit *) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void KilledUnit(Unit *) OVERRIDE
boss_skadiAI(Creature *creature)
std::vector< uint64 > triggersGUID
InstanceScript * instance
void JustSummoned(Creature *summoned) OVERRIDE
void JustReachedHome() OVERRIDE
void SpellHit(Unit *, const SpellInfo *spell) OVERRIDE
void SummonedCreatureDespawn(Creature *summoned) OVERRIDE
@ DATA_SKADI_THE_RUTHLESS
@ DATA_SKADI_THE_RUTHLESS_EVENT