mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-31 06:07:37 +01:00
Scripts/Naxxramas: Clean-up and bug-fix megacommit. Read the full commit message if you care.
- Maexxna: - No longer packages pets and returns them to sender. Web Wrap now only targets players. - Heigan the Unclean: Ripped its guts out. - Instance script hacks are gone. - GO spawns (done using the time-honored TC tradition of "eh, this'll work") are gone. You could say I evacuated the dance floor. - Sniffed spawns for all segments of the room. Because if you don't dance - well, you're no friends of mine. - Loatheb: - First spore now spawns properly after 18 seconds on 10-man (down from 36 seconds). Time between subsequent spawns is unchanged. - Thaddius: - Instance script hacks are gone. Again. Feels good man. - Players no longer drop out of combat during the phase transition. Put your snacks away, this is supposed to be a tense situation! - Thaddius will no longer savagely punish the main tank for stepping out of melee range for a fraction of a second by turning around and ball lightning-ing someone in the face. Typically a healer. He hates healers. - Thaddius will instead take out his frustration on another melee range target if available by smacking them in the face with his fists. It hurts, but a Ball Lightning would've hurt more. Blame the tank. - Feugen and Stalagg have been re-educated to improve their patience when a new target is flying towards them. They will no longer move while Magnetic Pull targets are mid-air, which should prevent them from running off their platform while the warrior helplessly flails trying to get them back. - Instructor Razuvious: - Razuvious has been informed that Rubik's Cubes become noticably easier to solve if you buy six-colored ones. Thus, he will no longer take out his frustration out on raid groups by throwing unsolved two-colored variants at them. Fixes and closes #14966. - Death Knight Understudies will now realize that their situation is Hopeless even if they're currently mind controlled by a player. Apparently, if your situation is hopeless you take 5000% extra damage. No, that is supposed to be three zeroes. - Gothik the Harvester: - Gothik has been schooled in proper Shadow Bolt spamming etiquette and will now take a brief pause to catch a breath and recompose himself between bolts. - The Four Horsemen: - Will no longer stop and stare at the group sometimes when engaged instead of starting the encounter. - Horsemen can no longer be affected by stun, snare and shackle (heh, yeah, you could totally shackle Baron Rivendare) effects. It's called "Four Horsemen" after all, not "Three Horsemen that never attack because their friend can't move". - Sapphiron: - When attempting to FREEZE THE BLOOD IN YOUR VEINS... Wait, no. Wrong boss. I was thinking of #16634. - Anyways, when freezing people into an Ice Block, Sapphiron now takes care to actually place the block on top of the frozen player, even if they were moving or jumping when the bolt hit them. Yay for positioning clarity! - Sapphiron has been sent to take multiple mandatory courses in "How to treat raid parties fairly while attempting to murder them" and will thus... - ...now properly pause after taking off to allow players to get into position before smacking them with ice bolts - ...no longer deal damage to players inside an Ice Block while they cannot fight back. - Being forced to attend the courses mentioned above has led to a large amount of pent-up frustration, which Sapphiron relieves by quite forcefully flapping his wings during take-off. Players immediately below him are now properly knocked back. - In addition, Kel'thuzad was sick of Sapphiron's continous pouting and allowed him to make Blizzard more malicious in exchange. Blizzard will now properly spawn near players and chase them down instead of pathing randomly. - Also, tons of code style cleanups and hack removal that wasn't mentioned above. Read the diff if you really care. Conflicts: src/server/game/Spells/Spell.cpp
This commit is contained in:
@@ -190,6 +190,7 @@ enum SpellCustomAttributes
|
||||
SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER = 0x00010000,
|
||||
SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET = 0x00020000,
|
||||
SPELL_ATTR0_CU_ALLOW_INFLIGHT_TARGET = 0x00040000,
|
||||
SPELL_ATTR0_CU_NEEDS_AMMO_DATA = 0x00080000,
|
||||
|
||||
SPELL_ATTR0_CU_NEGATIVE = SPELL_ATTR0_CU_NEGATIVE_EFF0 | SPELL_ATTR0_CU_NEGATIVE_EFF1 | SPELL_ATTR0_CU_NEGATIVE_EFF2
|
||||
};
|
||||
|
||||
@@ -3124,6 +3124,7 @@ void SpellMgr::LoadSpellInfoCorrections()
|
||||
case 52479: // Gift of the Harvester
|
||||
case 61588: // Blazing Harpoon
|
||||
case 55479: // Force Obedience
|
||||
case 28560: // Summon Blizzard (Sapphiron)
|
||||
spellInfo->MaxAffectedTargets = 1;
|
||||
break;
|
||||
case 36384: // Skartax Purple Beam
|
||||
|
||||
@@ -162,13 +162,13 @@ public:
|
||||
summons.DoZoneInCombat();
|
||||
|
||||
events.SetPhase(PHASE_NORMAL);
|
||||
events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL);
|
||||
events.ScheduleEvent(EVENT_SCARABS, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS), 0, PHASE_NORMAL);
|
||||
events.ScheduleEvent(EVENT_LOCUST, urand(80,120) * IN_MILLISECONDS, 0, PHASE_NORMAL);
|
||||
events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_IMPALE, randtime(Seconds(10), Seconds(20)), 0, PHASE_NORMAL);
|
||||
events.ScheduleEvent(EVENT_SCARABS, randtime(Seconds(20), Seconds(30)), 0, PHASE_NORMAL);
|
||||
events.ScheduleEvent(EVENT_LOCUST, Minutes(1)+randtime(Seconds(40), Seconds(60)), 0, PHASE_NORMAL);
|
||||
events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
|
||||
|
||||
if (!Is25ManRaid())
|
||||
events.ScheduleEvent(EVENT_SPAWN_GUARD, urand(15, 20) * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_SPAWN_GUARD, randtime(Seconds(15), Seconds(20)));
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
@@ -189,11 +189,9 @@ public:
|
||||
else
|
||||
EnterEvadeMode();
|
||||
|
||||
events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL);
|
||||
events.Repeat(randtime(Seconds(10), Seconds(20)));
|
||||
break;
|
||||
case EVENT_SCARABS:
|
||||
events.ScheduleEvent(EVENT_SCARABS, urand(40 * IN_MILLISECONDS, 60 * IN_MILLISECONDS), 0, PHASE_NORMAL);
|
||||
|
||||
if (!guardCorpses.empty())
|
||||
{
|
||||
if (ObjectGuid target = Trinity::Containers::SelectRandomContainerElement(guardCorpses))
|
||||
@@ -204,27 +202,28 @@ public:
|
||||
creatureTarget->DespawnOrUnsummon();
|
||||
}
|
||||
}
|
||||
events.Repeat(randtime(Seconds(40), Seconds(60)));
|
||||
break;
|
||||
case EVENT_LOCUST:
|
||||
Talk(EMOTE_LOCUST);
|
||||
DoCast(me, SPELL_LOCUST_SWARM);
|
||||
events.ScheduleEvent(EVENT_SPAWN_GUARD, 3 * IN_MILLISECONDS);
|
||||
|
||||
events.ScheduleEvent(EVENT_LOCUST_ENDS, RAID_MODE(19, 23) * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_LOCUST, 90000);
|
||||
events.SetPhase(PHASE_SWARM);
|
||||
DoCast(me, SPELL_LOCUST_SWARM);
|
||||
|
||||
events.ScheduleEvent(EVENT_SPAWN_GUARD, Seconds(3));
|
||||
events.ScheduleEvent(EVENT_LOCUST_ENDS, RAID_MODE(Seconds(19), Seconds(23)));
|
||||
events.Repeat(Minutes(1)+Seconds(30));
|
||||
break;
|
||||
case EVENT_LOCUST_ENDS:
|
||||
events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL);
|
||||
events.ScheduleEvent(EVENT_SCARABS, urand(20 * IN_MILLISECONDS, 30 * IN_MILLISECONDS), 0, PHASE_NORMAL);
|
||||
events.SetPhase(PHASE_NORMAL);
|
||||
events.ScheduleEvent(EVENT_IMPALE, randtime(Seconds(10), Seconds(20)), 0, PHASE_NORMAL);
|
||||
events.ScheduleEvent(EVENT_SCARABS, randtime(Seconds(20), Seconds(30)), 0, PHASE_NORMAL);
|
||||
break;
|
||||
case EVENT_SPAWN_GUARD:
|
||||
me->SummonCreatureGroup(GROUP_SINGLE_SPAWN);
|
||||
break;
|
||||
case EVENT_BERSERK:
|
||||
DoCast(me, SPELL_BERSERK, true);
|
||||
events.ScheduleEvent(EVENT_BERSERK, 600000);
|
||||
events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,9 +100,9 @@ class boss_faerlina : public CreatureScript
|
||||
_EnterCombat();
|
||||
Talk(SAY_AGGRO);
|
||||
summons.DoZoneInCombat();
|
||||
events.ScheduleEvent(EVENT_POISON, urand(10 * IN_MILLISECONDS, 15 * IN_MILLISECONDS));
|
||||
events.ScheduleEvent(EVENT_FIRE, urand(6 * IN_MILLISECONDS, 18 * IN_MILLISECONDS));
|
||||
events.ScheduleEvent(EVENT_FRENZY, urand(60 * IN_MILLISECONDS, 80 * IN_MILLISECONDS));
|
||||
events.ScheduleEvent(EVENT_POISON, randtime(Seconds(10), Seconds(15)));
|
||||
events.ScheduleEvent(EVENT_FIRE, randtime(Seconds(6), Seconds(18)));
|
||||
events.ScheduleEvent(EVENT_FRENZY, Minutes(1)+randtime(Seconds(0), Seconds(20)));
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
@@ -111,9 +111,9 @@ class boss_faerlina : public CreatureScript
|
||||
_frenzyDispels = 0;
|
||||
}
|
||||
|
||||
void KilledUnit(Unit* /*victim*/) override
|
||||
void KilledUnit(Unit* victim) override
|
||||
{
|
||||
if (!urand(0, 2))
|
||||
if (victim->GetTypeId() == TYPEID_PLAYER)
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
@@ -158,21 +158,21 @@ class boss_faerlina : public CreatureScript
|
||||
case EVENT_POISON:
|
||||
if (!me->HasAura(SPELL_WIDOWS_EMBRACE_HELPER))
|
||||
DoCastAOE(SPELL_POISON_BOLT_VOLLEY);
|
||||
events.ScheduleEvent(EVENT_POISON, urand(8000, 15000));
|
||||
events.Repeat(randtime(Seconds(8), Seconds(15)));
|
||||
break;
|
||||
case EVENT_FIRE:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
|
||||
DoCast(target, SPELL_RAIN_OF_FIRE);
|
||||
events.ScheduleEvent(EVENT_FIRE, urand(6000, 18000));
|
||||
events.Repeat(randtime(Seconds(6), Seconds(18)));
|
||||
break;
|
||||
case EVENT_FRENZY:
|
||||
if (Aura* widowsEmbrace = me->GetAura(SPELL_WIDOWS_EMBRACE_HELPER))
|
||||
events.ScheduleEvent(EVENT_FRENZY, widowsEmbrace->GetDuration()+1 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_FRENZY, Milliseconds(widowsEmbrace->GetDuration()+1));
|
||||
else
|
||||
{
|
||||
DoCast(SPELL_FRENZY);
|
||||
Talk(EMOTE_FRENZY);
|
||||
events.ScheduleEvent(EVENT_FRENZY, urand(60 * IN_MILLISECONDS, 80 * IN_MILLISECONDS));
|
||||
events.Repeat(Minutes(1) + randtime(Seconds(0), Seconds(20)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -285,7 +285,7 @@ struct boss_four_horsemen_baseAI : public BossAI
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
if (instance->GetBossState(BOSS_HORSEMEN) != NOT_STARTED) // another horseman already did it
|
||||
if (instance->GetBossState(BOSS_HORSEMEN) == IN_PROGRESS || instance->GetBossState(BOSS_HORSEMEN) == DONE) // another horseman already did it
|
||||
return;
|
||||
Talk(SAY_AGGRO);
|
||||
BeginEncounter();
|
||||
@@ -411,9 +411,9 @@ class boss_four_horsemen_baron : public CreatureScript
|
||||
else
|
||||
AttackStart(threat.getHostilTarget());
|
||||
|
||||
events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_UNHOLYSHADOW, urandms(3,7));
|
||||
events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
|
||||
events.ScheduleEvent(EVENT_MARK, Seconds(24));
|
||||
events.ScheduleEvent(EVENT_UNHOLYSHADOW, randtime(Seconds(3), Seconds(7)));
|
||||
}
|
||||
|
||||
void _UpdateAI(uint32 diff) override
|
||||
@@ -431,11 +431,11 @@ class boss_four_horsemen_baron : public CreatureScript
|
||||
break;
|
||||
case EVENT_MARK:
|
||||
DoCastAOE(SPELL_BARON_MARK, true);
|
||||
events.ScheduleEvent(EVENT_MARK, 12 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(12));
|
||||
break;
|
||||
case EVENT_UNHOLYSHADOW:
|
||||
DoCastVictim(SPELL_UNHOLY_SHADOW);
|
||||
events.ScheduleEvent(EVENT_UNHOLYSHADOW, urandms(10,30));
|
||||
events.Repeat(randtime(Seconds(10), Seconds(30)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -484,9 +484,9 @@ class boss_four_horsemen_thane : public CreatureScript
|
||||
else
|
||||
AttackStart(threat.getHostilTarget());
|
||||
|
||||
events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_METEOR, urandms(10,15));
|
||||
events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
|
||||
events.ScheduleEvent(EVENT_MARK, Seconds(24));
|
||||
events.ScheduleEvent(EVENT_METEOR, randtime(Seconds(10), Seconds(25)));
|
||||
}
|
||||
void _UpdateAI(uint32 diff) override
|
||||
{
|
||||
@@ -503,7 +503,7 @@ class boss_four_horsemen_thane : public CreatureScript
|
||||
break;
|
||||
case EVENT_MARK:
|
||||
DoCastAOE(SPELL_THANE_MARK, true);
|
||||
events.ScheduleEvent(EVENT_MARK, 12 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(12));
|
||||
break;
|
||||
case EVENT_METEOR:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.0f, true))
|
||||
@@ -511,7 +511,7 @@ class boss_four_horsemen_thane : public CreatureScript
|
||||
DoCast(target, SPELL_METEOR);
|
||||
_shouldSay = true;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_METEOR, urandms(13,17));
|
||||
events.Repeat(randtime(Seconds(13), Seconds(17)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -550,9 +550,9 @@ class boss_four_horsemen_lady : public CreatureScript
|
||||
boss_four_horsemen_ladyAI(Creature* creature) : boss_four_horsemen_baseAI(creature, LADY, ladyPath) { }
|
||||
void BeginFighting() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_VOIDZONE, urandms(5,10));
|
||||
events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
|
||||
events.ScheduleEvent(EVENT_MARK, Seconds(24));
|
||||
events.ScheduleEvent(EVENT_VOIDZONE, randtime(Seconds(5), Seconds(10)));
|
||||
}
|
||||
|
||||
void _UpdateAI(uint32 diff) override
|
||||
@@ -578,7 +578,7 @@ class boss_four_horsemen_lady : public CreatureScript
|
||||
break;
|
||||
case EVENT_MARK:
|
||||
DoCastAOE(SPELL_LADY_MARK, true);
|
||||
events.ScheduleEvent(EVENT_MARK, 15 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(15));
|
||||
break;
|
||||
case EVENT_VOIDZONE:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f, true))
|
||||
@@ -586,7 +586,7 @@ class boss_four_horsemen_lady : public CreatureScript
|
||||
DoCast(target, SPELL_VOID_ZONE, true);
|
||||
Talk(SAY_SPECIAL);
|
||||
}
|
||||
events.ScheduleEvent(EVENT_VOIDZONE, urandms(12, 18));
|
||||
events.Repeat(randtime(Seconds(12), Seconds(18)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -620,9 +620,9 @@ class boss_four_horsemen_sir : public CreatureScript
|
||||
boss_four_horsemen_sirAI(Creature* creature) : boss_four_horsemen_baseAI(creature, SIR, sirPath), _shouldSay(true) { }
|
||||
void BeginFighting() override
|
||||
{
|
||||
events.ScheduleEvent(EVENT_BERSERK, 10 * MINUTE * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_MARK, 24 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_HOLYWRATH, urandms(13,18));
|
||||
events.ScheduleEvent(EVENT_BERSERK, Minutes(10));
|
||||
events.ScheduleEvent(EVENT_MARK, Seconds(24));
|
||||
events.ScheduleEvent(EVENT_HOLYWRATH, randtime(Seconds(13), Seconds(18)));
|
||||
}
|
||||
|
||||
void _UpdateAI(uint32 diff) override
|
||||
@@ -648,7 +648,7 @@ class boss_four_horsemen_sir : public CreatureScript
|
||||
break;
|
||||
case EVENT_MARK:
|
||||
DoCastAOE(SPELL_SIR_MARK, true);
|
||||
events.ScheduleEvent(EVENT_MARK, 15 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(15));
|
||||
break;
|
||||
case EVENT_HOLYWRATH:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_NEAREST, 0, 45.0f, true))
|
||||
@@ -656,7 +656,7 @@ class boss_four_horsemen_sir : public CreatureScript
|
||||
DoCast(target, SPELL_HOLY_WRATH, true);
|
||||
_shouldSay = true;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_HOLYWRATH, urandms(10,18));
|
||||
events.Repeat(randtime(Seconds(10), Seconds(18)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,13 +324,13 @@ class boss_gothik : public CreatureScript
|
||||
{
|
||||
_EnterCombat();
|
||||
events.SetPhase(PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_SUMMON, 25 * IN_MILLISECONDS, 0, PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_DOORS_UNLOCK, 205 * IN_MILLISECONDS, 0, PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_PHASE_TWO, 270 * IN_MILLISECONDS, 0, PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_SUMMON, Seconds(25), 0, PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_DOORS_UNLOCK, Minutes(3) + Seconds(25), 0, PHASE_ONE);
|
||||
events.ScheduleEvent(EVENT_PHASE_TWO, Minutes(4) + Seconds(30), 0, PHASE_ONE);
|
||||
Talk(SAY_INTRO_1);
|
||||
events.ScheduleEvent(EVENT_INTRO_2, 4 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_INTRO_3, 9 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_INTRO_4, 14 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_INTRO_2, Seconds(4));
|
||||
events.ScheduleEvent(EVENT_INTRO_3, Seconds(9));
|
||||
events.ScheduleEvent(EVENT_INTRO_4, Seconds(14));
|
||||
instance->SetData(DATA_GOTHIK_GATE, GO_STATE_READY);
|
||||
_gateIsOpen = false;
|
||||
}
|
||||
@@ -480,7 +480,7 @@ class boss_gothik : public CreatureScript
|
||||
}
|
||||
|
||||
if (uint8 timeToNext = RAID_MODE(waves10, waves25)[_waveCount].second)
|
||||
events.ScheduleEvent(EVENT_SUMMON, timeToNext * IN_MILLISECONDS, 0, PHASE_ONE);
|
||||
events.Repeat(Seconds(timeToNext));
|
||||
|
||||
++_waveCount;
|
||||
break;
|
||||
@@ -497,9 +497,9 @@ class boss_gothik : public CreatureScript
|
||||
break;
|
||||
case EVENT_PHASE_TWO:
|
||||
events.SetPhase(PHASE_TWO);
|
||||
events.ScheduleEvent(EVENT_TELEPORT, 20 * IN_MILLISECONDS, 0, PHASE_TWO);
|
||||
events.ScheduleEvent(EVENT_HARVEST, 15 * IN_MILLISECONDS, 0, PHASE_TWO);
|
||||
events.ScheduleEvent(EVENT_RESUME_ATTACK, 2 * IN_MILLISECONDS, 0, PHASE_TWO);
|
||||
events.ScheduleEvent(EVENT_TELEPORT, Seconds(20), 0, PHASE_TWO);
|
||||
events.ScheduleEvent(EVENT_HARVEST, Seconds(15), 0, PHASE_TWO);
|
||||
events.ScheduleEvent(EVENT_RESUME_ATTACK, Seconds(2), 0, PHASE_TWO);
|
||||
Talk(SAY_PHASE_TWO);
|
||||
Talk(EMOTE_PHASE_TWO);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
@@ -518,23 +518,23 @@ class boss_gothik : public CreatureScript
|
||||
_lastTeleportDead = !_lastTeleportDead;
|
||||
|
||||
events.CancelEvent(EVENT_BOLT);
|
||||
events.ScheduleEvent(EVENT_TELEPORT, 20 * IN_MILLISECONDS, 0, PHASE_TWO);
|
||||
events.ScheduleEvent(EVENT_RESUME_ATTACK, 2 * IN_MILLISECONDS, 0, PHASE_TWO);
|
||||
events.Repeat(Seconds(20));
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_HARVEST:
|
||||
DoCastAOE(SPELL_HARVEST_SOUL, true); // triggered allows this to go "through" shadow bolt
|
||||
events.ScheduleEvent(EVENT_HARVEST, 15 * IN_MILLISECONDS, 0, PHASE_TWO);
|
||||
events.Repeat(Seconds(15));
|
||||
break;
|
||||
case EVENT_RESUME_ATTACK:
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
events.ScheduleEvent(EVENT_BOLT, 0, 0, PHASE_TWO);
|
||||
events.ScheduleEvent(EVENT_BOLT, Seconds(0), 0, PHASE_TWO);
|
||||
// return to the start of this method so victim side etc is re-evaluated
|
||||
return UpdateAI(0u); // tail recursion for efficiency
|
||||
case EVENT_BOLT:
|
||||
DoCastVictim(SPELL_SHADOW_BOLT);
|
||||
events.ScheduleEvent(EVENT_BOLT, 1 * IN_MILLISECONDS, 0, PHASE_TWO);
|
||||
events.Repeat(Seconds(2));
|
||||
break;
|
||||
case EVENT_INTRO_2:
|
||||
Talk(SAY_INTRO_2);
|
||||
|
||||
@@ -57,10 +57,10 @@ class boss_grobbulus : public CreatureScript
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_CLOUD, 15000);
|
||||
events.ScheduleEvent(EVENT_INJECT, 20000);
|
||||
events.ScheduleEvent(EVENT_SPRAY, urand(15000, 30000)); // not sure
|
||||
events.ScheduleEvent(EVENT_BERSERK, 12 * 60000);
|
||||
events.ScheduleEvent(EVENT_CLOUD, Seconds(15));
|
||||
events.ScheduleEvent(EVENT_INJECT, Seconds(20));
|
||||
events.ScheduleEvent(EVENT_SPRAY, randtime(Seconds(15), Seconds(30))); // not sure
|
||||
events.ScheduleEvent(EVENT_BERSERK, Minutes(12));
|
||||
}
|
||||
|
||||
void SpellHitTarget(Unit* target, SpellInfo const* spell) override
|
||||
@@ -82,19 +82,19 @@ class boss_grobbulus : public CreatureScript
|
||||
{
|
||||
case EVENT_CLOUD:
|
||||
DoCastAOE(SPELL_POISON_CLOUD);
|
||||
events.ScheduleEvent(EVENT_CLOUD, 15000);
|
||||
events.Repeat(Seconds(15));
|
||||
return;
|
||||
case EVENT_BERSERK:
|
||||
DoCastAOE(SPELL_BERSERK, true);
|
||||
return;
|
||||
case EVENT_SPRAY:
|
||||
DoCastAOE(SPELL_SLIME_SPRAY);
|
||||
events.ScheduleEvent(EVENT_SPRAY, urand(15000, 30000));
|
||||
events.Repeat(randtime(Seconds(15), Seconds(30)));
|
||||
return;
|
||||
case EVENT_INJECT:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_MUTATING_INJECTION))
|
||||
DoCast(target, SPELL_MUTATING_INJECTION);
|
||||
events.ScheduleEvent(EVENT_INJECT, 8000 + uint32(120 * me->GetHealthPct()));
|
||||
events.Repeat(Seconds(8) + Milliseconds(uint32(std::round(120 * me->GetHealthPct()))));
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -27,6 +27,7 @@ enum Spells
|
||||
SPELL_SPELL_DISRUPTION = 29310,
|
||||
SPELL_PLAGUE_CLOUD = 29350,
|
||||
SPELL_TELEPORT_SELF = 30211,
|
||||
SPELL_ERUPTION = 29371
|
||||
};
|
||||
|
||||
enum Yells
|
||||
@@ -60,6 +61,15 @@ enum Misc
|
||||
DATA_SAFETY_DANCE = 19962139
|
||||
};
|
||||
|
||||
static const uint32 firstEruptionDBGUID = 84980;
|
||||
static const uint8 numSections = 4;
|
||||
static const uint8 numEruptions[numSections] = { // count of sequential GO DBGUIDs in the respective section of the room
|
||||
15,
|
||||
25,
|
||||
23,
|
||||
13
|
||||
};
|
||||
|
||||
class boss_heigan : public CreatureScript
|
||||
{
|
||||
public:
|
||||
@@ -72,7 +82,7 @@ public:
|
||||
|
||||
struct boss_heiganAI : public BossAI
|
||||
{
|
||||
boss_heiganAI(Creature* creature) : BossAI(creature, BOSS_HEIGAN), eruptSection(0), eruptDirection(false), safetyDance(false) { }
|
||||
boss_heiganAI(Creature* creature) : BossAI(creature, BOSS_HEIGAN), _safeSection(0), _danceDirection(false), _safetyDance(false) { }
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
@@ -82,15 +92,16 @@ public:
|
||||
|
||||
void KilledUnit(Unit* who) override
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
|
||||
if (who->GetTypeId() == TYPEID_PLAYER)
|
||||
safetyDance = false;
|
||||
{
|
||||
Talk(SAY_SLAY);
|
||||
_safetyDance = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 type) const override
|
||||
{
|
||||
return (type == DATA_SAFETY_DANCE && safetyDance) ? 1u : 0u;
|
||||
return (type == DATA_SAFETY_DANCE && _safetyDance) ? 1u : 0u;
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
@@ -104,13 +115,27 @@ public:
|
||||
_EnterCombat();
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
eruptSection = 3;
|
||||
events.ScheduleEvent(EVENT_DISRUPT, urand(15 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_FEVER, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_DANCE, 90 * IN_MILLISECONDS, 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_ERUPT, 15 * IN_MILLISECONDS, 0, PHASE_FIGHT);
|
||||
_safeSection = 0;
|
||||
events.ScheduleEvent(EVENT_DISRUPT, randtime(Seconds(15), Seconds(20)), 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_FEVER, randtime(Seconds(10), Seconds(20)), 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_DANCE, Minutes(1) + Seconds(30), 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_ERUPT, Seconds(15), 0, PHASE_FIGHT);
|
||||
|
||||
safetyDance = true;
|
||||
_safetyDance = true;
|
||||
|
||||
// figure out the current GUIDs of our eruption tiles and which segment they belong in
|
||||
std::unordered_multimap<uint32, GameObject*> const& mapGOs = me->GetMap()->GetGameObjectBySpawnIdStore();
|
||||
uint32 spawnId = firstEruptionDBGUID;
|
||||
for (uint8 section = 0; section < numSections; ++section)
|
||||
{
|
||||
_eruptTiles[section].clear();
|
||||
for (uint8 i = 0; i < numEruptions[section]; ++i)
|
||||
{
|
||||
std::pair<std::unordered_multimap<uint32, GameObject*>::const_iterator, std::unordered_multimap<uint32, GameObject*>::const_iterator> tileIt = mapGOs.equal_range(spawnId++);
|
||||
for (std::unordered_multimap<uint32, GameObject*>::const_iterator it = tileIt.first; it != tileIt.second; ++it)
|
||||
_eruptTiles[section].push_back(it->second->GetGUID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
@@ -126,52 +151,56 @@ public:
|
||||
{
|
||||
case EVENT_DISRUPT:
|
||||
DoCastAOE(SPELL_SPELL_DISRUPTION);
|
||||
events.ScheduleEvent(EVENT_DISRUPT, 11 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(11));
|
||||
break;
|
||||
case EVENT_FEVER:
|
||||
DoCastAOE(SPELL_DECREPIT_FEVER);
|
||||
events.ScheduleEvent(EVENT_FEVER, urand(20 * IN_MILLISECONDS, 25 * IN_MILLISECONDS));
|
||||
events.Repeat(randtime(Seconds(20), Seconds(25)));
|
||||
break;
|
||||
case EVENT_DANCE:
|
||||
events.SetPhase(PHASE_DANCE);
|
||||
Talk(SAY_TAUNT);
|
||||
Talk(EMOTE_DANCE);
|
||||
eruptSection = 3;
|
||||
_safeSection = 0;
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->AttackStop();
|
||||
me->StopMoving();
|
||||
DoCast(SPELL_TELEPORT_SELF);
|
||||
DoCastAOE(SPELL_PLAGUE_CLOUD);
|
||||
events.ScheduleEvent(EVENT_DANCE_END, 45 * IN_MILLISECONDS, 0, PHASE_DANCE);
|
||||
events.ScheduleEvent(EVENT_ERUPT, 10 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_DANCE_END, Seconds(45), 0, PHASE_DANCE);
|
||||
events.ScheduleEvent(EVENT_ERUPT, Seconds(10));
|
||||
break;
|
||||
case EVENT_DANCE_END:
|
||||
events.SetPhase(PHASE_FIGHT);
|
||||
Talk(EMOTE_DANCE_END);
|
||||
eruptSection = 3;
|
||||
events.ScheduleEvent(EVENT_DISRUPT, urand(10, 25) * IN_MILLISECONDS, 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_FEVER, urand(15, 20) * IN_MILLISECONDS, 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_DANCE, 90 * IN_MILLISECONDS, 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_ERUPT, 15 * IN_MILLISECONDS, 0, PHASE_FIGHT);
|
||||
_safeSection = 0;
|
||||
events.ScheduleEvent(EVENT_DISRUPT, randtime(Seconds(10), Seconds(25)), 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_FEVER, randtime(Seconds(15), Seconds(20)), 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_DANCE, Minutes(1) + Seconds(30), 0, PHASE_FIGHT);
|
||||
events.ScheduleEvent(EVENT_ERUPT, Seconds(15), 0, PHASE_FIGHT);
|
||||
me->CastStop();
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
DoZoneInCombat();
|
||||
break;
|
||||
case EVENT_ERUPT:
|
||||
instance->SetData(DATA_HEIGAN_ERUPT, eruptSection);
|
||||
TeleportCheaters();
|
||||
for (uint8 section = 0; section < numSections; ++section)
|
||||
if (section != _safeSection)
|
||||
for (ObjectGuid tileGUID : _eruptTiles[section])
|
||||
if (GameObject* tile = ObjectAccessor::GetGameObject(*me, tileGUID))
|
||||
{
|
||||
tile->SendCustomAnim(0);
|
||||
tile->CastSpell(nullptr, SPELL_ERUPTION);
|
||||
}
|
||||
|
||||
if (eruptSection == 0)
|
||||
eruptDirection = true;
|
||||
else if (eruptSection == 3)
|
||||
eruptDirection = false;
|
||||
if (_safeSection == 0)
|
||||
_danceDirection = true;
|
||||
else if (_safeSection == numSections-1)
|
||||
_danceDirection = false;
|
||||
|
||||
eruptDirection ? ++eruptSection : --eruptSection;
|
||||
_danceDirection ? ++_safeSection : --_safeSection;
|
||||
|
||||
if (events.IsInPhase(PHASE_DANCE))
|
||||
events.ScheduleEvent(EVENT_ERUPT, 3 * IN_MILLISECONDS, 0, PHASE_DANCE);
|
||||
else
|
||||
events.ScheduleEvent(EVENT_ERUPT, 10 * IN_MILLISECONDS, 0, PHASE_FIGHT);
|
||||
events.Repeat(events.IsInPhase(PHASE_DANCE) ? Seconds(3) : Seconds(10));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -180,10 +209,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 eruptSection;
|
||||
bool eruptDirection;
|
||||
std::vector<ObjectGuid> _eruptTiles[numSections]; // populated on encounter start
|
||||
|
||||
bool safetyDance; // is achievement still possible? (= no player deaths yet)
|
||||
uint32 _safeSection; // 0 is next to the entrance
|
||||
bool _danceDirection; // true is counter-clockwise, false is clock-wise
|
||||
bool _safetyDance; // is achievement still possible? (= no player deaths yet)
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
enum Spells
|
||||
{
|
||||
SPELL_NECROTIC_AURA = 55593,
|
||||
SPELL_WARN_NECROTIC_AURA = 59481,
|
||||
SPELL_SUMMON_SPORE = 29234,
|
||||
SPELL_DEATHBLOOM = 29865,
|
||||
SPELL_INEVITABLE_DOOM = 29204,
|
||||
@@ -42,11 +41,12 @@ enum Texts
|
||||
|
||||
enum Events
|
||||
{
|
||||
EVENT_NECROTIC_AURA = 1,
|
||||
EVENT_DEATHBLOOM = 2,
|
||||
EVENT_INEVITABLE_DOOM = 3,
|
||||
EVENT_SPORE = 4,
|
||||
EVENT_NECROTIC_AURA_FADING = 5,
|
||||
EVENT_NECROTIC_AURA = 1,
|
||||
EVENT_DEATHBLOOM,
|
||||
EVENT_INEVITABLE_DOOM,
|
||||
EVENT_SPORE,
|
||||
EVENT_NECROTIC_AURA_FADING,
|
||||
EVENT_NECROTIC_AURA_FADED
|
||||
};
|
||||
|
||||
enum Achievement
|
||||
@@ -82,10 +82,10 @@ class boss_loatheb : public CreatureScript
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_NECROTIC_AURA, 17 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_DEATHBLOOM, 5 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_SPORE, RAID_MODE(36,18) * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 2 * MINUTE * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_NECROTIC_AURA, Seconds(17));
|
||||
events.ScheduleEvent(EVENT_DEATHBLOOM, Seconds(5));
|
||||
events.ScheduleEvent(EVENT_SPORE, Seconds(18));
|
||||
events.ScheduleEvent(EVENT_INEVITABLE_DOOM, Minutes(2));
|
||||
}
|
||||
|
||||
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
|
||||
@@ -94,13 +94,6 @@ class boss_loatheb : public CreatureScript
|
||||
summon->CastSpell(summon,SPELL_FUNGAL_CREEP,true);
|
||||
}
|
||||
|
||||
void SummonedCreatureDespawn(Creature* summon) override
|
||||
{
|
||||
summons.Despawn(summon);
|
||||
if (summon->IsAlive())
|
||||
summon->CastSpell(summon,SPELL_FUNGAL_CREEP,true);
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 id) const override
|
||||
{
|
||||
return (_sporeLoserData && id == DATA_ACHIEVEMENT_SPORE_LOSER) ? 1u : 0u;
|
||||
@@ -119,34 +112,33 @@ class boss_loatheb : public CreatureScript
|
||||
{
|
||||
case EVENT_NECROTIC_AURA:
|
||||
DoCastAOE(SPELL_NECROTIC_AURA);
|
||||
DoCast(me, SPELL_WARN_NECROTIC_AURA);
|
||||
events.ScheduleEvent(EVENT_NECROTIC_AURA, 20 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_NECROTIC_AURA_FADING, 14 * IN_MILLISECONDS);
|
||||
Talk(SAY_NECROTIC_AURA_APPLIED);
|
||||
events.ScheduleEvent(EVENT_NECROTIC_AURA_FADING, Seconds(14));
|
||||
events.ScheduleEvent(EVENT_NECROTIC_AURA_FADED, Seconds(17));
|
||||
events.Repeat(Seconds(20));
|
||||
break;
|
||||
case EVENT_DEATHBLOOM:
|
||||
DoCastAOE(SPELL_DEATHBLOOM);
|
||||
events.ScheduleEvent(EVENT_DEATHBLOOM, 30 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(30));
|
||||
break;
|
||||
case EVENT_INEVITABLE_DOOM:
|
||||
_doomCounter++;
|
||||
DoCastAOE(SPELL_INEVITABLE_DOOM);
|
||||
if (_doomCounter > 6)
|
||||
{
|
||||
if (_doomCounter & 1) // odd
|
||||
events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 14 * IN_MILLISECONDS);
|
||||
else
|
||||
events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 17 * IN_MILLISECONDS);
|
||||
}
|
||||
events.Repeat((_doomCounter & 1) ? Seconds(14) : Seconds(17));
|
||||
else
|
||||
events.ScheduleEvent(EVENT_INEVITABLE_DOOM, 30 * IN_MILLISECONDS);
|
||||
events.Repeat(30);
|
||||
break;
|
||||
case EVENT_SPORE:
|
||||
DoCast(me, SPELL_SUMMON_SPORE, false);
|
||||
events.ScheduleEvent(EVENT_SPORE, RAID_MODE(36,18) * IN_MILLISECONDS);
|
||||
events.Repeat(RAID_MODE(Seconds(36), Seconds(15)));
|
||||
break;
|
||||
case EVENT_NECROTIC_AURA_FADING:
|
||||
Talk(SAY_NECROTIC_AURA_FADING);
|
||||
break;
|
||||
case EVENT_NECROTIC_AURA_FADED:
|
||||
Talk(SAY_NECROTIC_AURA_REMOVED);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -177,49 +169,6 @@ class achievement_spore_loser : public AchievementCriteriaScript
|
||||
}
|
||||
};
|
||||
|
||||
typedef boss_loatheb::boss_loathebAI LoathebAI;
|
||||
|
||||
class spell_loatheb_necrotic_aura_warning : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_loatheb_necrotic_aura_warning() : SpellScriptLoader("spell_loatheb_necrotic_aura_warning") { }
|
||||
|
||||
class spell_loatheb_necrotic_aura_warning_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_loatheb_necrotic_aura_warning_AuraScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spell*/) override
|
||||
{
|
||||
if (!sSpellStore.LookupEntry(SPELL_WARN_NECROTIC_AURA))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (GetTarget()->IsAIEnabled)
|
||||
ENSURE_AI(LoathebAI, GetTarget()->GetAI())->Talk(SAY_NECROTIC_AURA_APPLIED);
|
||||
}
|
||||
|
||||
void HandleEffectRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (GetTarget()->IsAIEnabled)
|
||||
ENSURE_AI(LoathebAI, GetTarget()->GetAI())->Talk(SAY_NECROTIC_AURA_REMOVED);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterEffectApply += AuraEffectApplyFn(spell_loatheb_necrotic_aura_warning_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
AfterEffectRemove += AuraEffectRemoveFn(spell_loatheb_necrotic_aura_warning_AuraScript::HandleEffectRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
|
||||
}
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_loatheb_necrotic_aura_warning_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
class spell_loatheb_deathbloom : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
@@ -260,6 +209,5 @@ void AddSC_boss_loatheb()
|
||||
{
|
||||
new boss_loatheb();
|
||||
new achievement_spore_loser();
|
||||
new spell_loatheb_necrotic_aura_warning();
|
||||
new spell_loatheb_deathbloom();
|
||||
}
|
||||
|
||||
@@ -73,6 +73,8 @@ struct WebTargetSelector : public std::unary_function<Unit*, bool>
|
||||
WebTargetSelector(Unit* maexxna) : _maexxna(maexxna) {}
|
||||
bool operator()(Unit const* target) const
|
||||
{
|
||||
if (target->GetTypeId() != TYPEID_PLAYER) // never web nonplayers (pets, guardians, etc.)
|
||||
return false;
|
||||
if (_maexxna->GetVictim() == target) // never target tank
|
||||
return false;
|
||||
if (target->HasAura(SPELL_WEB_WRAP)) // never target targets that are already webbed
|
||||
@@ -101,11 +103,11 @@ public:
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
events.ScheduleEvent(EVENT_WRAP, 20 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_SPRAY, 40 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_SHOCK, urandms(5, 10));
|
||||
events.ScheduleEvent(EVENT_POISON, urandms(10, 15));
|
||||
events.ScheduleEvent(EVENT_SUMMON, 30 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_WRAP, Seconds(20));
|
||||
events.ScheduleEvent(EVENT_SPRAY, Seconds(40));
|
||||
events.ScheduleEvent(EVENT_SHOCK, randtime(Seconds(5), Seconds(10)));
|
||||
events.ScheduleEvent(EVENT_POISON, randtime(Seconds(10), Seconds(15)));
|
||||
events.ScheduleEvent(EVENT_SUMMON, Seconds(30));
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
@@ -153,28 +155,28 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
events.ScheduleEvent(EVENT_WRAP, 40000);
|
||||
events.Repeat(Seconds(40));
|
||||
break;
|
||||
}
|
||||
case EVENT_SPRAY:
|
||||
Talk(EMOTE_WEB_SPRAY);
|
||||
DoCastAOE(SPELL_WEB_SPRAY);
|
||||
events.ScheduleEvent(EVENT_SPRAY, 40000);
|
||||
events.Repeat(Seconds(40));
|
||||
break;
|
||||
case EVENT_SHOCK:
|
||||
DoCastAOE(SPELL_POISON_SHOCK);
|
||||
events.ScheduleEvent(EVENT_SHOCK, urandms(10, 20));
|
||||
events.Repeat(randtime(Seconds(10), Seconds(20)));
|
||||
break;
|
||||
case EVENT_POISON:
|
||||
DoCastVictim(SPELL_NECROTIC_POISON);
|
||||
events.ScheduleEvent(EVENT_POISON, urandms(10, 20));
|
||||
events.Repeat(randtime(Seconds(10), Seconds(20)));
|
||||
break;
|
||||
case EVENT_SUMMON:
|
||||
Talk(EMOTE_SPIDERS);
|
||||
uint8 amount = urand(8, 10);
|
||||
for (uint8 i = 0; i < amount; ++i)
|
||||
DoSummon(NPC_SPIDERLING, me, 4.0f, 5 * IN_MILLISECONDS, TEMPSUMMON_CORPSE_TIMED_DESPAWN);
|
||||
events.ScheduleEvent(EVENT_SUMMON, 40000);
|
||||
events.Repeat(Seconds(40));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,25 +131,25 @@ public:
|
||||
Reset();
|
||||
else
|
||||
{
|
||||
uint8 secondsGround;
|
||||
uint8 timeGround;
|
||||
switch (balconyCount)
|
||||
{
|
||||
case 0:
|
||||
secondsGround = 90;
|
||||
timeGround = 90;
|
||||
break;
|
||||
case 1:
|
||||
secondsGround = 110;
|
||||
timeGround = 110;
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
secondsGround = 180;
|
||||
timeGround = 180;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_GROUND_ATTACKABLE, 2 * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_BALCONY, secondsGround * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_CURSE, urand(10,25) * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_WARRIOR, urand(20,30) * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_GROUND_ATTACKABLE, Seconds(2), 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_BALCONY, Seconds(timeGround), 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_CURSE, randtime(Seconds(10), Seconds(25)), 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_WARRIOR, randtime(Seconds(20), Seconds(30)), 0, PHASE_GROUND);
|
||||
if (GetDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL)
|
||||
events.ScheduleEvent(EVENT_BLINK, urand(20,30) * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_BLINK, randtime(Seconds(20), Seconds(30)), 0, PHASE_GROUND);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ public:
|
||||
case EVENT_CURSE:
|
||||
{
|
||||
DoCastAOE(SPELL_CURSE);
|
||||
events.ScheduleEvent(EVENT_CURSE, urand(50, 70) * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.Repeat(randtime(Seconds(50), Seconds(70)));
|
||||
break;
|
||||
}
|
||||
case EVENT_WARRIOR:
|
||||
@@ -229,7 +229,7 @@ public:
|
||||
|
||||
CastSummon(RAID_MODE(2, 3), 0, 0);
|
||||
|
||||
events.ScheduleEvent(EVENT_WARRIOR, 40 * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.Repeat(Seconds(40));
|
||||
break;
|
||||
case EVENT_BLINK:
|
||||
DoCastAOE(SPELL_CRIPPLE, true);
|
||||
@@ -237,7 +237,7 @@ public:
|
||||
DoResetThreat();
|
||||
justBlinked = true;
|
||||
|
||||
events.ScheduleEvent(EVENT_BLINK, 40000, 0, PHASE_GROUND);
|
||||
events.Repeat(Seconds(40));
|
||||
break;
|
||||
case EVENT_BALCONY:
|
||||
events.SetPhase(PHASE_BALCONY);
|
||||
@@ -247,24 +247,24 @@ public:
|
||||
me->StopMoving();
|
||||
me->RemoveAllAuras();
|
||||
|
||||
events.ScheduleEvent(EVENT_BALCONY_TELEPORT, 3 * IN_MILLISECONDS, 0, PHASE_BALCONY);
|
||||
events.ScheduleEvent(EVENT_WAVE, urand(5 * IN_MILLISECONDS, 8 * IN_MILLISECONDS), 0, PHASE_BALCONY);
|
||||
events.ScheduleEvent(EVENT_BALCONY_TELEPORT, Seconds(3), 0, PHASE_BALCONY);
|
||||
events.ScheduleEvent(EVENT_WAVE, randtime(Seconds(5), Seconds(8)), 0, PHASE_BALCONY);
|
||||
|
||||
uint8 secondsBalcony;
|
||||
uint8 timeBalcony;
|
||||
switch (balconyCount)
|
||||
{
|
||||
case 0:
|
||||
secondsBalcony = 70;
|
||||
timeBalcony = 70;
|
||||
break;
|
||||
case 1:
|
||||
secondsBalcony = 97;
|
||||
timeBalcony = 97;
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
secondsBalcony = 120;
|
||||
timeBalcony = 120;
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_GROUND, secondsBalcony * IN_MILLISECONDS, 0, PHASE_BALCONY);
|
||||
events.ScheduleEvent(EVENT_GROUND, Seconds(timeBalcony), 0, PHASE_BALCONY);
|
||||
break;
|
||||
case EVENT_BALCONY_TELEPORT:
|
||||
Talk(EMOTE_TELEPORT_1);
|
||||
@@ -287,7 +287,7 @@ public:
|
||||
CastSummon(0, RAID_MODE(5, 10), RAID_MODE(5, 10));
|
||||
break;
|
||||
}
|
||||
events.ScheduleEvent(EVENT_WAVE, urand(30, 45) * IN_MILLISECONDS, 0, PHASE_BALCONY);
|
||||
events.Repeat(randtime(Seconds(30), Seconds(45)));
|
||||
break;
|
||||
case EVENT_GROUND:
|
||||
++balconyCount;
|
||||
|
||||
@@ -97,8 +97,8 @@ public:
|
||||
_EnterCombat();
|
||||
Enraged = false;
|
||||
Talk(SAY_AGGRO);
|
||||
events.ScheduleEvent(EVENT_HATEFUL, 1 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_BERSERK, 6 * MINUTE * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_HATEFUL, Seconds(1));
|
||||
events.ScheduleEvent(EVENT_BERSERK, Minutes(6));
|
||||
|
||||
instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_MAKE_QUICK_WERK_OF_HIM_STARTING_EVENT);
|
||||
}
|
||||
@@ -167,17 +167,17 @@ public:
|
||||
if (thirdThreatTarget)
|
||||
me->getThreatManager().addThreat(thirdThreatTarget, HATEFUL_THREAT_AMT); // this will only ever be used in 25m
|
||||
|
||||
events.ScheduleEvent(EVENT_HATEFUL, 1 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(1));
|
||||
break;
|
||||
}
|
||||
case EVENT_BERSERK:
|
||||
DoCast(me, SPELL_BERSERK, true);
|
||||
Talk(EMOTE_BERSERK);
|
||||
events.ScheduleEvent(EVENT_SLIME, 2 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_SLIME, Seconds(2));
|
||||
break;
|
||||
case EVENT_SLIME:
|
||||
DoCastVictim(SPELL_SLIME_BOLT, true);
|
||||
events.ScheduleEvent(EVENT_SLIME, 2 * IN_MILLISECONDS);
|
||||
DoCastAOE(SPELL_SLIME_BOLT, true);
|
||||
events.Repeat(Seconds(2));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +104,9 @@ public:
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
for (ObjectGuid summonGuid : summons)
|
||||
if (Creature* summon = ObjectAccessor::GetCreature(*me, summonGuid))
|
||||
summon->RemoveCharmAuras();
|
||||
Talk(SAY_DEATH);
|
||||
DoCastAOE(SPELL_HOPELESS, true);
|
||||
|
||||
@@ -117,10 +120,10 @@ public:
|
||||
me->StopMoving();
|
||||
summons.DoZoneInCombat();
|
||||
Talk(SAY_AGGRO);
|
||||
events.ScheduleEvent(EVENT_ATTACK, 7 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_STRIKE, 21 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_SHOUT, 16 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_KNIFE, 10 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_ATTACK, Seconds(7));
|
||||
events.ScheduleEvent(EVENT_STRIKE, Seconds(21));
|
||||
events.ScheduleEvent(EVENT_SHOUT, Seconds(16));
|
||||
events.ScheduleEvent(EVENT_KNIFE, Seconds(10));
|
||||
}
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
@@ -141,16 +144,16 @@ public:
|
||||
break;
|
||||
case EVENT_STRIKE:
|
||||
DoCastVictim(SPELL_UNBALANCING_STRIKE);
|
||||
events.ScheduleEvent(EVENT_STRIKE, 6 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(6));
|
||||
return;
|
||||
case EVENT_SHOUT:
|
||||
DoCastAOE(SPELL_DISRUPTING_SHOUT);
|
||||
events.ScheduleEvent(EVENT_SHOUT, 16 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(16));
|
||||
return;
|
||||
case EVENT_KNIFE:
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 45.0f))
|
||||
DoCast(target, SPELL_JAGGED_KNIFE);
|
||||
events.ScheduleEvent(EVENT_KNIFE, urandms(10,15));
|
||||
events.Repeat(randtime(Seconds(10), Seconds(15)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -174,7 +177,10 @@ class npc_dk_understudy : public CreatureScript
|
||||
|
||||
struct npc_dk_understudyAI : public ScriptedAI
|
||||
{
|
||||
npc_dk_understudyAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), bloodStrikeTimer(0) { }
|
||||
npc_dk_understudyAI(Creature* creature) : ScriptedAI(creature), _instance(creature->GetInstanceScript()), bloodStrikeTimer(0)
|
||||
{
|
||||
creature->LoadEquipment(1);
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
*/
|
||||
|
||||
#include "ScriptMgr.h"
|
||||
#include "GameObjectAI.h"
|
||||
#include "ScriptedCreature.h"
|
||||
#include "SpellScript.h"
|
||||
#include "Player.h"
|
||||
#include "SpellInfo.h"
|
||||
#include "naxxramas.h"
|
||||
@@ -31,25 +33,24 @@ enum Yells
|
||||
|
||||
enum Spells
|
||||
{
|
||||
SPELL_FROST_AURA = 28531,
|
||||
SPELL_CLEAVE = 19983,
|
||||
SPELL_TAIL_SWEEP = 55697,
|
||||
SPELL_SUMMON_BLIZZARD = 28560,
|
||||
SPELL_LIFE_DRAIN = 28542,
|
||||
SPELL_ICEBOLT = 28522,
|
||||
SPELL_FROST_BREATH = 29318,
|
||||
SPELL_FROST_EXPLOSION = 28524,
|
||||
SPELL_FROST_MISSILE = 30101,
|
||||
SPELL_BERSERK = 26662,
|
||||
SPELL_DIES = 29357,
|
||||
SPELL_CHILL = 28547,
|
||||
SPELL_CHECK_RESISTS = 60539,
|
||||
SPELL_FROST_AURA = 28531,
|
||||
SPELL_CLEAVE = 19983,
|
||||
SPELL_TAIL_SWEEP = 55697,
|
||||
SPELL_SUMMON_BLIZZARD = 28560,
|
||||
SPELL_LIFE_DRAIN = 28542,
|
||||
SPELL_ICEBOLT = 28522,
|
||||
SPELL_FROST_BREATH_ANTICHEAT = 29318, // damage effect ignoring LoS on the entrance platform to prevent cheese
|
||||
SPELL_FROST_BREATH = 28524, // damage effect below sapphiron
|
||||
SPELL_FROST_MISSILE = 30101, // visual only
|
||||
SPELL_BERSERK = 26662,
|
||||
SPELL_DIES = 29357,
|
||||
SPELL_CHECK_RESISTS = 60539,
|
||||
SPELL_SAPPHIRON_WING_BUFFET = 29328
|
||||
};
|
||||
|
||||
enum Phases
|
||||
{
|
||||
PHASE_NULL = 0,
|
||||
PHASE_BIRTH,
|
||||
PHASE_BIRTH = 1,
|
||||
PHASE_GROUND,
|
||||
PHASE_FLIGHT
|
||||
};
|
||||
@@ -72,9 +73,15 @@ enum Events
|
||||
EVENT_CHECK_RESISTS
|
||||
};
|
||||
|
||||
enum Actions
|
||||
{
|
||||
ACTION_BIRTH = 1
|
||||
};
|
||||
|
||||
enum Misc
|
||||
{
|
||||
NPC_BLIZZARD = 16474,
|
||||
NPC_WING_BUFFET = 17025,
|
||||
GO_ICEBLOCK = 181247,
|
||||
|
||||
// The Hundred Club
|
||||
@@ -92,77 +99,74 @@ class boss_sapphiron : public CreatureScript
|
||||
struct boss_sapphironAI : public BossAI
|
||||
{
|
||||
boss_sapphironAI(Creature* creature) :
|
||||
BossAI(creature, BOSS_SAPPHIRON), _iceboltCount(0), _map(me->GetMap())
|
||||
BossAI(creature, BOSS_SAPPHIRON)
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void Initialize()
|
||||
{
|
||||
_phase = PHASE_NULL;
|
||||
|
||||
_delayedDrain = false;
|
||||
_canTheHundredClub = true;
|
||||
}
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
if (instance->GetBossState(BOSS_SAPPHIRON) == DONE)
|
||||
return;
|
||||
|
||||
_canTheHundredClub = true;
|
||||
|
||||
float x, y, z;
|
||||
me->GetPosition(x, y, z);
|
||||
me->SummonGameObject(GO_BIRTH, x, y, z, 0, 0, 0, 0, 0, 0);
|
||||
me->SetVisible(false);
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
if (!instance->GetData(DATA_HAD_SAPPHIRON_BIRTH))
|
||||
{
|
||||
me->SetVisible(false);
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
}
|
||||
|
||||
BossAI::InitializeAI();
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_Reset();
|
||||
|
||||
if (_phase == PHASE_FLIGHT)
|
||||
if (events.IsInPhase(PHASE_FLIGHT))
|
||||
{
|
||||
ClearIceBlock();
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_ICEBOLT);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
if (me->IsHovering())
|
||||
{
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
me->SetHover(false);
|
||||
}
|
||||
me->SetDisableGravity(false);
|
||||
}
|
||||
|
||||
_Reset();
|
||||
Initialize();
|
||||
}
|
||||
|
||||
void DamageTaken(Unit* /*who*/, uint32& damage) override
|
||||
{
|
||||
if (damage < me->GetHealth() || !events.IsInPhase(PHASE_FLIGHT))
|
||||
return;
|
||||
damage = me->GetHealth()-1; // don't die during air phase
|
||||
}
|
||||
|
||||
void EnterCombat(Unit* /*who*/) override
|
||||
{
|
||||
_EnterCombat();
|
||||
|
||||
me->CastSpell(me, SPELL_FROST_AURA, true);
|
||||
|
||||
DoCast(me, SPELL_CHECK_RESISTS);
|
||||
events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_BERSERK, 15 * MINUTE * IN_MILLISECONDS);
|
||||
EnterPhaseGround();
|
||||
events.SetPhase(PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_CHECK_RESISTS, Seconds(0));
|
||||
events.ScheduleEvent(EVENT_BERSERK, Minutes(15));
|
||||
EnterPhaseGround(true);
|
||||
}
|
||||
|
||||
void SpellHitTarget(Unit* target, SpellInfo const* spell) override
|
||||
{
|
||||
switch(spell->Id)
|
||||
{
|
||||
case SPELL_ICEBOLT:
|
||||
{
|
||||
IceBlockMap::iterator itr = _iceblocks.find(target->GetGUID());
|
||||
if (itr != _iceblocks.end() && !itr->second)
|
||||
{
|
||||
if (GameObject* iceblock = me->SummonGameObject(GO_ICEBLOCK, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, 0, 0, 0, 0, 25))
|
||||
itr->second = iceblock->GetGUID();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SPELL_CHECK_RESISTS:
|
||||
if (target && target->GetResistance(SPELL_SCHOOL_FROST) > MAX_FROST_RESISTANCE)
|
||||
_canTheHundredClub = false;
|
||||
@@ -179,41 +183,37 @@ class boss_sapphiron : public CreatureScript
|
||||
void MovementInform(uint32 /*type*/, uint32 id) override
|
||||
{
|
||||
if (id == 1)
|
||||
events.ScheduleEvent(EVENT_LIFTOFF, 0);
|
||||
events.ScheduleEvent(EVENT_LIFTOFF, Seconds(0), 0, PHASE_FLIGHT);
|
||||
}
|
||||
|
||||
void DoAction(int32 param) override
|
||||
{
|
||||
if (param == DATA_SAPPHIRON_BIRTH)
|
||||
if (param == ACTION_BIRTH)
|
||||
{
|
||||
_phase = PHASE_BIRTH;
|
||||
events.ScheduleEvent(EVENT_BIRTH, 23 * IN_MILLISECONDS);
|
||||
events.SetPhase(PHASE_BIRTH);
|
||||
events.ScheduleEvent(EVENT_BIRTH, Seconds(23));
|
||||
}
|
||||
}
|
||||
|
||||
void EnterPhaseGround()
|
||||
void EnterPhaseGround(bool initial)
|
||||
{
|
||||
_phase = PHASE_GROUND;
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
events.SetPhase(PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_TAIL, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_DRAIN, 24 * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_BLIZZARD, urand(5, 10) * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_FLIGHT, 45 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(5), Seconds(15)), 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_TAIL, randtime(Seconds(7), Seconds(10)), 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_BLIZZARD, randtime(Seconds(5), Seconds(10)), 0, PHASE_GROUND);
|
||||
if (initial)
|
||||
{
|
||||
events.ScheduleEvent(EVENT_DRAIN, randtime(Seconds(22), Seconds(28)));
|
||||
events.ScheduleEvent(EVENT_FLIGHT, Seconds(48) + Milliseconds(500), 0, PHASE_GROUND);
|
||||
}
|
||||
else
|
||||
events.ScheduleEvent(EVENT_FLIGHT, Minutes(1), 0, PHASE_GROUND);
|
||||
}
|
||||
|
||||
void ClearIceBlock()
|
||||
inline void CastDrain()
|
||||
{
|
||||
for (IceBlockMap::const_iterator itr = _iceblocks.begin(); itr != _iceblocks.end(); ++itr)
|
||||
{
|
||||
if (Player* player = ObjectAccessor::GetPlayer(*me, itr->first))
|
||||
player->RemoveAura(SPELL_ICEBOLT);
|
||||
|
||||
if (GameObject* go = ObjectAccessor::GetGameObject(*me, itr->second))
|
||||
go->Delete();
|
||||
}
|
||||
_iceblocks.clear();
|
||||
DoCastAOE(SPELL_LIFE_DRAIN);
|
||||
events.ScheduleEvent(EVENT_DRAIN, randtime(Seconds(22), Seconds(28)));
|
||||
}
|
||||
|
||||
uint32 GetData(uint32 data) const override
|
||||
@@ -226,15 +226,12 @@ class boss_sapphiron : public CreatureScript
|
||||
|
||||
void UpdateAI(uint32 diff) override
|
||||
{
|
||||
if (!_phase)
|
||||
return;
|
||||
|
||||
events.Update(diff);
|
||||
|
||||
if (_phase != PHASE_BIRTH && !UpdateVictim())
|
||||
if (!events.IsInPhase(PHASE_BIRTH) && !UpdateVictim())
|
||||
return;
|
||||
|
||||
if (_phase == PHASE_GROUND)
|
||||
if (events.IsInPhase(PHASE_GROUND))
|
||||
{
|
||||
while (uint32 eventId = events.ExecuteEvent())
|
||||
{
|
||||
@@ -242,7 +239,10 @@ class boss_sapphiron : public CreatureScript
|
||||
{
|
||||
case EVENT_CHECK_RESISTS:
|
||||
DoCast(me, SPELL_CHECK_RESISTS);
|
||||
events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(30));
|
||||
return;
|
||||
case EVENT_GROUND:
|
||||
EnterPhaseGround(false);
|
||||
return;
|
||||
case EVENT_BERSERK:
|
||||
Talk(EMOTE_ENRAGE);
|
||||
@@ -250,27 +250,26 @@ class boss_sapphiron : public CreatureScript
|
||||
return;
|
||||
case EVENT_CLEAVE:
|
||||
DoCastVictim(SPELL_CLEAVE);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_CLEAVE, randtime(Seconds(5), Seconds(15)), 0, PHASE_GROUND);
|
||||
return;
|
||||
case EVENT_TAIL:
|
||||
DoCastAOE(SPELL_TAIL_SWEEP);
|
||||
events.ScheduleEvent(EVENT_TAIL, urand(5, 15) * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_TAIL, randtime(Seconds(7), Seconds(10)), 0, PHASE_GROUND);
|
||||
return;
|
||||
case EVENT_DRAIN:
|
||||
DoCastAOE(SPELL_LIFE_DRAIN);
|
||||
events.ScheduleEvent(EVENT_DRAIN, 24 * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
if (events.IsInPhase(PHASE_FLIGHT))
|
||||
_delayedDrain = true;
|
||||
else
|
||||
CastDrain();
|
||||
return;
|
||||
case EVENT_BLIZZARD:
|
||||
{
|
||||
if (Creature* summon = DoSummon(NPC_BLIZZARD, me, 0.0f, urand(25, 30) * IN_MILLISECONDS, TEMPSUMMON_TIMED_DESPAWN))
|
||||
summon->GetMotionMaster()->MoveRandom(40);
|
||||
events.ScheduleEvent(EVENT_BLIZZARD, RAID_MODE(20, 7) * IN_MILLISECONDS, 0, PHASE_GROUND);
|
||||
DoCastAOE(SPELL_SUMMON_BLIZZARD);
|
||||
events.ScheduleEvent(EVENT_BLIZZARD, RAID_MODE(Seconds(20), Seconds(7)), 0, PHASE_GROUND);
|
||||
break;
|
||||
}
|
||||
case EVENT_FLIGHT:
|
||||
if (HealthAbovePct(10))
|
||||
{
|
||||
_phase = PHASE_FLIGHT;
|
||||
_delayedDrain = false;
|
||||
events.SetPhase(PHASE_FLIGHT);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
me->AttackStop();
|
||||
@@ -293,61 +292,69 @@ class boss_sapphiron : public CreatureScript
|
||||
{
|
||||
case EVENT_CHECK_RESISTS:
|
||||
DoCast(me, SPELL_CHECK_RESISTS);
|
||||
events.ScheduleEvent(EVENT_CHECK_RESISTS, 30 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(30));
|
||||
return;
|
||||
case EVENT_LIFTOFF:
|
||||
{
|
||||
Talk(EMOTE_AIR_PHASE);
|
||||
me->SetDisableGravity(true);
|
||||
if (Creature* buffet = DoSummon(NPC_WING_BUFFET, me, 0.0f, 0, TEMPSUMMON_MANUAL_DESPAWN))
|
||||
_buffet = buffet->GetGUID();
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LIFTOFF);
|
||||
me->SetHover(true);
|
||||
events.ScheduleEvent(EVENT_ICEBOLT, 1500);
|
||||
_iceboltCount = RAID_MODE(2, 3);
|
||||
events.ScheduleEvent(EVENT_ICEBOLT, Seconds(7), 0, PHASE_FLIGHT);
|
||||
|
||||
_iceboltTargets.clear();
|
||||
std::list<Unit*> targets;
|
||||
SelectTargetList(targets, RAID_MODE(2, 3), SELECT_TARGET_RANDOM, 200.0f, true);
|
||||
for (Unit* target : targets)
|
||||
if (target)
|
||||
_iceboltTargets.push_back(target->GetGUID());
|
||||
return;
|
||||
}
|
||||
case EVENT_ICEBOLT:
|
||||
{
|
||||
std::vector<Unit*> targets;
|
||||
std::list<HostileReference*>::const_iterator i = me->getThreatManager().getThreatList().begin();
|
||||
for (; i != me->getThreatManager().getThreatList().end(); ++i)
|
||||
if ((*i)->getTarget()->GetTypeId() == TYPEID_PLAYER && !(*i)->getTarget()->HasAura(SPELL_ICEBOLT))
|
||||
targets.push_back((*i)->getTarget());
|
||||
|
||||
if (targets.empty())
|
||||
_iceboltCount = 0;
|
||||
else
|
||||
if (_iceboltTargets.empty())
|
||||
{
|
||||
std::vector<Unit*>::const_iterator itr = targets.begin();
|
||||
advance(itr, rand32() % targets.size());
|
||||
_iceblocks.insert(std::make_pair((*itr)->GetGUID(), ObjectGuid::Empty));
|
||||
DoCast(*itr, SPELL_ICEBOLT);
|
||||
--_iceboltCount;
|
||||
events.ScheduleEvent(EVENT_BREATH, Seconds(2), 0, PHASE_FLIGHT);
|
||||
return;
|
||||
}
|
||||
ObjectGuid target = _iceboltTargets.back();
|
||||
if (Player* pTarget = ObjectAccessor::GetPlayer(*me, target))
|
||||
if (pTarget->IsAlive())
|
||||
DoCast(pTarget, SPELL_ICEBOLT);
|
||||
_iceboltTargets.pop_back();
|
||||
|
||||
if (_iceboltCount)
|
||||
events.ScheduleEvent(EVENT_ICEBOLT, 1 * IN_MILLISECONDS);
|
||||
if (_iceboltTargets.empty())
|
||||
events.ScheduleEvent(EVENT_BREATH, Seconds(2), 0, PHASE_FLIGHT);
|
||||
else
|
||||
events.ScheduleEvent(EVENT_BREATH, 1 * IN_MILLISECONDS);
|
||||
events.Repeat(Seconds(3));
|
||||
return;
|
||||
}
|
||||
case EVENT_BREATH:
|
||||
{
|
||||
Talk(EMOTE_BREATH);
|
||||
DoCastAOE(SPELL_FROST_MISSILE);
|
||||
events.ScheduleEvent(EVENT_EXPLOSION, 8 * IN_MILLISECONDS);
|
||||
events.ScheduleEvent(EVENT_EXPLOSION, Seconds(8), 0, PHASE_FLIGHT);
|
||||
return;
|
||||
}
|
||||
case EVENT_EXPLOSION:
|
||||
CastExplosion();
|
||||
ClearIceBlock();
|
||||
events.ScheduleEvent(EVENT_LAND, 3 * IN_MILLISECONDS);
|
||||
DoCastAOE(SPELL_FROST_BREATH);
|
||||
DoCastAOE(SPELL_FROST_BREATH_ANTICHEAT);
|
||||
events.ScheduleEvent(EVENT_LAND, Seconds(3) + Milliseconds(500), 0, PHASE_FLIGHT);
|
||||
return;
|
||||
case EVENT_LAND:
|
||||
if (_delayedDrain)
|
||||
CastDrain();
|
||||
if (Creature* cBuffet = ObjectAccessor::GetCreature(*me, _buffet))
|
||||
{
|
||||
cBuffet->DespawnOrUnsummon(1 * IN_MILLISECONDS);
|
||||
_buffet.Clear();
|
||||
}
|
||||
me->HandleEmoteCommand(EMOTE_ONESHOT_LAND);
|
||||
Talk(EMOTE_GROUND_PHASE);
|
||||
me->SetHover(false);
|
||||
me->SetDisableGravity(false);
|
||||
events.ScheduleEvent(EVENT_GROUND, 1500);
|
||||
return;
|
||||
case EVENT_GROUND:
|
||||
EnterPhaseGround();
|
||||
events.SetPhase(PHASE_GROUND);
|
||||
events.ScheduleEvent(EVENT_GROUND, Seconds(3) + Milliseconds(500), 0, PHASE_GROUND);
|
||||
return;
|
||||
case EVENT_BIRTH:
|
||||
me->SetVisible(true);
|
||||
@@ -359,51 +366,11 @@ class boss_sapphiron : public CreatureScript
|
||||
}
|
||||
}
|
||||
|
||||
void CastExplosion()
|
||||
{
|
||||
DoZoneInCombat(); // make sure everyone is in threatlist
|
||||
std::vector<Unit*> targets;
|
||||
std::list<HostileReference*>::const_iterator i = me->getThreatManager().getThreatList().begin();
|
||||
for (; i != me->getThreatManager().getThreatList().end(); ++i)
|
||||
{
|
||||
Unit* target = (*i)->getTarget();
|
||||
if (target->GetTypeId() != TYPEID_PLAYER)
|
||||
continue;
|
||||
|
||||
if (target->HasAura(SPELL_ICEBOLT))
|
||||
{
|
||||
target->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, true);
|
||||
targets.push_back(target);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (IceBlockMap::const_iterator itr = _iceblocks.begin(); itr != _iceblocks.end(); ++itr)
|
||||
{
|
||||
if (GameObject* go = ObjectAccessor::GetGameObject(*me, itr->second))
|
||||
{
|
||||
if (go->IsInBetween(me, target, 2.0f)
|
||||
&& me->GetExactDist2d(target->GetPositionX(), target->GetPositionY()) - me->GetExactDist2d(go->GetPositionX(), go->GetPositionY()) < 5.0f)
|
||||
{
|
||||
target->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, true);
|
||||
targets.push_back(target);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
me->CastSpell(me, SPELL_FROST_EXPLOSION, true);
|
||||
|
||||
for (std::vector<Unit*>::const_iterator itr = targets.begin(); itr != targets.end(); ++itr)
|
||||
(*itr)->ApplySpellImmune(0, IMMUNITY_ID, SPELL_FROST_EXPLOSION, false);
|
||||
}
|
||||
|
||||
private:
|
||||
Phases _phase;
|
||||
uint32 _iceboltCount;
|
||||
IceBlockMap _iceblocks;
|
||||
std::vector<ObjectGuid> _iceboltTargets;
|
||||
ObjectGuid _buffet;
|
||||
bool _delayedDrain;
|
||||
bool _canTheHundredClub;
|
||||
Map* _map;
|
||||
};
|
||||
|
||||
CreatureAI* GetAI(Creature* creature) const override
|
||||
@@ -412,6 +379,251 @@ class boss_sapphiron : public CreatureScript
|
||||
}
|
||||
};
|
||||
|
||||
class go_sapphiron_birth : public GameObjectScript
|
||||
{
|
||||
public:
|
||||
go_sapphiron_birth() : GameObjectScript("go_sapphiron_birth") { }
|
||||
|
||||
struct go_sapphiron_birthAI : public GameObjectAI
|
||||
{
|
||||
go_sapphiron_birthAI(GameObject* go) : GameObjectAI(go), instance(go->GetInstanceScript()) { }
|
||||
|
||||
void OnStateChanged(uint32 state, Unit* who) override
|
||||
{
|
||||
if (state == GO_ACTIVATED)
|
||||
{
|
||||
if (who)
|
||||
{
|
||||
if (Creature* sapphiron = ObjectAccessor::GetCreature(*go, instance->GetGuidData(DATA_SAPPHIRON)))
|
||||
sapphiron->AI()->DoAction(ACTION_BIRTH);
|
||||
instance->SetData(DATA_HAD_SAPPHIRON_BIRTH, 1u);
|
||||
}
|
||||
}
|
||||
else if (state == GO_JUST_DEACTIVATED)
|
||||
{ // prevent ourselves from going back to _READY and resetting the client anim
|
||||
go->SetRespawnTime(0);
|
||||
go->Delete();
|
||||
}
|
||||
}
|
||||
|
||||
InstanceScript* instance;
|
||||
};
|
||||
|
||||
GameObjectAI* GetAI(GameObject* go) const override
|
||||
{
|
||||
return GetInstanceAI<go_sapphiron_birthAI>(go);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class spell_sapphiron_change_blizzard_target : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_sapphiron_change_blizzard_target() : SpellScriptLoader("spell_sapphiron_change_blizzard_target") { }
|
||||
|
||||
class spell_sapphiron_change_blizzard_target_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_sapphiron_change_blizzard_target_AuraScript);
|
||||
|
||||
void HandlePeriodic(AuraEffect const* /*eff*/)
|
||||
{
|
||||
TempSummon* me = GetTarget()->ToTempSummon();
|
||||
if (Creature* owner = me ? me->GetSummonerCreatureBase() : nullptr)
|
||||
{
|
||||
Unit* newTarget = owner->AI()->SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true);
|
||||
if (!newTarget)
|
||||
newTarget = owner->getAttackerForHelper();
|
||||
if (newTarget)
|
||||
me->GetMotionMaster()->MoveFollow(newTarget, 0.1f, 0.0f);
|
||||
else
|
||||
{
|
||||
me->StopMoving();
|
||||
me->GetMotionMaster()->Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectPeriodic += AuraEffectPeriodicFn(spell_sapphiron_change_blizzard_target_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
|
||||
}
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_sapphiron_change_blizzard_target_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
class spell_sapphiron_icebolt : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_sapphiron_icebolt() : SpellScriptLoader("spell_sapphiron_icebolt") { }
|
||||
|
||||
class spell_sapphiron_icebolt_AuraScript : public AuraScript
|
||||
{
|
||||
PrepareAuraScript(spell_sapphiron_icebolt_AuraScript);
|
||||
|
||||
void HandleApply(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
GetTarget()->ApplySpellImmune(SPELL_ICEBOLT, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_FROST, true);
|
||||
}
|
||||
|
||||
void HandleRemove(AuraEffect const* /*eff*/, AuraEffectHandleModes /*mode*/)
|
||||
{
|
||||
if (_block)
|
||||
if (GameObject* oBlock = ObjectAccessor::GetGameObject(*GetTarget(), _block))
|
||||
oBlock->Delete();
|
||||
GetTarget()->ApplySpellImmune(SPELL_ICEBOLT, IMMUNITY_DAMAGE, SPELL_SCHOOL_MASK_FROST, false);
|
||||
}
|
||||
|
||||
void HandlePeriodic(AuraEffect const* /*eff*/)
|
||||
{
|
||||
if (_block)
|
||||
return;
|
||||
if (GetTarget()->isMoving())
|
||||
return;
|
||||
float x, y, z;
|
||||
GetTarget()->GetPosition(x, y, z);
|
||||
if (GameObject* block = GetTarget()->SummonGameObject(GO_ICEBLOCK, x, y, z, 0, 0, 0, 0, 0, 25))
|
||||
_block = block->GetGUID();
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
AfterEffectApply += AuraEffectApplyFn(spell_sapphiron_icebolt_AuraScript::HandleApply, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
|
||||
AfterEffectRemove += AuraEffectRemoveFn(spell_sapphiron_icebolt_AuraScript::HandleRemove, EFFECT_0, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL);
|
||||
OnEffectPeriodic += AuraEffectPeriodicFn(spell_sapphiron_icebolt_AuraScript::HandlePeriodic, EFFECT_2, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
|
||||
}
|
||||
|
||||
ObjectGuid _block;
|
||||
};
|
||||
|
||||
AuraScript* GetAuraScript() const override
|
||||
{
|
||||
return new spell_sapphiron_icebolt_AuraScript();
|
||||
}
|
||||
};
|
||||
|
||||
// @hack Hello, developer from the future! How has your day been?
|
||||
// Anyway, this is, as you can undoubtedly see, a hack to emulate line of sight checks on a spell that abides line of sight anyway.
|
||||
// In the current core, line of sight is not properly checked for people standing behind an ice block. This is not a good thing and kills people.
|
||||
// Thus, we have this hack to check for ice block LoS in a "safe" way. Kind of. It's inaccurate, but in a good way (tends to save people when it shouldn't in edge cases).
|
||||
// If LoS handling is better in whatever the current revision is when you read this, please get rid of the hack. Thanks!
|
||||
class spell_sapphiron_frost_breath : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_sapphiron_frost_breath() : SpellScriptLoader("spell_sapphiron_frost_breath") { }
|
||||
|
||||
class spell_sapphiron_frost_breath_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_sapphiron_frost_breath_SpellScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spell*/) override
|
||||
{
|
||||
return !!sSpellMgr->GetSpellInfo(SPELL_FROST_BREATH);
|
||||
}
|
||||
|
||||
void HandleTargets(std::list<WorldObject*>& targetList)
|
||||
{
|
||||
std::list<GameObject*> blocks;
|
||||
if(GetCaster())
|
||||
GetCaster()->GetGameObjectListWithEntryInGrid(blocks, GO_ICEBLOCK, 200.0f);
|
||||
|
||||
std::vector<Unit*> toRemove;
|
||||
toRemove.reserve(3);
|
||||
std::list<WorldObject*>::iterator it = targetList.begin();
|
||||
while (it != targetList.end())
|
||||
{
|
||||
Unit* target = (*it)->ToUnit();
|
||||
if (!target)
|
||||
{
|
||||
it = targetList.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (target->HasAura(SPELL_ICEBOLT))
|
||||
{
|
||||
it = targetList.erase(it);
|
||||
toRemove.push_back(target);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (GameObject* block : blocks)
|
||||
if (block->IsInBetween(GetCaster(), target, 2.0f) && GetCaster()->GetExactDist2d(block) + 5 >= GetCaster()->GetExactDist2d(target))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
it = targetList.erase(it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
|
||||
for (Unit* block : toRemove)
|
||||
block->RemoveAura(SPELL_ICEBOLT);
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sapphiron_frost_breath_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_sapphiron_frost_breath_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
class spell_sapphiron_summon_blizzard : public SpellScriptLoader
|
||||
{
|
||||
public:
|
||||
spell_sapphiron_summon_blizzard() : SpellScriptLoader("spell_sapphiron_summon_blizzard") { }
|
||||
|
||||
class spell_sapphiron_summon_blizzard_SpellScript : public SpellScript
|
||||
{
|
||||
PrepareSpellScript(spell_sapphiron_summon_blizzard_SpellScript);
|
||||
|
||||
bool Validate(SpellInfo const* /*spell*/) override
|
||||
{
|
||||
return !!sSpellMgr->GetSpellInfo(SPELL_SUMMON_BLIZZARD);
|
||||
}
|
||||
|
||||
void HandleDummy(SpellEffIndex /*effIndex*/)
|
||||
{
|
||||
if (Unit* target = GetHitUnit())
|
||||
if (Creature* blizzard = GetCaster()->SummonCreature(NPC_BLIZZARD, *target, TEMPSUMMON_TIMED_DESPAWN, urandms(25, 30)))
|
||||
{
|
||||
blizzard->CastSpell(nullptr, blizzard->m_spells[0], TRIGGERED_NONE);
|
||||
if (Creature* creatureCaster = GetCaster()->ToCreature())
|
||||
{
|
||||
if (Unit* newTarget = creatureCaster->AI()->SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true))
|
||||
{
|
||||
blizzard->GetMotionMaster()->MoveFollow(newTarget, 0.1f, 0.0f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
blizzard->GetMotionMaster()->MoveFollow(target, 0.1f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void Register() override
|
||||
{
|
||||
OnEffectHitTarget += SpellEffectFn(spell_sapphiron_summon_blizzard_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
|
||||
}
|
||||
};
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_sapphiron_summon_blizzard_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
class achievement_the_hundred_club : public AchievementCriteriaScript
|
||||
{
|
||||
public:
|
||||
@@ -426,5 +638,10 @@ class achievement_the_hundred_club : public AchievementCriteriaScript
|
||||
void AddSC_boss_sapphiron()
|
||||
{
|
||||
new boss_sapphiron();
|
||||
new go_sapphiron_birth();
|
||||
new spell_sapphiron_change_blizzard_target();
|
||||
new spell_sapphiron_icebolt();
|
||||
new spell_sapphiron_frost_breath();
|
||||
new spell_sapphiron_summon_blizzard();
|
||||
new achievement_the_hundred_club();
|
||||
}
|
||||
|
||||
@@ -109,6 +109,10 @@ enum PetSpells
|
||||
SPELL_MAGNETIC_PULL = 54517,
|
||||
SPELL_MAGNETIC_PULL_EFFECT = 28337,
|
||||
|
||||
// @hack feugen/stalagg use this in P1 after gripping tanks to prevent mmaps from pathing them off the platform once they approach the ramp
|
||||
// developer from the future, if you read this and mmaps in the room has been fixed, then get rid of the hackfix, please
|
||||
SPELL_ROOT_SELF = 75215,
|
||||
|
||||
SPELL_TESLA_SHOCK = 28099
|
||||
};
|
||||
|
||||
@@ -166,10 +170,12 @@ public:
|
||||
struct boss_thaddiusAI : public BossAI
|
||||
{
|
||||
public:
|
||||
boss_thaddiusAI(Creature* creature) : BossAI(creature, BOSS_THADDIUS), stalaggAlive(true), feugenAlive(true), ballLightningEnabled(false), shockingEligibility(true)
|
||||
boss_thaddiusAI(Creature* creature) : BossAI(creature, BOSS_THADDIUS), stalaggAlive(true), feugenAlive(true), ballLightningUnlocked(false), ballLightningEnabled(false), shockingEligibility(true) {}
|
||||
|
||||
void InitializeAI() override
|
||||
{
|
||||
if (instance->GetBossState(BOSS_THADDIUS) != DONE)
|
||||
{
|
||||
{
|
||||
events.SetPhase(PHASE_NOT_ENGAGED);
|
||||
SetCombatMovement(false);
|
||||
|
||||
@@ -184,12 +190,33 @@ public:
|
||||
Talk(SAY_SLAY);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
void Reset() override { }
|
||||
|
||||
void EnterEvadeMode(EvadeReason why) override
|
||||
{
|
||||
if (!ballLightningEnabled && why == EVADE_REASON_NO_HOSTILES)
|
||||
{
|
||||
ballLightningEnabled = true;
|
||||
return; // try again
|
||||
}
|
||||
if (events.IsInPhase(PHASE_TRANSITION) || (events.IsInPhase(PHASE_THADDIUS) && me->IsAlive()))
|
||||
BeginResetEncounter();
|
||||
}
|
||||
|
||||
bool CanAIAttack(Unit const* who) const override
|
||||
{
|
||||
if (ballLightningEnabled || me->IsWithinMeleeRange(who))
|
||||
return BossAI::CanAIAttack(who);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void JustRespawned() override
|
||||
{
|
||||
if (events.IsInPhase(PHASE_RESETTING))
|
||||
ResetEncounter();
|
||||
}
|
||||
|
||||
void JustDied(Unit* /*killer*/) override
|
||||
{
|
||||
_JustDied();
|
||||
@@ -217,7 +244,10 @@ public:
|
||||
case ACTION_FEUGEN_AGGRO:
|
||||
case ACTION_STALAGG_AGGRO:
|
||||
if (events.IsInPhase(PHASE_RESETTING))
|
||||
return BeginResetEncounter();
|
||||
{
|
||||
BeginResetEncounter();
|
||||
return;
|
||||
}
|
||||
if (!events.IsInPhase(PHASE_NOT_ENGAGED))
|
||||
return;
|
||||
events.SetPhase(PHASE_PETS);
|
||||
@@ -225,10 +255,14 @@ public:
|
||||
shockingEligibility = true;
|
||||
|
||||
if (!instance->CheckRequiredBosses(BOSS_THADDIUS))
|
||||
return BeginResetEncounter();
|
||||
{
|
||||
BeginResetEncounter();
|
||||
return;
|
||||
}
|
||||
instance->SetBossState(BOSS_THADDIUS, IN_PROGRESS);
|
||||
|
||||
me->setActive(true);
|
||||
DoZoneInCombat();
|
||||
if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
|
||||
stalagg->setActive(true);
|
||||
if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
|
||||
@@ -239,7 +273,7 @@ public:
|
||||
feugen->AI()->DoAction(ACTION_FEUGEN_REVIVING_FX);
|
||||
feugenAlive = false;
|
||||
if (stalaggAlive)
|
||||
events.ScheduleEvent(EVENT_REVIVE_FEUGEN, 5 * IN_MILLISECONDS, 0, PHASE_PETS);
|
||||
events.ScheduleEvent(EVENT_REVIVE_FEUGEN, Seconds(5), 0, PHASE_PETS);
|
||||
else
|
||||
Transition();
|
||||
|
||||
@@ -249,7 +283,7 @@ public:
|
||||
stalagg->AI()->DoAction(ACTION_STALAGG_REVIVING_FX);
|
||||
stalaggAlive = false;
|
||||
if (feugenAlive)
|
||||
events.ScheduleEvent(EVENT_REVIVE_STALAGG, 5 * IN_MILLISECONDS, 0, PHASE_PETS);
|
||||
events.ScheduleEvent(EVENT_REVIVE_STALAGG, Seconds(5), 0, PHASE_PETS);
|
||||
else
|
||||
Transition();
|
||||
|
||||
@@ -274,9 +308,9 @@ public:
|
||||
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
|
||||
|
||||
events.ScheduleEvent(EVENT_TRANSITION_1, 10 * IN_MILLISECONDS, 0, PHASE_TRANSITION);
|
||||
events.ScheduleEvent(EVENT_TRANSITION_2, 12 * IN_MILLISECONDS, 0, PHASE_TRANSITION);
|
||||
events.ScheduleEvent(EVENT_TRANSITION_3, 14 * IN_MILLISECONDS, 0, PHASE_TRANSITION);
|
||||
events.ScheduleEvent(EVENT_TRANSITION_1, Seconds(10), 0, PHASE_TRANSITION);
|
||||
events.ScheduleEvent(EVENT_TRANSITION_2, Seconds(12), 0, PHASE_TRANSITION);
|
||||
events.ScheduleEvent(EVENT_TRANSITION_3, Seconds(14), 0, PHASE_TRANSITION);
|
||||
}
|
||||
|
||||
void BeginResetEncounter(bool initial = false)
|
||||
@@ -286,16 +320,12 @@ public:
|
||||
if (events.IsInPhase(PHASE_RESETTING))
|
||||
return;
|
||||
|
||||
if (initial) // signal shorter spawn timer to instance script
|
||||
instance->SetBossState(BOSS_THADDIUS, SPECIAL);
|
||||
instance->ProcessEvent(me, EVENT_THADDIUS_BEGIN_RESET);
|
||||
instance->SetBossState(BOSS_THADDIUS, NOT_STARTED);
|
||||
|
||||
// remove polarity shift debuffs on reset
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_POSITIVE_CHARGE_APPLY);
|
||||
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_NEGATIVE_CHARGE_APPLY);
|
||||
|
||||
me->DespawnOrUnsummon();
|
||||
me->SetRespawnTime(initial ? 5 : 30);
|
||||
|
||||
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_STUNNED);
|
||||
events.SetPhase(PHASE_RESETTING);
|
||||
@@ -312,11 +342,9 @@ public:
|
||||
feugenAlive = true;
|
||||
stalaggAlive = true;
|
||||
|
||||
me->Respawn(true);
|
||||
_Reset();
|
||||
events.SetPhase(PHASE_NOT_ENGAGED);
|
||||
|
||||
me->CastSpell(me, SPELL_THADDIUS_INACTIVE_VISUAL, true);
|
||||
me->SetReactState(REACT_PASSIVE);
|
||||
|
||||
if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
|
||||
feugen->AI()->DoAction(ACTION_RESET_ENCOUNTER);
|
||||
@@ -361,16 +389,20 @@ public:
|
||||
break;
|
||||
case EVENT_TRANSITION_3: // thaddius becomes active
|
||||
me->CastSpell(me, SPELL_THADDIUS_SPARK_VISUAL, true);
|
||||
ballLightningEnabled = false;
|
||||
ballLightningUnlocked = false;
|
||||
me->RemoveAura(SPELL_THADDIUS_INACTIVE_VISUAL);
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED);
|
||||
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
|
||||
me->SetReactState(REACT_AGGRESSIVE);
|
||||
|
||||
DoZoneInCombat();
|
||||
if (Unit* closest = SelectTarget(SELECT_TARGET_NEAREST, 0, 500.0f))
|
||||
AttackStart(closest);
|
||||
else // if there is no nearest target, then there is no target, meaning we should reset
|
||||
return BeginResetEncounter();
|
||||
{
|
||||
BeginResetEncounter();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Creature* feugen = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_FEUGEN)))
|
||||
feugen->AI()->DoAction(ACTION_TRANSITION_3);
|
||||
@@ -381,20 +413,20 @@ public:
|
||||
|
||||
Talk(SAY_AGGRO);
|
||||
|
||||
events.ScheduleEvent(EVENT_ENABLE_BALL_LIGHTNING, 5 * IN_MILLISECONDS, 0, PHASE_THADDIUS);
|
||||
events.ScheduleEvent(EVENT_SHIFT, 10 * IN_MILLISECONDS, 0, PHASE_THADDIUS);
|
||||
events.ScheduleEvent(EVENT_CHAIN, urand(10, 20) * IN_MILLISECONDS, 0, PHASE_THADDIUS);
|
||||
events.ScheduleEvent(EVENT_BERSERK, 6 * MINUTE * IN_MILLISECONDS, 0, PHASE_THADDIUS);
|
||||
events.ScheduleEvent(EVENT_ENABLE_BALL_LIGHTNING, Seconds(5), 0, PHASE_THADDIUS);
|
||||
events.ScheduleEvent(EVENT_SHIFT, Seconds(10), 0, PHASE_THADDIUS);
|
||||
events.ScheduleEvent(EVENT_CHAIN, randtime(Seconds(10), Seconds(20)), 0, PHASE_THADDIUS);
|
||||
events.ScheduleEvent(EVENT_BERSERK, Minutes(6), 0, PHASE_THADDIUS);
|
||||
|
||||
break;
|
||||
case EVENT_ENABLE_BALL_LIGHTNING:
|
||||
ballLightningEnabled = true;
|
||||
ballLightningUnlocked = true;
|
||||
break;
|
||||
case EVENT_SHIFT:
|
||||
me->CastStop(); // shift overrides all other spells
|
||||
DoCastAOE(SPELL_POLARITY_SHIFT);
|
||||
events.ScheduleEvent(EVENT_SHIFT_TALK, 3 * IN_MILLISECONDS, PHASE_THADDIUS);
|
||||
events.ScheduleEvent(EVENT_SHIFT, 30 * IN_MILLISECONDS, PHASE_THADDIUS);
|
||||
events.ScheduleEvent(EVENT_SHIFT_TALK, Seconds(3), PHASE_THADDIUS);
|
||||
events.ScheduleEvent(EVENT_SHIFT, Seconds(30), PHASE_THADDIUS);
|
||||
break;
|
||||
case EVENT_SHIFT_TALK:
|
||||
Talk(SAY_ELECT);
|
||||
@@ -402,12 +434,12 @@ public:
|
||||
break;
|
||||
case EVENT_CHAIN:
|
||||
if (me->FindCurrentSpellBySpellId(SPELL_POLARITY_SHIFT)) // delay until shift is over
|
||||
events.ScheduleEvent(EVENT_CHAIN, 3 * IN_MILLISECONDS, 0, PHASE_THADDIUS);
|
||||
events.Repeat(Seconds(3));
|
||||
else
|
||||
{
|
||||
me->CastStop();
|
||||
DoCastVictim(SPELL_CHAIN_LIGHTNING);
|
||||
events.ScheduleEvent(EVENT_CHAIN, urand(10, 20) * IN_MILLISECONDS, PHASE_THADDIUS);
|
||||
events.Repeat(randtime(Seconds(10), Seconds(20)));
|
||||
}
|
||||
break;
|
||||
case EVENT_BERSERK:
|
||||
@@ -418,22 +450,24 @@ public:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (events.IsInPhase(PHASE_THADDIUS))
|
||||
if (events.IsInPhase(PHASE_THADDIUS) && !me->HasUnitState(UNIT_STATE_CASTING) && me->isAttackReady())
|
||||
{
|
||||
if (me->IsWithinMeleeRange(me->GetVictim()))
|
||||
{
|
||||
ballLightningEnabled = false;
|
||||
DoMeleeAttackIfReady();
|
||||
else
|
||||
if (ballLightningEnabled)
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
|
||||
DoCast(target, SPELL_BALL_LIGHTNING);
|
||||
}
|
||||
else if (ballLightningUnlocked)
|
||||
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM))
|
||||
DoCast(target, SPELL_BALL_LIGHTNING);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool stalaggAlive;
|
||||
bool feugenAlive;
|
||||
bool ballLightningEnabled;
|
||||
bool ballLightningUnlocked; // whether the initial ball lightning grace period has expired and we should proceed to exterminate with extreme prejudice
|
||||
bool ballLightningEnabled; // switch that is flipped to true if we try to evade due to no eligible targets in melee range
|
||||
bool shockingEligibility;
|
||||
};
|
||||
|
||||
@@ -652,7 +686,7 @@ public:
|
||||
else
|
||||
{
|
||||
DoCast(me, SPELL_STALAGG_POWERSURGE);
|
||||
powerSurgeTimer = urand(25, 30) * IN_MILLISECONDS;
|
||||
powerSurgeTimer = urandms(25, 30);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -836,7 +870,7 @@ public:
|
||||
Talk(SAY_FEUGEN_AGGRO);
|
||||
|
||||
if (Creature* thaddius = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_THADDIUS)))
|
||||
thaddius->AI()->DoAction(ACTION_STALAGG_AGGRO);
|
||||
thaddius->AI()->DoAction(ACTION_FEUGEN_AGGRO);
|
||||
|
||||
if (Creature* stalagg = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_STALAGG)))
|
||||
if (!stalagg->IsInCombat())
|
||||
@@ -1094,7 +1128,7 @@ class spell_thaddius_polarity_charge : public SpellScriptLoader
|
||||
|
||||
SpellScript* GetSpellScript() const override
|
||||
{
|
||||
return new spell_thaddius_polarity_charge_SpellScript;
|
||||
return new spell_thaddius_polarity_charge_SpellScript();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1212,6 +1246,10 @@ class spell_thaddius_magnetic_pull : public SpellScriptLoader
|
||||
feugenTank->CastSpell(stalaggTank, SPELL_MAGNETIC_PULL_EFFECT, true);
|
||||
stalaggTank->CastSpell(feugenTank, SPELL_MAGNETIC_PULL_EFFECT, true);
|
||||
|
||||
// @hack prevent mmaps clusterfucks from breaking tesla while tanks are midair
|
||||
feugen->AddAura(SPELL_ROOT_SELF, feugen);
|
||||
stalagg->AddAura(SPELL_ROOT_SELF, stalagg);
|
||||
|
||||
// and make both attack their respective new tanks
|
||||
if (feugen->GetAI())
|
||||
feugen->GetAI()->AttackStart(stalaggTank);
|
||||
|
||||
@@ -100,36 +100,6 @@ ObjectData const objectData[] =
|
||||
{ 0, 0, }
|
||||
};
|
||||
|
||||
// from P2 teleport spell stored target
|
||||
float const HeiganPos[2] = { 2793.86f, -3707.38f };
|
||||
float const HeiganEruptionSlope[3] =
|
||||
{
|
||||
(-3703.303223f - HeiganPos[1]) / (2777.494141f - HeiganPos[0]), // between right center and far right
|
||||
(-3696.948242f - HeiganPos[1]) / (2785.624268f - HeiganPos[0]), // between left and right halves
|
||||
(-3691.880615f - HeiganPos[1]) / (2790.280029f - HeiganPos[0]) // between far left and left center
|
||||
};
|
||||
|
||||
// 0 H x
|
||||
// 1 ^
|
||||
// 2 |
|
||||
// 3 y<--o
|
||||
inline uint32 GetEruptionSection(float x, float y)
|
||||
{
|
||||
y -= HeiganPos[1];
|
||||
if (y < 1.0f)
|
||||
return 0;
|
||||
|
||||
x -= HeiganPos[0];
|
||||
if (x > -1.0f)
|
||||
return 3;
|
||||
|
||||
float slope = y/x;
|
||||
for (uint32 i = 0; i < 3; ++i)
|
||||
if (slope > HeiganEruptionSlope[i])
|
||||
return i;
|
||||
return 3;
|
||||
}
|
||||
|
||||
class instance_naxxramas : public InstanceMapScript
|
||||
{
|
||||
public:
|
||||
@@ -149,6 +119,7 @@ class instance_naxxramas : public InstanceMapScript
|
||||
hadAnubRekhanGreet = false;
|
||||
hadFaerlinaGreet = false;
|
||||
hadThaddiusGreet = false;
|
||||
hadSapphironBirth = false;
|
||||
CurrentWingTaunt = SAY_KELTHUZAD_FIRST_WING_TAUNT;
|
||||
|
||||
playerDied = 0;
|
||||
@@ -211,28 +182,8 @@ class instance_naxxramas : public InstanceMapScript
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessEvent(WorldObject* /*source*/, uint32 eventId) override
|
||||
{
|
||||
switch (eventId)
|
||||
{
|
||||
case EVENT_THADDIUS_BEGIN_RESET:
|
||||
if (GetBossState(BOSS_THADDIUS) == SPECIAL) // this is the initial spawn, we want a shorter spawn time
|
||||
events.ScheduleEvent(EVENT_THADDIUS_RESET, 5 * IN_MILLISECONDS);
|
||||
else
|
||||
events.ScheduleEvent(EVENT_THADDIUS_RESET, 30 * IN_MILLISECONDS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameObjectCreate(GameObject* go) override
|
||||
{
|
||||
if (go->GetGOInfo()->displayId == 6785 || go->GetGOInfo()->displayId == 1287)
|
||||
{
|
||||
uint32 section = GetEruptionSection(go->GetPositionX(), go->GetPositionY());
|
||||
HeiganEruptionGUID[section].insert(go->GetGUID());
|
||||
return;
|
||||
}
|
||||
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_GOTHIK_GATE:
|
||||
@@ -276,37 +227,18 @@ class instance_naxxramas : public InstanceMapScript
|
||||
if (GetBossState(BOSS_HORSEMEN) == DONE)
|
||||
go->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
InstanceScript::OnGameObjectCreate(go);
|
||||
}
|
||||
|
||||
void OnGameObjectRemove(GameObject* go) override
|
||||
{
|
||||
if (go->GetGOInfo()->displayId == 6785 || go->GetGOInfo()->displayId == 1287)
|
||||
{
|
||||
uint32 section = GetEruptionSection(go->GetPositionX(), go->GetPositionY());
|
||||
HeiganEruptionGUID[section].erase(go->GetGUID());
|
||||
return;
|
||||
}
|
||||
|
||||
switch (go->GetEntry())
|
||||
{
|
||||
case GO_BIRTH:
|
||||
if (SapphironGUID)
|
||||
if (hadSapphironBirth || GetBossState(BOSS_SAPPHIRON) == DONE)
|
||||
{
|
||||
if (Creature* sapphiron = instance->GetCreature(SapphironGUID))
|
||||
sapphiron->AI()->DoAction(DATA_SAPPHIRON_BIRTH);
|
||||
return;
|
||||
hadSapphironBirth = true;
|
||||
go->Delete();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
InstanceScript::OnGameObjectRemove(go);
|
||||
InstanceScript::OnGameObjectCreate(go);
|
||||
}
|
||||
|
||||
void OnUnitDeath(Unit* unit) override
|
||||
@@ -331,9 +263,6 @@ class instance_naxxramas : public InstanceMapScript
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case DATA_HEIGAN_ERUPT:
|
||||
HeiganErupt(value);
|
||||
break;
|
||||
case DATA_GOTHIK_GATE:
|
||||
if (GameObject* gate = instance->GetGameObject(GothikGateGUID))
|
||||
gate->SetGoState(GOState(value));
|
||||
@@ -350,6 +279,9 @@ class instance_naxxramas : public InstanceMapScript
|
||||
case DATA_HAD_THADDIUS_GREET:
|
||||
hadThaddiusGreet = (value == 1u);
|
||||
break;
|
||||
case DATA_HAD_SAPPHIRON_BIRTH:
|
||||
hadSapphironBirth = (value == 1u);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -367,6 +299,8 @@ class instance_naxxramas : public InstanceMapScript
|
||||
return hadFaerlinaGreet ? 1u : 0u;
|
||||
case DATA_HAD_THADDIUS_GREET:
|
||||
return hadThaddiusGreet ? 1u : 0u;
|
||||
case DATA_HAD_SAPPHIRON_BIRTH:
|
||||
return hadSapphironBirth ? 1u : 0u;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -404,6 +338,8 @@ class instance_naxxramas : public InstanceMapScript
|
||||
return StalaggGUID;
|
||||
case DATA_THADDIUS:
|
||||
return ThaddiusGUID;
|
||||
case DATA_SAPPHIRON:
|
||||
return SapphironGUID;
|
||||
case DATA_KELTHUZAD:
|
||||
return KelthuzadGUID;
|
||||
case DATA_KELTHUZAD_PORTAL01:
|
||||
@@ -436,7 +372,7 @@ class instance_naxxramas : public InstanceMapScript
|
||||
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_ARACHNID))
|
||||
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6));
|
||||
}
|
||||
break;
|
||||
case BOSS_LOATHEB:
|
||||
@@ -445,7 +381,7 @@ class instance_naxxramas : public InstanceMapScript
|
||||
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_PLAGUE))
|
||||
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6));
|
||||
}
|
||||
break;
|
||||
case BOSS_THADDIUS:
|
||||
@@ -454,12 +390,12 @@ class instance_naxxramas : public InstanceMapScript
|
||||
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_CONSTRUCT))
|
||||
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6));
|
||||
}
|
||||
break;
|
||||
case BOSS_GOTHIK:
|
||||
if (state == DONE)
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ, 10000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ, Seconds(10));
|
||||
break;
|
||||
case BOSS_HORSEMEN:
|
||||
if (state == DONE)
|
||||
@@ -473,12 +409,12 @@ class instance_naxxramas : public InstanceMapScript
|
||||
if (GameObject* teleporter = GetGameObject(DATA_NAXX_PORTAL_MILITARY))
|
||||
teleporter->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
|
||||
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000);
|
||||
events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, Seconds(6));
|
||||
}
|
||||
break;
|
||||
case BOSS_SAPPHIRON:
|
||||
if (state == DONE)
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD, 6000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD, Seconds(6));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -498,37 +434,37 @@ class instance_naxxramas : public InstanceMapScript
|
||||
case EVENT_DIALOGUE_GOTHIK_KORTHAZZ:
|
||||
if (Creature* korthazz = instance->GetCreature(ThaneGUID))
|
||||
korthazz->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK, 5000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK, Seconds(5));
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_ZELIEK:
|
||||
if (Creature* zeliek = instance->GetCreature(SirGUID))
|
||||
zeliek->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX, 6000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX, Seconds(6));
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_BLAUMEUX:
|
||||
if (Creature* blaumeux = instance->GetCreature(LadyGUID))
|
||||
blaumeux->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE, 6000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE, Seconds(6));
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_RIVENDARE:
|
||||
if (Creature* rivendare = instance->GetCreature(BaronGUID))
|
||||
rivendare->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX2, 6000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_BLAUMEUX2, Seconds(6));
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_BLAUMEUX2:
|
||||
if (Creature* blaumeux = instance->GetCreature(LadyGUID))
|
||||
blaumeux->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK2, 6000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_ZELIEK2, Seconds(6));
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_ZELIEK2:
|
||||
if (Creature* zeliek = instance->GetCreature(SirGUID))
|
||||
zeliek->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ2, 6000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_KORTHAZZ2, Seconds(6));
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_KORTHAZZ2:
|
||||
if (Creature* korthazz = instance->GetCreature(ThaneGUID))
|
||||
korthazz->AI()->Talk(SAY_DIALOGUE_GOTHIK_HORSEMAN2);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE2, 6000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_GOTHIK_RIVENDARE2, Seconds(6));
|
||||
break;
|
||||
case EVENT_DIALOGUE_GOTHIK_RIVENDARE2:
|
||||
if (Creature* rivendare = instance->GetCreature(BaronGUID))
|
||||
@@ -545,62 +481,39 @@ class instance_naxxramas : public InstanceMapScript
|
||||
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
|
||||
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD);
|
||||
HandleGameObject(KelthuzadDoorGUID, false);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING, 6000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING, Seconds(6));
|
||||
break;
|
||||
case EVENT_DIALOGUE_SAPPHIRON_LICHKING:
|
||||
if (Creature* lichKing = instance->GetCreature(LichKingGUID))
|
||||
lichKing->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_LICH_KING);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2, 16000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2, Seconds(16));
|
||||
break;
|
||||
case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD2:
|
||||
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
|
||||
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD2);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING2, 9000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_LICHKING2, Seconds(9));
|
||||
break;
|
||||
case EVENT_DIALOGUE_SAPPHIRON_LICHKING2:
|
||||
if (Creature* lichKing = instance->GetCreature(LichKingGUID))
|
||||
lichKing->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_LICH_KING2);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3, 12000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3, Seconds(12));
|
||||
break;
|
||||
case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD3:
|
||||
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
|
||||
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD3);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4, 6000);
|
||||
events.ScheduleEvent(EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4, Seconds(6));
|
||||
break;
|
||||
case EVENT_DIALOGUE_SAPPHIRON_KELTHUZAD4:
|
||||
if (Creature* kelthuzad = instance->GetCreature(KelthuzadGUID))
|
||||
kelthuzad->AI()->Talk(SAY_DIALOGUE_SAPPHIRON_KELTHUZAD4);
|
||||
HandleGameObject(KelthuzadDoorGUID, true);
|
||||
break;
|
||||
case EVENT_THADDIUS_RESET:
|
||||
if (GetBossState(BOSS_THADDIUS) != DONE)
|
||||
if (Creature* thaddius = instance->GetCreature(ThaddiusGUID))
|
||||
thaddius->AI()->DoAction(-1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HeiganErupt(uint32 section)
|
||||
{
|
||||
for (uint32 i = 0; i < 4; ++i)
|
||||
{
|
||||
if (i == section)
|
||||
continue;
|
||||
|
||||
for (ObjectGuid guid : HeiganEruptionGUID[i])
|
||||
{
|
||||
if (GameObject* heiganEruption = instance->GetGameObject(guid))
|
||||
{
|
||||
heiganEruption->SendCustomAnim(heiganEruption->GetGoAnimProgress());
|
||||
heiganEruption->CastSpell(NULL, SPELL_ERUPTION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This Function is called in CheckAchievementCriteriaMeet and CheckAchievementCriteriaMeet is called before SetBossState(bossId, DONE),
|
||||
// so to check if all bosses are done the checker must exclude 1 boss, the last done, if there is at most 1 encouter in progress when is
|
||||
// called this function then all bosses are done. The one boss that check is the boss that calls this function, so it is dead.
|
||||
@@ -658,7 +571,6 @@ class instance_naxxramas : public InstanceMapScript
|
||||
|
||||
/* The Plague Quarter */
|
||||
// Heigan the Unclean
|
||||
GuidSet HeiganEruptionGUID[4];
|
||||
ObjectGuid HeiganGUID;
|
||||
|
||||
/* The Military Quarter */
|
||||
@@ -695,6 +607,7 @@ class instance_naxxramas : public InstanceMapScript
|
||||
bool hadAnubRekhanGreet;
|
||||
bool hadFaerlinaGreet;
|
||||
bool hadThaddiusGreet;
|
||||
bool hadSapphironBirth;
|
||||
uint8 CurrentWingTaunt;
|
||||
|
||||
/* The Immortal / The Undying */
|
||||
|
||||
@@ -43,12 +43,11 @@ enum Encounter
|
||||
|
||||
enum Data
|
||||
{
|
||||
DATA_HEIGAN_ERUPT,
|
||||
DATA_GOTHIK_GATE,
|
||||
DATA_SAPPHIRON_BIRTH,
|
||||
DATA_HAD_ANUBREKHAN_GREET,
|
||||
DATA_HAD_FAERLINA_GREET,
|
||||
DATA_HAD_THADDIUS_GREET,
|
||||
DATA_HAD_SAPPHIRON_BIRTH,
|
||||
|
||||
DATA_HORSEMEN_CHECK_ACHIEVEMENT_CREDIT,
|
||||
DATA_ABOMINATION_KILLED,
|
||||
@@ -74,6 +73,7 @@ enum Data64
|
||||
DATA_HEIGAN,
|
||||
DATA_FEUGEN,
|
||||
DATA_STALAGG,
|
||||
DATA_SAPPHIRON,
|
||||
DATA_KELTHUZAD,
|
||||
DATA_KELTHUZAD_PORTAL01,
|
||||
DATA_KELTHUZAD_PORTAL02,
|
||||
@@ -160,12 +160,6 @@ enum GameObjectsIds
|
||||
GO_NAXX_PORTAL_MILITARY = 181578
|
||||
};
|
||||
|
||||
enum SpellIds
|
||||
{
|
||||
SPELL_ERUPTION = 29371,
|
||||
SPELL_SLIME = 28801
|
||||
};
|
||||
|
||||
enum InstanceEvents
|
||||
{
|
||||
// Dialogue that happens after Gothik's death.
|
||||
@@ -178,10 +172,6 @@ enum InstanceEvents
|
||||
EVENT_DIALOGUE_GOTHIK_KORTHAZZ2,
|
||||
EVENT_DIALOGUE_GOTHIK_RIVENDARE2,
|
||||
|
||||
// Thaddius AI requesting timed encounter (re-)spawn
|
||||
EVENT_THADDIUS_BEGIN_RESET,
|
||||
EVENT_THADDIUS_RESET,
|
||||
|
||||
// Dialogue that happens after each wing.
|
||||
EVENT_KELTHUZAD_WING_TAUNT,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user