From 2b37ea11a97c9c2640da37c23e7e12889835bbd9 Mon Sep 17 00:00:00 2001 From: Nefertumm Date: Fri, 28 Jun 2019 05:59:28 -0300 Subject: [PATCH] Fix(Core/DB): Naxxramas overhaul (#1657) Co-authored-by: Pondaveia Pondaveia@users.noreply.github.com Co-authored-by: FALL1N1 FALL1N1@users.noreply.github.com --- .../rev_1553965568217074300.sql | 43 ++++ src/server/game/Maps/Map.cpp | 15 ++ src/server/game/Maps/Map.h | 1 + .../Northrend/Naxxramas/boss_anubrekhan.cpp | 29 +-- .../Northrend/Naxxramas/boss_faerlina.cpp | 51 +++-- .../Naxxramas/boss_four_horsemen.cpp | 28 ++- .../Northrend/Naxxramas/boss_gluth.cpp | 52 +++-- .../Northrend/Naxxramas/boss_gothik.cpp | 86 +++++--- .../Northrend/Naxxramas/boss_grobbulus.cpp | 52 +++-- .../Northrend/Naxxramas/boss_heigan.cpp | 35 +-- .../Northrend/Naxxramas/boss_kelthuzad.cpp | 77 +++---- .../Northrend/Naxxramas/boss_loatheb.cpp | 63 ++++-- .../Northrend/Naxxramas/boss_maexxna.cpp | 35 +-- .../scripts/Northrend/Naxxramas/boss_noth.cpp | 36 ++-- .../Northrend/Naxxramas/boss_patchwerk.cpp | 16 +- .../Northrend/Naxxramas/boss_razuvious.cpp | 85 +++----- .../Northrend/Naxxramas/boss_sapphiron.cpp | 24 +-- .../Northrend/Naxxramas/boss_thaddius.cpp | 199 +++++++++++++----- .../Naxxramas/instance_naxxramas.cpp | 101 ++++++++- .../scripts/Northrend/Naxxramas/naxxramas.h | 30 ++- 20 files changed, 706 insertions(+), 352 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1553965568217074300.sql diff --git a/data/sql/updates/pending_db_world/rev_1553965568217074300.sql b/data/sql/updates/pending_db_world/rev_1553965568217074300.sql new file mode 100644 index 000000000..3064bfb5b --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1553965568217074300.sql @@ -0,0 +1,43 @@ +INSERT INTO `version_db_world` (`sql_rev`) VALUES ('1553965568217074300'); + +DELETE FROM `creature_text` WHERE `CreatureID` = 15931 AND `GroupID` = 0; +DELETE FROM `creature_text` WHERE `CreatureID` = 16061 AND `GroupID` IN (0,1,2,4); +DELETE FROM `creature_text` WHERE `CreatureID` = 15953 AND `GroupID` IN (1,6); +DELETE FROM `creature_text` WHERE `CreatureID` = 15936 AND `GroupID` IN (2,6); +DELETE FROM `creature_text` WHERE `CreatureID` = 15954 AND `GroupID` = 8; +INSERT INTO `creature_text` VALUES +-- Grobbulus +(15931, 0, 0, '%s sprays slime across the room!', 16, 0, 100, 0, 0, 0, 32318, 1, 'Grobbulus - slime'), +-- Noth +(15954, 8, 0, '%s blinks away!', 41, 0, 100, 0, 0, 0, 32978, 3, 'Noth EMOTE_BLINK'), +-- Razuvious +(16061,0,0,'Do as I taught you!',14,0,100,0,0,8855,13075,3,'Razuvious SAY_AGGRO #1'), +(16061,0,1,'The time for practice is over! Show me what you have learned!',14,0,100,0,0,8859,13078,3,'Razuvious SAY_AGGRO #2'), +(16061,0,2,'Show them no mercy!',14,0,100,0,0,8856,13076,3,'Razuvious SAY_AGGRO #3'), +(16061,0,3,'Sweep the leg... Do you have a problem with that?',14,0,50,0,0,8861,13080,3,'Razuvious SAY_AGGRO #3'), +(16061,1,0,'You should have stayed home.',14,0,50,0,0,8861,13081,3,'Razuvious SAY_SLAY #1'), +(16061,1,1,'You disappoint me, students!',14,0,50,0,0,8858,13077,3,'Razuvious SAY_SLAY #2'), +(16061,2,0,'Hah hah, I\'m just getting warmed up!',14,0,50,0,0,8852,13072,3,'Razuvious SAY_TAUNTED #1'), +(16061,2,1,'Stand and fight!',14,0,50,0,0,8853,13073,3,'Razuvious SAY_TAUNTED #2'), +(16061,2,2,'Show me what you\'ve got!',14,0,50,0,0,8854,13074,3,'Razuvious SAY_TAUNTED #3'), +(16061,4,0,'%s lets loose a triumphant shout.',41,0,30,0,0,0,13082,3,'Razuvious SAY_SHOUT'), +-- Faerlina +(15953,1,0,'Slay them in the master\'s name!',14,0,100,0,0,8794,12856,0,'faerlina SAY_AGGRO'), +(15953,6,0,'You cannot hide from me!',14,0,100,0,0,8795,12857,0,'faerlina SAY_ENRAGE1'), +(15953,6,1,'Kneel before me, worm!',14,0,100,0,0,8796,12858,0,'faerlina SAY_ENRAGE2'), +(15953,6,2,'Run while you still can!',14,0,100,0,0,8797,61582,0,'faerlina SAY_ENRAGE3'), +-- Heigan +(15936,2,0,'The races of the world will perish. It is only a matter of time.',14,0,100,0,0,8830,13046,0,'heigan SAY_TAUNT1'), +(15936,2,1,'I see endless suffering. I see torment. I see rage. I see everything...',14,0,100,0,0,8831,13047,0,'heigan SAY_TAUNT2'), +(15936,2,2,'Soon the world will tremble.',14,0,100,0,0,8832,13048,0,'heigan SAY_TAUNT3'), +(15936,2,3,'Hungry worms will feast on your rotting flesh.',14,0,100,0,0,8834,13050,0,'heigan SAY_TAUNT4'), +(15936,6,0,'The end is upon you.',14,0,100,0,0,8833,13049,0,'heigan SAY_DANCE'); + +UPDATE `creature_text` SET `BroadcastTextId` = 12984 WHERE `CreatureID` = 15990 AND `GroupID` = 16; + +UPDATE `creature_template` SET `AIName` = '', `ScriptName` = 'npc_tesla', `dynamicflags` = 0 WHERE `entry` = 16218; + +-- trigger when entering thaddius' room +DELETE FROM `areatrigger_scripts` WHERE `entry`=4113; +INSERT INTO `areatrigger_scripts` (`entry`,`ScriptName`) VALUES +(4113,"at_thaddius_entrance"); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 67aae20da..c5fddd3ca 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -3252,6 +3252,21 @@ void Map::SendZoneDynamicInfo(Player* player) } } +void Map::PlayDirectSoundToMap(uint32 soundId, uint32 zoneId) +{ + Map::PlayerList const& players = GetPlayers(); + if (!players.isEmpty()) + { + WorldPacket data(SMSG_PLAY_SOUND, 4); + data << uint32(soundId); + + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->GetSource()) + if (!zoneId || player->GetZoneId() == zoneId) + player->SendDirectMessage(&data); + } +} + void Map::SetZoneMusic(uint32 zoneId, uint32 musicId) { if (_zoneDynamicInfo.find(zoneId) == _zoneDynamicInfo.end()) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 72691a607..a090b7bfa 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -501,6 +501,7 @@ class Map : public GridRefManager void SendZoneDynamicInfo(Player* player); void SendInitSelf(Player* player); + void PlayDirectSoundToMap(uint32 soundId, uint32 zoneId = 0); void SetZoneMusic(uint32 zoneId, uint32 musicId); void SetZoneWeather(uint32 zoneId, uint32 weatherId, float weatherGrade); void SetZoneOverrideLight(uint32 zoneId, uint32 lightId, uint32 fadeInTime); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index 42d0b00ce..fc7d28bb4 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -11,6 +11,7 @@ enum Says SAY_AGGRO = 0, SAY_GREET = 1, SAY_SLAY = 2, + EMOTE_LOCUST = 3 }; enum Spells @@ -44,7 +45,7 @@ class boss_anubrekhan : public CreatureScript public: boss_anubrekhan() : CreatureScript("boss_anubrekhan") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_anubrekhanAI (pCreature); } @@ -71,7 +72,7 @@ public: } } - void Reset() + void Reset() override { BossAI::Reset(); events.Reset(); @@ -85,7 +86,7 @@ public: } } - void JustSummoned(Creature* cr) + void JustSummoned(Creature* cr) override { if (me->IsInCombat()) cr->SetInCombatWithZone(); @@ -99,15 +100,15 @@ public: summons.Summon(cr); } - void SummonedCreatureDies(Creature* cr, Unit*) + void SummonedCreatureDies(Creature* cr, Unit*) override { if (cr->GetEntry() == NPC_CRYPT_GUARD) - cr->CastSpell(cr, SPELL_SUMMON_CORPSE_SCRABS_10, true, NULL, NULL, me->GetGUID()); + cr->CastSpell(cr, SPELL_SUMMON_CORPSE_SCRABS_10, true, nullptr, nullptr, me->GetGUID()); } - void SummonedCreatureDespawn(Creature* cr) { summons.Despawn(cr); } + void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); summons.DespawnAll(); @@ -117,22 +118,21 @@ public: } } - void KilledUnit(Unit* victim) + void KilledUnit(Unit* victim) override { if (victim->GetTypeId() != TYPEID_PLAYER) return; - if (!urand(0,3)) - Talk(SAY_SLAY); + Talk(SAY_SLAY); //Force the player to spawn corpse scarabs via spell - victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCRABS_5, true, NULL, NULL, me->GetGUID()); + victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCRABS_5, true, nullptr, nullptr, me->GetGUID()); if (pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); me->CallForHelp(30.0f); // catch helpers @@ -151,7 +151,7 @@ public: SummonCryptGuards(); } - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit *who) override { if (!sayGreet && who->GetTypeId() == TYPEID_PLAYER) { @@ -162,7 +162,7 @@ public: ScriptedAI::MoveInLineOfSight(who); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; @@ -180,6 +180,7 @@ public: break; case EVENT_SPELL_LOCUST_SWARM: { + Talk(EMOTE_LOCUST); me->CastSpell(me, RAID_MODE(SPELL_LOCUST_SWARM_10, SPELL_LOCUST_SWARM_25), false); Position pos; me->GetNearPosition(pos, 10.0f, rand_norm() * 2 * M_PI); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp index 01ca9c1a6..4c5bee27b 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_faerlina.cpp @@ -9,10 +9,13 @@ enum Yells { - SAY_GREET = 0, - SAY_AGGRO = 1, - SAY_SLAY = 2, - SAY_DEATH = 3 + SAY_GREET = 0, + SAY_AGGRO = 1, + SAY_SLAY = 2, + SAY_DEATH = 3, + EMOTE_WIDOWS_EMBRACE = 4, + EMOTE_FRENZY = 5, + SAY_FRENZY = 6 }; enum Spells @@ -44,7 +47,7 @@ class boss_faerlina : public CreatureScript public: boss_faerlina() : CreatureScript("boss_faerlina") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_faerlinaAI (pCreature); } @@ -77,9 +80,9 @@ public: } } - void JustSummoned(Creature* cr) { summons.Summon(cr); } + void JustSummoned(Creature* cr) override { summons.Summon(cr); } - void Reset() + void Reset() override { BossAI::Reset(); events.Reset(); @@ -87,9 +90,10 @@ public: SummonHelpers(); } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); + me->CallForHelp(VISIBLE_RANGE); summons.DoZoneInCombat(); Talk(SAY_AGGRO); events.ScheduleEvent(EVENT_SPELL_POISON_BOLT, urand(12000,15000)); @@ -98,7 +102,7 @@ public: events.SetPhase(1); } - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit *who) override { if (!sayGreet && who->GetTypeId() == TYPEID_PLAYER) { @@ -109,7 +113,7 @@ public: ScriptedAI::MoveInLineOfSight(who); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER) return; @@ -121,13 +125,13 @@ public: pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); Talk(SAY_DEATH); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; @@ -149,30 +153,33 @@ public: events.RepeatEvent(12000); break; case EVENT_SPELL_FRENZY: - me->MonsterTextEmote("%s goes into a frenzy!", 0, true); - me->CastSpell(me, RAID_MODE(SPELL_FRENZY_10, SPELL_FRENZY_25), true); - events.RepeatEvent(70000); + if (!me->HasAura(RAID_MODE(SPELL_FRENZY_10, SPELL_FRENZY_25))) + { + Talk(SAY_FRENZY); + Talk(EMOTE_FRENZY); + me->CastSpell(me, RAID_MODE(SPELL_FRENZY_10, SPELL_FRENZY_25), true); + events.RepeatEvent(60000); + } + else + events.RepeatEvent(30000); break; } DoMeleeAttackIfReady(); } - void SpellHit(Unit* /*caster*/, const SpellInfo *spell) + void SpellHit(Unit* /*caster*/, const SpellInfo *spell) override { if (spell->Id == SPELL_WIDOWS_EMBRACE) { - me->MonsterTextEmote("%s is affected by Widow's Embrace!", 0, true); + Talk(EMOTE_WIDOWS_EMBRACE); if (me->HasAura(RAID_MODE(SPELL_FRENZY_10, SPELL_FRENZY_25))) { me->RemoveAurasDueToSpell(RAID_MODE(SPELL_FRENZY_10, SPELL_FRENZY_25)); - events.DelayEvents(60000, 1); + events.RescheduleEvent(EVENT_SPELL_FRENZY, 60000); } - else - events.DelayEvents(30000, 1); - if (pInstance) - pInstance->SetData(DATA_FRENZY_REMOVED, 0); + pInstance->SetData(DATA_FRENZY_REMOVED, 0); } } }; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp index 08a731a60..511d31cc9 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_four_horsemen.cpp @@ -116,7 +116,7 @@ class boss_four_horsemen : public CreatureScript public: boss_four_horsemen() : CreatureScript("boss_four_horsemen") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_four_horsemenAI (pCreature); } @@ -172,7 +172,7 @@ public: return true; } - void Reset() + void Reset() override { BossAI::Reset(); me->SetPosition(me->GetHomePosition()); @@ -194,7 +194,7 @@ public: } } - void MovementInform(uint32 type, uint32 id) + void MovementInform(uint32 type, uint32 id) override { if (type != POINT_MOTION_TYPE) return; @@ -223,7 +223,7 @@ public: currentWaypoint = id+1; } - void AttackStart(Unit* who) + void AttackStart(Unit* who) override { if (movementPhase == MOVE_PHASE_FINISHED) { @@ -234,19 +234,18 @@ public: } } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER) return; - if (!urand(0,4)) - Talk(SAY_SLAY); + Talk(SAY_SLAY); if (pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); if (pInstance) @@ -261,7 +260,7 @@ public: Talk(SAY_DEATH); } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); if (movementPhase == MOVE_PHASE_NONE) @@ -275,7 +274,7 @@ public: } } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (movementPhase == MOVE_PHASE_STARTED && currentWaypoint) { @@ -305,8 +304,7 @@ public: events.PopEvent(); return; case EVENT_SPELL_PRIMARY: - if (!urand(0,10)) - Talk(SAY_TAUNT); + Talk(SAY_TAUNT); me->CastSpell(me->GetVictim(), RAID_MODE(TABLE_SPELL_PRIMARY_10[horsemanId], TABLE_SPELL_PRIMARY_25[horsemanId]), false); events.RepeatEvent(15000); @@ -376,13 +374,13 @@ class spell_four_horsemen_mark : public SpellScriptLoader } } - void Register() + void Register() override { AfterEffectApply += AuraEffectApplyFn(spell_four_horsemen_mark_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); } }; - AuraScript* GetAuraScript() const + AuraScript* GetAuraScript() const override { return new spell_four_horsemen_mark_AuraScript(); } @@ -392,4 +390,4 @@ void AddSC_boss_four_horsemen() { new boss_four_horsemen(); new spell_four_horsemen_mark(); -} \ No newline at end of file +} diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp index 02f5238dc..15aa27607 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gluth.cpp @@ -35,6 +35,15 @@ enum Misc NPC_ZOMBIE_CHOW = 16360, }; +enum Emotes +{ + EMOTE_SPOTS_ONE = 0, + EMOTE_DECIMATE = 1, + EMOTE_ENRAGE = 2, + EMOTE_DEVOURS_ALL = 3, + EMOTE_BERSERK = 4 +}; + const Position zombiePos[3] = { {3267.9f, -3172.1f, 297.42f, 0.94f}, @@ -47,7 +56,7 @@ class boss_gluth : public CreatureScript public: boss_gluth() : CreatureScript("boss_gluth") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_gluthAI (pCreature); } @@ -64,28 +73,31 @@ public: InstanceScript* pInstance; uint64 gazeTarget; - void Reset() + void Reset() override { BossAI::Reset(); - me->ApplySpellImmune(29306, IMMUNITY_ID, 29306, true); + me->ApplySpellImmune(SPELL_INFECTED_WOUND, IMMUNITY_ID, SPELL_INFECTED_WOUND, true); events.Reset(); summons.DespawnAll(); gazeTarget = 0; me->SetReactState(REACT_AGGRESSIVE); } - void MoveInLineOfSight(Unit *who) + void MoveInLineOfSight(Unit *who) override { - if ((!me->GetVictim() || me->GetVictim()->GetEntry() != NPC_ZOMBIE_CHOW) && who->GetEntry() == NPC_ZOMBIE_CHOW && me->IsWithinDistInMap(who, 6.5f)) + if (!me->GetVictim() || me->GetVictim()->GetEntry() != NPC_ZOMBIE_CHOW) { - SetGazeOn(who); - me->MonsterTextEmote("%s spots a nearby zombie to devour!", 0, false); + if (who->GetEntry() == NPC_ZOMBIE_CHOW && me->IsWithinDistInMap(who, 6.5f)) + { + SetGazeOn(who); + Talk(EMOTE_SPOTS_ONE); + } + else + ScriptedAI::MoveInLineOfSight(who); } - else - ScriptedAI::MoveInLineOfSight(who); } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); me->SetInCombatWithZone(); @@ -97,7 +109,7 @@ public: events.ScheduleEvent(EVENT_CAN_EAT_ZOMBIE, 1000); } - void JustSummoned(Creature *summon) + void JustSummoned(Creature *summon) override { if (summon->GetEntry() == NPC_ZOMBIE_CHOW) summon->AI()->AttackStart(me); @@ -105,9 +117,9 @@ public: summons.Summon(summon); } - void SummonedCreatureDies(Creature* cr, Unit*) { summons.Despawn(cr); } + void SummonedCreatureDies(Creature* cr, Unit*) override { summons.Despawn(cr); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (me->IsAlive() && who->GetEntry() == NPC_ZOMBIE_CHOW) me->ModifyHealth(int32(me->GetMaxHealth()*0.05f)); @@ -116,7 +128,7 @@ public: pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); summons.DespawnAll(); @@ -143,7 +155,7 @@ public: return false; } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!UpdateVictimWithGaze() && !SelectPlayerInRoom()) return; @@ -159,7 +171,7 @@ public: events.PopEvent(); break; case EVENT_SPELL_ENRAGE: - me->MonsterTextEmote("Gluth becomes enraged!", 0, true); + Talk(EMOTE_ENRAGE); me->CastSpell(me, RAID_MODE(SPELL_ENRAGE_10, SPELL_ENRAGE_25), true); events.RepeatEvent(30000); break; @@ -168,7 +180,7 @@ public: events.RepeatEvent(10000); break; case EVENT_SPELL_DECIMATE: - me->MonsterTextEmote("Gluth decimates all nearby flesh!", 0, true); + Talk(EMOTE_DECIMATE); me->CastSpell(me, RAID_MODE(SPELL_DECIMATE_10, SPELL_DECIMATE_25), false); events.RepeatEvent(105000); break; @@ -195,7 +207,7 @@ public: if (me->GetVictim()->GetEntry() == NPC_ZOMBIE_CHOW && me->IsWithinMeleeRange(me->GetVictim())) { me->CastCustomSpell(SPELL_CHOW_SEARCHER, SPELLVALUE_RADIUS_MOD, 20000, me, true); - me->MonsterTextEmote("%s devour all nearby zombies!", 0, false); + Talk(EMOTE_DEVOURS_ALL); return; // leave it to skip DoMeleeAttackIfReady } break; @@ -236,13 +248,13 @@ class spell_gluth_decimate : public SpellScriptLoader } } - void Register() + void Register() override { OnEffectHitTarget += SpellEffectFn(spell_gluth_decimate_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; - SpellScript* GetSpellScript() const + SpellScript* GetSpellScript() const override { return new spell_gluth_decimate_SpellScript(); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp index b323e76c9..139b69935 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_gothik.cpp @@ -11,10 +11,16 @@ enum Yells { - SAY_SPEECH = 0, - SAY_KILL = 1, - SAY_DEATH = 2, - SAY_TELEPORT = 3 + SAY_INTRO_1 = 0, + SAY_INTRO_2 = 1, + SAY_INTRO_3 = 2, + SAY_INTRO_4 = 3, + SAY_PHASE_TWO = 4, + SAY_DEATH = 5, + SAY_KILL = 6, + + EMOTE_PHASE_TWO = 7, + EMOTE_GATE_OPENED = 8 }; enum Spells @@ -94,7 +100,11 @@ enum Events EVENT_SPELL_UNHOLY_FRENZY = 19, // HORSE - EVENT_SPELL_STOMP = 20 + EVENT_SPELL_STOMP = 20, + + EVENT_INTRO_2 = 21, + EVENT_INTRO_3 = 22, + EVENT_INTRO_4 = 23, }; const uint32 gothikWaves[24][2] = @@ -172,7 +182,7 @@ class boss_gothik : public CreatureScript public: boss_gothik() : CreatureScript("boss_gothik") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_gothikAI (pCreature); } @@ -202,7 +212,7 @@ public: return true; } - void Reset() + void Reset() override { BossAI::Reset(); events.Reset(); @@ -224,11 +234,14 @@ public: } } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); me->SetInCombatWithZone(); - Talk(SAY_SPEECH); + Talk(SAY_INTRO_1); + events.ScheduleEvent(EVENT_INTRO_2, 4000); + events.ScheduleEvent(EVENT_INTRO_3, 9000); + events.ScheduleEvent(EVENT_INTRO_4, 14000); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_DISABLE_MOVE); me->NearTeleportTo(PosPlatform.GetPositionX(), PosPlatform.GetPositionY(), PosPlatform.GetPositionZ(), PosPlatform.GetOrientation()); @@ -244,7 +257,7 @@ public: } } - void JustSummoned(Creature *summon) + void JustSummoned(Creature *summon) override { if (gateOpened) summon->AI()->DoAction(ACTION_GATE_OPEN); @@ -253,21 +266,20 @@ public: summon->SetInCombatWithZone(); } - void SummonedCreatureDespawn(Creature* cr) { summons.Despawn(cr); } + void SummonedCreatureDespawn(Creature* cr) override { summons.Despawn(cr); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER) return; - if (!urand(0,3)) - Talk(SAY_KILL); + Talk(SAY_KILL); if (pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); Talk(SAY_DEATH); @@ -335,7 +347,7 @@ public: return false; } - void SpellHit(Unit * /*caster*/, const SpellInfo* spellInfo) + void SpellHit(Unit * /*caster*/, const SpellInfo* spellInfo) override { uint8 pos = urand(0,4); switch (spellInfo->Id) @@ -355,13 +367,13 @@ public: me->HandleEmoteCommand(EMOTE_ONESHOT_SPELL_CAST); } - void DamageTaken(Unit*, uint32 &damage, DamageEffectType, SpellSchoolMask) + void DamageTaken(Unit*, uint32 &damage, DamageEffectType, SpellSchoolMask) override { if (!secondPhase) damage = 0; } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!IsInRoom()) return; @@ -375,6 +387,18 @@ public: switch (events.GetEvent()) { + case EVENT_INTRO_2: + Talk(SAY_INTRO_2); + events.PopEvent(); + break; + case EVENT_INTRO_3: + Talk(SAY_INTRO_3); + events.PopEvent(); + break; + case EVENT_INTRO_4: + Talk(SAY_INTRO_4); + events.PopEvent(); + break; case EVENT_SPELL_SHADOW_BOLT: me->CastSpell(me->GetVictim(), RAID_MODE(SPELL_SHADOW_BOLT_10, SPELL_SHADOW_BOLT_25), false); events.RepeatEvent(2000); @@ -419,7 +443,8 @@ public: else { secondPhase = true; - Talk(SAY_TELEPORT); + Talk(SAY_PHASE_TWO); + Talk(EMOTE_PHASE_TWO); me->NearTeleportTo(PosGroundLivingSide.GetPositionX(), PosGroundLivingSide.GetPositionY(), PosGroundLivingSide.GetPositionZ(), PosGroundLivingSide.GetOrientation()); me->SetReactState(REACT_AGGRESSIVE); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE|UNIT_FLAG_IMMUNE_TO_PC|UNIT_FLAG_DISABLE_MOVE); @@ -444,6 +469,7 @@ public: summons.DoAction(ACTION_GATE_OPEN); summons.DoZoneInCombat(); gateOpened = true; + Talk(EMOTE_GATE_OPENED); } events.PopEvent(); break; @@ -459,7 +485,7 @@ class npc_boss_gothik_minion : public CreatureScript public: npc_boss_gothik_minion() : CreatureScript("npc_boss_gothik_minion") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new npc_boss_gothik_minionAI (pCreature); } @@ -477,10 +503,10 @@ public: bool gateOpened; bool IsOnSameSide(Unit const* who) const { return livingSide == IN_LIVE_SIDE(who); } - bool CanAIAttack(Unit const* target) const { return gateOpened || IsOnSameSide(target); } + bool CanAIAttack(Unit const* target) const override { return gateOpened || IsOnSameSide(target); } - void Reset() { events.Reset(); } - void EnterCombat(Unit* /*who*/) + void Reset() override { events.Reset(); } + void EnterCombat(Unit* /*who*/) override { me->SetInCombatWithZone(); @@ -516,19 +542,19 @@ public: break; } } - void DamageTaken(Unit* attacker, uint32 &damage, DamageEffectType, SpellSchoolMask) + void DamageTaken(Unit* attacker, uint32 &damage, DamageEffectType, SpellSchoolMask) override { if (!attacker || (!gateOpened && !IsOnSameSide(attacker))) damage = 0; } - void DoAction(int32 param) + void DoAction(int32 param) override { if (param == ACTION_GATE_OPEN) gateOpened = true; } - void JustDied(Unit *) + void JustDied(Unit *) override { switch (me->GetEntry()) { @@ -544,13 +570,13 @@ public: } } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER && me->GetInstanceScript()) me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { events.Update(diff); @@ -650,13 +676,13 @@ class spell_gothik_shadow_bolt_volley : public SpellScriptLoader targets.remove_if(Trinity::UnitAuraCheck(false, SPELL_SHADOW_MARK)); } - void Register() + void Register() override { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gothik_shadow_bolt_volley_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); } }; - SpellScript* GetSpellScript() const + SpellScript* GetSpellScript() const override { return new spell_gothik_shadow_bolt_volley_SpellScript(); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp index 59a08e519..af76b809e 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_grobbulus.cpp @@ -21,6 +21,11 @@ enum Spells SPELL_BOMBARD_SLIME = 28280, // Spawn slime when hit by slime spray }; +enum Emotes +{ + EMOTE_SLIME = 0 +}; + enum Events { EVENT_SPELL_BERSERK = 1, @@ -33,6 +38,7 @@ enum Misc { NPC_FALLOUT_SLIME = 16290, NPC_SEWAGE_SLIME = 16375, + NPC_STICHED_GIANT = 16025 }; class boss_grobbulus : public CreatureScript @@ -40,7 +46,7 @@ class boss_grobbulus : public CreatureScript public: boss_grobbulus() : CreatureScript("boss_grobbulus") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_grobbulusAI (pCreature); } @@ -57,7 +63,7 @@ public: InstanceScript* pInstance; uint32 dropSludgeTimer; - void Reset() + void Reset() override { BossAI::Reset(); events.Reset(); @@ -65,9 +71,21 @@ public: dropSludgeTimer = 0; } - void EnterCombat(Unit * who) + void PullChamberAdds() + { + std::list StichedGiants; + me->GetCreaturesWithEntryInRange(StichedGiants, 300.0f, NPC_STICHED_GIANT); + for (std::list::const_iterator itr = StichedGiants.begin(); itr != StichedGiants.end(); ++itr) + { + if ((*itr)->GetGUID()) + (*itr)->ToCreature()->AI()->AttackStart(me->GetVictim()); + } + } + + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); + PullChamberAdds(); me->SetInCombatWithZone(); events.ScheduleEvent(EVENT_SPELL_POISON_CLOUD, 15000); events.ScheduleEvent(EVENT_SPELL_MUTATING_INJECTION, 20000); @@ -75,13 +93,13 @@ public: events.ScheduleEvent(EVENT_SPELL_BERSERK, RAID_MODE(12*MINUTE*IN_MILLISECONDS, 9*MINUTE*IN_MILLISECONDS)); } - void SpellHitTarget(Unit *target, const SpellInfo* spellInfo) + void SpellHitTarget(Unit *target, const SpellInfo* spellInfo) override { if (spellInfo->Id == RAID_MODE(SPELL_SLIME_SPRAY_10, SPELL_SLIME_SPRAY_25) && target->GetTypeId() == TYPEID_PLAYER) me->SummonCreature(NPC_FALLOUT_SLIME, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()); } - void JustSummoned(Creature* cr) + void JustSummoned(Creature* cr) override { if (cr->GetEntry() == NPC_FALLOUT_SLIME) cr->SetInCombatWithZone(); @@ -89,21 +107,21 @@ public: summons.Summon(cr); } - void SummonedCreatureDespawn(Creature* summon){ summons.Despawn(summon); } + void SummonedCreatureDespawn(Creature* summon) override { summons.Despawn(summon); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); summons.DespawnAll(); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER && pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { // Some nice visuals dropSludgeTimer += diff; @@ -133,7 +151,7 @@ public: events.PopEvent(); break; case EVENT_SPELL_SLIME_SPRAY: - me->MonsterTextEmote("Grobbulus sprays slime across the room!", 0, true); + Talk(EMOTE_SLIME); me->CastSpell(me->GetVictim(), RAID_MODE(SPELL_SLIME_SPRAY_10, SPELL_SLIME_SPRAY_25), false); events.RepeatEvent(20000); break; @@ -155,7 +173,7 @@ class boss_grobbulus_poison_cloud : public CreatureScript public: boss_grobbulus_poison_cloud() : CreatureScript("boss_grobbulus_poison_cloud") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_grobbulus_poison_cloudAI(pCreature); } @@ -169,7 +187,7 @@ public: uint32 sizeTimer; uint32 auraVisualTimer; - void Reset() + void Reset() override { sizeTimer = 0; auraVisualTimer = 1; @@ -177,13 +195,13 @@ public: me->setFaction(21); // Grobbulus one } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER && me->GetInstanceScript()) me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { // this has to be delayed to be visible :/ if (auraVisualTimer) @@ -225,13 +243,13 @@ class spell_grobbulus_poison : public SpellScriptLoader targets.push_back(*itr); } - void Register() + void Register() override { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_grobbulus_poison_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); } }; - SpellScript* GetSpellScript() const + SpellScript* GetSpellScript() const override { return new spell_grobbulus_poison_SpellScript(); } @@ -242,4 +260,4 @@ void AddSC_boss_grobbulus() new boss_grobbulus(); new boss_grobbulus_poison_cloud(); new spell_grobbulus_poison(); -} \ No newline at end of file +} diff --git a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp index 98f415382..b4d390b86 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_heigan.cpp @@ -12,7 +12,10 @@ enum Says SAY_AGGRO = 0, SAY_SLAY = 1, SAY_TAUNT = 2, - SAY_DEATH = 3 + SAY_DEATH = 3, + EMOTE_DANCE = 4, + EMOTE_DANCE_END = 5, + SAY_DANCE = 6 }; enum Spells @@ -43,7 +46,7 @@ class boss_heigan : public CreatureScript public: boss_heigan() : CreatureScript("boss_heigan") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_heiganAI (pCreature); } @@ -61,7 +64,7 @@ public: uint8 currentSection; bool moveRight; - void Reset() + void Reset() override { BossAI::Reset(); events.Reset(); @@ -76,25 +79,24 @@ public: } } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER) return; - if (!urand(0,3)) - Talk(SAY_SLAY); + Talk(SAY_SLAY); if (pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); Talk(SAY_DEATH); } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); me->SetInCombatWithZone(); @@ -122,7 +124,8 @@ public: } else // if (phase == PHASE_FAST_DANCE) { - me->MonsterTextEmote("%s teleports and begins to channel a spell!", 0, true); + Talk(EMOTE_DANCE); + Talk(SAY_DANCE); // teleport float x, y, z, o; me->GetHomePosition(x, y, z, o); @@ -147,7 +150,7 @@ public: return true; } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!IsInRoom(me)) return; @@ -170,7 +173,15 @@ public: events.RepeatEvent(20000); break; case EVENT_SWITCH_PHASE: - StartFightPhase(currentPhase == PHASE_SLOW_DANCE ? PHASE_FAST_DANCE : PHASE_SLOW_DANCE); + if (currentPhase == PHASE_SLOW_DANCE) + { + StartFightPhase(PHASE_FAST_DANCE); + } + else + { + StartFightPhase(PHASE_SLOW_DANCE); + Talk(EMOTE_DANCE_END); // we put this here to avoid play the emote on aggro. + } // no pop, there is reset in start fight break; case EVENT_ERUPT_SECTION: @@ -185,7 +196,7 @@ public: moveRight ? currentSection++ : currentSection--; } - if (currentPhase == PHASE_SLOW_DANCE && !urand(0,3)) + if (currentPhase == PHASE_SLOW_DANCE) Talk(SAY_TAUNT); events.RepeatEvent(currentPhase == PHASE_SLOW_DANCE ? 10000 : 4000); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp index 84a889f70..14d8db926 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_kelthuzad.cpp @@ -1,4 +1,4 @@ -/* +/* * Originally written by Xinef - Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 */ @@ -17,9 +17,12 @@ enum Yells SAY_CHAIN = 10, SAY_FROST_BLAST = 11, SAY_REQUEST_AID = 12, //start of phase 3 - SAY_ANSWER_REQUEST = 13, //lich king answer + SAY_ANSWER_REQUEST = 3, //lich king answer SAY_SUMMON_MINIONS = 14, //start of phase 1 - SAY_SPECIAL = 15 + SAY_SPECIAL = 15, + + EMOTE_GUARDIAN_FLEE = 0, + EMOTE_GUARDIAN_APPEAR = 1 }; enum Spells @@ -110,7 +113,7 @@ class boss_kelthuzad : public CreatureScript public: boss_kelthuzad() : CreatureScript("boss_kelthuzad") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_kelthuzadAI (pCreature); } @@ -162,7 +165,7 @@ public: } } - void Reset() + void Reset() override { BossAI::Reset(); events.Reset(); @@ -185,27 +188,30 @@ public: } - void EnterEvadeMode() + void EnterEvadeMode() override { me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE|UNIT_FLAG_DISABLE_MOVE); ScriptedAI::EnterEvadeMode(); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER) return; - if (!urand(0,3)) - Talk(SAY_SLAY); + Talk(SAY_SLAY); if (pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); + if (Creature* guardian = summons.GetCreatureWithEntry(NPC_GUARDIAN_OF_ICECROWN)) + { + guardian->AI()->Talk(EMOTE_GUARDIAN_FLEE); + } summons.DespawnAll(); Talk(SAY_DEATH); @@ -216,13 +222,13 @@ public: } } - void MoveInLineOfSight(Unit* who) + void MoveInLineOfSight(Unit* who) override { if (!me->IsInCombat() && who->GetTypeId() == TYPEID_PLAYER && who->IsAlive() && me->GetDistance(who) <= 50.0f) AttackStart(who); } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); Talk(SAY_SUMMON_MINIONS); @@ -250,9 +256,9 @@ public: go->SetGoState(GO_STATE_READY); } - void JustSummoned(Creature* cr) { summons.Summon(cr); } + void JustSummoned(Creature* cr) override { summons.Summon(cr); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; @@ -345,8 +351,7 @@ public: if (Unit *target = SelectTarget(SELECT_TARGET_RANDOM, RAID_MODE(1,0), 0, true)) me->CastSpell(target, SPELL_FROST_BLAST, false); - if (!urand(0,2)) - Talk(SAY_FROST_BLAST); + Talk(SAY_FROST_BLAST); events.RepeatEvent(45000); break; case EVENT_SPELL_CHAINS: @@ -354,8 +359,7 @@ public: if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 200, true, -SPELL_CHAINS_OF_KELTHUZAD)) me->CastSpell(target, SPELL_CHAINS_OF_KELTHUZAD, true); - if (!urand(0,2)) - Talk(SAY_CHAIN); + Talk(SAY_CHAIN); events.RepeatEvent(50000); break; case EVENT_SPELL_DETONATE_MANA: @@ -375,8 +379,7 @@ public: std::vector::iterator itr = unitList.begin(); advance(itr, urand(0, unitList.size()-1)); me->CastSpell(*itr, SPELL_DETONATE_MANA, false); - if (!urand(0,2)) - Talk(SAY_SPECIAL); + Talk(SAY_SPECIAL); } events.RepeatEvent(30000); @@ -403,9 +406,11 @@ public: events.PopEvent(); break; case EVENT_SUMMON_GUARDIAN_OF_ICECROWN: - me->MonsterTextEmote("A Guardian of Icecrown enter the fight!", 0, true); if (Creature* cr = me->SummonCreature(NPC_GUARDIAN_OF_ICECROWN, SummonPositions[RAND(0, 1, 3, 4)])) + { + cr->AI()->Talk(EMOTE_GUARDIAN_APPEAR); cr->AI()->AttackStart(me->GetVictim()); + } events.PopEvent(); break; @@ -422,7 +427,7 @@ class boss_kelthuzad_minion : public CreatureScript public: boss_kelthuzad_minion() : CreatureScript("boss_kelthuzad_minion") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_kelthuzad_minionAI (pCreature); } @@ -436,14 +441,14 @@ public: EventMap events; bool callHelp; - void Reset() + void Reset() override { me->SetNoCallAssistance(true); callHelp = true; events.Reset(); } - void DoAction(int32 param) + void DoAction(int32 param) override { if (param == ACTION_CALL_HELP_ON) callHelp = true; @@ -456,7 +461,7 @@ public: } } - void MoveInLineOfSight(Unit* who) + void MoveInLineOfSight(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER && !who->IsPet()) return; @@ -464,13 +469,13 @@ public: ScriptedAI::MoveInLineOfSight(who); } - void JustDied(Unit* ) + void JustDied(Unit* ) override { if (me->GetEntry() == NPC_UNSTOPPABLE_ABOMINATION && me->GetInstanceScript()) me->GetInstanceScript()->SetData(DATA_ABOMINATION_KILLED, 0); } - void AttackStart(Unit* who) + void AttackStart(Unit* who) override { ScriptedAI::AttackStart(who); if (callHelp) @@ -491,7 +496,7 @@ public: me->AddThreat(who, 1000000.0f); } - void EnterCombat(Unit* /*who*/) + void EnterCombat(Unit* /*who*/) override { me->SetInCombatWithZone(); if (me->GetEntry() == NPC_UNSTOPPABLE_ABOMINATION) @@ -503,13 +508,13 @@ public: events.ScheduleEvent(EVENT_MINION_SPELL_BLOOD_TAP, 15000); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER && me->GetInstanceScript()) me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; @@ -569,13 +574,13 @@ class spell_kelthuzad_frost_blast : public SpellScriptLoader targets.push_back(*itr); } - void Register() + void Register() override { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_kelthuzad_frost_blast_SpellScript::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY); } }; - SpellScript* GetSpellScript() const + SpellScript* GetSpellScript() const override { return new spell_kelthuzad_frost_blast_SpellScript(); } @@ -590,7 +595,7 @@ class spell_kelthuzad_detonate_mana : public SpellScriptLoader { PrepareAuraScript(spell_kelthuzad_detonate_mana_AuraScript); - bool Validate(SpellInfo const* /*spell*/) + bool Validate(SpellInfo const* /*spell*/) override { if (!sSpellMgr->GetSpellInfo(SPELL_MANA_DETONATION_DAMAGE)) return false; @@ -605,17 +610,17 @@ class spell_kelthuzad_detonate_mana : public SpellScriptLoader if (int32 mana = int32(target->GetMaxPower(POWER_MANA) / 10)) { mana = target->ModifyPower(POWER_MANA, -mana); - target->CastCustomSpell(SPELL_MANA_DETONATION_DAMAGE, SPELLVALUE_BASE_POINT0, -mana * 10, target, true, NULL, aurEff); + target->CastCustomSpell(SPELL_MANA_DETONATION_DAMAGE, SPELLVALUE_BASE_POINT0, -mana * 10, target, true, nullptr, aurEff); } } - void Register() + void Register() override { OnEffectPeriodic += AuraEffectPeriodicFn(spell_kelthuzad_detonate_mana_AuraScript::HandleScript, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); } }; - AuraScript* GetAuraScript() const + AuraScript* GetAuraScript() const override { return new spell_kelthuzad_detonate_mana_AuraScript(); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp index 12a05d27c..d00fdbf17 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_loatheb.cpp @@ -23,6 +23,7 @@ enum Events EVENT_SPELL_DEATHBLOOM = 2, EVENT_SPELL_INEVITABLE_DOOM = 3, EVENT_SPELL_BERSERK = 4, + EVENT_SUMMON_SPORE = 5, }; enum Texts @@ -37,65 +38,81 @@ class boss_loatheb : public CreatureScript public: boss_loatheb() : CreatureScript("boss_loatheb") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_loathebAI (pCreature); } struct boss_loathebAI : public BossAI { - boss_loathebAI(Creature *c) : BossAI(c, BOSS_LOATHEB) + boss_loathebAI(Creature *c) : BossAI(c, BOSS_LOATHEB), summons(me) { pInstance = me->GetInstanceScript(); + me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); } InstanceScript* pInstance; EventMap events; + SummonList summons; - void Reset() + void Reset() override { BossAI::Reset(); events.Reset(); + summons.DespawnAll(); if (pInstance) { + pInstance->SetData(BOSS_LOATHEB, NOT_STARTED); if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_LOATHEB_GATE))) go->SetGoState(GO_STATE_ACTIVE); } } - void JustSummoned(Creature* cr) { cr->SetInCombatWithZone(); } + void JustSummoned(Creature* cr) override + { + cr->SetInCombatWithZone(); + summons.Summon(cr); + } - void SummonedCreatureDies(Creature* /*cr*/, Unit*) + void SummonedCreatureDies(Creature* /*cr*/, Unit*) override { if (pInstance) pInstance->SetData(DATA_SPORE_KILLED, 0); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER && pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); if (pInstance) { + pInstance->SetData(BOSS_LOATHEB, IN_PROGRESS); if (GameObject* go = me->GetMap()->GetGameObject(pInstance->GetData64(DATA_LOATHEB_GATE))) go->SetGoState(GO_STATE_READY); } me->SetInCombatWithZone(); - events.ScheduleEvent(EVENT_SPELL_NECROTIC_AURA, 0); - events.ScheduleEvent(EVENT_SPELL_DEATHBLOOM, 25000); - events.ScheduleEvent(EVENT_SPELL_INEVITABLE_DOOM, 120000); + events.ScheduleEvent(EVENT_SPELL_NECROTIC_AURA, 10000); + events.ScheduleEvent(EVENT_SPELL_DEATHBLOOM, 6000); + events.ScheduleEvent(EVENT_SUMMON_SPORE, 12000); events.ScheduleEvent(EVENT_SPELL_BERSERK, 720000); } - void UpdateAI(uint32 diff) + void JustDied(Unit* /*killer*/) override { - if (!UpdateVictim()) + if (pInstance) + pInstance->SetData(BOSS_LOATHEB, DONE); + summons.DespawnAll(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() || !IsInRoom()) return; events.Update(diff); @@ -104,12 +121,15 @@ public: switch (events.GetEvent()) { + case EVENT_SUMMON_SPORE: + me->CastSpell(me, SPELL_SUMMON_SPORE, true); + events.RepeatEvent(35000); + break; case EVENT_SPELL_NECROTIC_AURA: me->CastSpell(me, SPELL_NECROTIC_AURA, true); events.RepeatEvent(20000); break; case EVENT_SPELL_DEATHBLOOM: - me->CastSpell(me, SPELL_SUMMON_SPORE, true); me->CastSpell(me, RAID_MODE(SPELL_DEATHBLOOM_10, SPELL_DEATHBLOOM_25), false); events.RepeatEvent(30000); break; @@ -125,6 +145,19 @@ public: DoMeleeAttackIfReady(); } + + bool IsInRoom() + { + // Calculate the distance between his home position to the gate + if (me->GetExactDist(me->GetHomePosition().GetPositionX(), + me->GetHomePosition().GetPositionY(), + me->GetHomePosition().GetPositionZ()) > 50.0f) + { + EnterEvadeMode(); + return false; + } + return true; + } }; }; @@ -151,14 +184,14 @@ class spell_loatheb_necrotic_aura_warning : public SpellScriptLoader target->AI()->Talk(SAY_NECROTIC_AURA_REMOVED); } - void Register() + 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 + AuraScript* GetAuraScript() const override { return new spell_loatheb_necrotic_aura_warning_AuraScript(); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp index 255ccad1a..4acd0b139 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_maexxna.cpp @@ -1,4 +1,4 @@ -/* +/* * Originally written by Xinef - Copyright (C) 2016+ AzerothCore , released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3 */ @@ -30,6 +30,13 @@ enum Events EVENT_SUMMON_SPIDERLINGS = 6, }; +enum Emotes +{ + EMOTE_SPIDERS = 0, + EMOTE_WEB_WRAP = 1, + EMOTE_WEB_SPRAY = 2 +}; + enum Misc { NPC_WEB_WRAP = 16486, @@ -48,7 +55,7 @@ class boss_maexxna : public CreatureScript public: boss_maexxna() : CreatureScript("boss_maexxna") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_maexxnaAI (pCreature); } @@ -75,7 +82,7 @@ public: return true; } - void Reset() + void Reset() override { BossAI::Reset(); events.Reset(); @@ -89,7 +96,7 @@ public: } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); me->SetInCombatWithZone(); @@ -107,7 +114,7 @@ public: } } - void JustSummoned(Creature* cr) + void JustSummoned(Creature* cr) override { if (cr->GetEntry() == NPC_MAEXXNA_SPIDERLING) { @@ -119,13 +126,13 @@ public: summons.Summon(cr); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER && pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!IsInRoom()) return; @@ -140,7 +147,7 @@ public: switch (events.GetEvent()) { case EVENT_SPELL_WEB_SPRAY: - me->MonsterTextEmote("%s sprays strands of web everywhere!", 0, true); + Talk(EMOTE_WEB_SPRAY); me->CastSpell(me, RAID_MODE(SPELL_WEB_SPRAY_10, SPELL_WEB_SPRAY_25), true); events.RepeatEvent(40000); break; @@ -153,7 +160,7 @@ public: events.RepeatEvent(30000); break; case EVENT_SUMMON_SPIDERLINGS: - me->MonsterTextEmote("Spiderlings appear on the web!", 0, true); + Talk(EMOTE_SPIDERS); for (uint8 i = 0; i < 8; ++i) me->SummonCreature(NPC_MAEXXNA_SPIDERLING, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); events.RepeatEvent(40000); @@ -169,7 +176,7 @@ public: events.RepeatEvent(1000); break; case EVENT_WEB_WRAP: - me->MonsterTextEmote("%s spins her web into a cocoon!", 0, true); + Talk(EMOTE_WEB_WRAP); for (uint8 i = 0; i < RAID_MODE(1,2); ++i) if (Unit *target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0, true, -SPELL_WEB_WRAP)) { @@ -197,7 +204,7 @@ class boss_maexxna_webwrap : public CreatureScript public: boss_maexxna_webwrap() : CreatureScript("boss_maexxna_webwrap") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_maexxna_webwrapAI (pCreature); } @@ -207,15 +214,15 @@ public: boss_maexxna_webwrapAI(Creature *c) : NullCreatureAI(c), victimGUID(0) {} uint64 victimGUID; - void SetGUID(uint64 guid, int32 /*param*/) + void SetGUID(uint64 guid, int32 /*param*/) override { victimGUID = guid; if (me->m_spells[0] && victimGUID) if (Unit *victim = ObjectAccessor::GetUnit(*me, victimGUID)) - victim->CastSpell(victim, me->m_spells[0], true, NULL, NULL, me->GetGUID()); + victim->CastSpell(victim, me->m_spells[0], true, nullptr, nullptr, me->GetGUID()); } - void JustDied(Unit * /*killer*/) + void JustDied(Unit * /*killer*/) override { if (me->m_spells[0] && victimGUID) if (Unit *victim = ObjectAccessor::GetUnit(*me, victimGUID)) diff --git a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp index 5a4fd4876..3b905e2fb 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_noth.cpp @@ -11,7 +11,12 @@ enum Says SAY_AGGRO = 0, SAY_SUMMON = 1, SAY_SLAY = 2, - SAY_DEATH = 3 + SAY_DEATH = 3, + EMOTE_SUMMON = 4, + EMOTE_SUMMON_WAVE = 5, + EMOTE_TELEPORT_BALCONY = 6, + EMOTE_TELEPORT_BACK = 7, + EMOTE_BLINK = 8 }; enum Spells @@ -61,7 +66,7 @@ class boss_noth : public CreatureScript public: boss_noth() : CreatureScript("boss_noth") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_nothAI (pCreature); } @@ -121,7 +126,7 @@ public: return true; } - void Reset() + void Reset() override { BossAI::Reset(); events.Reset(); @@ -131,44 +136,43 @@ public: events.SetPhase(0); } - void EnterEvadeMode() + void EnterEvadeMode() override { me->SetControlled(false, UNIT_STATE_ROOT); ScriptedAI::EnterEvadeMode(); } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); Talk(SAY_AGGRO); StartGroundPhase(); } - void JustSummoned(Creature *summon) + void JustSummoned(Creature *summon) override { summons.Summon(summon); summon->SetInCombatWithZone(); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); Talk(SAY_DEATH); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER) return; - if (!urand(0,3)) - Talk(SAY_SLAY); + Talk(SAY_SLAY); if (pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!IsInRoom()) return; @@ -189,8 +193,8 @@ public: events.RepeatEvent(25000); break; case EVENT_SUMMON_PLAGUED_WARRIOR_ANNOUNCE: - me->MonsterTextEmote("Noth the Plaguebringer summons forth Skeletal Warriors!", 0, true); Talk(SAY_SUMMON); + Talk(EMOTE_SUMMON); events.RepeatEvent(25000); events.ScheduleEvent(EVENT_SUMMON_PLAGUED_WARRIOR_REAL, 4000); break; @@ -200,21 +204,21 @@ public: events.PopEvent(); break; case EVENT_MOVE_TO_BALCONY: - me->MonsterTextEmote("%s teleports to the balcony above!", 0, true); + Talk(EMOTE_TELEPORT_BALCONY); me->CastSpell(me, SPELL_TELEPORT, true); StartBalconyPhase(); //events.PopEvent(); events.Reset()!! break; case EVENT_SPELL_BLINK: DoResetThreat(); - me->MonsterTextEmote("%s blinks away!", 0, true); me->CastSpell(me, RAID_MODE(SPELL_CRIPPLE_10, SPELL_CRIPPLE_25), false); me->CastSpell(me, SPELL_BLINK, true); + Talk(EMOTE_BLINK); events.RepeatEvent(30000); break; // BALCONY case EVENT_BALCONY_SUMMON_ANNOUNCE: - me->MonsterTextEmote("%s raises more skeletons!", 0, true); + Talk(EMOTE_SUMMON_WAVE); events.RepeatEvent(25000); events.ScheduleEvent(EVENT_BALCONY_SUMMON_REAL, 4000); break; @@ -232,7 +236,7 @@ public: events.PopEvent(); break; case EVENT_MOVE_TO_GROUND: - me->MonsterTextEmote("%s teleports back into the battle!", 0, true); + Talk(EMOTE_TELEPORT_BACK); StartGroundPhase(); me->NearTeleportTo(nothPosition.GetPositionX(), nothPosition.GetPositionY(), nothPosition.GetPositionZ(), nothPosition.GetOrientation(), true); break; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp index 624193be8..4ffc175dc 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_patchwerk.cpp @@ -42,7 +42,7 @@ class boss_patchwerk : public CreatureScript public: boss_patchwerk() : CreatureScript("boss_patchwerk") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_patchwerkAI (pCreature); } @@ -57,13 +57,13 @@ public: EventMap events; InstanceScript* pInstance; - void Reset() + void Reset() override { BossAI::Reset(); events.Reset(); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER) return; @@ -75,13 +75,13 @@ public: pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); Talk(SAY_DEATH); } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); Talk(SAY_AGGRO); @@ -97,7 +97,7 @@ public: } } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; @@ -113,7 +113,7 @@ public: //Cast Hateful strike on the player with the highest //amount of HP within melee distance, and second threat amount std::list meleeRangeTargets; - Unit* finalTarget = NULL; + Unit* finalTarget = nullptr; uint8 counter = 0; ThreatContainer::StorageType::const_iterator i = me->getThreatManager().getThreatList().begin(); @@ -183,4 +183,4 @@ public: void AddSC_boss_patchwerk() { new boss_patchwerk(); -} \ No newline at end of file +} diff --git a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp index 29763725f..473a63db9 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_razuvious.cpp @@ -6,18 +6,13 @@ #include "ScriptedCreature.h" #include "naxxramas.h" -enum Sounds +enum Says { - SOUND_AGGRO_1 = 8852, - SOUND_AGGRO_2 = 8853, - SOUND_AGGRO_3 = 8854, - SOUND_SLAY = 8861, - SOUND_COMMAND_1 = 8855, - SOUND_COMMAND_2 = 8856, - SOUND_COMMAND_3 = 8858, - SOUND_COMMAND_4 = 8859, - SOUND_COMMAND_5 = 8861, - SOUND_DEATH = 8860, + SAY_AGGRO = 0, + SAY_SLAY = 1, + SAY_TAUNTED = 2, + SAY_DEATH = 3, + SAY_SHOUT = 4 }; enum Spells @@ -55,7 +50,7 @@ class boss_razuvious : public CreatureScript public: boss_razuvious() : CreatureScript("boss_razuvious") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_razuviousAI (pCreature); } @@ -82,9 +77,9 @@ public: } } - void JustSummoned(Creature* cr) { summons.Summon(cr); } + void JustSummoned(Creature* cr) override { summons.Summon(cr); } - void Reset() + void Reset() override { BossAI::Reset(); summons.DespawnAll(); @@ -92,55 +87,36 @@ public: SpawnHelpers(); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER) return; - if (!urand(0,3)) - { - DoPlaySoundToSet(me, SOUND_SLAY); - me->MonsterYell("You should've stayed home!", LANG_UNIVERSAL, 0); - } + Talk(SAY_SLAY); if (pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) + void DamageTaken(Unit* who, uint32& damage, DamageEffectType, SpellSchoolMask) override { // Damage done by the controlled Death Knight understudies should also count toward damage done by players if(who && who->GetTypeId() == TYPEID_UNIT && who->GetEntry() == NPC_DEATH_KNIGHT_UNDERSTUDY) me->LowerPlayerDamageReq(damage); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); - DoPlaySoundToSet(me, SOUND_DEATH); - me->MonsterYell("An honorable... death...", LANG_UNIVERSAL, 0); + Talk(SAY_DEATH); me->CastSpell(me, SPELL_HOPELESS, true); } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); - switch (urand(0,2)) - { - case 0: - DoPlaySoundToSet(me, SOUND_AGGRO_1); - me->MonsterYell("Hah hah, I'm just getting warmed up!", LANG_UNIVERSAL, 0); - break; - case 1: - DoPlaySoundToSet(me, SOUND_AGGRO_2); - me->MonsterYell("Stand and fight!", LANG_UNIVERSAL, 0); - break; - case 2: - DoPlaySoundToSet(me, SOUND_AGGRO_3); - me->MonsterYell("Show me what you've got!", LANG_UNIVERSAL, 0); - break; - } + Talk(SAY_AGGRO); events.ScheduleEvent(EVENT_SPELL_UNBALANCING_STRIKE, 30000); events.ScheduleEvent(EVENT_SPELL_DISRUPTING_SHOUT, 25000); @@ -150,7 +126,7 @@ public: summons.DoZoneInCombat(); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; @@ -166,6 +142,7 @@ public: events.RepeatEvent(30000); break; case EVENT_SPELL_DISRUPTING_SHOUT: + Talk(SAY_SHOUT); me->CastSpell(me, RAID_MODE(SPELL_DISRUPTING_SHOUT_10, SPELL_DISRUPTING_SHOUT_25), false); events.RepeatEvent(25000); break; @@ -176,21 +153,7 @@ public: events.RepeatEvent(25000); break; case EVENT_PLAY_COMMAND: - switch (urand(0,2)) - { - case 0: - DoPlaySoundToSet(me, SOUND_COMMAND_1); - me->MonsterYell("Do as I taught you!", LANG_UNIVERSAL, 0); - break; - case 1: - DoPlaySoundToSet(me, SOUND_COMMAND_2); - me->MonsterYell("Show them no mercy!", LANG_UNIVERSAL, 0); - break; - case 2: - DoPlaySoundToSet(me, SOUND_COMMAND_3); - me->MonsterYell("You disappoint me, students!", LANG_UNIVERSAL, 0); - break; - } + Talk(SAY_TAUNTED); events.RepeatEvent(40000); break; } @@ -205,7 +168,7 @@ class boss_razuvious_minion : public CreatureScript public: boss_razuvious_minion() : CreatureScript("boss_razuvious_minion") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_razuvious_minionAI (pCreature); } @@ -218,12 +181,12 @@ public: EventMap events; - void Reset() + void Reset() override { events.Reset(); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER) return; @@ -232,7 +195,7 @@ public: me->GetInstanceScript()->SetData(DATA_IMMORTAL_FAIL, 0); } - void EnterCombat(Unit *who) + void EnterCombat(Unit *who) override { if (Creature* cr = me->FindNearestCreature(NPC_RAZUVIOUS, 100.0f)) { @@ -244,7 +207,7 @@ public: events.ScheduleEvent(EVENT_MINION_BONE_BARRIER, 9000); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; diff --git a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp index c7f3f31d0..fb698e820 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp @@ -72,7 +72,7 @@ class boss_sapphiron : public CreatureScript public: boss_sapphiron() : CreatureScript("boss_sapphiron") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_sapphironAI (pCreature); } @@ -91,7 +91,7 @@ public: std::list blockList; uint64 currentTarget; - void InitializeAI() + void InitializeAI() override { me->SummonGameObject(GO_SAPPHIRON_BIRTH, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, 0, 0, 0, 0, 0); me->SetVisible(false); @@ -111,7 +111,7 @@ public: return true; } - void Reset() + void Reset() override { BossAI::Reset(); if (me->IsVisible()) @@ -145,7 +145,7 @@ public: } } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); EnterCombatSelfFunction(); @@ -160,25 +160,25 @@ public: events.ScheduleEvent(EVENT_HUNDRED_CLUB, 5000); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); me->CastSpell(me, SPELL_SAPPHIRON_DIES, true); } - void DoAction(int32 param) + void DoAction(int32 param) override { if (param == ACTION_SAPPHIRON_BIRTH) spawnTimer = 1; } - void MovementInform(uint32 type, uint32 id) + void MovementInform(uint32 type, uint32 id) override { if (type == POINT_MOTION_TYPE && id == POINT_CENTER) events.ScheduleEvent(EVENT_FLIGHT_LIFTOFF, 500); } - void SpellHitTarget(Unit* target, const SpellInfo* spellInfo) + void SpellHitTarget(Unit* target, const SpellInfo* spellInfo) override { if (spellInfo->Id == SPELL_ICEBOLT_CAST) { @@ -203,13 +203,13 @@ public: return true; } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() == TYPEID_PLAYER && pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (spawnTimer) { @@ -416,13 +416,13 @@ class spell_sapphiron_frost_explosion : public SpellScriptLoader targets.push_back(*itr); } - void Register() + void Register() override { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sapphiron_frost_explosion_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); } }; - SpellScript* GetSpellScript() const + SpellScript* GetSpellScript() const override { return new spell_sapphiron_frost_explosion_SpellScript(); } diff --git a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp index 0ec63b04e..438479d79 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_thaddius.cpp @@ -14,11 +14,15 @@ enum Says SAY_STAL_AGGRO = 0, SAY_STAL_SLAY = 1, SAY_STAL_DEATH = 2, + EMOTE_STAL_DEATH = 3, + EMOTE_STAL_REVIVE = 4, // Feugen SAY_FEUG_AGGRO = 0, SAY_FEUG_SLAY = 1, SAY_FEUG_DEATH = 2, + EMOTE_FEUG_DEATH = 3, + EMOTE_FEUG_REVIVE = 4, // Thaddius SAY_GREET = 0, @@ -26,7 +30,11 @@ enum Says SAY_SLAY = 2, SAY_ELECT = 3, SAY_DEATH = 4, - SAY_SCREAM = 5 + EMOTE_POLARITY_SHIFTED = 6, + + // Tesla Coil + EMOTE_TESLA_LINK_BREAKS = 0, + EMOTE_TESLA_OVERLOAD = 1 }; enum Spells @@ -74,6 +82,7 @@ enum Events EVENT_THADDIUS_SPELL_BERSERK = 12, EVENT_THADDIUS_POLARITY_SHIFT = 13, EVENT_THADDIUS_START_2 = 14, + EVENT_ACTIVATE_BALL_LIGHTNING = 15 }; enum Misc @@ -89,14 +98,14 @@ class boss_thaddius : public CreatureScript public: boss_thaddius() : CreatureScript("boss_thaddius") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_thaddiusAI (pCreature); } struct boss_thaddiusAI : public BossAI { - boss_thaddiusAI(Creature *c) : BossAI(c, BOSS_THADDIUS), summons(me) + boss_thaddiusAI(Creature *c) : BossAI(c, BOSS_THADDIUS), summons(me), ballLightningEnabled(false) { pInstance = me->GetInstanceScript(); } @@ -107,22 +116,17 @@ public: uint32 summonTimer; uint32 reviveTimer; uint32 resetTimer; + bool ballLightningEnabled; void StartEvent() { me->RemoveAllAuras(); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE); + me->CastSpell(me, SPELL_THADDIUS_VISUAL_LIGHTNING, true); events.ScheduleEvent(EVENT_THADDIUS_START_2, 1000); - for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr) - if (Creature* cr = ObjectAccessor::GetCreature(*me, (*itr))) - if (cr->GetEntry() == NPC_TESLA_COIL) - { - cr->CastSpell(me, SPELL_TESLA_SHOCK, true); // till smth better is found ;( ZOMG - Unit::Kill(cr, cr); - } } - void DoAction(int32 param) + void DoAction(int32 param) override { if (param == ACTION_SUMMON_DIED) { @@ -139,7 +143,7 @@ public: } } - void Reset() + void Reset() override { BossAI::Reset(); events.Reset(); @@ -149,6 +153,7 @@ public: reviveTimer = 0; resetTimer = 1; me->SetPosition(me->GetHomePosition()); + ballLightningEnabled = false; me->SummonCreature(NPC_STALAGG, 3450.45f, -2931.42f, 312.091f, 5.49779f); me->SummonCreature(NPC_FEUGEN, 3508.14f, -2988.65f, 312.092f, 2.37365f); @@ -158,6 +163,7 @@ public: cr->InterruptNonMeleeSpells(true); cr->CastSpell(cr, SPELL_FEUGEN_CHAIN, false); cr->SetDisableGravity(true); + cr->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); } if (Creature* cr = me->SummonCreature(NPC_TESLA_COIL, 3487.04f, -2911.68f, 318.75f, 0.0f)) { @@ -165,22 +171,22 @@ public: cr->InterruptNonMeleeSpells(true); cr->CastSpell(cr, SPELL_STALAGG_CHAIN, false); cr->SetDisableGravity(true); + cr->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); } } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER) return; - if (!urand(0,3)) - Talk(SAY_SLAY); + Talk(SAY_SLAY); if (pInstance) pInstance->SetData(DATA_IMMORTAL_FAIL, 0); } - void JustDied(Unit* killer) + void JustDied(Unit* killer) override { BossAI::JustDied(killer); Talk(SAY_DEATH); @@ -191,9 +197,9 @@ public: } } - void JustSummoned(Creature* cr) { summons.Summon(cr); } + void JustSummoned(Creature* cr) override { summons.Summon(cr); } - void EnterCombat(Unit * who) + void EnterCombat(Unit * who) override { BossAI::EnterCombat(who); me->SetInCombatWithZone(); @@ -201,7 +207,7 @@ public: summons.DoZoneInCombat(NPC_STALAGG); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (resetTimer) { @@ -218,7 +224,15 @@ public: reviveTimer += diff; if (reviveTimer >= 12000) { - StartEvent(); + events.ScheduleEvent(EVENT_THADDIUS_START, 1500); + for (SummonList::const_iterator itr = summons.begin(); itr != summons.end(); ++itr) + if (Creature* cr = ObjectAccessor::GetCreature(*me, (*itr))) + if (cr->GetEntry() == NPC_TESLA_COIL) + { + cr->AI()->Talk(EMOTE_TESLA_OVERLOAD); + cr->CastSpell(me, SPELL_TESLA_SHOCK, true); // till smth better is found ;( ZOMG + Unit::Kill(cr, cr); + } reviveTimer = 0; } return; @@ -244,10 +258,10 @@ public: switch (events.GetEvent()) { - //case EVENT_THADDIUS_START: - // StartEvent(); - // events.PopEvent(); - // break; + case EVENT_THADDIUS_START: + StartEvent(); + events.PopEvent(); + break; case EVENT_THADDIUS_START_2: events.PopEvent(); Talk(SAY_AGGRO); @@ -259,6 +273,7 @@ public: events.ScheduleEvent(EVENT_THADDIUS_SPELL_CHAIN_LIGHTNING, 14000); events.ScheduleEvent(EVENT_THADDIUS_SPELL_BERSERK, 360000); events.ScheduleEvent(EVENT_THADDIUS_POLARITY_SHIFT, 30000); + events.ScheduleEvent(EVENT_ACTIVATE_BALL_LIGHTNING, 5000); return; case EVENT_THADDIUS_SPELL_BERSERK: me->CastSpell(me, SPELL_BERSERK, true); @@ -272,15 +287,18 @@ public: me->CastSpell(me, SPELL_POLARITY_SHIFT, false); events.RepeatEvent(30000); break; + case EVENT_ACTIVATE_BALL_LIGHTNING: + ballLightningEnabled = true; + events.PopEvent(); + break; } - if (me->isAttackReady()) - { - if (!me->IsWithinMeleeRange(me->GetVictim())) - me->CastSpell(me->GetVictim(), SPELL_BALL_LIGHTNING, false); - else - DoMeleeAttackIfReady(); - } + if (me->IsWithinMeleeRange(me->GetVictim())) + DoMeleeAttackIfReady(); + else + if (ballLightningEnabled) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM)) + DoCast(target, SPELL_BALL_LIGHTNING); } }; }; @@ -290,7 +308,7 @@ class boss_thaddius_summon : public CreatureScript public: boss_thaddius_summon() : CreatureScript("boss_thaddius_summon") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_thaddius_summonAI (pCreature); } @@ -300,33 +318,44 @@ public: boss_thaddius_summonAI(Creature *c) : ScriptedAI(c) { pInstance = me->GetInstanceScript(); + overload = false; + myCoil = 0; } InstanceScript* pInstance; EventMap events; uint32 pullTimer; uint32 visualTimer; + bool overload; + uint64 myCoil; - void Reset() + void Reset() override { pullTimer = 0; visualTimer = 1; + overload = false; events.Reset(); me->SetControlled(false, UNIT_STATE_STUNNED); if (Creature* cr = me->FindNearestCreature(NPC_TESLA_COIL, 150.0f)) + { cr->CastSpell(cr, me->GetEntry() == NPC_STALAGG ? SPELL_STALAGG_CHAIN : SPELL_FEUGEN_CHAIN, false); + cr->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + myCoil = cr->GetGUID(); + } } - void EnterEvadeMode() + void EnterEvadeMode() override { me->SetControlled(false, UNIT_STATE_STUNNED); ScriptedAI::EnterEvadeMode(); } - void EnterCombat(Unit* pWho) + void EnterCombat(Unit* pWho) override { me->SetInCombatWithZone(); + if (Creature* cr = me->FindNearestCreature(NPC_TESLA_COIL, 150.f, true)) + myCoil = cr->GetGUID(); if (me->GetEntry() == NPC_STALAGG) { @@ -353,7 +382,7 @@ public: } } - void DoAction(int32 param) + void DoAction(int32 param) override { if (param == ACTION_MAGNETIC_PULL) { @@ -366,21 +395,23 @@ public: { me->Respawn(); me->SetInCombatWithZone(); + Talk(me->GetEntry() == NPC_STALAGG ? EMOTE_STAL_REVIVE : EMOTE_FEUG_REVIVE); } else me->SetHealth(me->GetMaxHealth()); } } - void JustDied(Unit* ) + void JustDied(Unit* ) override { - Talk(me->GetEntry() == NPC_STALAGG ? SAY_FEUG_DEATH : SAY_STAL_DEATH); + Talk(me->GetEntry() == NPC_STALAGG ? SAY_STAL_DEATH : SAY_FEUG_DEATH); + Talk(me->GetEntry() == NPC_STALAGG ? EMOTE_STAL_DEATH : EMOTE_FEUG_DEATH); if (pInstance) if (Creature* cr = ObjectAccessor::GetCreature(*me, pInstance->GetData64(DATA_THADDIUS_BOSS))) cr->AI()->DoAction(ACTION_SUMMON_DIED); } - void KilledUnit(Unit* who) + void KilledUnit(Unit* who) override { if (who->GetTypeId() != TYPEID_PLAYER) return; @@ -389,10 +420,10 @@ public: pInstance->SetData(DATA_IMMORTAL_FAIL, 0); if (!urand(0,2)) - Talk(me->GetEntry() == NPC_STALAGG ? SAY_FEUG_SLAY : SAY_STAL_SLAY); + Talk(me->GetEntry() == NPC_STALAGG ? SAY_STAL_SLAY : SAY_FEUG_SLAY); } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (visualTimer) { @@ -460,17 +491,28 @@ public: break; case EVENT_MINION_CHECK_DISTANCE: - if (Creature* cr = me->FindNearestCreature(NPC_TESLA_COIL, 150.0f)) + if (Creature* cr = ObjectAccessor::GetCreature(*me, myCoil)) { - if (me->GetExactDist(cr) > 60.0f || me->GetExactDist(cr) < 20.0f) + if (!me->GetHomePosition().IsInDist(me, 28) && me->IsInCombat()) { - cr->InterruptNonMeleeSpells(true); - cr->CastSpell(me->GetVictim(), SPELL_TESLA_SHOCK, true); // dont know real spell + if (!overload) + { + overload = true; + cr->AI()->Talk(EMOTE_TESLA_LINK_BREAKS); + me->RemoveAurasDueToSpell(me->GetEntry() == NPC_STALAGG ? SPELL_STALAGG_CHAIN : SPELL_FEUGEN_CHAIN); + cr->InterruptNonMeleeSpells(true); + } + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 1000.f, true)) + { + cr->CastStop(SPELL_TESLA_SHOCK); + cr->CastSpell(target, SPELL_TESLA_SHOCK, true); + } events.RepeatEvent(1500); break; } else { + overload = false; cr->CastSpell(cr, me->GetEntry() == NPC_STALAGG ? SPELL_STALAGG_CHAIN : SPELL_FEUGEN_CHAIN, false); } } @@ -530,14 +572,14 @@ class spell_thaddius_pos_neg_charge : public SpellScriptLoader target->GetInstanceScript()->SetData(DATA_CHARGES_CROSSED, 0); } - void Register() + void Register() override { OnEffectHitTarget += SpellEffectFn(spell_thaddius_pos_neg_charge_SpellScript::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_thaddius_pos_neg_charge_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); } }; - SpellScript* GetSpellScript() const + SpellScript* GetSpellScript() const override { return new spell_thaddius_pos_neg_charge_SpellScript(); } @@ -552,7 +594,7 @@ class spell_thaddius_polarity_shift : public SpellScriptLoader { PrepareSpellScript(spell_thaddius_polarity_shift_SpellScript); - bool Validate(SpellInfo const* /*spell*/) + bool Validate(SpellInfo const* /*spell*/) override { if (!sSpellMgr->GetSpellInfo(SPELL_POSITIVE_POLARITY) || !sSpellMgr->GetSpellInfo(SPELL_NEGATIVE_POLARITY)) return false; @@ -563,26 +605,81 @@ class spell_thaddius_polarity_shift : public SpellScriptLoader { Unit* caster = GetCaster(); if (Unit* target = GetHitUnit()) - target->CastSpell(target, roll_chance_i(50) ? SPELL_POSITIVE_POLARITY : SPELL_NEGATIVE_POLARITY, true, NULL, NULL, caster->GetGUID()); + target->CastSpell(target, roll_chance_i(50) ? SPELL_POSITIVE_POLARITY : SPELL_NEGATIVE_POLARITY, true, nullptr, nullptr, caster->GetGUID()); } - void Register() + void HandleAfterCast() + { + if (GetCaster()) + if (Creature* caster = GetCaster()->ToCreature()) + if (caster->GetEntry() == NPC_THADDIUS) + { + caster->AI()->Talk(SAY_ELECT); + caster->AI()->Talk(EMOTE_POLARITY_SHIFTED); + } + } + + void Register() override { OnEffectHitTarget += SpellEffectFn(spell_thaddius_polarity_shift_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + AfterCast += SpellCastFn(spell_thaddius_polarity_shift_SpellScript::HandleAfterCast); } }; - SpellScript* GetSpellScript() const + SpellScript* GetSpellScript() const override { return new spell_thaddius_polarity_shift_SpellScript(); } }; +class npc_tesla : public CreatureScript +{ +public: + npc_tesla() : CreatureScript("npc_tesla") { } + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI(creature); + } + + struct npc_teslaAI : public ScriptedAI + { + public: + npc_teslaAI(Creature* creature) : ScriptedAI(creature) { } + void EnterEvadeMode() override { } // never stop casting due to evade + void UpdateAI(uint32 /*diff*/) override { } // never do anything unless told + void EnterCombat(Unit* /*who*/) override { } + void DamageTaken(Unit* /*who*/, uint32& damage, DamageEffectType, SpellSchoolMask) override { damage = 0; } // no, you can't kill it + }; +}; + +class at_thaddius_entrance : public AreaTriggerScript +{ + public: + at_thaddius_entrance() : AreaTriggerScript("at_thaddius_entrance") { } + + bool OnTrigger(Player* player, AreaTrigger const* /*areaTrigger*/) override + { + InstanceScript* instance = player->GetInstanceScript(); + if (!instance || instance->GetData(DATA_HAD_THADDIUS_GREET) || instance->GetBossState(BOSS_THADDIUS) == DONE) + return true; + + if (Creature* thaddius = ObjectAccessor::GetCreature(*player, instance->GetData64(DATA_THADDIUS_BOSS))) + thaddius->AI()->Talk(SAY_GREET); + instance->SetData(DATA_HAD_THADDIUS_GREET, 1); + + return true; + } +}; + void AddSC_boss_thaddius() { new boss_thaddius(); new boss_thaddius_summon(); + new npc_tesla(); new spell_thaddius_pos_neg_charge(); new spell_thaddius_polarity_shift(); + + new at_thaddius_entrance(); } diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index 6a1748c74..553520fab 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -40,7 +40,7 @@ class instance_naxxramas : public InstanceMapScript public: instance_naxxramas() : InstanceMapScript("instance_naxxramas", 533) { } - InstanceScript* GetInstanceScript(InstanceMap* pMap) const + InstanceScript* GetInstanceScript(InstanceMap* pMap) const override { return new instance_naxxramas_InstanceMapScript(pMap); } @@ -75,6 +75,8 @@ public: _thaddiusPortalGUID = 0; // NPCs + PatchwerkRoomTrash.clear(); + _patchwerkGUID = 0; _thaddiusGUID = 0; _stalaggGUID = 0; _feugenGUID = 0; @@ -90,6 +92,9 @@ public: _horsemanKilled = 0; _speakTimer = 0; _horsemanTimer = 0; + _screamTimer = 2 * MINUTE * IN_MILLISECONDS; + _hadThaddiusGreet = false; + _currentWingTaunt = SAY_FIRST_WING_TAUNT; // Achievements abominationsKilled = 0; @@ -99,6 +104,7 @@ public: sapphironAchievement = true; heiganAchievement = true; immortalAchievement = 1; + } std::set HeiganEruption[4]; @@ -128,6 +134,8 @@ public: uint64 _thaddiusPortalGUID; // NPCs + std::list PatchwerkRoomTrash; + uint64 _patchwerkGUID; uint64 _thaddiusGUID; uint64 _stalaggGUID; uint64 _feugenGUID; @@ -143,6 +151,10 @@ public: uint8 _horsemanKilled; uint32 _speakTimer; uint32 _horsemanTimer; + uint32 _screamTimer; + bool _hadThaddiusGreet; + EventMap events; + uint8 _currentWingTaunt; // Achievements uint8 abominationsKilled; @@ -163,7 +175,7 @@ public: for (std::set::iterator itr = HeiganEruption[i].begin(); itr != HeiganEruption[i].end(); ++itr) { (*itr)->SendCustomAnim((*itr)->GetGoAnimProgress()); - (*itr)->CastSpell(NULL, SPELL_ERUPTION); + (*itr)->CastSpell(nullptr, SPELL_ERUPTION); } } } @@ -182,6 +194,29 @@ public: { switch(creature->GetEntry()) { + case NPC_PATCHWERK: + _patchwerkGUID = creature->GetGUID(); + return; + case NPC_PATCHWORK_GOLEM: + PatchwerkRoomTrash.push_back(creature->GetGUID()); + return; + case NPC_BILE_RETCHER: + if (creature->GetPositionY() > -3258.0f) // we want only those inside the room, not before + PatchwerkRoomTrash.push_back(creature->GetGUID()); + return; + case NPC_SLUDGE_BELCHER: + if (creature->GetPositionY() > -3258.0f) // we want only those inside the room, not before + PatchwerkRoomTrash.push_back(creature->GetGUID()); + return; + case NPC_MAD_SCIENTIST: + PatchwerkRoomTrash.push_back(creature->GetGUID()); + return; + case NPC_LIVING_MONSTROSITY: + PatchwerkRoomTrash.push_back(creature->GetGUID()); + return; + case NPC_SURGICAL_ASSIST: + PatchwerkRoomTrash.push_back(creature->GetGUID()); + return; case NPC_THADDIUS: _thaddiusGUID = creature->GetGUID(); return; @@ -428,11 +463,37 @@ public: case DATA_HEIGAN_ERUPTION: HeiganEruptSections(data); return; + case DATA_HAD_THADDIUS_GREET: + _hadThaddiusGreet = (data == 1); } } + + uint32 GetData(uint32 id) const override + { + switch (id) + { + case DATA_HAD_THADDIUS_GREET: + return _hadThaddiusGreet ? 1 : 0; + } + return 0; + } bool SetBossState(uint32 bossId, EncounterState state) override { + // pull all the trash if not killed + if (bossId == BOSS_PATCHWERK && state == IN_PROGRESS) + { + if (Creature* patch = instance->GetCreature(_patchwerkGUID)) + { + for (auto &itr : PatchwerkRoomTrash) + { + Creature* trash = ObjectAccessor::GetCreature(*patch, itr); + if (trash && trash->IsAlive() && !trash->IsInCombat()) + trash->AI()->AttackStart(patch->GetVictim()); + } + } + } + // Horseman handling if (bossId == BOSS_HORSEMAN) { @@ -569,6 +630,7 @@ public: go->SetGoState(GO_STATE_ACTIVE); if (GameObject* go = instance->GetGameObject(_loathebPortalGUID)) go->SetPhaseMask(1, true); + events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000); break; case BOSS_ANUB: if (GameObject* go = instance->GetGameObject(_anubGateGUID)) @@ -587,6 +649,7 @@ public: go->SetGoState(GO_STATE_ACTIVE); if (GameObject* go = instance->GetGameObject(_maexxnaPortalGUID)) go->SetPhaseMask(1, true); + events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000); break; case BOSS_GOTHIK: if (GameObject* go = instance->GetGameObject(_gothikEnterGateGUID)) @@ -603,10 +666,12 @@ public: case BOSS_THADDIUS: if (GameObject* go = instance->GetGameObject(_thaddiusPortalGUID)) go->SetPhaseMask(1, true); + events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000); break; case BOSS_HORSEMAN: if (GameObject* go = instance->GetGameObject(_horsemanPortalGUID)) go->SetPhaseMask(1, true); + events.ScheduleEvent(EVENT_KELTHUZAD_WING_TAUNT, 6000); break; } } @@ -661,6 +726,30 @@ public: // And They would all if (_horsemanTimer) _horsemanTimer += diff; + + if (_screamTimer && GetBossState(BOSS_THADDIUS) != DONE) + { + if (_screamTimer <= diff) + { + instance->PlayDirectSoundToMap(SOUND_SCREAM + urand(0, 3)); + _screamTimer = (2 * MINUTE + urand(0, 30)) * IN_MILLISECONDS; + } + else + _screamTimer -= diff; + } + + events.Update(diff); + switch (events.ExecuteEvent()) + { + case EVENT_KELTHUZAD_WING_TAUNT: + // Loads Kel'Thuzad's grid. We need this as he must be active in order for his texts to work. + instance->LoadGrid(3749.67f, -5114.06f); + if (Creature* kelthuzad = instance->GetCreature(_kelthuzadGUID)) + kelthuzad->AI()->Talk(_currentWingTaunt); + ++_currentWingTaunt; + events.PopEvent(); + break; + } } uint64 GetData64(uint32 id) const override @@ -751,7 +840,7 @@ class boss_naxxramas_misc : public CreatureScript public: boss_naxxramas_misc() : CreatureScript("boss_naxxramas_misc") { } - CreatureAI* GetAI(Creature* pCreature) const + CreatureAI* GetAI(Creature* pCreature) const override { return new boss_naxxramas_miscAI (pCreature); } @@ -765,7 +854,7 @@ public: uint32 timer; - void JustDied(Unit* ) + void JustDied(Unit* ) override { if (me->GetEntry() == NPC_MR_BIGGLESWORTH && me->GetInstanceScript()) { @@ -777,7 +866,7 @@ public: } } - void UpdateAI(uint32 diff) + void UpdateAI(uint32 diff) override { if (me->GetEntry() == NPC_NAXXRAMAS_TRIGGER) { @@ -794,7 +883,7 @@ public: } else if (me->GetEntry() == NPC_LIVING_POISON) { - Unit* target = NULL; + Unit* target = nullptr; Trinity::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 0.5f); Trinity::UnitLastSearcher searcher(me, target, u_check); me->VisitNearbyObject(1.5f, searcher); diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h index 008299ef5..555ab63c0 100644 --- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h +++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h @@ -50,6 +50,7 @@ enum NXData DATA_DANCE_FAIL = 118, DATA_IMMORTAL_FAIL = 119, DATA_KELTHUZAD_GATE = 120, + DATA_HAD_THADDIUS_GREET = 121, }; enum NXGOs @@ -82,6 +83,9 @@ enum NXGOs GO_THADDIUS_PORTAL = 181576, //Thadius portal GO_MAEXXNA_PORTAL = 181575, //Maexxna portal GO_HORSEMAN_PORTAL = 181578, //Four Horseman portal + + GO_CONS_NOX_TESLA_STALAGG = 268049, + GO_CONS_NOX_TESLA_FEUGEN = 268050 }; enum NXNPCs @@ -107,7 +111,16 @@ enum NXNPCs // Frogger NPC_LIVING_POISON = 16027, NPC_NAXXRAMAS_TRIGGER = 16082, - NPC_MR_BIGGLESWORTH = 16998 + NPC_MR_BIGGLESWORTH = 16998, + + // Patchwerk + NPC_PATCHWERK = 16028, + NPC_PATCHWORK_GOLEM = 16017, + NPC_BILE_RETCHER = 16018, + NPC_MAD_SCIENTIST = 16020, + NPC_LIVING_MONSTROSITY = 16021, + NPC_SURGICAL_ASSIST = 16022, + NPC_SLUDGE_BELCHER = 16029, }; enum NXMisc @@ -117,7 +130,11 @@ enum NXMisc SPELL_FROGGER_EXPLODE = 28433, // Actions - ACTION_SAPPHIRON_BIRTH = 1 + ACTION_SAPPHIRON_BIRTH = 1, + + // Sounds + // Background screams in instance if Thaddius still alive, four of them from 8873 to 8876 + SOUND_SCREAM = 8873 }; enum NXSays @@ -128,7 +145,14 @@ enum NXSays SAY_SAPP_DIALOG4_LICH = 2, SAY_SAPP_DIALOG5 = 4, SAY_SAPP_DIALOG6 = 20, - SAY_CAT_DIED = 0 + SAY_CAT_DIED = 5, + SAY_FIRST_WING_TAUNT = 16 +}; + +enum NXEvents +{ + EVENT_THADDIUS_SCREAMS = 0, + EVENT_KELTHUZAD_WING_TAUNT }; #endif