TrinityCore
Loading...
Searching...
No Matches
boss_emerald_dragons.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 "ObjectMgr.h"
19#include "MotionMaster.h"
20#include "PassiveAI.h"
21#include "ScriptedCreature.h"
22#include "ScriptMgr.h"
23#include "Spell.h"
24#include "SpellAuraEffects.h"
25#include "SpellScript.h"
26
27//
28// Emerald Dragon NPCs and IDs (kept here for reference)
29//
30
39
40//
41// Emerald Dragon Spells (used for the dragons)
42//
43
45{
46 SPELL_TAIL_SWEEP = 15847, // tail sweep - slap everything behind dragon (2 seconds interval)
47 SPELL_SUMMON_PLAYER = 24776, // teleport highest threat player in front of dragon if wandering off
48 SPELL_DREAM_FOG = 24777, // auraspell for Dream Fog NPC (15224)
49 SPELL_SLEEP = 24778, // sleep triggerspell (used for Dream Fog)
50 SPELL_SEEPING_FOG_LEFT = 24813, // dream fog - summon left
51 SPELL_SEEPING_FOG_RIGHT = 24814, // dream fog - summon right
53 SPELL_MARK_OF_NATURE = 25040, // Mark of Nature trigger (applied on target death - 15 minutes of being suspectible to Aura Of Nature)
54 SPELL_MARK_OF_NATURE_AURA = 25041, // Mark of Nature (passive marker-test, ticks every 10 seconds from boss, triggers spellID 25042 (scripted)
55 SPELL_AURA_OF_NATURE = 25043, // Stun for 2 minutes (used when SPELL_MARK_OF_NATURE exists on the target)
56};
57
58//
59// Emerald Dragon Eventlists (shared and specials)
60//
61
84
85/*
86 * ---
87 * --- Emerald Dragons : Base AI-structure used for all the Emerald dragons
88 * ---
89 */
90
92{
93 emerald_dragonAI(Creature* creature) : WorldBossAI(creature)
94 {
95 }
96
107
108 // Target killed during encounter, mark them as suspectible for Aura Of Nature
109 void KilledUnit(Unit* who) override
110 {
111 if (who->GetTypeId() == TYPEID_PLAYER)
112 who->CastSpell(who, SPELL_MARK_OF_NATURE, true);
113 }
114
115 // Execute and reschedule base events shared between all Emerald Dragons
116 void ExecuteEvent(uint32 eventId) override
117 {
118 switch (eventId)
119 {
121 // Seeping Fog appears only as "pairs", and only ONE pair at any given time!
122 // Despawntime is 2 minutes, so reschedule it for new cast after 2 minutes + a minor "random time" (30 seconds at max)
126 break;
128 // Noxious Breath is cast on random intervals, no less than 7.5 seconds between
131 break;
132 case EVENT_TAIL_SWEEP:
133 // Tail Sweep is cast every two seconds, no matter what goes on in front of the dragon
136 break;
137 }
138 }
139
140 void UpdateAI(uint32 diff) override
141 {
142 if (!UpdateVictim())
143 return;
144
145 events.Update(diff);
146
148 return;
149
150 while (uint32 eventId = events.ExecuteEvent())
151 {
152 ExecuteEvent(eventId);
153
155 return;
156 }
157
158 if (Unit* target = SelectTarget(SelectTargetMethod::MaxThreat, 0, -50.0f, true))
160
162 }
163};
164
165/*
166 * --- NPC: Dream Fog
167 */
168
170{
171 public:
172 npc_dream_fog() : CreatureScript("npc_dream_fog") { }
173
175 {
176 npc_dream_fogAI(Creature* creature) : ScriptedAI(creature)
177 {
178 Initialize();
179 }
180
182 {
183 _roamTimer = 0;
184 }
185
186 void Reset() override
187 {
188 Initialize();
189 }
190
191 void UpdateAI(uint32 diff) override
192 {
193 if (!UpdateVictim())
194 return;
195
196 if (!_roamTimer)
197 {
198 // Chase target, but don't attack - otherwise just roam around
199 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 0.0f, true))
200 {
201 _roamTimer = urand(15000, 30000);
203 me->GetMotionMaster()->MoveChase(target, 0.2f);
204 }
205 else
206 {
207 _roamTimer = 2500;
209 me->GetMotionMaster()->MoveRandom(25.0f);
210 }
211 // Seeping fog movement is slow enough for a player to be able to walk backwards and still outpace it
212 me->SetWalk(true);
213 me->SetSpeedRate(MOVE_WALK, 0.75f);
214 }
215 else
216 _roamTimer -= diff;
217 }
218
219 private:
221 };
222
223 CreatureAI* GetAI(Creature* creature) const override
224 {
225 return new npc_dream_fogAI(creature);
226 }
227};
228
229/*
230 * ---
231 * --- Dragonspecific scripts and handling: YSONDRE
232 * ---
233 */
234
236{
238};
239
245
251
253{
254 public:
255 boss_ysondre() : CreatureScript("boss_ysondre") { }
256
258 {
260 {
261 Initialize();
262 }
263
265 {
266 _stage = 1;
267 }
268
269 void Reset() override
270 {
271 Initialize();
274 }
275
276 void JustEngagedWith(Unit* who) override
277 {
280 }
281
282 // Summon druid spirits on 75%, 50% and 25% health
283 void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
284 {
285 if (!HealthAbovePct(100 - 25 * _stage))
286 {
288
289 for (uint8 i = 0; i < 10; ++i)
291 ++_stage;
292 }
293 }
294
295 void ExecuteEvent(uint32 eventId) override
296 {
297 switch (eventId)
298 {
302 break;
303 default:
305 break;
306 }
307 }
308
309 private:
311 };
312
313 CreatureAI* GetAI(Creature* creature) const override
314 {
315 return new boss_ysondreAI(creature);
316 }
317};
318
319/*
320 * ---
321 * --- Dragonspecific scripts and handling: LETHON
322 * ---
323 *
324 * @todo
325 * - Spell: Shadow bolt whirl casts needs custom handling (spellscript)
326 */
327
333
340
342{
344};
345
347{
348 public:
349 boss_lethon() : CreatureScript("boss_lethon") { }
350
352 {
354 {
355 Initialize();
356 }
357
359 {
360 _stage = 1;
361 }
362
363 void Reset() override
364 {
365 Initialize();
368 }
369
370 void JustEngagedWith(Unit* who) override
371 {
374 }
375
376 void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
377 {
378 if (!HealthAbovePct(100 - 25 * _stage))
379 {
382 ++_stage;
383 }
384 }
385
386 void SpellHitTarget(WorldObject* target, SpellInfo const* spellInfo) override
387 {
388 if (spellInfo->Id == SPELL_DRAW_SPIRIT && target->GetTypeId() == TYPEID_PLAYER)
389 {
390 Position targetPos = target->GetPosition();
392 }
393 }
394
395 void ExecuteEvent(uint32 eventId) override
396 {
397 switch (eventId)
398 {
400 me->CastSpell(nullptr, SPELL_SHADOW_BOLT_WHIRL, false);
402 break;
403 default:
405 break;
406 }
407 }
408
409 private:
411 };
412
413 CreatureAI* GetAI(Creature* creature) const override
414 {
415 return new boss_lethonAI(creature);
416 }
417};
418
420{
421 public:
422 npc_spirit_shade() : CreatureScript("npc_spirit_shade") { }
423
425 {
427 {
428 }
429
430 void IsSummonedBy(WorldObject* summonerWO) override
431 {
432 Unit* summoner = summonerWO->ToUnit();
433 if (!summoner)
434 return;
435
436 _summonerGuid = summoner->GetGUID();
437 me->GetMotionMaster()->MoveFollow(summoner, 0.0f, 0.0f);
438 }
439
440 void MovementInform(uint32 moveType, uint32 data) override
441 {
442 if (moveType == FOLLOW_MOTION_TYPE && data == _summonerGuid.GetCounter())
443 {
444 me->CastSpell(nullptr, SPELL_DARK_OFFERING, false);
446 }
447 }
448
449 private:
451 };
452
453 CreatureAI* GetAI(Creature* creature) const override
454 {
455 return new npc_spirit_shadeAI(creature);
456 }
457};
458
459/*
460 * ---
461 * --- Dragonspecific scripts and handling: EMERISS
462 * ---
463 */
464
470
477
479{
480 public:
481 boss_emeriss() : CreatureScript("boss_emeriss") { }
482
484 {
486 {
487 Initialize();
488 }
489
491 {
492 _stage = 1;
493 }
494
495 void Reset() override
496 {
497 Initialize();
500 }
501
502 void KilledUnit(Unit* who) override
503 {
504 if (who->GetTypeId() == TYPEID_PLAYER)
505 DoCast(who, SPELL_PUTRID_MUSHROOM, true);
507 }
508
509 void JustEngagedWith(Unit* who) override
510 {
513 }
514
515 void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
516 {
517 if (!HealthAbovePct(100 - 25 * _stage))
518 {
521 ++_stage;
522 }
523 }
524
525 void ExecuteEvent(uint32 eventId) override
526 {
527 switch (eventId)
528 {
532 break;
533 default:
535 break;
536 }
537 }
538
539 private:
541 };
542
543 CreatureAI* GetAI(Creature* creature) const override
544 {
545 return new boss_emerissAI(creature);
546 }
547};
548
549/*
550 * ---
551 * --- Dragonspecific scripts and handling: TAERAR
552 * ---
553 */
554
560
570
575
577{
578 public:
579 boss_taerar() : CreatureScript("boss_taerar") { }
580
582 {
584 {
585 Initialize();
586 }
587
589 {
590 _stage = 1;
591 _shades = 0;
592 _banished = false;
593 _banishedTimer = 0;
594 }
595
606
607 void JustEngagedWith(Unit* who) override
608 {
611 }
612
613 void SummonedCreatureDies(Creature* /*summon*/, Unit* /*killer*/) override
614 {
615 --_shades;
616 }
617
618 void DamageTaken(Unit* /*attacker*/, uint32& /*damage*/, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
619 {
620 // At 75, 50 or 25 percent health, we need to activate the shades and go "banished"
621 // Note: _stage holds the amount of times they have been summoned
622 if (!_banished && !HealthAbovePct(100 - 25 * _stage))
623 {
624 _banished = true;
625 _banishedTimer = 60000;
626
628 DoStopAttack();
629
631
632 uint32 count = sizeof(TaerarShadeSpells) / sizeof(uint32);
633 for (uint32 i = 0; i < count; ++i)
635 _shades += count;
636
640
641 ++_stage;
642 }
643 }
644
645 void ExecuteEvent(uint32 eventId) override
646 {
647 switch (eventId)
648 {
652 break;
656 break;
657 default:
659 break;
660 }
661 }
662
663 void UpdateAI(uint32 diff) override
664 {
665 if (!me->IsInCombat())
666 return;
667
668 if (_banished)
669 {
670 // If all three shades are dead, OR it has taken too long, end the current event and get Taerar back into business
671 if (_banishedTimer <= diff || !_shades)
672 {
673 _banished = false;
674
678 }
679 // _banishtimer has not expired, and we still have active shades:
680 else
681 _banishedTimer -= diff;
682
683 // Update the events before we return (handled under emerald_dragonAI::UpdateAI(diff); if we're not inside this check)
684 events.Update(diff);
685
686 return;
687 }
688
690 }
691
692 private:
693 bool _banished; // used for shades activation testing
694 uint32 _banishedTimer; // counter for banishment timeout
695 uint8 _shades; // keep track of how many shades are dead
696 uint8 _stage; // check which "shade phase" we're at (75-50-25 percentage counters)
697 };
698
699 CreatureAI* GetAI(Creature* creature) const override
700 {
701 return new boss_taerarAI(creature);
702 }
703};
704
705/*
706 * --- Spell: Dream Fog
707 */
708
710{
711 public:
713
715 {
716 if (Unit* unit = object->ToUnit())
717 return unit->HasAura(SPELL_SLEEP);
718 return true;
719 }
720};
721
722// 24778 - Sleep
724{
725 public:
726 spell_dream_fog_sleep() : SpellScriptLoader("spell_dream_fog_sleep") { }
727
742
743 SpellScript* GetSpellScript() const override
744 {
746 }
747};
748
749/*
750 * --- Spell: Mark of Nature
751 */
752
754{
755 public:
757
759 {
760 // return those not tagged or already under the influence of Aura of Nature
761 if (Unit* unit = object->ToUnit())
762 return !(unit->HasAura(SPELL_MARK_OF_NATURE) && !unit->HasAura(SPELL_AURA_OF_NATURE));
763 return true;
764 }
765};
766
767// 25042 - Triggerspell - Mark of Nature
809
811{
812 // helper NPC scripts
813 new npc_dream_fog();
814 new npc_spirit_shade();
815
816 // dragons
817 new boss_ysondre();
818 new boss_taerar();
819 new boss_emeriss();
820 new boss_lethon();
821
822 // dragon spellscripts
825}
uint8_t uint8
Definition Define.h:135
uint32_t uint32
Definition Define.h:133
@ FOLLOW_MOTION_TYPE
@ TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
SpellEffIndex
@ EFFECT_0
@ SPELL_EFFECT_APPLY_AURA
@ TARGET_UNIT_DEST_AREA_ENEMY
@ TARGET_UNIT_SRC_AREA_ENEMY
#define SpellEffectFn(F, I, N)
#define SpellObjectAreaTargetSelectFn(F, I, N)
@ REACT_PASSIVE
@ REACT_AGGRESSIVE
@ MOVE_WALK
@ UNIT_FLAG_NON_ATTACKABLE
@ UNIT_FLAG_UNINTERACTIBLE
@ UNIT_STATE_CASTING
Definition Unit.h:235
DamageEffectType
Definition Unit.h:352
@ SAY_TAERAR_SUMMON_SHADES
@ SPELL_MARK_OF_NATURE
@ SPELL_SUMMON_PLAYER
@ SPELL_MARK_OF_NATURE_AURA
@ SPELL_AURA_OF_NATURE
@ SPELL_SEEPING_FOG_RIGHT
@ SPELL_TAIL_SWEEP
@ SPELL_DREAM_FOG
@ SPELL_SEEPING_FOG_LEFT
@ SPELL_NOXIOUS_BREATH
@ SPELL_CORRUPTION_OF_EARTH
@ SPELL_VOLATILE_INFECTION
@ SPELL_PUTRID_MUSHROOM
uint32 const TaerarShadeSpells[]
@ SPELL_LIGHTNING_WAVE
@ SPELL_SUMMON_DRUID_SPIRITS
@ SPELL_SUMMON_SHADE_3
@ SPELL_SUMMON_SHADE_1
@ SPELL_BELLOWING_ROAR
@ SPELL_SUMMON_SHADE_2
@ SPELL_ARCANE_BLAST
@ SAY_LETHON_DRAW_SPIRIT
@ SAY_YSONDRE_SUMMON_DRUIDS
@ SAY_YSONDRE_AGGRO
@ NPC_DEMENTED_DRUID
@ SAY_EMERISS_CAST_CORRUPTION
@ SAY_EMERISS_AGGRO
void AddSC_emerald_dragons()
@ SPELL_DARK_OFFERING
@ SPELL_SHADOW_BOLT_WHIRL
@ SPELL_DRAW_SPIRIT
@ EVENT_CORRUPTION_OF_EARTH
@ EVENT_TAIL_SWEEP
@ EVENT_ARCANE_BLAST
@ EVENT_SUMMON_DRUID_SPIRITS
@ EVENT_LIGHTNING_WAVE
@ EVENT_BELLOWING_ROAR
@ EVENT_VOLATILE_INFECTION
@ EVENT_NOXIOUS_BREATH
@ EVENT_SEEPING_FOG
@ EVENT_SHADOW_BOLT_WHIRL
virtual void JustEngagedWith(Unit *)
Definition CreatureAI.h:127
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:82
void SetReactState(ReactStates st)
Definition Creature.h:119
void DespawnOrUnsummon(Milliseconds timeToDespawn=0s, Seconds forceRespawnTime=0s)
bool operator()(WorldObject *object)
void Update(uint32 time)
Definition EventMap.h:67
EventId ExecuteEvent()
Definition EventMap.cpp:73
void ScheduleEvent(EventId eventId, Milliseconds time, GroupIndex group=0u, PhaseIndex phase=0u)
Definition EventMap.cpp:36
bool operator()(WorldObject *object)
void MoveChase(Unit *target, Optional< ChaseRange > dist={}, Optional< ChaseAngle > angle={})
void MoveFollow(Unit *target, float dist, ChaseAngle angle, MovementSlot slot=MOTION_SLOT_ACTIVE)
void MoveRandom(float wanderDistance=0.0f)
LowType GetCounter() const
Definition ObjectGuid.h:156
static Unit * ToUnit(Object *o)
Definition Object.h:192
TypeID GetTypeId() const
Definition Object.h:93
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
uint32 Id
Definition SpellInfo.h:289
void PreventHitDefaultEffect(SpellEffIndex effIndex)
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:54
SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const &args={})
Definition UnitAI.cpp:166
Unit * SelectTarget(SelectTargetMethod targetType, uint32 offset=0, float dist=0.0f, bool playerOnly=false, bool withTank=true, int32 aura=0)
Definition UnitAI.cpp:96
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:106
Definition Unit.h:769
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3093
MotionMaster * GetMotionMaster()
Definition Unit.h:1667
bool SetWalk(bool enable)
Definition Unit.cpp:13268
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3784
void SetSpeedRate(UnitMoveType mtype, float rate)
Definition Unit.cpp:8678
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
void SetUnitFlag(UnitFlags flags)
Definition Unit.h:954
bool IsInCombat() const
Definition Unit.h:1144
void RemoveUnitFlag(UnitFlags flags)
Definition Unit.h:955
void JustEngagedWith(Unit *) override
void Reset() override
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2832
TempSummon * SummonCreature(uint32 entry, Position const &pos, TempSummonType despawnType=TEMPSUMMON_MANUAL_DESPAWN, Milliseconds despawnTime=0s, uint32 vehId=0, uint32 spellId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty)
Definition Object.cpp:1992
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
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 FilterTargets(std::list< WorldObject * > &targets)
PrepareSpellScript(spell_dream_fog_sleep_SpellScript)
SpellScript * GetSpellScript() const override
PrepareSpellScript(spell_mark_of_nature_SpellScript)
void FilterTargets(std::list< WorldObject * > &targets)
SpellScript * GetSpellScript() const override
void GetPosition(float &x, float &y) const
Definition Position.h:84
bool HealthAbovePct(uint32 pct) const
void JustEngagedWith(Unit *who) override
void ExecuteEvent(uint32 eventId) override
void KilledUnit(Unit *who) override
void DamageTaken(Unit *, uint32 &, DamageEffectType, SpellInfo const *) override
void SpellHitTarget(WorldObject *target, SpellInfo const *spellInfo) override
void JustEngagedWith(Unit *who) override
void ExecuteEvent(uint32 eventId) override
void DamageTaken(Unit *, uint32 &, DamageEffectType, SpellInfo const *) override
void SummonedCreatureDies(Creature *, Unit *) override
void UpdateAI(uint32 diff) override
void ExecuteEvent(uint32 eventId) override
void DamageTaken(Unit *, uint32 &, DamageEffectType, SpellInfo const *) override
void JustEngagedWith(Unit *who) override
void DamageTaken(Unit *, uint32 &, DamageEffectType, SpellInfo const *) override
void ExecuteEvent(uint32 eventId) override
void JustEngagedWith(Unit *who) override
void UpdateAI(uint32 diff) override
void KilledUnit(Unit *who) override
void ExecuteEvent(uint32 eventId) override
emerald_dragonAI(Creature *creature)
void UpdateAI(uint32 diff) override
void IsSummonedBy(WorldObject *summonerWO) override
void MovementInform(uint32 moveType, uint32 data) override