TrinityCore
Loading...
Searching...
No Matches
boss_twinemperors.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_Twinemperors
20SD%Complete: 95
21SDComment:
22SDCategory: Temple of Ahn'Qiraj
23EndScriptData */
24
25#include "ScriptMgr.h"
26#include "InstanceScript.h"
27#include "Item.h"
28#include "MotionMaster.h"
29#include "ObjectAccessor.h"
30#include "ScriptedCreature.h"
31#include "Spell.h"
32#include "SpellInfo.h"
33#include "temple_of_ahnqiraj.h"
34#include "WorldPacket.h"
35
37{
39 SPELL_TWIN_TELEPORT = 800, // CTRA watches for this spell to start its teleport timer
40 SPELL_TWIN_TELEPORT_VISUAL = 26638, // visual
49};
50
52{
53 SOUND_VL_AGGRO = 8657, //8657 - Aggro - To Late
54 SOUND_VL_KILL = 8658, //8658 - Kill - You will not
55 SOUND_VL_DEATH = 8659, //8659 - Death
56 SOUND_VN_DEATH = 8660, //8660 - Death - Feel
57 SOUND_VN_AGGRO = 8661, //8661 - Aggro - Let none
58 SOUND_VN_KILL = 8662, //8661 - Kill - your fate
59};
60
61enum Misc
62{
64 VEKLOR_DIST = 20, // VL will not come to melee when attacking
65 TELEPORTTIME = 30000
66};
67
68static constexpr float PULL_RANGE = 50.0f;
69
71{
73 {
74 Initialize();
75 }
76
78 {
79 Heal_Timer = 0; // first heal immediately when they get close together
81 AfterTeleport = false;
82 tspellcast = false;
84 Abuse_Bug_Timer = urand(10000, 17000);
85 BugsTimer = 2000;
86
87 DontYellWhenDead = false;
88 EnrageTimer = 15 * 60000;
89 }
90
99
100 virtual bool IAmVeklor() = 0;
101 virtual void Reset() override = 0;
102 virtual void CastSpellOnBug(Creature* target) = 0;
103
105 {
106 Initialize();
108 _Reset();
109 }
110
115
116 void DamageTaken(Unit* /*done_by*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
117 {
118 Unit* pOtherBoss = GetOtherBoss();
119 if (pOtherBoss)
120 {
121 float dPercent = ((float)damage) / ((float)me->GetMaxHealth());
122 int odmg = (int)(dPercent * ((float)pOtherBoss->GetMaxHealth()));
123 int ohealth = pOtherBoss->GetHealth()-odmg;
124 pOtherBoss->SetHealth(ohealth > 0 ? ohealth : 0);
125 if (ohealth <= 0)
126 {
127 pOtherBoss->setDeathState(JUST_DIED);
129 }
130 }
131 }
132
133 void JustDied(Unit* /*killer*/) override
134 {
135 Creature* pOtherBoss = GetOtherBoss();
136 if (pOtherBoss)
137 {
138 pOtherBoss->SetHealth(0);
139 pOtherBoss->setDeathState(JUST_DIED);
141 ENSURE_AI(boss_twinemperorsAI, pOtherBoss->AI())->DontYellWhenDead = true;
142 }
143 if (!DontYellWhenDead) // I hope AI is not threaded
145 _JustDied();
146 }
147
148 void KilledUnit(Unit* /*victim*/) override
149 {
151 }
152
153 void JustEngagedWith(Unit* who) override
154 {
156 Creature* pOtherBoss = GetOtherBoss();
157 if (pOtherBoss)
158 {
160 // is near I dont know how to do that
161 if (!pOtherBoss->IsInCombat())
162 {
163 ScriptedAI* otherAI = ENSURE_AI(ScriptedAI, pOtherBoss->AI());
165 otherAI->AttackStart(who);
166 otherAI->DoZoneInCombat();
167 }
168 }
169 }
170
171 void SpellHit(WorldObject* caster, SpellInfo const* spellInfo) override
172 {
173 if (caster == me)
174 return;
175
176 Creature* pOtherBoss = GetOtherBoss();
177 if (spellInfo->Id != SPELL_HEAL_BROTHER || !pOtherBoss)
178 return;
179
180 // add health so we keep same percentage for both brothers
181 uint32 mytotal = me->GetMaxHealth(), histotal = pOtherBoss->GetMaxHealth();
182 float mult = ((float)mytotal) / ((float)histotal);
183 if (mult < 1)
184 mult = 1.0f/mult;
185 #define HEAL_BROTHER_AMOUNT 30000.0f
186 uint32 largerAmount = (uint32)((HEAL_BROTHER_AMOUNT * mult) - HEAL_BROTHER_AMOUNT);
187
188 if (mytotal > histotal)
189 {
190 uint32 h = me->GetHealth()+largerAmount;
191 me->SetHealth(std::min(mytotal, h));
192 }
193 else
194 {
195 uint32 h = pOtherBoss->GetHealth()+largerAmount;
196 pOtherBoss->SetHealth(std::min(histotal, h));
197 }
198 }
199
201 {
202 if (IAmVeklor()) // this spell heals caster and the other brother so let VN cast it
203 return;
204
205 if (Heal_Timer <= diff)
206 {
207 Unit* pOtherBoss = GetOtherBoss();
208 if (pOtherBoss && pOtherBoss->IsWithinDist(me, 60))
209 {
210 DoCast(pOtherBoss, SPELL_HEAL_BROTHER);
211 Heal_Timer = 1000;
212 }
213 } else Heal_Timer -= diff;
214 }
215
217 {
219
220 if (IAmVeklor())
221 return; // mechanics handled by veknilash so they teleport exactly at the same time and to correct coordinates
222
223 Creature* pOtherBoss = GetOtherBoss();
224 if (pOtherBoss)
225 {
226 //me->MonsterYell("Teleporting ...", LANG_UNIVERSAL, 0);
227 Position thisPos;
228 thisPos.Relocate(me);
229 Position otherPos;
230 otherPos.Relocate(pOtherBoss);
231 pOtherBoss->UpdatePosition(thisPos);
232 me->UpdatePosition(otherPos);
233
235 ENSURE_AI(boss_twinemperorsAI, pOtherBoss->AI())->SetAfterTeleport();
236 }
237 }
238
250
252 {
253 if (AfterTeleport)
254 {
255 if (!tspellcast)
256 {
260 }
261
262 tspellcast = true;
263
264 if (AfterTeleportTimer <= diff)
265 {
266 AfterTeleport = false;
268 if (Unit* nearu = me->SelectNearestTarget(100))
269 {
270 //DoYell(nearu->GetName(), LANG_UNIVERSAL, 0);
271 AttackStart(nearu);
272 AddThreat(nearu, 10000);
273 }
274 return true;
275 }
276 else
277 {
278 AfterTeleportTimer -= diff;
279 // update important timers which would otherwise get skipped
280 if (EnrageTimer > diff)
281 EnrageTimer -= diff;
282 else
283 EnrageTimer = 0;
284 if (Teleport_Timer > diff)
285 Teleport_Timer -= diff;
286 else
287 Teleport_Timer = 0;
288 return false;
289 }
290 }
291 else
292 {
293 return true;
294 }
295 }
296
297 void MoveInLineOfSight(Unit* who) override
298
299 {
300 if (!who || me->GetVictim())
301 return;
302
303 if (me->CanCreatureAttack(who))
304 {
305 float attackRadius = me->GetAttackDistance(who);
306 if (attackRadius < PULL_RANGE)
307 attackRadius = PULL_RANGE;
308 if (me->IsWithinDistInMap(who, attackRadius) && me->GetDistanceZ(who) <= /*CREATURE_Z_ATTACK_RANGE*/7 /*there are stairs*/)
309 {
310 //if (who->HasStealthAura())
311 // who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
312 AttackStart(who);
313 }
314 }
315 }
316
318 {
319 std::list<Creature*> lUnitList;
320 me->GetCreatureListWithEntryInGrid(lUnitList, 15316, 150.0f);
321 me->GetCreatureListWithEntryInGrid(lUnitList, 15317, 150.0f);
322
323 if (lUnitList.empty())
324 return nullptr;
325
326 Creature* nearb = nullptr;
327
328 for (std::list<Creature*>::const_iterator iter = lUnitList.begin(); iter != lUnitList.end(); ++iter)
329 {
330 Creature* c = *iter;
331 if (c)
332 {
333 if (c->isDead())
334 {
335 c->Respawn();
337 c->RemoveAllAuras();
338 }
340 {
341 if (!nearb || (rand32() % 4) == 0)
342 nearb = c;
343 }
344 }
345 }
346 return nearb;
347 }
348
350 {
351 if (BugsTimer < diff || Abuse_Bug_Timer <= diff)
352 {
354 if (Abuse_Bug_Timer <= diff)
355 {
356 if (c)
357 {
359 Abuse_Bug_Timer = urand(10000, 17000);
360 }
361 else
362 {
363 Abuse_Bug_Timer = 1000;
364 }
365 }
366 else
367 {
368 Abuse_Bug_Timer -= diff;
369 }
370 BugsTimer = 2000;
371 }
372 else
373 {
374 BugsTimer -= diff;
375 Abuse_Bug_Timer -= diff;
376 }
377 }
378
380 {
381 if (EnrageTimer <= diff)
382 {
383 if (!me->IsNonMeleeSpellCast(true))
384 {
386 EnrageTimer = 60 * 60000;
387 }
388 else
389 EnrageTimer = 0;
390 }
391 else
392 EnrageTimer -= diff;
393 }
394};
395
397{
398public:
399 boss_veknilash() : CreatureScript("boss_veknilash") { }
400
401 CreatureAI* GetAI(Creature* creature) const override
402 {
403 return GetAQ40AI<boss_veknilashAI>(creature);
404 }
405
407 {
408 bool IAmVeklor() override {return false;}
410 {
411 Initialize();
412 }
413
415 {
416 UpperCut_Timer = urand(14000, 29000);
417 UnbalancingStrike_Timer = urand(8000, 18000);
418 Scarabs_Timer = urand(7000, 14000);
419 }
420
424
425 void Reset() override
426 {
427 TwinReset();
428 Initialize();
429 }
430
431 void CastSpellOnBug(Creature* target) override
432 {
435 target->AddAura(SPELL_MUTATE_BUG, target);
436 target->SetFullHealth();
437 }
438
439 void UpdateAI(uint32 diff) override
440 {
441 //Return since we have no target
442 if (!UpdateVictim())
443 return;
444
445 if (!TryActivateAfterTTelep(diff))
446 return;
447
448 //UnbalancingStrike_Timer
449 if (UnbalancingStrike_Timer <= diff)
450 {
452 UnbalancingStrike_Timer = 8000 + rand32() % 12000;
453 } else UnbalancingStrike_Timer -= diff;
454
455 if (UpperCut_Timer <= diff)
456 {
458 if (randomMelee)
459 DoCast(randomMelee, SPELL_UPPERCUT);
460 UpperCut_Timer = 15000 + rand32() % 15000;
461 } else UpperCut_Timer -= diff;
462
463 HandleBugs(diff);
464
465 //Heal brother when 60yrds close
466 TryHealBrother(diff);
467
468 //Teleporting to brother
469 if (Teleport_Timer <= diff)
470 {
472 } else Teleport_Timer -= diff;
473
474 CheckEnrage(diff);
475
477 }
478 };
479
480};
481
483{
484public:
485 boss_veklor() : CreatureScript("boss_veklor") { }
486
487 CreatureAI* GetAI(Creature* creature) const override
488 {
489 return GetAQ40AI<boss_veklorAI>(creature);
490 }
491
493 {
494 bool IAmVeklor() override {return true;}
496 {
497 Initialize();
498 }
499
501 {
503 Blizzard_Timer = urand(15000, 20000);
504 ArcaneBurst_Timer = 1000;
505 Scorpions_Timer = urand(7000, 14000);
506 }
507
512
513 void Reset() override
514 {
515 TwinReset();
516 Initialize();
517 }
518
519 void CastSpellOnBug(Creature* target) override
520 {
522 target->AddAura(SPELL_EXPLODEBUG, target);
523 target->SetFullHealth();
524 }
525
526 void UpdateAI(uint32 diff) override
527 {
528 //Return since we have no target
529 if (!UpdateVictim())
530 return;
531
532 // reset arcane burst after teleport - we need to do this because
533 // when VL jumps to VN's location there will be a warrior who will get only 2s to run away
534 // which is almost impossible
535 if (AfterTeleport)
536 ArcaneBurst_Timer = 5000;
537 if (!TryActivateAfterTTelep(diff))
538 return;
539
540 //ShadowBolt_Timer
541 if (ShadowBolt_Timer <= diff)
542 {
543 if (!me->IsWithinDist(me->GetVictim(), 45.0f))
545 else
547 ShadowBolt_Timer = 2000;
548 } else ShadowBolt_Timer -= diff;
549
550 //Blizzard_Timer
551 if (Blizzard_Timer <= diff)
552 {
553 if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 45, true))
554 DoCast(target, SPELL_BLIZZARD);
555 Blizzard_Timer = 15000 + rand32() % 15000;
556 } else Blizzard_Timer -= diff;
557
558 if (ArcaneBurst_Timer <= diff)
559 {
561 {
563 ArcaneBurst_Timer = 5000;
564 }
565 } else ArcaneBurst_Timer -= diff;
566
567 HandleBugs(diff);
568
569 //Heal brother when 60yrds close
570 TryHealBrother(diff);
571
572 //Teleporting to brother
573 if (Teleport_Timer <= diff)
574 {
576 } else Teleport_Timer -= diff;
577
578 CheckEnrage(diff);
579
580 //VL doesn't melee
581 //DoMeleeAttackIfReady();
582 }
583
584 void AttackStart(Unit* who) override
585 {
586 if (!who)
587 return;
588
589 if (who->isTargetableForAttack())
590 {
591 // VL doesn't melee
592 if (me->Attack(who, false))
593 {
595 AddThreat(who, 0.0f);
596 }
597 }
598 }
599 };
600
601};
602
604{
605 new boss_veknilash();
606 new boss_veklor();
607}
uint32_t uint32
Definition Define.h:133
#define NOMINAL_MELEE_RANGE
Spells
Definition PlayerAI.cpp:32
uint32 urand(uint32 min, uint32 max)
Definition Random.cpp:42
uint32 rand32()
Definition Random.cpp:70
@ UNIT_DYNFLAG_LOOTABLE
@ FACTION_MONSTER
@ FACTION_CREATURE
#define ENSURE_AI(a, b)
Definition UnitAI.h:28
@ JUST_DIED
Definition Unit.h:212
@ UNIT_STATE_STUNNED
Definition Unit.h:223
DamageEffectType
Definition Unit.h:352
#define HEAL_BROTHER_AMOUNT
@ VEKLOR_DIST
@ ABUSE_BUG_RANGE
@ TELEPORTTIME
@ SPELL_EXPLODEBUG
@ SPELL_UNBALANCING_STRIKE
@ SPELL_HEAL_BROTHER
@ SPELL_MUTATE_BUG
@ SPELL_SHADOWBOLT
@ SPELL_BLIZZARD
@ SPELL_TWIN_TELEPORT_VISUAL
@ SPELL_ARCANEBURST
@ SPELL_TWIN_TELEPORT
@ SPELL_BERSERK
@ SPELL_UPPERCUT
static constexpr float PULL_RANGE
@ SOUND_VN_KILL
@ SOUND_VL_KILL
@ SOUND_VL_AGGRO
@ SOUND_VL_DEATH
@ SOUND_VN_AGGRO
@ SOUND_VN_DEATH
void AddSC_boss_twinemperors()
InstanceScript *const instance
void JustEngagedWith(Unit *who) override
void DoZoneInCombat(Creature *creature=nullptr)
bool UpdateVictim()
Creature *const me
Definition CreatureAI.h:82
void Respawn(bool force=false)
void setDeathState(DeathState s) override
float GetAttackDistance(Unit const *player) const
bool CanCreatureAttack(Unit const *victim, bool force=true) const
Unit * SelectNearestTarget(float dist=0, bool playerOnly=false) const
CreatureAI * AI() const
Definition Creature.h:154
Creature * GetCreature(uint32 type)
void MoveChase(Unit *target, Optional< ChaseRange > dist={}, Optional< ChaseAngle > angle={})
virtual void SetDynamicFlag(uint32 flag)
Definition Object.h:89
uint32 Id
Definition SpellInfo.h:289
Unit * GetCurrentVictim()
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
virtual void AttackStart(Unit *)
Definition UnitAI.cpp:30
SpellCastResult DoCast(uint32 spellId)
Definition UnitAI.cpp:106
Definition Unit.h:769
void ClearUnitState(uint32 f)
Definition Unit.h:877
bool isTargetableForAttack(bool checkFakeDeath=true) const
Definition Unit.cpp:8367
void SetFullHealth()
Definition Unit.h:927
ThreatManager & GetThreatManager()
Definition Unit.h:1155
void SetFaction(uint32 faction) override
Definition Unit.h:974
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition Unit.cpp:3093
MotionMaster * GetMotionMaster()
Definition Unit.h:1667
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition Unit.cpp:3063
uint32 GetMaxHealth() const
Definition Unit.h:914
Aura * AddAura(uint32 spellId, Unit *target)
Definition Unit.cpp:11964
void SetHealth(uint32 val)
Definition Unit.cpp:9361
void AddUnitState(uint32 f)
Definition Unit.h:875
virtual bool UpdatePosition(float x, float y, float z, float ang, bool teleport=false)
Definition Unit.cpp:12890
bool Attack(Unit *victim, bool meleeAttack)
Definition Unit.cpp:5535
uint32 GetHealth() const
Definition Unit.h:913
Unit * GetVictim() const
Definition Unit.h:859
void RemoveAllAuras()
Definition Unit.cpp:4157
virtual void setDeathState(DeathState s)
Definition Unit.cpp:8728
bool IsInCombat() const
Definition Unit.h:1144
bool isDead() const
Definition Unit.h:1236
void GetCreatureListWithEntryInGrid(Container &creatureContainer, uint32 entry, float maxSearchRange=250.0f) const
Definition Object.cpp:3153
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:1192
bool IsWithinDist(WorldObject const *obj, float dist2compare, bool is3D=true) const
Definition Object.cpp:1187
float GetDistanceZ(WorldObject const *obj) const
Definition Object.cpp:1093
CreatureAI * GetAI(Creature *creature) const override
CreatureAI * GetAI(Creature *creature) const override
void Relocate(float x, float y)
Definition Position.h:66
void AttackStart(Unit *) override
void ResetThreatList(Unit *who=nullptr)
void DoPlaySoundToSet(WorldObject *source, uint32 soundId)
void AddThreat(Unit *victim, float amount, Unit *who=nullptr)
void HandleBugs(uint32 diff)
bool TryActivateAfterTTelep(uint32 diff)
void JustDied(Unit *) override
void CheckEnrage(uint32 diff)
Creature * RespawnNearbyBugsAndGetOne()
void MoveInLineOfSight(Unit *who) override
virtual void CastSpellOnBug(Creature *target)=0
void SpellHit(WorldObject *caster, SpellInfo const *spellInfo) override
void TryHealBrother(uint32 diff)
void DamageTaken(Unit *, uint32 &damage, DamageEffectType, SpellInfo const *) override
virtual void Reset() override=0
void KilledUnit(Unit *) override
void JustEngagedWith(Unit *who) override
virtual bool IAmVeklor()=0
boss_twinemperorsAI(Creature *creature)
boss_veklorAI(Creature *creature)
void CastSpellOnBug(Creature *target) override
void UpdateAI(uint32 diff) override
void AttackStart(Unit *who) override
void CastSpellOnBug(Creature *target) override
void UpdateAI(uint32 diff) override
@ DATA_VEKNILASH
@ DATA_TWIN_EMPERORS
@ DATA_VEKLOR