TrinityCore
boss_eredar_twins.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "ScriptMgr.h"
19#include "InstanceScript.h"
20#include "ScriptedCreature.h"
21#include "SpellInfo.h"
22#include "sunwell_plateau.h"
23
25{
36
46 YELL_BERSERK = 9
47};
48
50{
51 //Lady Sacrolash spells
53 SPELL_SHADOW_BLADES = 45248, //10 secs
55 SPELL_SHADOW_NOVA = 45329, //30-35 secs
56 SPELL_CONFOUNDING_BLOW = 45256, //25 secs
57
58 //Shadow Image spells
61
62 //Misc spells
63 SPELL_ENRAGE = 46587,
66
67 //Grand Warlock Alythess spells
68 SPELL_PYROGENICS = 45230, //15secs
70 SPELL_CONFLAGRATION = 45342, //30-35 secs
71 SPELL_BLAZE = 45235, //on main target every 3 secs
73 SPELL_BLAZE_SUMMON = 45236, //187366 GO
74 SPELL_BLAZE_BURN = 45246
75};
76
78{
79public:
80 boss_sacrolash() : CreatureScript("boss_sacrolash") { }
81
83 {
84 boss_sacrolashAI(Creature* creature) : ScriptedAI(creature)
85 {
86 Initialize();
87 instance = creature->GetInstanceScript();
88 }
89
91 {
92 ShadowbladesTimer = 10000;
93 ShadownovaTimer = 30000;
95 ShadowimageTimer = 20000;
96 ConflagrationTimer = 30000;
97 EnrageTimer = 360000;
98 SisterDeath = false;
99 Enraged = false;
100 }
101
103
106
113
114 void Reset() override
115 {
116 Enraged = false;
117
119 {
120 if (temp->isDead())
121 temp->Respawn();
122 else if (temp->GetVictim())
123 AddThreat(temp->GetVictim(), 0.0f);
124 }
125
126 if (!me->IsInCombat())
127 {
128 Initialize();
129 }
130
132 }
133
134 void JustEngagedWith(Unit* who) override
135 {
137
139 if (temp && temp->IsAlive() && !temp->GetVictim())
140 temp->AI()->AttackStart(who);
141
143 }
144
145 void KilledUnit(Unit* /*victim*/) override
146 {
147 if (rand32() % 4 == 0)
149 }
150
151 void JustDied(Unit* /*killer*/) override
152 {
153 // only if ALY death
154 if (SisterDeath)
155 {
157
159 }
160 else
162 }
163
164 void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
165 {
166 Unit* unitTarget = target->ToUnit();
167 if (!unitTarget)
168 return;
169
170 switch (spellInfo->Id)
171 {
177 break;
180 break;
181 }
182 }
183
184 void HandleTouchedSpells(Unit* target, uint32 TouchedType)
185 {
186 switch (TouchedType)
187 {
189 if (!target->HasAura(SPELL_DARK_FLAME))
190 {
191 if (target->HasAura(SPELL_DARK_TOUCHED))
192 {
194 target->CastSpell(target, SPELL_DARK_FLAME, true);
195 } else target->CastSpell(target, SPELL_FLAME_TOUCHED, true);
196 }
197 break;
199 if (!target->HasAura(SPELL_DARK_FLAME))
200 {
201 if (target->HasAura(SPELL_FLAME_TOUCHED))
202 {
204 target->CastSpell(target, SPELL_DARK_FLAME, true);
205 } else target->CastSpell(target, SPELL_DARK_TOUCHED, true);
206 }
207 break;
208 }
209 }
210
211 void UpdateAI(uint32 diff) override
212 {
213 if (!SisterDeath)
214 {
216 if (Temp && Temp->isDead())
217 {
221 SisterDeath = true;
222 }
223 }
224
225 if (!UpdateVictim())
226 return;
227
228 if (SisterDeath)
229 {
230 if (ConflagrationTimer <= diff)
231 {
232 if (!me->IsNonMeleeSpellCast(false))
233 {
237 ConflagrationTimer = 30000 + (rand32() % 5000);
238 }
239 } else ConflagrationTimer -= diff;
240 }
241 else
242 {
243 if (ShadownovaTimer <= diff)
244 {
245 if (!me->IsNonMeleeSpellCast(false))
246 {
248 if (target)
249 DoCast(target, SPELL_SHADOW_NOVA);
250
251 if (!SisterDeath)
252 {
253 if (target)
254 Talk(EMOTE_SHADOW_NOVA, target);
256 }
257 ShadownovaTimer = 30000 + (rand32() % 5000);
258 }
259 } else ShadownovaTimer -=diff;
260 }
261
262 if (ConfoundingblowTimer <= diff)
263 {
264 if (!me->IsNonMeleeSpellCast(false))
265 {
268 ConfoundingblowTimer = 20000 + (rand32() % 5000);
269 }
270 } else ConfoundingblowTimer -=diff;
271
272 if (ShadowimageTimer <= diff)
273 {
274 Unit* target = nullptr;
275 Creature* temp = nullptr;
276 for (uint8 i = 0; i<3; ++i)
277 {
280 if (temp && target)
281 {
282 AddThreat(target, 1000000.0f, temp); //don't change target(healers)
283 temp->AI()->AttackStart(target);
284 }
285 }
286 ShadowimageTimer = 20000;
287 } else ShadowimageTimer -=diff;
288
289 if (ShadowbladesTimer <= diff)
290 {
291 if (!me->IsNonMeleeSpellCast(false))
292 {
294 ShadowbladesTimer = 10000;
295 }
296 } else ShadowbladesTimer -=diff;
297
298 if (EnrageTimer < diff && !Enraged)
299 {
303 Enraged = true;
304 } else EnrageTimer -= diff;
305
306 if (me->isAttackReady() && !me->IsNonMeleeSpellCast(false))
307 {
308 //If we are within range melee the target
310 {
312 }
313 }
314 }
315 };
316
317 CreatureAI* GetAI(Creature* creature) const override
318 {
319 return GetSunwellPlateauAI<boss_sacrolashAI>(creature);
320 };
321};
322
324{
325public:
326 boss_alythess() : CreatureScript("boss_alythess") { }
327
329 {
330 boss_alythessAI(Creature* creature) : ScriptedAI(creature)
331 {
332 Initialize();
333 SetCombatMovement(false);
334
335 instance = creature->GetInstanceScript();
336 IntroStepCounter = 10;
337 }
338
340 {
341 ConflagrationTimer = 45000;
342 BlazeTimer = 100;
343 PyrogenicsTimer = 15000;
344 ShadownovaTimer = 40000;
345 EnrageTimer = 360000;
346 FlamesearTimer = 15000;
347 IntroYellTimer = 10000;
348
349 SisterDeath = false;
350 Enraged = false;
351 }
352
354
357
360
367
368 void Reset() override
369 {
370 Enraged = false;
371
373 {
374 if (temp->isDead())
375 temp->Respawn();
376 else if (temp->GetVictim())
377 AddThreat(temp->GetVictim(), 0.0f);
378 }
379
380 if (!me->IsInCombat())
381 {
382 Initialize();
383 }
384
386 }
387
388 void JustEngagedWith(Unit* who) override
389 {
391
393 if (temp && temp->IsAlive() && !temp->GetVictim())
394 temp->AI()->AttackStart(who);
395
397 }
398
399 void AttackStart(Unit* who) override
400 {
401 if (!me->IsInCombat())
403 }
404
405 void MoveInLineOfSight(Unit* who) override
406 {
407 if (!who || me->GetVictim())
408 return;
409
410 if (me->CanCreatureAttack(who))
411 {
412 float attackRadius = me->GetAttackDistance(who);
413 if (me->IsWithinDistInMap(who, attackRadius) && me->GetDistanceZ(who) <= CREATURE_Z_ATTACK_RANGE && me->IsWithinLOSInMap(who))
414 {
415 if (!me->IsInCombat())
416 {
418 }
419 }
420 }
421 else if (IntroStepCounter == 10 && me->IsWithinLOSInMap(who)&& me->IsWithinDistInMap(who, 30))
423 }
424
425 void KilledUnit(Unit* /*victim*/) override
426 {
427 if (rand32() % 4 == 0)
429 }
430
431 void JustDied(Unit* /*killer*/) override
432 {
433 if (SisterDeath)
434 {
437 }
438 else
440 }
441
442 void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
443 {
444 Unit* unitTarget = target->ToUnit();
445 if (!unitTarget)
446 return;
447
448 switch (spellInfo->Id)
449 {
450 case SPELL_BLAZE:
451 target->CastSpell(unitTarget, SPELL_BLAZE_SUMMON, true);
452 break;
454 case SPELL_FLAME_SEAR:
456 break;
459 break;
460 }
461 }
462
463 void HandleTouchedSpells(Unit* target, uint32 TouchedType)
464 {
465 switch (TouchedType)
466 {
468 if (!target->HasAura(SPELL_DARK_FLAME))
469 {
470 if (target->HasAura(SPELL_DARK_TOUCHED))
471 {
473 target->CastSpell(target, SPELL_DARK_FLAME, true);
474 }
475 else
476 target->CastSpell(target, SPELL_FLAME_TOUCHED, true);
477 }
478 break;
480 if (!target->HasAura(SPELL_DARK_FLAME))
481 {
482 if (target->HasAura(SPELL_FLAME_TOUCHED))
483 {
485 target->CastSpell(target, SPELL_DARK_FLAME, true);
486 }
487 else
488 target->CastSpell(target, SPELL_DARK_TOUCHED, true);
489 }
490 break;
491 }
492 }
493
495 {
497 switch (step)
498 {
499 case 0:
500 return 0;
501 case 1:
502 if (Sacrolash)
503 Sacrolash->AI()->Talk(YELL_INTRO_SAC_1);
504 return 1000;
505 case 2:
507 return 1000;
508 case 3:
509 if (Sacrolash)
510 Sacrolash->AI()->Talk(YELL_INTRO_SAC_3);
511 return 2000;
512 case 4:
514 return 1000;
515 case 5:
516 if (Sacrolash)
517 Sacrolash->AI()->Talk(YELL_INTRO_SAC_5);
518 return 2000;
519 case 6:
521 return 1000;
522 case 7:
523 if (Sacrolash)
524 Sacrolash->AI()->Talk(YELL_INTRO_SAC_7);
525 return 3000;
526 case 8:
528 return 900000;
529 }
530 return 10000;
531 }
532
533 void UpdateAI(uint32 diff) override
534 {
535 if (IntroStepCounter < 9)
536 {
537 if (IntroYellTimer <= diff)
538 {
540 } else IntroYellTimer -= diff;
541 }
542
543 if (!SisterDeath)
544 {
546 if (Temp && Temp->isDead())
547 {
551 SisterDeath = true;
552 }
553 }
554 if (!me->GetVictim())
555 {
557 if (sisiter && !sisiter->isDead() && sisiter->GetVictim())
558 {
559 AddThreat(sisiter->GetVictim(), 0.0f);
560 DoStartNoMovement(sisiter->GetVictim());
561 me->Attack(sisiter->GetVictim(), false);
562 }
563 }
564
565 if (!UpdateVictim())
566 return;
567
568 if (SisterDeath)
569 {
570 if (ShadownovaTimer <= diff)
571 {
572 if (!me->IsNonMeleeSpellCast(false))
573 {
575 DoCast(target, SPELL_SHADOW_NOVA);
576 ShadownovaTimer = 30000 + (rand32() % 5000);
577 }
578 } else ShadownovaTimer -=diff;
579 }
580 else
581 {
582 if (ConflagrationTimer <= diff)
583 {
584 if (!me->IsNonMeleeSpellCast(false))
585 {
588 if (target)
590 ConflagrationTimer = 30000 + (rand32() % 5000);
591
592 if (!SisterDeath)
593 {
594 if (target)
595 Talk(EMOTE_CONFLAGRATION, target);
597 }
598
599 BlazeTimer = 4000;
600 }
601 } else ConflagrationTimer -= diff;
602 }
603
604 if (FlamesearTimer <= diff)
605 {
606 if (!me->IsNonMeleeSpellCast(false))
607 {
609 FlamesearTimer = 15000;
610 }
611 } else FlamesearTimer -=diff;
612
613 if (PyrogenicsTimer <= diff)
614 {
615 if (!me->IsNonMeleeSpellCast(false))
616 {
617 DoCast(me, SPELL_PYROGENICS, true);
618 PyrogenicsTimer = 15000;
619 }
620 } else PyrogenicsTimer -= diff;
621
622 if (BlazeTimer <= diff)
623 {
624 if (!me->IsNonMeleeSpellCast(false))
625 {
627 BlazeTimer = 3800;
628 }
629 } else BlazeTimer -= diff;
630
631 if (EnrageTimer < diff && !Enraged)
632 {
636 Enraged = true;
637 } else EnrageTimer -= diff;
638 }
639 };
640
641 CreatureAI* GetAI(Creature* creature) const override
642 {
643 return GetSunwellPlateauAI<boss_alythessAI>(creature);
644 };
645};
646
648{
649public:
650 npc_shadow_image() : CreatureScript("npc_shadow_image") { }
651
652 CreatureAI* GetAI(Creature* creature) const override
653 {
654 return GetSunwellPlateauAI<npc_shadow_imageAI>(creature);
655 };
656
658 {
660 {
661 Initialize();
662 }
663
665 {
666 ShadowfuryTimer = 5000 + (rand32() % 15000);
667 DarkstrikeTimer = 3000;
668 KillTimer = 15000;
669 }
670
674
675 void Reset() override
676 {
677 Initialize();
678 }
679
680 void JustEngagedWith(Unit* /*who*/) override { }
681
682 void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
683 {
684 Unit* unitTarget = target->ToUnit();
685 if (!unitTarget)
686 return;
687
688 switch (spellInfo->Id)
689 {
692 if (!unitTarget->HasAura(SPELL_DARK_FLAME))
693 {
694 if (unitTarget->HasAura(SPELL_FLAME_TOUCHED))
695 {
697 unitTarget->CastSpell(unitTarget, SPELL_DARK_FLAME, true);
698 }
699 else
700 unitTarget->CastSpell(unitTarget, SPELL_DARK_TOUCHED, true);
701 }
702 break;
703 }
704 }
705
706 void UpdateAI(uint32 diff) override
707 {
710
711 if (KillTimer <= diff)
712 {
713 me->KillSelf();
714 KillTimer = 9999999;
715 } else KillTimer -= diff;
716
717 if (!UpdateVictim())
718 return;
719
720 if (ShadowfuryTimer <= diff)
721 {
723 ShadowfuryTimer = 10000;
724 } else ShadowfuryTimer -=diff;
725
726 if (DarkstrikeTimer <= diff)
727 {
728 if (!me->IsNonMeleeSpellCast(false))
729 {
730 //If we are within range melee the target
733 }
734 DarkstrikeTimer = 3000;
735 } else DarkstrikeTimer -= diff;
736 }
737 };
738};
739
741{
742 new boss_sacrolash();
743 new boss_alythess();
744 new npc_shadow_image();
745}
#define CREATURE_Z_ATTACK_RANGE
Definition: Creature.h:52
uint8_t uint8
Definition: Define.h:144
uint32_t uint32
Definition: Define.h:142
@ IN_PROGRESS
@ DONE
@ NOT_STARTED
@ TEMPSUMMON_CORPSE_DESPAWN
Definition: ObjectDefines.h:67
Spells
Definition: PlayerAI.cpp:32
uint32 rand32()
Definition: Random.cpp:70
@ UNIT_DYNFLAG_LOOTABLE
@ CURRENT_GENERIC_SPELL
Definition: Unit.h:590
Quotes
@ YELL_SHADOW_NOVA
@ YELL_INTRO_ALY_2
@ YELL_SAC_KILL
@ YELL_INTRO_ALY_6
@ YELL_ENRAGE
@ EMOTE_CONFLAGRATION
@ YELL_ALY_KILL
@ YELL_INTRO_SAC_1
@ YELL_SAC_DEAD
@ YELL_INTRO_SAC_5
@ YELL_INTRO_ALY_8
@ YELL_BERSERK
@ YELL_ALY_DEAD
@ YELL_SISTER_SACROLASH_DEAD
@ YELL_CANFLAGRATION
@ YELL_SISTER_ALYTHESS_DEAD
@ YELL_INTRO_SAC_3
@ EMOTE_SHADOW_NOVA
@ YELL_INTRO_ALY_4
@ YELL_INTRO_SAC_7
void AddSC_boss_eredar_twins()
@ SPELL_EMPOWER
@ SPELL_CONFOUNDING_BLOW
@ SPELL_FLAME_TOUCHED
@ SPELL_SHADOW_BLADES
@ SPELL_ENRAGE
@ SPELL_BLAZE_BURN
@ SPELL_CONFLAGRATION
@ SPELL_PYROGENICS
@ SPELL_BLAZE_SUMMON
@ SPELL_SHADOW_FURY
@ SPELL_IMAGE_VISUAL
@ SPELL_SHADOW_NOVA
@ SPELL_DARK_FLAME
@ SPELL_BLAZE
@ SPELL_DARK_STRIKE
@ SPELL_DARK_TOUCHED
@ SPELL_FLAME_SEAR
void DoZoneInCombat()
Definition: CreatureAI.h:161
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
Definition: CreatureAI.cpp:56
bool UpdateVictim()
Definition: CreatureAI.cpp:245
void AttackStart(Unit *victim) override
== Triggered Actions Requested ==================
Definition: CreatureAI.cpp:328
Creature *const me
Definition: CreatureAI.h:61
float GetAttackDistance(Unit const *player) const
Definition: Creature.cpp:2153
bool CanCreatureAttack(Unit const *victim, bool force=true) const
Definition: Creature.cpp:2686
CreatureAI * AI() const
Definition: Creature.h:214
virtual bool SetBossState(uint32 id, EncounterState state)
Creature * GetCreature(uint32 type)
static Unit * ToUnit(Object *o)
Definition: Object.h:225
void RemoveDynamicFlag(uint32 flag)
Definition: Object.h:170
uint32 const Id
Definition: SpellInfo.h:325
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition: UnitAI.cpp:180
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition: UnitAI.cpp:79
SpellCastResult DoCast(uint32 spellId)
Definition: UnitAI.cpp:89
Definition: Unit.h:627
bool IsWithinMeleeRange(Unit const *obj) const
Definition: Unit.h:699
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition: Unit.cpp:3059
bool IsAlive() const
Definition: Unit.h:1164
bool Attack(Unit *victim, bool meleeAttack)
Definition: Unit.cpp:5670
Unit * GetVictim() const
Definition: Unit.h:715
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4664
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition: Unit.h:690
void KillSelf(bool durabilityLoss=true, bool skipSettingDeathState=false)
Definition: Unit.h:921
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3831
bool IsInCombat() const
Definition: Unit.h:1043
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true)
Definition: Unit.cpp:3017
bool isDead() const
Definition: Unit.h:1166
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1042
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition: Object.cpp:1181
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1147
float GetDistanceZ(WorldObject const *obj) const
Definition: Object.cpp:1048
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
void DoStartNoMovement(Unit *target)
void AttackStart(Unit *) override
== Triggered Actions Requested ==================
void SetCombatMovement(bool allowMovement)
Creature * DoSpawnCreature(uint32 entry, float offsetX, float offsetY, float offsetZ, float angle, uint32 type, Milliseconds despawntime)
void AddThreat(Unit *victim, float amount, Unit *who=nullptr)
void SpellHitTarget(WorldObject *target, SpellInfo const *spellInfo) override
void HandleTouchedSpells(Unit *target, uint32 TouchedType)
void JustEngagedWith(Unit *who) override
void MoveInLineOfSight(Unit *who) override
void UpdateAI(uint32 diff) override
void AttackStart(Unit *who) override
== Triggered Actions Requested ==================
void SpellHitTarget(WorldObject *target, SpellInfo const *spellInfo) override
void JustEngagedWith(Unit *who) override
void UpdateAI(uint32 diff) override
void HandleTouchedSpells(Unit *target, uint32 TouchedType)
void SpellHitTarget(WorldObject *target, SpellInfo const *spellInfo) override
@ DATA_EREDAR_TWINS
@ DATA_ALYTHESS
@ DATA_SACROLASH
@ NPC_SHADOW_IMAGE