Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_shade_of_aran.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_Shade_of_Aran
8SD%Complete: 95
9SDComment: Flame wreath missing cast animation, mods won't triggere.
10SDCategory: Karazhan
11EndScriptData */
12
13#include "ScriptMgr.h"
14#include "ScriptedCreature.h"
15#include "karazhan.h"
16#include "GameObject.h"
17#include "SpellInfo.h"
18
61
68
70{
71public:
72 boss_shade_of_aran() : CreatureScript("boss_shade_of_aran") { }
73
75 {
76 return new boss_aranAI(creature);
77 }
78
79 struct boss_aranAI : public ScriptedAI
80 {
81 boss_aranAI(Creature* creature) : ScriptedAI(creature)
82 {
83 instance = creature->GetInstanceScript();
84 }
85
87
92 uint32 CloseDoorTimer; // Don't close the door right on aggro in case some people are still entering.
93
95
99 float FWTargPosX[3];
100 float FWTargPosY[3];
101
106
108
112
114 {
115 SecondarySpellTimer = 5000;
116 NormalCastTimer = 0;
117 SuperCastTimer = 35000;
118 BerserkTimer = 720000;
119 CloseDoorTimer = 15000;
120
121 LastSuperSpell = rand()%3;
122
125
127 ArcaneCooldown = 0;
128 FireCooldown = 0;
129 FrostCooldown = 0;
130
131 DrinkInterruptTimer = 10000;
132
133 ElementalsSpawned = false;
134 Drinking = false;
135 DrinkInturrupted = false;
136
137 if (instance)
138 {
139 // Not in progress
140 instance->SetData(TYPE_ARAN, NOT_STARTED);
141 instance->HandleGameObject(instance->GetData64(DATA_GO_LIBRARY_DOOR), true);
142 }
143 }
144
145 void KilledUnit(Unit* /*victim*/) OVERRIDE
146 {
147 Talk(SAY_KILL);
148 }
149
150 void JustDied(Unit* /*killer*/) OVERRIDE
151 {
153
154 if (instance)
155 {
156 instance->SetData(TYPE_ARAN, DONE);
157 instance->HandleGameObject(instance->GetData64(DATA_GO_LIBRARY_DOOR), true);
158 }
159 }
160
161 void EnterCombat(Unit* /*who*/) OVERRIDE
162 {
164
165 if (instance)
166 {
167 instance->SetData(TYPE_ARAN, IN_PROGRESS);
168 instance->HandleGameObject(instance->GetData64(DATA_GO_LIBRARY_DOOR), false);
169 }
170 }
171
173 {
174 std::vector<Unit*> targets;
175 ThreatContainer::StorageType const &t_list = me->getThreatManager().getThreatList();
176
177 if (t_list.empty())
178 return;
179
180 //store the threat list in a different container
181 for (ThreatContainer::StorageType::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr)
182 {
183 Unit* target = Unit::GetUnit(*me, (*itr)->getUnitGuid());
184 //only on alive players
185 if (target && target->IsAlive() && target->GetTypeId() == TypeID::TYPEID_PLAYER)
186 targets.push_back(target);
187 }
188
189 //cut down to size if we have more than 3 targets
190 while (targets.size() > 3)
191 targets.erase(targets.begin()+rand()%targets.size());
192
193 uint32 i = 0;
194 for (std::vector<Unit*>::const_iterator itr = targets.begin(); itr!= targets.end(); ++itr)
195 {
196 if (*itr)
197 {
198 FlameWreathTarget[i] = (*itr)->GetGUID();
199 FWTargPosX[i] = (*itr)->GetPositionX();
200 FWTargPosY[i] = (*itr)->GetPositionY();
201 DoCast((*itr), SPELL_FLAME_WREATH, true);
202 ++i;
203 }
204 }
205 }
206
208 {
209 if (!UpdateVictim())
210 return;
211
212 if (CloseDoorTimer)
213 {
214 if (CloseDoorTimer <= diff)
215 {
216 if (instance)
217 {
218 instance->HandleGameObject(instance->GetData64(DATA_GO_LIBRARY_DOOR), false);
219 CloseDoorTimer = 0;
220 }
221 } else CloseDoorTimer -= diff;
222 }
223
224 //Cooldowns for casts
225 if (ArcaneCooldown)
226 {
227 if (ArcaneCooldown >= diff)
228 ArcaneCooldown -= diff;
229 else ArcaneCooldown = 0;
230 }
231
232 if (FireCooldown)
233 {
234 if (FireCooldown >= diff)
235 FireCooldown -= diff;
236 else FireCooldown = 0;
237 }
238
239 if (FrostCooldown)
240 {
241 if (FrostCooldown >= diff)
242 FrostCooldown -= diff;
243 else FrostCooldown = 0;
244 }
245
246 if (!Drinking && me->GetMaxPower(POWER_MANA) && (me->GetPower(POWER_MANA)*100 / me->GetMaxPower(POWER_MANA)) < 20)
247 {
248 Drinking = true;
249 me->InterruptNonMeleeSpells(false);
250
252
253 if (!DrinkInturrupted)
254 {
255 DoCast(me, SPELL_MASS_POLY, true);
256 DoCast(me, SPELL_CONJURE, false);
257 DoCast(me, SPELL_DRINK, false);
258 me->SetStandState(UNIT_STAND_STATE_SIT);
259 DrinkInterruptTimer = 10000;
260 }
261 }
262
263 //Drink Interrupt
265 {
266 Drinking = false;
267 me->RemoveAurasDueToSpell(SPELL_DRINK);
268 me->SetStandState(UNIT_STAND_STATE_STAND);
269 me->SetPower(POWER_MANA, me->GetMaxPower(POWER_MANA)-32000);
270 DoCast(me, SPELL_POTION, false);
271 }
272
273 //Drink Interrupt Timer
275 {
276 if (DrinkInterruptTimer >= diff)
277 DrinkInterruptTimer -= diff;
278 else
279 {
280 me->SetStandState(UNIT_STAND_STATE_STAND);
281 DoCast(me, SPELL_POTION, true);
283 DrinkInturrupted = true;
284 Drinking = false;
285 }
286 }
287
288 //Don't execute any more code if we are drinking
289 if (Drinking)
290 return;
291
292 //Normal casts
293 if (NormalCastTimer <= diff)
294 {
295 if (!me->IsNonMeleeSpellCasted(false))
296 {
297 Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true);
298 if (!target)
299 return;
300
301 uint32 Spells[3];
302 uint8 AvailableSpells = 0;
303
304 //Check for what spells are not on cooldown
305 if (!ArcaneCooldown)
306 {
307 Spells[AvailableSpells] = SPELL_ARCMISSLE;
308 ++AvailableSpells;
309 }
310 if (!FireCooldown)
311 {
312 Spells[AvailableSpells] = SPELL_FIREBALL;
313 ++AvailableSpells;
314 }
315 if (!FrostCooldown)
316 {
317 Spells[AvailableSpells] = SPELL_FROSTBOLT;
318 ++AvailableSpells;
319 }
320
321 //If no available spells wait 1 second and try again
322 if (AvailableSpells)
323 {
324 CurrentNormalSpell = Spells[rand() % AvailableSpells];
325 DoCast(target, CurrentNormalSpell);
326 }
327 }
328 NormalCastTimer = 1000;
329 } else NormalCastTimer -= diff;
330
331 if (SecondarySpellTimer <= diff)
332 {
333 switch (std::rand() % 1)
334 {
335 case 0:
337 break;
338 case 1:
339 if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
340 DoCast(target, SPELL_CHAINSOFICE);
341 break;
342 }
343 SecondarySpellTimer = std::rand() % 20000 + 5000;
344 } else SecondarySpellTimer -= diff;
345
346 if (SuperCastTimer <= diff)
347 {
348 uint8 Available[2];
349
350 switch (LastSuperSpell)
351 {
352 case SUPER_AE:
353 Available[0] = SUPER_FLAME;
354 Available[1] = SUPER_BLIZZARD;
355 break;
356 case SUPER_FLAME:
357 Available[0] = SUPER_AE;
358 Available[1] = SUPER_BLIZZARD;
359 break;
360 case SUPER_BLIZZARD:
361 Available[0] = SUPER_FLAME;
362 Available[1] = SUPER_AE;
363 break;
364 }
365
366 LastSuperSpell = Available[std::rand() % 1];
367
368 switch (LastSuperSpell)
369 {
370 case SUPER_AE:
372
374 DoCast(me, SPELL_PLAYERPULL, true);
375 DoCast(me, SPELL_MASSSLOW, true);
376 DoCast(me, SPELL_AEXPLOSION, false);
377 break;
378
379 case SUPER_FLAME:
381
382 FlameWreathTimer = 20000;
384
385 FlameWreathTarget[0] = 0;
386 FlameWreathTarget[1] = 0;
387 FlameWreathTarget[2] = 0;
388
390 break;
391
392 case SUPER_BLIZZARD:
394
395 if (Creature* pSpawn = me->SummonCreature(CREATURE_ARAN_BLIZZARD, 0.0f, 0.0f, 0.0f, 0.0f, TempSummonType::TEMPSUMMON_TIMED_DESPAWN, 25000))
396 {
397 pSpawn->setFaction(me->getFaction());
398 pSpawn->CastSpell(pSpawn, SPELL_CIRCULAR_BLIZZARD, false);
399 }
400 break;
401 }
402
403 SuperCastTimer = std::rand() % 40000 + 35000;
404 } else SuperCastTimer -= diff;
405
407 {
408 ElementalsSpawned = true;
409
410 for (uint32 i = 0; i < 4; ++i)
411 {
412 if (Creature* unit = me->SummonCreature(CREATURE_WATER_ELEMENTAL, 0.0f, 0.0f, 0.0f, 0.0f, TempSummonType::TEMPSUMMON_TIMED_DESPAWN, 90000))
413 {
414 unit->Attack(me->GetVictim(), true);
415 unit->setFaction(me->getFaction());
416 }
417 }
418
420 }
421
422 if (BerserkTimer <= diff)
423 {
424 for (uint32 i = 0; i < 5; ++i)
425 {
426 if (Creature* unit = me->SummonCreature(CREATURE_SHADOW_OF_ARAN, 0.0f, 0.0f, 0.0f, 0.0f, TempSummonType::TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5000))
427 {
428 unit->Attack(me->GetVictim(), true);
429 unit->setFaction(me->getFaction());
430 }
431 }
432
434
435 BerserkTimer = 60000;
436 } else BerserkTimer -= diff;
437
438 //Flame Wreath check
440 {
441 if (FlameWreathTimer >= diff)
442 FlameWreathTimer -= diff;
443 else FlameWreathTimer = 0;
444
445 if (FlameWreathCheckTime <= diff)
446 {
447 for (uint8 i = 0; i < 3; ++i)
448 {
449 if (!FlameWreathTarget[i])
450 continue;
451
453 if (unit && !unit->IsWithinDist2d(FWTargPosX[i], FWTargPosY[i], 3))
454 {
455 unit->CastSpell(unit, 20476, true, 0, 0, me->GetGUID());
456 unit->CastSpell(unit, 11027, true);
457 FlameWreathTarget[i] = 0;
458 }
459 }
461 } else FlameWreathCheckTime -= diff;
462 }
463
466 }
467
468 void DamageTaken(Unit* /*pAttacker*/, uint32 &damage) OVERRIDE
469 {
470 if (!DrinkInturrupted && Drinking && damage)
471 DrinkInturrupted = true;
472 }
473
474 void SpellHit(Unit* /*pAttacker*/, const SpellInfo* Spell) OVERRIDE
475 {
476 //We only care about interrupt effects and only if they are durring a spell currently being casted
477 if ((Spell->Effects[0].Effect != SPELL_EFFECT_INTERRUPT_CAST &&
478 Spell->Effects[1].Effect != SPELL_EFFECT_INTERRUPT_CAST &&
479 Spell->Effects[2].Effect != SPELL_EFFECT_INTERRUPT_CAST) || !me->IsNonMeleeSpellCasted(false))
480 return;
481
482 //Interrupt effect
483 me->InterruptNonMeleeSpells(false);
484
485 //Normally we would set the cooldown equal to the spell duration
486 //but we do not have access to the DurationStore
487
488 switch (CurrentNormalSpell)
489 {
490 case SPELL_ARCMISSLE: ArcaneCooldown = 5000; break;
491 case SPELL_FIREBALL: FireCooldown = 5000; break;
492 case SPELL_FROSTBOLT: FrostCooldown = 5000; break;
493 }
494 }
495 };
496};
497
499{
500public:
501 npc_aran_elemental() : CreatureScript("npc_aran_elemental") { }
502
504 {
505 return new water_elementalAI(creature);
506 }
507
509 {
510 water_elementalAI(Creature* creature) : ScriptedAI(creature) { }
511
513
515 {
516 CastTimer = 2000 + (rand()%3000);
517 }
518
519 void EnterCombat(Unit* /*who*/) OVERRIDE { }
520
522 {
523 if (!UpdateVictim())
524 return;
525
526 if (CastTimer <= diff)
527 {
529 CastTimer = std::rand() % 5000 + 2000;
530 } else CastTimer -= diff;
531 }
532 };
533};
534
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_DESPAWN_OUT_OF_COMBAT
Definition Object.h:71
@ TEMPSUMMON_TIMED_DESPAWN
Definition Object.h:70
@ POWER_MANA
@ SPELL_EFFECT_INTERRUPT_CAST
@ UNIT_STAND_STATE_STAND
Definition Unit.h:162
@ UNIT_STAND_STATE_SIT
Definition Unit.h:163
@ SELECT_TARGET_RANDOM
Definition UnitAI.h:23
@ SPELL_WATERBOLT
@ SPELL_FROSTBOLT
@ SPELL_FIREBALL
#define SAY_DEATH
#define SAY_AGGRO
#define SAY_KILL
void AddSC_boss_shade_of_aran()
@ SUPER_FLAME
@ SUPER_BLIZZARD
@ SPELL_CHAINSOFICE
@ SPELL_DRINK
@ SPELL_ELEMENTALS
@ SPELL_WATERBOLT
@ SPELL_FROSTBOLT
@ SPELL_ARCMISSLE
@ SPELL_PLAYERPULL
@ SPELL_AOE_CS
@ CREATURE_ARAN_BLIZZARD
@ SPELL_FLAME_WREATH
@ SPELL_FIREBALL
@ CREATURE_SHADOW_OF_ARAN
@ SAY_ELEMENTALS
@ SPELL_MASSSLOW
@ SPELL_CONJURE
@ SPELL_AOE_PYROBLAST
@ SAY_FLAMEWREATH
@ SPELL_BLINK_CENTER
@ SPELL_AEXPLOSION
@ CREATURE_WATER_ELEMENTAL
@ SAY_TIMEOVER
@ SPELL_DRAGONSBREATH
@ SAY_BLIZZARD
@ SPELL_MASS_POLY
@ SPELL_SHADOW_PYRO
@ SPELL_POTION
@ SPELL_CIRCULAR_BLIZZARD
@ SAY_EXPLOSION
void Talk(uint8 id, WorldObject const *whisperTarget=NULL)
bool UpdateVictim()
CreatureScript(const char *name)
TypeID GetTypeId() const
Definition Object.h:131
Definition Spell.h:289
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
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)
bool IsAlive() const
Definition Unit.h:2032
static Unit * GetUnit(WorldObject &object, uint64 guid)
Definition Unit.cpp:4895
bool IsWithinDist2d(float x, float y, float dist) const
Definition Object.cpp:1720
InstanceScript * GetInstanceScript()
Definition Object.cpp:1612
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
@ DATA_GO_LIBRARY_DOOR
Definition karazhan.h:33
@ TYPE_ARAN
Definition karazhan.h:17
Creature * me
bool HealthBelowPct(uint32 pct) const
ScriptedAI(Creature *creature)
void SpellHit(Unit *, const SpellInfo *Spell) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void DamageTaken(Unit *, uint32 &damage) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================