TrinityCore
boss_archimonde.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/* ScriptData
19SDName: Boss_Archimonde
20SD%Complete: 85
21SDComment: Doomfires not completely offlike due to core limitations for random moving. Tyrande and second phase not fully implemented.
22SDCategory: Caverns of Time, Mount Hyjal
23EndScriptData */
24
25#include "ScriptMgr.h"
26#include "hyjal.h"
27#include "InstanceScript.h"
28#include "MotionMaster.h"
29#include "ObjectAccessor.h"
30#include "ScriptedCreature.h"
31#include "SpellScript.h"
32
34{
42 // YELL_ARCHIMONDE_INTRO = 8
43};
44
46{
50
53
59 SPELL_DOOMFIRE_STRIKE = 31903, // summons two creatures
68 SPELL_FEAR = 31970
69};
70
72{
73 EVENT_HAND_OF_DEATH = 1, // Raid wiper
80 EVENT_DISTANCE_CHECK, // This checks if he's too close to the World Tree (75 yards from a point on the tree), if true then he will enrage
84};
85
87{
88 NPC_DOOMFIRE = 18095,
90 NPC_ANCIENT_WISP = 17946
91};
92
94{
97};
98
100{
101public:
102 npc_ancient_wisp() : CreatureScript("npc_ancient_wisp") { }
103
104 CreatureAI* GetAI(Creature* creature) const override
105 {
106 return GetHyjalAI<npc_ancient_wispAI>(creature);
107 }
108
110 {
112 {
113 Initialize();
114 instance = creature->GetInstanceScript();
115 }
116
118 {
119 CheckTimer = 1000;
121 }
122
126
127 void Reset() override
128 {
129 Initialize();
130
132
134 }
135
136 void JustEngagedWith(Unit* /*who*/) override { }
137
138 void DamageTaken(Unit* /*done_by*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
139 {
140 damage = 0;
141 }
142
143 void UpdateAI(uint32 diff) override
144 {
145 if (CheckTimer <= diff)
146 {
147 if (Creature* Archimonde = instance->GetCreature(DATA_ARCHIMONDE))
148 {
149 if (Archimonde->HealthBelowPct(2) || !Archimonde->IsAlive())
151 else
152 DoCast(Archimonde, SPELL_ANCIENT_SPARK);
153 }
154 CheckTimer = 1000;
155 } else CheckTimer -= diff;
156 }
157 };
158};
159
160/* This script is merely a placeholder for the Doomfire that triggers Doomfire spell. It will
161 MoveChase the Doomfire Spirit always, until despawn (AttackStart is called upon it's spawn) */
163{
164public:
165 npc_doomfire() : CreatureScript("npc_doomfire") { }
166
167 CreatureAI* GetAI(Creature* creature) const override
168 {
169 return GetHyjalAI<npc_doomfireAI>(creature);
170 }
171
173 {
174 npc_doomfireAI(Creature* creature) : ScriptedAI(creature) { }
175
176 void Reset() override { }
177
178 void MoveInLineOfSight(Unit* /*who*/) override { }
179
180 void JustEngagedWith(Unit* /*who*/) override { }
181
182 void DamageTaken(Unit* /*done_by*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
183 {
184 damage = 0;
185 }
186 };
187};
188
189/* This is the script for the Doomfire Spirit Mob. This mob simply follow players or
190 travels in random directions if target cannot be found. */
192{
193public:
194 npc_doomfire_targetting() : CreatureScript("npc_doomfire_targetting") { }
195
196 CreatureAI* GetAI(Creature* creature) const override
197 {
198 return GetHyjalAI<npc_doomfire_targettingAI>(creature);
199 }
200
202 {
204 {
205 Initialize();
206 }
207
209 {
211 ChangeTargetTimer = 5000;
212 }
213
216
217 void Reset() override
218 {
219 Initialize();
220 }
221
222 void MoveInLineOfSight(Unit* who) override
223 {
224 //will update once TargetGUID is 0. In case noone actually moves(not likely) and this is 0
225 //when UpdateAI needs it, it will be forced to select randomPoint
226 if (!TargetGUID && who->GetTypeId() == TYPEID_PLAYER)
227 TargetGUID = who->GetGUID();
228 }
229
230 void JustEngagedWith(Unit* /*who*/) override { }
231
232 void DamageTaken(Unit* /*done_by*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
233 {
234 damage = 0;
235 }
236
237 void UpdateAI(uint32 diff) override
238 {
239 if (ChangeTargetTimer <= diff)
240 {
242 {
243 me->GetMotionMaster()->MoveFollow(temp, 0.0f, 0.0f);
245 }
246 else
247 {
250 }
251
252 ChangeTargetTimer = 5000;
253 } else ChangeTargetTimer -= diff;
254 }
255 };
256};
257
258/* Finally, Archimonde's script. His script isn't extremely complex, most are simply spells on timers.
259 The only complicated aspect of the battle is Finger of Death and Doomfire, with Doomfire being the
260 hardest bit to code. Finger of Death is simply a distance check - if no one is in melee range, then
261 select a random target and cast the spell on them. However, if someone IS in melee range, and this
262 is NOT the main tank (creature's victim), then we aggro that player and they become the new victim.
263 For Doomfire, we summon a mob (Doomfire Spirit) for the Doomfire mob to follow. It's spirit will
264 randomly select it's target to follow and then we create the random movement making it unpredictable. */
265
267{
268public:
269 boss_archimonde() : CreatureScript("boss_archimonde") { }
270
271 struct boss_archimondeAI : public BossAI
272 {
274 {
275 Initialize();
276 }
277
279 {
280
281 SoulChargeCount = 0;
282 WispCount = 0; // When ~30 wisps are summoned, Archimonde dies
283 _unleashSpell = 0;
284 _chargeSpell = 0;
285
286 Enraged = false;
287 HasProtected = false;
288 }
289
290 void InitializeAI() override
291 {
293 }
294
295 void Reset() override
296 {
297 Initialize();
298 _Reset();
303 {
304 DoCast(WorldtreeTraget, SPELL_DRAIN_WORLD_TREE);
305 }
306 me->RemoveAllAuras(); // Reset Soul Charge auras.
307 }
308
309 void JustEngagedWith(Unit* who) override
310 {
322 }
323
324 void ExecuteEvent(uint32 eventId) override
325 {
326 switch (eventId)
327 {
331 break;
333 _chargeSpell = 0;
334 _unleashSpell = 0;
336 switch (urand(0, 2))
337 {
338 case 0:
341 break;
342 case 1:
345 break;
346 case 2:
349 break;
350 }
351
352 if (me->HasAura(_chargeSpell))
353 {
358 }
359 break;
361 if (!SelectTarget(SelectTargetMethod::Random, 0, 5.0f)) // Checks if there are no targets in melee range
362 {
365 }
366 else
368 break;
373 break;
374 case EVENT_AIR_BURST:
377 DoCast(target, SPELL_AIR_BURST); //not on tank
379 break;
380 case EVENT_FEAR:
383 break;
384 case EVENT_DOOMFIRE:
387 SummonDoomfire(temp);
388 else
391 break;
393 if (Creature* channelTrigger = instance->GetCreature(DATA_CHANNEL_TARGET))
394 if (me->IsWithinDistInMap(channelTrigger, 75.0f))
397 break;
398 case EVENT_PROTECTION_OF_ELUNE: // hp below 10% only cast finger of death
399 events.Reset();
404 break;
407 ++WispCount;
408 if (WispCount >= 30)
409 {
410 me->KillSelf();
411 return;
412 }
414 break;
418 break;
419 default:
420 break;
421 }
422 }
423
424 void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
425 {
426 if (me->HealthBelowPctDamaged(10, damage))
427 {
428 if (!Enraged)
430
431 if (!HasProtected)
432 {
435 // All members of raid must get this buff
437 HasProtected = true;
438 }
439 }
440 }
441
442 void KilledUnit(Unit* victim) override
443 {
444 Talk(SAY_SLAY);
445
446 if (victim->GetTypeId() == TYPEID_PLAYER)
447 {
448 switch (victim->GetClass())
449 {
450 case CLASS_PRIEST:
451 case CLASS_PALADIN:
452 case CLASS_WARLOCK:
453 victim->CastSpell(me, SPELL_SOUL_CHARGE_RED, true);
454 break;
455 case CLASS_MAGE:
456 case CLASS_ROGUE:
457 case CLASS_WARRIOR:
458 victim->CastSpell(me, SPELL_SOUL_CHARGE_YELLOW, true);
459 break;
460 case CLASS_DRUID:
461 case CLASS_SHAMAN:
462 case CLASS_HUNTER:
463 victim->CastSpell(me, SPELL_SOUL_CHARGE_GREEN, true);
464 break;
465 }
466
469 }
470 }
471
472 void JustReachedHome() override
473 {
475 }
476
477 void JustDied(Unit* /*killer*/) override
478 {
481 _JustDied();
482 // @todo: remove this when instance script gets updated, kept for compatibility only
484 }
485
486 void JustSummoned(Creature* summoned) override
487 {
488 switch (summoned->GetEntry())
489 {
490 case NPC_ANCIENT_WISP:
491 summoned->AI()->AttackStart(me);
492 break;
494 DoomfireSpiritGUID = summoned->GetGUID();
495 break;
496 case NPC_DOOMFIRE:
497 {
498 summoned->CastSpell(summoned, SPELL_DOOMFIRE_SPAWN, false);
499
501 .SetOriginalCaster(me->GetGUID()));
502
503 if (Unit* DoomfireSpirit = ObjectAccessor::GetUnit(*me, DoomfireSpiritGUID))
504 {
505 summoned->GetMotionMaster()->MoveFollow(DoomfireSpirit, 0.0f, 0.0f);
507 }
508 break;
509 }
510 default:
511 break;
512 }
513 }
514
515 void DoAction(int32 actionId) override
516 {
517 switch (actionId)
518 {
519 case ACTION_ENRAGE:
522 Enraged = true;
524 break;
527 break;
528 default:
529 break;
530 }
531 }
532
533 //this is code doing close to what the summoning spell would do (spell 31903)
534 void SummonDoomfire(Unit* target)
535 {
536 if (!target)
537 return;
538
540 target->GetPositionX()+15.0f, target->GetPositionY()+15.0f, target->GetPositionZ(), 0,
543 target->GetPositionX()-15.0f, target->GetPositionY()-15.0f, target->GetPositionZ(), 0,
545 }
546
547 private:
556 };
557
558 CreatureAI* GetAI(Creature* creature) const override
559 {
560 return GetHyjalAI<boss_archimondeAI>(creature);
561 }
562};
563
564// 39142 - Drain World Tree Dummy
566{
567 public:
568 spell_archimonde_drain_world_tree_dummy() : SpellScriptLoader("spell_archimonde_drain_world_tree_dummy") { }
569
571 {
572 bool Validate(SpellInfo const* /*spellInfo*/) override
573 {
575 }
576
577 void HandleScript(SpellEffIndex /*effIndex*/)
578 {
579 if (Unit* target = GetHitUnit())
580 target->CastSpell(GetCaster(), SPELL_DRAIN_WORLD_TREE_TRIGGERED, true);
581 }
582
583 void Register() override
584 {
586 }
587 };
588
589 SpellScript* GetSpellScript() const override
590 {
592 }
593};
594
595// Protection of Elune 38528
597{
598 bool Validate(SpellInfo const* /*spellInfo*/) override
599 {
600 return ValidateSpellInfo(
601 {
603 });
604 }
605
606 void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
607 {
608 Unit* target = GetTarget();
613 }
614
615 void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
616 {
617 Unit* target = GetTarget();
622 }
623
624 void Register() override
625 {
628 }
629};
630
632{
633 new boss_archimonde();
634 new npc_doomfire();
636 new npc_ancient_wisp();
639}
Texts
Actions
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
@ DONE
@ TEMPSUMMON_TIMED_DESPAWN
Definition: ObjectDefines.h:65
@ TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT
Definition: ObjectDefines.h:66
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
Spells
Definition: PlayerAI.cpp:32
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
uint32 rand32()
Definition: Random.cpp:70
#define RegisterSpellScript(spell_script)
Definition: ScriptMgr.h:1369
SpellEffIndex
Definition: SharedDefines.h:29
@ EFFECT_0
Definition: SharedDefines.h:30
@ CLASS_HUNTER
@ CLASS_DRUID
@ CLASS_SHAMAN
@ CLASS_PRIEST
@ CLASS_WARRIOR
@ CLASS_WARLOCK
@ CLASS_MAGE
@ CLASS_PALADIN
@ CLASS_ROGUE
@ SPELL_EFFECT_DUMMY
@ IMMUNITY_ID
AuraEffectHandleModes
@ AURA_EFFECT_HANDLE_REAL
@ SPELL_AURA_SCHOOL_IMMUNITY
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
Definition: SpellDefines.h:266
#define SpellEffectFn(F, I, N)
Definition: SpellScript.h:842
#define AuraEffectApplyFn(F, I, N, M)
Definition: SpellScript.h:2029
#define AuraEffectRemoveFn(F, I, N, M)
Definition: SpellScript.h:2040
DamageEffectType
Definition: UnitDefines.h:131
@ UNIT_FLAG_NON_ATTACKABLE
Definition: UnitDefines.h:145
@ CURRENT_CHANNELED_SPELL
Definition: Unit.h:591
void AddSC_boss_archimonde()
@ ACTION_ENRAGE
@ ACTION_CHANNEL_WORLD_TREE
@ SPELL_DRAIN_WORLD_TREE
@ SPELL_SOUL_CHARGE_RED
@ SPELL_DOOMFIRE
@ SPELL_PROTECTION_OF_ELUNE
@ SPELL_FINGER_OF_DEATH
@ SPELL_UNLEASH_SOUL_GREEN
@ SPELL_FINGER_OF_DEATH_LAST_PHASE
@ SPELL_DOOMFIRE_SPAWN
@ SPELL_SOUL_CHARGE_GREEN
@ SPELL_DRAIN_WORLD_TREE_TRIGGERED
@ SPELL_FEAR
@ SPELL_UNLEASH_SOUL_RED
@ SPELL_ANCIENT_SPARK
@ SPELL_DENOUEMENT_WISP
@ SPELL_DOOMFIRE_STRIKE
@ SPELL_HAND_OF_DEATH
@ SPELL_GRIP_OF_THE_LEGION
@ SPELL_UNLEASH_SOUL_YELLOW
@ SPELL_AIR_BURST
@ SPELL_SOUL_CHARGE_YELLOW
@ SAY_DEATH
@ SAY_SOUL_CHARGE
@ SAY_AGGRO
@ SAY_AIR_BURST
@ SAY_SLAY
@ SAY_DOOMFIRE
@ SAY_ENRAGE
@ NPC_ANCIENT_WISP
@ NPC_DOOMFIRE
@ NPC_DOOMFIRE_SPIRIT
@ EVENT_FINGER_OF_DEATH_LAST_PHASE
@ EVENT_DISTANCE_CHECK
@ EVENT_AIR_BURST
@ EVENT_SUMMON_WHISP
@ EVENT_GRIP_OF_THE_LEGION
@ EVENT_FINGER_OF_DEATH
@ EVENT_DOOMFIRE
@ EVENT_FEAR
@ EVENT_PROTECTION_OF_ELUNE
@ EVENT_UNLEASH_SOUL_CHARGE
@ EVENT_HAND_OF_DEATH
HookList< EffectApplyHandler > AfterEffectRemove
Definition: SpellScript.h:2039
HookList< EffectApplyHandler > AfterEffectApply
Definition: SpellScript.h:2028
Unit * GetTarget() const
InstanceScript *const instance
void JustEngagedWith(Unit *who) override
SummonList summons
EventMap events
void _JustDied()
void Talk(uint8 id, WorldObject const *whisperTarget=nullptr)
Definition: CreatureAI.cpp:56
void AttackStart(Unit *victim) override
== Triggered Actions Requested ==================
Definition: CreatureAI.cpp:328
Creature *const me
Definition: CreatureAI.h:61
CreatureAI * AI() const
Definition: Creature.h:214
void ScheduleEvent(uint32 eventId, Milliseconds time, uint32 group=0, uint8 phase=0)
Definition: EventMap.cpp:36
void Reset()
Definition: EventMap.cpp:21
Creature * GetCreature(uint32 type)
virtual ObjectGuid GetGuidData(uint32 type) const override
void MovePoint(uint32 id, Position const &pos, bool generatePath=true, Optional< float > finalOrient={}, Optional< float > speed={}, MovementWalkRunSpeedSelectionMode speedSelectionMode=MovementWalkRunSpeedSelectionMode::Default, Optional< float > closeEnoughDistance={})
void MoveFollow(Unit *target, float dist, ChaseAngle angle, Optional< Milliseconds > duration={}, MovementSlot slot=MOTION_SLOT_ACTIVE)
void Clear()
Definition: ObjectGuid.h:286
TypeID GetTypeId() const
Definition: Object.h:173
uint32 GetEntry() const
Definition: Object.h:161
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
Definition: SpellScript.h:162
Unit * GetCaster() const
Unit * GetHitUnit() const
HookList< EffectHandler > OnEffectHitTarget
Definition: SpellScript.h:840
virtual void InitializeAI()
Definition: UnitAI.cpp:43
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 DoCastAOE(uint32 spellId, CastSpellExtraArgs const &args={})
Definition: UnitAI.h:161
SpellCastResult DoCast(uint32 spellId)
Definition: UnitAI.cpp:89
Definition: Unit.h:627
void ApplySpellImmune(uint32 spellId, SpellImmunity op, uint32 type, bool apply)
Definition: Unit.cpp:7845
uint8 GetClass() const
Definition: Unit.h:752
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition: Unit.cpp:3089
MotionMaster * GetMotionMaster()
Definition: Unit.h:1652
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint16 num=1)
Definition: Unit.cpp:3847
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
void RemoveAllAuras()
Definition: Unit.cpp:4242
bool HealthBelowPctDamaged(int32 pct, uint32 damage) const
Definition: Unit.h:781
void SetUnitFlag(UnitFlags flags)
Definition: Unit.h:833
void KillSelf(bool durabilityLoss=true, bool skipSettingDeathState=false)
Definition: Unit.h:921
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true)
Definition: Unit.cpp:3017
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1042
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
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:2025
Position GetRandomNearPosition(float radius)
Definition: Object.cpp:3423
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1147
virtual void SetData(uint32, uint32)
Definition: ZoneScript.h:92
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
SpellScript * GetSpellScript() const override
void HandleEffectRemove(AuraEffect const *, AuraEffectHandleModes)
bool Validate(SpellInfo const *) override
void HandleEffectApply(AuraEffect const *, AuraEffectHandleModes)
@ DATA_CHANNEL_TARGET
Definition: hyjal.h:46
@ DATA_ARCHIMONDE
Definition: hyjal.h:34
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
constexpr float GetPositionX() const
Definition: Position.h:76
float m_positionZ
Definition: Position.h:55
constexpr float GetPositionY() const
Definition: Position.h:77
float m_positionX
Definition: Position.h:53
float m_positionY
Definition: Position.h:54
constexpr float GetPositionZ() const
Definition: Position.h:78
Creature * DoSpawnCreature(uint32 entry, float offsetX, float offsetY, float offsetZ, float angle, uint32 type, Milliseconds despawntime)
void JustSummoned(Creature *summoned) override
void KilledUnit(Unit *victim) override
void JustEngagedWith(Unit *who) override
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override
void ExecuteEvent(uint32 eventId) override
void DoAction(int32 actionId) override
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override
void UpdateAI(uint32 diff) override
void JustEngagedWith(Unit *) override
void MoveInLineOfSight(Unit *) override
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override
npc_doomfireAI(Creature *creature)
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override