Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
boss_twinemperors.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6/* ScriptData
7SDName: Boss_Twinemperors
8SD%Complete: 95
9SDComment:
10SDCategory: Temple of Ahn'Qiraj
11EndScriptData */
12
13#include "ScriptMgr.h"
14#include "ScriptedCreature.h"
15#include "temple_of_ahnqiraj.h"
16#include "WorldPacket.h"
17#include "Item.h"
18#include "Spell.h"
19
21{
23 SPELL_TWIN_TELEPORT = 800, // CTRA watches for this spell to start its teleport timer
24 SPELL_TWIN_TELEPORT_VISUAL = 26638, // visual
33};
34
36{
37 SOUND_VL_AGGRO = 8657, //8657 - Aggro - To Late
38 SOUND_VL_KILL = 8658, //8658 - Kill - You will not
39 SOUND_VL_DEATH = 8659, //8659 - Death
40 SOUND_VN_DEATH = 8660, //8660 - Death - Feel
41 SOUND_VN_AGGRO = 8661, //8661 - Aggro - Let none
42 SOUND_VN_KILL = 8662, //8661 - Kill - your fate
43};
44
45enum Misc
46{
48 VEKLOR_DIST = 20, // VL will not come to melee when attacking
50};
51
53{
54 virtual bool IAmVeklor() = 0;
55 virtual void Reset() = 0;
56 virtual void CastSpellOnBug(Creature* target) = 0;
57
59 {
60 instance = creature->GetInstanceScript();
61
62 Heal_Timer = 0;
64 AfterTeleport = false;
68 BugsTimer = 0;
69 tspellcasted = false;
70 EnrageTimer = 0;
71 }
72
73 void TwinReset()
74 {
75 Heal_Timer = 0; // first heal immediately when they get close together
77 AfterTeleport = false;
78 tspellcasted = false;
80 Abuse_Bug_Timer = std::rand() % 17000 + 10000;
81 BugsTimer = 2000;
82 me->ClearUnitState(UNIT_STATE_STUNNED);
83 DontYellWhenDead = false;
84 EnrageTimer = 15*60000;
85 }
86
88 {
89 if (instance)
91 else
92 return NULL;
93 }
94
95 void DamageTaken(Unit* /*done_by*/, uint32 &damage) OVERRIDE
96 {
97 Unit* pOtherBoss = GetOtherBoss();
98 if (pOtherBoss)
99 {
100 float dPercent = ((float)damage) / ((float)me->GetMaxHealth());
101 int odmg = (int)(dPercent * ((float)pOtherBoss->GetMaxHealth()));
102 int ohealth = pOtherBoss->GetHealth()-odmg;
103 pOtherBoss->SetHealth(ohealth > 0 ? ohealth : 0);
104 if (ohealth <= 0)
105 {
108 }
109 }
110 }
111
112 void JustDied(Unit* /*killer*/) OVERRIDE
113 {
114 Creature* pOtherBoss = GetOtherBoss();
115 if (pOtherBoss)
116 {
117 pOtherBoss->SetHealth(0);
120 CAST_AI(boss_twinemperorsAI, pOtherBoss->AI())->DontYellWhenDead = true;
121 }
122 if (!DontYellWhenDead) // I hope AI is not threaded
124 }
125
130
132 {
134 Creature* pOtherBoss = GetOtherBoss();
135 if (pOtherBoss)
136 {
138 // is near I dont know how to do that
139 ScriptedAI* otherAI = CAST_AI(ScriptedAI, pOtherBoss->AI());
140 if (!pOtherBoss->IsInCombat())
141 {
143 otherAI->AttackStart(who);
144 otherAI->DoZoneInCombat();
145 }
146 }
147 }
148
149 void SpellHit(Unit* caster, const SpellInfo* entry) OVERRIDE
150 {
151 if (caster == me)
152 return;
153
154 Creature* pOtherBoss = GetOtherBoss();
155 if (entry->Id != SPELL_HEAL_BROTHER || !pOtherBoss)
156 return;
157
158 // add health so we keep same percentage for both brothers
159 uint32 mytotal = me->GetMaxHealth(), histotal = pOtherBoss->GetMaxHealth();
160 float mult = ((float)mytotal) / ((float)histotal);
161 if (mult < 1)
162 mult = 1.0f/mult;
163 #define HEAL_BROTHER_AMOUNT 30000.0f
164 uint32 largerAmount = (uint32)((HEAL_BROTHER_AMOUNT * mult) - HEAL_BROTHER_AMOUNT);
165
166 if (mytotal > histotal)
167 {
168 uint32 h = me->GetHealth()+largerAmount;
169 me->SetHealth(std::min(mytotal, h));
170 }
171 else
172 {
173 uint32 h = pOtherBoss->GetHealth()+largerAmount;
174 pOtherBoss->SetHealth(std::min(histotal, h));
175 }
176 }
177
179 {
180 if (IAmVeklor()) // this spell heals caster and the other brother so let VN cast it
181 return;
182
183 if (Heal_Timer <= diff)
184 {
185 Unit* pOtherBoss = GetOtherBoss();
186 if (pOtherBoss && pOtherBoss->IsWithinDist(me, 60))
187 {
188 DoCast(pOtherBoss, SPELL_HEAL_BROTHER);
189 Heal_Timer = 1000;
190 }
191 } else Heal_Timer -= diff;
192 }
193
195 {
196 if (!instance)
197 return;
198
200
201 if (IAmVeklor())
202 return; // mechanics handled by veknilash so they teleport exactly at the same time and to correct coordinates
203
204 Creature* pOtherBoss = GetOtherBoss();
205 if (pOtherBoss)
206 {
207 //me->MonsterYell("Teleporting ...", LANG_UNIVERSAL, 0);
208 Position thisPos;
209 thisPos.Relocate(me);
210 Position otherPos;
211 otherPos.Relocate(pOtherBoss);
212 pOtherBoss->SetPosition(thisPos);
213 me->SetPosition(otherPos);
214
216 CAST_AI(boss_twinemperorsAI, pOtherBoss->AI())->SetAfterTeleport();
217 }
218 }
219
221 {
222 me->InterruptNonMeleeSpells(false);
223 DoStopAttack();
226 me->AddUnitState(UNIT_STATE_STUNNED);
227 AfterTeleport = true;
228 AfterTeleportTimer = 2000;
229 tspellcasted = false;
230 }
231
233 {
234 if (AfterTeleport)
235 {
236 if (!tspellcasted)
237 {
238 me->ClearUnitState(UNIT_STATE_STUNNED);
240 me->AddUnitState(UNIT_STATE_STUNNED);
241 }
242
243 tspellcasted = true;
244
245 if (AfterTeleportTimer <= diff)
246 {
247 AfterTeleport = false;
248 me->ClearUnitState(UNIT_STATE_STUNNED);
249 if (Unit* nearu = me->SelectNearestTarget(100))
250 {
251 //DoYell(nearu->GetName(), LANG_UNIVERSAL, 0);
252 AttackStart(nearu);
253 me->AddThreat(nearu, 10000);
254 }
255 return true;
256 }
257 else
258 {
259 AfterTeleportTimer -= diff;
260 // update important timers which would otherwise get skipped
261 if (EnrageTimer > diff)
262 EnrageTimer -= diff;
263 else
264 EnrageTimer = 0;
265 if (Teleport_Timer > diff)
266 Teleport_Timer -= diff;
267 else
268 Teleport_Timer = 0;
269 return false;
270 }
271 }
272 else
273 {
274 return true;
275 }
276 }
277
279
280 {
281 if (!who || me->GetVictim())
282 return;
283
284 if (me->CanCreatureAttack(who))
285 {
286 float attackRadius = me->GetAttackDistance(who);
287 if (attackRadius < 50.0f)
288 attackRadius = 50.0f;
289 if (me->IsWithinDistInMap(who, attackRadius) && me->GetDistanceZ(who) <= /*CREATURE_Z_ATTACK_RANGE*/7 /*there are stairs*/)
290 {
291 //if (who->HasStealthAura())
292 // who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);
293 AttackStart(who);
294 }
295 }
296 }
297
299 {
300 std::list<Creature*> lUnitList;
301 me->GetCreatureListWithEntryInGrid(lUnitList, 15316, 150.0f);
302 me->GetCreatureListWithEntryInGrid(lUnitList, 15317, 150.0f);
303
304 if (lUnitList.empty())
305 return NULL;
306
307 Creature* nearb = NULL;
308
309 for (std::list<Creature*>::const_iterator iter = lUnitList.begin(); iter != lUnitList.end(); ++iter)
310 {
311 Creature* c = *iter;
312 if (c)
313 {
314 if (c->isDead())
315 {
316 c->Respawn();
317 c->setFaction(7);
318 c->RemoveAllAuras();
319 }
321 {
322 if (!nearb || (rand()%4) == 0)
323 nearb = c;
324 }
325 }
326 }
327 return nearb;
328 }
329
331 {
332 if (BugsTimer < diff || Abuse_Bug_Timer <= diff)
333 {
335 if (Abuse_Bug_Timer <= diff)
336 {
337 if (c)
338 {
340 Abuse_Bug_Timer = std::rand() % 17000 + 10000;
341 }
342 else
343 {
344 Abuse_Bug_Timer = 1000;
345 }
346 }
347 else
348 {
349 Abuse_Bug_Timer -= diff;
350 }
351 BugsTimer = 2000;
352 }
353 else
354 {
355 BugsTimer -= diff;
356 Abuse_Bug_Timer -= diff;
357 }
358 }
359
361 {
362 if (EnrageTimer <= diff)
363 {
364 if (!me->IsNonMeleeSpellCasted(true))
365 {
367 EnrageTimer = 60*60000;
368 } else EnrageTimer = 0;
369 } else EnrageTimer-=diff;
370 }
371
373
382};
383
385{
386public:
387 boss_veknilash() : CreatureScript("boss_veknilash") { }
388
390 {
391 bool IAmVeklor() OVERRIDE {return false;}
392
394 {
395 UpperCut_Timer = 0;
397 Scarabs_Timer = 0;
398 Rand = 0;
399 RandX = 0;
400 RandY = 0;
401 Summoned = NULL;
402 }
403
405 {
406 TwinReset();
407 UpperCut_Timer = std::rand() % 29000 + 14000;
408 UnbalancingStrike_Timer = std::rand() % 18000 + 8000;
409 Scarabs_Timer = std::rand() % 14000 + 7000;
410
411 //Added. Can be removed if its included in DB.
412 me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_MAGIC, true);
413 }
414
416 {
417 target->setFaction(14);
418 target->AI()->AttackStart(me->getThreatManager().getHostilTarget());
419 target->AddAura(SPELL_MUTATE_BUG, target);
420 target->SetFullHealth();
421 }
422
424 {
425 //Return since we have no target
426 if (!UpdateVictim())
427 return;
428
429 if (!TryActivateAfterTTelep(diff))
430 return;
431
432 //UnbalancingStrike_Timer
433 if (UnbalancingStrike_Timer <= diff)
434 {
436 UnbalancingStrike_Timer = 8000+rand()%12000;
437 } else UnbalancingStrike_Timer -= diff;
438
439 if (UpperCut_Timer <= diff)
440 {
442 if (randomMelee)
443 DoCast(randomMelee, SPELL_UPPERCUT);
444 UpperCut_Timer = 15000+rand()%15000;
445 } else UpperCut_Timer -= diff;
446
447 HandleBugs(diff);
448
449 //Heal brother when 60yrds close
450 TryHealBrother(diff);
451
452 //Teleporting to brother
453 if (Teleport_Timer <= diff)
454 {
456 } else Teleport_Timer -= diff;
457
458 CheckEnrage(diff);
459
461 }
462
467 int Rand;
468 int RandX;
469 int RandY;
470 };
471
473 {
474 return new boss_veknilashAI(creature);
475 }
476};
477
479{
480public:
481 boss_veklor() : CreatureScript("boss_veklor") { }
482
484 {
485 bool IAmVeklor() OVERRIDE {return true;}
486
488 {
490 Blizzard_Timer = 0;
492 Scorpions_Timer = 0;
493 Rand = 0;
494 RandX = 0;
495 RandY = 0;
496 Summoned = NULL;
497 }
498
500 {
501 TwinReset();
503 Blizzard_Timer = std::rand() % 20000 + 15000;
504 ArcaneBurst_Timer = 1000;
505 Scorpions_Timer = std::rand() % 14000 + 7000;
506
507 //Added. Can be removed if its included in DB.
508 me->ApplySpellImmune(0, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, true);
511 }
512
514 {
515 target->setFaction(14);
516 target->AddAura(SPELL_EXPLODEBUG, target);
517 target->SetFullHealth();
518 }
519
521 {
522 //Return since we have no target
523 if (!UpdateVictim())
524 return;
525
526 // reset arcane burst after teleport - we need to do this because
527 // when VL jumps to VN's location there will be a warrior who will get only 2s to run away
528 // which is almost impossible
529 if (AfterTeleport)
530 ArcaneBurst_Timer = 5000;
531 if (!TryActivateAfterTTelep(diff))
532 return;
533
534 //ShadowBolt_Timer
535 if (ShadowBolt_Timer <= diff)
536 {
537 if (!me->IsWithinDist(me->GetVictim(), 45.0f))
538 me->GetMotionMaster()->MoveChase(me->GetVictim(), VEKLOR_DIST, 0);
539 else
541 ShadowBolt_Timer = 2000;
542 } else ShadowBolt_Timer -= diff;
543
544 //Blizzard_Timer
545 if (Blizzard_Timer <= diff)
546 {
547 Unit* target = NULL;
548 target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45, true);
549 if (target)
550 DoCast(target, SPELL_BLIZZARD);
551 Blizzard_Timer = 15000+rand()%15000;
552 } else Blizzard_Timer -= diff;
553
554 if (ArcaneBurst_Timer <= diff)
555 {
556 Unit* mvic;
557 if ((mvic=SelectTarget(SELECT_TARGET_NEAREST, 0, NOMINAL_MELEE_RANGE, true)) != NULL)
558 {
560 ArcaneBurst_Timer = 5000;
561 }
562 } else ArcaneBurst_Timer -= diff;
563
564 HandleBugs(diff);
565
566 //Heal brother when 60yrds close
567 TryHealBrother(diff);
568
569 //Teleporting to brother
570 if (Teleport_Timer <= diff)
571 {
573 } else Teleport_Timer -= diff;
574
575 CheckEnrage(diff);
576
577 //VL doesn't melee
578 //DoMeleeAttackIfReady();
579 }
580
582 {
583 if (!who)
584 return;
585
586 if (who->isTargetableForAttack())
587 {
588 // VL doesn't melee
589 if (me->Attack(who, false))
590 {
591 me->GetMotionMaster()->MoveChase(who, VEKLOR_DIST, 0);
592 me->AddThreat(who, 0.0f);
593 }
594 }
595 }
596
602 int Rand;
603 int RandX;
604 int RandY;
605 };
606
608 {
609 return new boss_veklorAI(creature);
610 }
611};
612
614{
615 new boss_veknilash();
616 new boss_veklor();
617}
std::uint32_t uint32
Definition Define.h:77
#define OVERRIDE
Definition Define.h:60
#define NOMINAL_MELEE_RANGE
Definition Object.h:32
#define CAST_AI(a, b)
@ UNIT_DYNFLAG_LOOTABLE
@ IMMUNITY_DAMAGE
@ SPELL_SCHOOL_MASK_NORMAL
@ SPELL_SCHOOL_MASK_MAGIC
@ JUST_DIED
Definition Unit.h:504
@ UNIT_STATE_STUNNED
Definition Unit.h:515
@ SELECT_TARGET_NEAREST
Definition UnitAI.h:26
@ SELECT_TARGET_RANDOM
Definition UnitAI.h:23
@ OBJECT_FIELD_DYNAMIC_FLAGS
@ SPELL_SHADOWBOLT
#define SPELL_BERSERK
#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
@ SOUND_VN_KILL
@ SOUND_VL_KILL
@ SOUND_VL_AGGRO
@ SOUND_VL_DEATH
@ SOUND_VN_AGGRO
@ SOUND_VN_DEATH
void AddSC_boss_twinemperors()
void DoZoneInCombat(Creature *creature=NULL, float maxRangeToNearestTarget=50.0f)
bool UpdateVictim()
void Respawn(bool force=false)
void SetPosition(float x, float y, float z, float o)
void setDeathState(DeathState s) OVERRIDE
CreatureAI * AI() const
Definition Creature.h:483
CreatureScript(const char *name)
void SetFlag(uint16 index, uint32 newFlag)
Definition Object.cpp:1261
void DoMeleeAttackIfReady()
Definition UnitAI.cpp:28
void DoCast(uint32 spellId)
Definition UnitAI.cpp:110
Unit * SelectTarget(SelectAggroTarget targetType, uint32 position=0, float dist=0.0f, bool playerOnly=false, int32 aura=0)
Definition UnitAI.cpp:66
void DoCastVictim(uint32 spellId, bool triggered=false)
Definition UnitAI.cpp:168
Definition Unit.h:1367
void setFaction(uint32 faction)
Definition Unit.h:1699
uint32 GetMaxHealth() const
Definition Unit.h:1604
void SetHealth(uint32 val)
Definition Unit.cpp:5162
static Creature * GetCreature(WorldObject &object, uint64 guid)
Definition Unit.cpp:4905
uint32 GetHealth() const
Definition Unit.h:1600
void RemoveAllAuras()
virtual void setDeathState(DeathState s)
Definition Unit.cpp:4365
bool IsInCombat() const
Definition Unit.h:1896
bool isDead() const
Definition Unit.h:2040
InstanceScript * GetInstanceScript()
Definition Object.cpp:1612
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true) const
Definition Object.cpp:1735
bool IsWithinDist(WorldObject const *obj, float dist2compare, bool is3D=true) const
Definition Object.cpp:1730
CreatureAI * GetAI(Creature *creature) const OVERRIDE
CreatureAI * GetAI(Creature *creature) const OVERRIDE
void Relocate(float x, float y)
Definition Object.h:302
Creature * me
ScriptedAI(Creature *creature)
void DoPlaySoundToSet(WorldObject *source, uint32 soundId)
void AttackStart(Unit *) OVERRIDE
void HandleBugs(uint32 diff)
bool TryActivateAfterTTelep(uint32 diff)
void MoveInLineOfSight(Unit *who) OVERRIDE
InstanceScript * instance
void EnterCombat(Unit *who) OVERRIDE
void CheckEnrage(uint32 diff)
Creature * RespawnNearbyBugsAndGetOne()
virtual void CastSpellOnBug(Creature *target)=0
void TryHealBrother(uint32 diff)
void KilledUnit(Unit *) OVERRIDE
void JustDied(Unit *) OVERRIDE
void SpellHit(Unit *caster, const SpellInfo *entry) OVERRIDE
virtual void Reset()=0
virtual bool IAmVeklor()=0
void DamageTaken(Unit *, uint32 &damage) OVERRIDE
boss_twinemperorsAI(Creature *creature)
void CastSpellOnBug(Creature *target) OVERRIDE
boss_veklorAI(Creature *creature)
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void AttackStart(Unit *who) OVERRIDE
void UpdateAI(uint32 diff) OVERRIDE
== Triggered Actions Requested ==================
void CastSpellOnBug(Creature *target) OVERRIDE
@ DATA_VEKNILASH
@ DATA_VEKLOR