TrinityCore
boss_prince_malchezaar.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_Prince_Malchezzar
20SD%Complete: 100
21SDComment:
22SDCategory: Karazhan
23EndScriptData */
24
25#include "ScriptMgr.h"
26#include "Containers.h"
27#include "karazhan.h"
28#include "InstanceScript.h"
29#include "ObjectAccessor.h"
30#include "ScriptedCreature.h"
31#include "SpellInfo.h"
32#include "SpellMgr.h"
33#include "TemporarySummon.h"
34
35// 18 Coordinates for Infernal spawns
37{
38 float x, y;
39};
40
41#define INFERNAL_Z 275.5f
42
44{
45 {-10922.8f, -1985.2f},
46 {-10916.2f, -1996.2f},
47 {-10932.2f, -2008.1f},
48 {-10948.8f, -2022.1f},
49 {-10958.7f, -1997.7f},
50 {-10971.5f, -1997.5f},
51 {-10990.8f, -1995.1f},
52 {-10989.8f, -1976.5f},
53 {-10971.6f, -1973.0f},
54 {-10955.5f, -1974.0f},
55 {-10939.6f, -1969.8f},
56 {-10958.0f, -1952.2f},
57 {-10941.7f, -1954.8f},
58 {-10943.1f, -1988.5f},
59 {-10948.8f, -2005.1f},
60 {-10984.0f, -2019.3f},
61 {-10932.8f, -1979.6f},
62 {-10935.7f, -1996.0f}
63};
64
65//Enfeeble is supposed to reduce hp to 1 and then heal player back to full when it ends
66//Along with reducing healing and regen while enfeebled to 0%
67//This spell effect will only reduce healing
69{
73// SAY_SPECIAL1 = 3, Not used, needs to be implemented, but I don't know where it should be used.
74// SAY_SPECIAL2 = 4, Not used, needs to be implemented, but I don't know where it should be used.
75// SAY_SPECIAL3 = 5, Not used, needs to be implemented, but I don't know where it should be used.
79
81
82 SPELL_ENFEEBLE = 30843, //Enfeeble during phase 1 and 2
84
85 SPELL_SHADOWNOVA = 30852, //Shadownova used during all phases
86 SPELL_SW_PAIN = 30854, //Shadow word pain during phase 1 and 3 (different targeting rules though)
87 SPELL_THRASH_PASSIVE = 12787, //Extra attack chance during phase 2
88 SPELL_SUNDER_ARMOR = 30901, //Sunder armor during phase 2
89 SPELL_THRASH_AURA = 12787, //Passive proc chance for thrash
90 SPELL_EQUIP_AXES = 30857, //Visual for axe equiping
91 SPELL_AMPLIFY_DAMAGE = 39095, //Amplifiy during phase 3
92 SPELL_CLEAVE = 30131, //Same as Nightbane.
93 SPELL_HELLFIRE = 30859, //Infenals' hellfire aura
94 NETHERSPITE_INFERNAL = 17646, //The netherspite infernal creature
95 MALCHEZARS_AXE = 17650, //Malchezar's axes (creatures), summoned during phase 3
96
97 INFERNAL_MODEL_INVISIBLE = 11686, //Infernal Effects
99
100 EQUIP_ID_AXE = 33542 //Axes info
102
103//---------Infernal code first
105{
106public:
107 netherspite_infernal() : CreatureScript("netherspite_infernal") { }
108
109 CreatureAI* GetAI(Creature* creature) const override
110 {
111 return GetKarazhanAI<netherspite_infernalAI>(creature);
112 }
113
115 {
117 HellfireTimer(0), CleanupTimer(0), point(nullptr) { }
118
123
124 void Reset() override { }
125 void JustEngagedWith(Unit* /*who*/) override { }
126 void MoveInLineOfSight(Unit* /*who*/) override { }
127
128 void UpdateAI(uint32 diff) override
129 {
130 if (HellfireTimer)
131 {
132 if (HellfireTimer <= diff)
133 {
135 HellfireTimer = 0;
136 }
137 else HellfireTimer -= diff;
138 }
139
140 if (CleanupTimer)
141 {
142 if (CleanupTimer <= diff)
143 {
144 Cleanup();
145 CleanupTimer = 0;
146 } else CleanupTimer -= diff;
147 }
148 }
149
150 void KilledUnit(Unit* who) override
151 {
153 if (Creature* creature = unit->ToCreature())
154 creature->AI()->KilledUnit(who);
155 }
156
157 void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
158 {
159 if (spellInfo->Id == SPELL_INFERNAL_RELAY)
160 {
162 me->SetUninteractible(true);
163 HellfireTimer = 4000;
164 CleanupTimer = 170000;
165 }
166 }
167
168 void DamageTaken(Unit* done_by, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
169 {
170 if (!done_by || done_by->GetGUID() != malchezaar)
171 damage = 0;
172 }
173
174 void Cleanup();
175 };
176};
177
179{
180public:
181 boss_malchezaar() : CreatureScript("boss_malchezaar") { }
182
183 CreatureAI* GetAI(Creature* creature) const override
184 {
185 return GetKarazhanAI<boss_malchezaarAI>(creature);
186 }
187
189 {
190 boss_malchezaarAI(Creature* creature) : ScriptedAI(creature)
191 {
192 Initialize();
193
194 instance = creature->GetInstanceScript();
195 }
196
198 {
199 EnfeebleTimer = 30000;
200 EnfeebleResetTimer = 38000;
201 ShadowNovaTimer = 35500;
202 SWPainTimer = 20000;
203 AmplifyDamageTimer = 5000;
204 Cleave_Timer = 8000;
205 InfernalTimer = 40000;
206 InfernalCleanupTimer = 47000;
207 AxesTargetSwitchTimer = urand(7500, 20000);
208 SunderArmorTimer = urand(5000, 10000);
209 phase = 1;
210
211 for (uint8 i = 0; i < 5; ++i)
212 {
214 enfeeble_health[i] = 0;
215 }
216 }
217
229
231 std::vector<InfernalPoint*> positions;
232
236
238
239 void Reset() override
240 {
241 AxesCleanup();
242 ClearWeapons();
244 positions.clear();
245
246 Initialize();
247
248 for (uint8 i = 0; i < TOTAL_INFERNAL_POINTS; ++i)
249 positions.push_back(&InfernalPoints[i]);
250
253 }
254
255 void KilledUnit(Unit* /*victim*/) override
256 {
257 Talk(SAY_SLAY);
258 }
259
260 void JustDied(Unit* /*killer*/) override
261 {
263
264 AxesCleanup();
265 ClearWeapons();
267 positions.clear();
268
269 for (uint8 i = 0; i < TOTAL_INFERNAL_POINTS; ++i)
270 positions.push_back(&InfernalPoints[i]);
271
274 }
275
276 void JustEngagedWith(Unit* /*who*/) override
277 {
279
280 instance->HandleGameObject(instance->GetGuidData(DATA_GO_NETHER_DOOR), false); // Open the door leading further in
282 }
283
285 {
286 //Infernal Cleanup
287 for (GuidVector::const_iterator itr = infernals.begin(); itr != infernals.end(); ++itr)
288 if (Unit* pInfernal = ObjectAccessor::GetUnit(*me, *itr))
289 if (pInfernal->IsAlive())
290 {
291 pInfernal->SetVisible(false);
292 pInfernal->setDeathState(JUST_DIED);
293 }
294
295 infernals.clear();
296 }
297
299 {
300 for (uint8 i = 0; i < 2; ++i)
301 {
302 Unit* axe = ObjectAccessor::GetUnit(*me, axes[i]);
303 if (axe && axe->IsAlive())
304 axe->KillSelf();
305 axes[i].Clear();
306 }
307 }
308
310 {
312 me->SetCanDualWield(false);
313 }
314
316 {
317 SpellInfo const* info = sSpellMgr->GetSpellInfo(SPELL_ENFEEBLE_EFFECT, GetDifficulty());
318 if (!info)
319 return;
320
322 std::vector<Unit*> targets;
323
325 {
326 Unit* target = ref->GetVictim();
327 if (target != tank && target->IsAlive() && target->GetTypeId() == TYPEID_PLAYER)
328 targets.push_back(target);
329 }
330
331 if (targets.empty())
332 return;
333
334 //cut down to size if we have more than 5 targets
335 while (targets.size() > 5)
336 targets.erase(targets.begin() + rand32() % targets.size());
337
338 uint32 i = 0;
339 for (std::vector<Unit*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter, ++i)
340 if (Unit* target = *iter)
341 {
342 enfeeble_targets[i] = target->GetGUID();
343 enfeeble_health[i] = target->GetHealth();
344
347 args.OriginalCaster = me->GetGUID();
348 target->CastSpell(target, SPELL_ENFEEBLE, args);
349 target->SetHealth(1);
350 }
351 }
352
354 {
355 for (uint8 i = 0; i < 5; ++i)
356 {
358 if (target && target->IsAlive())
359 target->SetHealth(enfeeble_health[i]);
361 enfeeble_health[i] = 0;
362 }
363 }
364
365 void SummonInfernal(const uint32 /*diff*/)
366 {
367 InfernalPoint *point = nullptr;
368 Position pos;
369 if ((me->GetMapId() != 532) || positions.empty())
370 pos = me->GetRandomNearPosition(60);
371 else
372 {
374 pos.Relocate(point->x, point->y, INFERNAL_Z, frand(0.0f, float(M_PI * 2)));
375 }
376
378
379 if (infernal)
380 {
382 infernal->SetFaction(me->GetFaction());
383 if (point)
384 ENSURE_AI(netherspite_infernal::netherspite_infernalAI, infernal->AI())->point = point;
386
387 infernals.push_back(infernal->GetGUID());
388 DoCast(infernal, SPELL_INFERNAL_RELAY);
389 }
390
392 }
393
394 void UpdateAI(uint32 diff) override
395 {
396 if (!UpdateVictim())
397 return;
398
399 if (EnfeebleResetTimer && EnfeebleResetTimer <= diff) // Let's not forget to reset that
400 {
403 } else EnfeebleResetTimer -= diff;
404
405 if (me->HasUnitState(UNIT_STATE_STUNNED)) // While shifting to phase 2 malchezaar stuns himself
406 return;
407
408 if (me->GetVictim() && me->GetTarget() != me->EnsureVictim()->GetGUID())
410
411 if (phase == 1)
412 {
413 if (HealthBelowPct(60))
414 {
416
417 phase = 2;
418
419 //animation
421
422 //text
424
425 //passive thrash aura
427
428 //models
430
432 me->SetCanDualWield(true);
433 }
434 }
435 else if (phase == 2)
436 {
437 if (HealthBelowPct(30))
438 {
439 InfernalTimer = 15000;
440
441 phase = 3;
442
443 ClearWeapons();
444
445 //remove thrash
447
449
450 Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true);
451 for (uint8 i = 0; i < 2; ++i)
452 {
454 if (axe)
455 {
456 axe->SetUninteractible(true);
457 axe->SetFaction(me->GetFaction());
458 axes[i] = axe->GetGUID();
459 if (target)
460 {
461 axe->AI()->AttackStart(target);
462 AddThreat(target, 10000000.0f, axe);
463 }
464 }
465 }
466
467 if (ShadowNovaTimer > 35000)
469
470 return;
471 }
472
473 if (SunderArmorTimer <= diff)
474 {
476 SunderArmorTimer = urand(10000, 18000);
477 } else SunderArmorTimer -= diff;
478
479 if (Cleave_Timer <= diff)
480 {
482 Cleave_Timer = urand(6000, 12000);
483 } else Cleave_Timer -= diff;
484 }
485 else
486 {
487 if (AxesTargetSwitchTimer <= diff)
488 {
489 AxesTargetSwitchTimer = urand(7500, 20000);
490
491 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
492 {
493 for (uint8 i = 0; i < 2; ++i)
494 {
495 if (Unit* axe = ObjectAccessor::GetUnit(*me, axes[i]))
496 {
497 if (axe->GetVictim())
498 ResetThreat(axe->GetVictim(), axe);
499 AddThreat(target, 1000000.0f, axe);
500 }
501 }
502 }
503 } else AxesTargetSwitchTimer -= diff;
504
505 if (AmplifyDamageTimer <= diff)
506 {
507 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
509 AmplifyDamageTimer = urand(20000, 30000);
510 } else AmplifyDamageTimer -= diff;
511 }
512
513 //Time for global and double timers
514 if (InfernalTimer <= diff)
515 {
516 SummonInfernal(diff);
517 InfernalTimer = phase == 3 ? 14500 : 44500; // 15 secs in phase 3, 45 otherwise
518 } else InfernalTimer -= diff;
519
520 if (ShadowNovaTimer <= diff)
521 {
523 ShadowNovaTimer = phase == 3 ? 31000 : uint32(-1);
524 } else ShadowNovaTimer -= diff;
525
526 if (phase != 2)
527 {
528 if (SWPainTimer <= diff)
529 {
530 Unit* target = nullptr;
531 if (phase == 1)
532 target = me->GetVictim(); // the tank
533 else // anyone but the tank
534 target = SelectTarget(SelectTargetMethod::Random, 1, 100, true);
535
536 if (target)
537 DoCast(target, SPELL_SW_PAIN);
538
539 SWPainTimer = 20000;
540 } else SWPainTimer -= diff;
541 }
542
543 if (phase != 3)
544 {
545 if (EnfeebleTimer <= diff)
546 {
548 EnfeebleTimer = 30000;
549 ShadowNovaTimer = 5000;
550 EnfeebleResetTimer = 9000;
551 } else EnfeebleTimer -= diff;
552 }
553 }
554
555 void Cleanup(Creature* infernal, InfernalPoint *point)
556 {
557 for (GuidVector::iterator itr = infernals.begin(); itr!= infernals.end(); ++itr)
558 {
559 if (*itr == infernal->GetGUID())
560 {
561 infernals.erase(itr);
562 break;
563 }
564 }
565
566 positions.push_back(point);
567 }
568 };
569};
570
572{
574
575 if (pMalchezaar && pMalchezaar->IsAlive())
576 ENSURE_AI(boss_malchezaar::boss_malchezaarAI, pMalchezaar->AI())->Cleanup(me, point);
577}
578
580{
581 new boss_malchezaar();
583}
#define M_PI
Definition: Common.h:115
@ EQUIP_UNEQUIP
Definition: CreatureAI.h:55
@ EQUIP_NO_CHANGE
Definition: CreatureAI.h:54
uint8_t uint8
Definition: Define.h:144
uint64_t uint64
Definition: Define.h:141
uint32_t uint32
Definition: Define.h:142
@ IN_PROGRESS
@ DONE
@ NOT_STARTED
@ TEMPSUMMON_TIMED_DESPAWN
Definition: ObjectDefines.h:65
@ TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT
Definition: ObjectDefines.h:66
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
std::vector< ObjectGuid > GuidVector
Definition: ObjectGuid.h:395
float frand(float min, float max)
Definition: Random.cpp:55
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
uint32 rand32()
Definition: Random.cpp:70
@ OFF_ATTACK
@ BASE_ATTACK
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
Definition: SpellDefines.h:266
#define sSpellMgr
Definition: SpellMgr.h:849
#define ENSURE_AI(a, b)
Definition: UnitAI.h:29
DamageEffectType
Definition: UnitDefines.h:131
@ JUST_DIED
Definition: Unit.h:247
@ UNIT_STATE_STUNNED
Definition: Unit.h:258
#define INFERNAL_Z
static InfernalPoint InfernalPoints[]
@ SPELL_SHADOWNOVA
@ NETHERSPITE_INFERNAL
@ SPELL_ENFEEBLE_EFFECT
@ SPELL_THRASH_PASSIVE
@ SPELL_THRASH_AURA
@ INFERNAL_MODEL_INVISIBLE
@ SPELL_INFERNAL_RELAY
@ SPELL_SUNDER_ARMOR
@ SPELL_AMPLIFY_DAMAGE
@ SPELL_EQUIP_AXES
@ TOTAL_INFERNAL_POINTS
void AddSC_boss_malchezaar()
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
void SetTarget(ObjectGuid const &guid) override
Definition: Creature.cpp:3419
void SetDisplayId(uint32 displayId, bool setNative=false) override
Definition: Creature.cpp:3402
void SetCanDualWield(bool value) override
Definition: Creature.cpp:1940
CreatureAI * AI() const
Definition: Creature.h:214
virtual bool SetBossState(uint32 id, EncounterState state)
void HandleGameObject(ObjectGuid guid, bool open, GameObject *go=nullptr)
virtual ObjectGuid GetGuidData(uint32 type) const override
void Clear()
Definition: ObjectGuid.h:286
static Creature * ToCreature(Object *o)
Definition: Object.h:219
TypeID GetTypeId() const
Definition: Object.h:173
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
uint32 const Id
Definition: SpellInfo.h:325
Unit * GetCurrentVictim()
Trinity::IteratorPair< ThreatListIterator, std::nullptr_t > GetUnsortedThreatList() const
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
void SetHealth(uint64 val)
Definition: Unit.cpp:9346
ThreatManager & GetThreatManager()
Definition: Unit.h:1063
void SetFaction(uint32 faction) override
Definition: Unit.h:859
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition: Unit.cpp:3089
uint32 GetBaseAttackTime(WeaponAttackType att) const
Definition: Unit.cpp:10303
bool IsAlive() const
Definition: Unit.h:1164
void SetUninteractible(bool apply)
Definition: Unit.cpp:8147
void SetBaseAttackTime(WeaponAttackType att, uint32 val)
Definition: Unit.cpp:10308
Unit * EnsureVictim() const
Definition: Unit.h:717
uint32 GetNativeDisplayId() const
Definition: Unit.h:1570
uint32 GetFaction() const override
Definition: Unit.h:858
Unit * GetVictim() const
Definition: Unit.h:715
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
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
ObjectGuid GetTarget() const
Definition: Unit.h:1759
constexpr uint32 GetMapId() const
Definition: Position.h:201
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1042
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
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
@ DATA_MALCHEZZAR
Definition: karazhan.h:40
@ DATA_GO_NETHER_DOOR
Definition: karazhan.h:51
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
auto SelectRandomContainerElement(C const &container) -> typename std::add_const< decltype(*std::begin(container))>::type &
Definition: Containers.h:109
TriggerCastFlags TriggerFlags
Definition: SpellDefines.h:478
ObjectGuid OriginalCaster
Definition: SpellDefines.h:482
constexpr float GetPositionX() const
Definition: Position.h:76
constexpr float GetPositionY() const
Definition: Position.h:77
constexpr void Relocate(float x, float y)
Definition: Position.h:63
constexpr float GetPositionZ() const
Definition: Position.h:78
void SetEquipmentSlots(bool loadDefault, int32 mainHand=EQUIP_NO_CHANGE, int32 offHand=EQUIP_NO_CHANGE, int32 ranged=EQUIP_NO_CHANGE)
bool HealthBelowPct(uint32 pct) const
Difficulty GetDifficulty() const
void ResetThreat(Unit *victim, Unit *who=nullptr)
void AddThreat(Unit *victim, float amount, Unit *who=nullptr)
void Cleanup(Creature *infernal, InfernalPoint *point)
std::vector< InfernalPoint * > positions
void SpellHit(WorldObject *, SpellInfo const *spellInfo) override
void DamageTaken(Unit *done_by, uint32 &damage, DamageEffectType, SpellInfo const *) override