diff options
4 files changed, 185 insertions, 69 deletions
diff --git a/sql/updates/world/2015_11_06_29_world_2015_11_02_00.sql b/sql/updates/world/2015_11_06_29_world_2015_11_02_00.sql new file mode 100644 index 00000000000..19379ad7d71 --- /dev/null +++ b/sql/updates/world/2015_11_06_29_world_2015_11_02_00.sql @@ -0,0 +1,26 @@ +-- Anub'Rekhan cleanup +-- areatrigger for greeting upon entering room +DELETE FROM `areatrigger_scripts` WHERE `entry`=4119; +INSERT INTO `areatrigger_scripts` (`entry`,`ScriptName`) VALUES +(4119,"at_anubrekhan_entrance"); + +-- make crypt guards aggro anub when pulled +DELETE FROM `smart_scripts` WHERE `entryorguid`=16573 AND `source_type`=0 AND `id` IN (6,7); +INSERT INTO `smart_scripts` (`entryorguid`,`source_type`,`id`,`link`,`event_type`,`event_chance`,`event_flags`,`action_type`,`action_param1`,`action_param2`,`action_param3`,`target_type`,`comment`) VALUES +(16573,0, 6, 0, 4,100,0,39, 25, 0, 0, 0, "Crypt Guard - On Aggro - Call For Help (25yd)"), +(16573,0, 7, 5,61,100,0,1, 0, 0, 0, 0, "Crypt Guard - On Cast Frenzy - Say EMOTE_FRENZY"); +UPDATE `smart_scripts` SET `link`=7 WHERE `entryorguid`=16573 AND `source_type`=0 AND `id`=5; + +DELETE FROM `creature_text` WHERE `entry`=16573; +DELETE FROM `creature_text` WHERE `entry`=15956 AND `groupid`=3; +INSERT INTO `creature_text` (`entry`,`groupid`,`id`,`text`,`type`,`probability`,`BroadcastTextId`,`TextRange`,`comment`) VALUES +(16573,0,0,"%s goes into a frenzy!",16,100,1191,3,"Crypt Guard EMOTE_FRENZY"), +(16573,1,0,"A Crypt Guard joins the fight!",41,100,29887,3,"Crypt Guard EMOTE_SPAWN"), +(16573,2,0,"Corpse Scarabs appear from a Crypt Guard's corpse!",41,100,32796,3,"Crypt Guard EMOTE_SCARAB"), +(15956,3,0,"Anub'Rekhan begins to unleash an insect swarm!",41,100,13443,3,"Anub'Rekhan EMOTE_LOCUST"); + +DELETE FROM `creature_summon_groups` WHERE `summonerId`=15956; +INSERT INTO `creature_summon_groups` (`summonerId`,`summonerType`,`groupId`,`entry`,`position_x`,`position_y`,`position_z`,`orientation`,`summonType`) VALUES +(15956,0,1,16573, 3300.503, -3503.574, 287.1606, 2.321288, 8), +(15956,0,1,16573, 3299.283, -3450.938, 287.1606, 3.839724, 8), +(15956,0,2,16573, 3334.41 , -3476.84 , 287.1553, 0, 8); diff --git a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp index 28d181a990e..471a7adc9d6 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp @@ -17,39 +17,61 @@ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "Player.h" #include "naxxramas.h" -enum Says +enum AnubSays { SAY_AGGRO = 0, SAY_GREET = 1, - SAY_SLAY = 2 + SAY_SLAY = 2, + + EMOTE_LOCUST = 3 }; -Position const GuardSummonPos = {3333.72f, -3476.30f, 287.1f, 6.2801f}; +enum GuardSays +{ + EMOTE_FRENZY = 0, + EMOTE_SPAWN = 1, + EMOTE_SCARAB = 2 +}; enum Events { - EVENT_IMPALE = 1, - EVENT_LOCUST, - EVENT_SPAWN_GUARDIAN_NORMAL, - EVENT_BERSERK + EVENT_IMPALE = 1, // Cast Impale on a random target + EVENT_LOCUST, // Begin channeling Locust Swarm + EVENT_LOCUST_ENDS, // Locust swarm dissipates + EVENT_SPAWN_GUARD, // 10-man only - crypt guard has delayed spawn; also used for the locust swarm crypt guard in both modes + EVENT_SCARABS, // spawn corpse scarabs + EVENT_BERSERK // Berserk }; enum Spells { - SPELL_IMPALE = 28783, - SPELL_LOCUST_SWARM = 28785, + SPELL_IMPALE = 28783, // 25-man: 56090 + SPELL_LOCUST_SWARM = 28785, // 25-man: 54021 SPELL_SUMMON_CORPSE_SCARABS_PLR = 29105, // This spawns 5 corpse scarabs on top of player SPELL_SUMMON_CORPSE_SCARABS_MOB = 28864, // This spawns 10 corpse scarabs on top of dead guards SPELL_BERSERK = 27680 }; +enum SpawnGroups +{ + GROUP_INITIAL_25M = 1, + GROUP_SINGLE_SPAWN = 2 +}; + enum Misc { ACHIEV_TIMED_START_EVENT = 9891 }; +enum Phases +{ + PHASE_NORMAL = 1, + PHASE_SWARM +}; + class boss_anubrekhan : public CreatureScript { public: @@ -62,46 +84,64 @@ public: struct boss_anubrekhanAI : public BossAI { - boss_anubrekhanAI(Creature* creature) : BossAI(creature, BOSS_ANUBREKHAN) + boss_anubrekhanAI(Creature* creature) : BossAI(creature, BOSS_ANUBREKHAN) { } + + void SummonGuards() { - Initialize(); + if (Is25ManRaid()) + me->SummonCreatureGroup(GROUP_INITIAL_25M); } - void Initialize() + void InitializeAI() override { - hasTaunted = false; + if (!me->isDead()) + { + Reset(); + SummonGuards(); + } } - bool hasTaunted; - void Reset() override { _Reset(); + guardCorpses.clear(); + } - Initialize(); + void JustReachedHome() override + { + _JustReachedHome(); + SummonGuards(); + } - if (GetDifficulty() == DIFFICULTY_25_N) - { - Position pos; + void JustSummoned(Creature* summon) override + { + BossAI::JustSummoned(summon); + + if (me->IsInCombat()) + if (summon->GetEntry() == NPC_CRYPT_GUARD) + summon->AI()->Talk(EMOTE_SPAWN, me); + } - // respawn guard using home position, - // otherwise, after a wipe, they respawn where boss was at wipe moment. - pos = me->GetHomePosition(); - pos.m_positionY -= 10.0f; - me->SummonCreature(NPC_CRYPT_GUARD, pos, TEMPSUMMON_CORPSE_DESPAWN); + void SummonedCreatureDies(Creature* summon, Unit* killer) override + { + BossAI::SummonedCreatureDies(summon, killer); - pos = me->GetHomePosition(); - pos.m_positionY += 10.0f; - me->SummonCreature(NPC_CRYPT_GUARD, pos, TEMPSUMMON_CORPSE_DESPAWN); - } + if (summon->GetEntry() == NPC_CRYPT_GUARD) + guardCorpses.insert(summon->GetGUID()); + } + + void SummonedCreatureDespawn(Creature* summon) override + { + BossAI::SummonedCreatureDespawn(summon); + + if (summon->GetEntry() == NPC_CRYPT_GUARD) + guardCorpses.erase(summon->GetGUID()); } void KilledUnit(Unit* victim) override { - /// Force the player to spawn corpse scarabs via spell, @todo Check percent chance for scarabs, 20% at the moment - if (!(rand32() % 5)) - if (victim->GetTypeId() == TYPEID_PLAYER) - victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCARABS_PLR, true, NULL, NULL, me->GetGUID()); + if (victim->GetTypeId() == TYPEID_PLAYER) + victim->CastSpell(victim, SPELL_SUMMON_CORPSE_SCARABS_PLR, true, nullptr, nullptr, me->GetGUID()); Talk(SAY_SLAY); } @@ -113,37 +153,22 @@ public: // start achievement timer (kill Maexna within 20 min) instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_TIMED_START_EVENT); } + void EnterCombat(Unit* /*who*/) override { _EnterCombat(); Talk(SAY_AGGRO); - events.ScheduleEvent(EVENT_IMPALE, urand(10000, 20000)); - events.ScheduleEvent(EVENT_LOCUST, 90000); - events.ScheduleEvent(EVENT_BERSERK, 600000); - - if (GetDifficulty() == DIFFICULTY_10_N) - events.ScheduleEvent(EVENT_SPAWN_GUARDIAN_NORMAL, urand(15000, 20000)); - } - void MoveInLineOfSight(Unit* who) override - { - if (!hasTaunted && me->IsWithinDistInMap(who, 60.0f) && who->GetTypeId() == TYPEID_PLAYER) - { - Talk(SAY_GREET); - hasTaunted = true; - } - ScriptedAI::MoveInLineOfSight(who); - } - - void SummonedCreatureDespawn(Creature* summon) override - { - BossAI::SummonedCreatureDespawn(summon); - - // check if it is an actual killed guard - if (!me->IsAlive() || summon->IsAlive() || summon->GetEntry() != NPC_CRYPT_GUARD) - return; + 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); - summon->CastSpell(summon, SPELL_SUMMON_CORPSE_SCARABS_MOB, true, NULL, NULL, me->GetGUID()); + if (!Is25ManRaid()) + events.ScheduleEvent(EVENT_SPAWN_GUARD, urand(15, 20) * IN_MILLISECONDS); } void UpdateAI(uint32 diff) override @@ -158,22 +183,44 @@ public: switch (eventId) { case EVENT_IMPALE: - //Cast Impale on a random target - //Do NOT cast it when we are afflicted by locust swarm - if (!me->HasAura(SPELL_LOCUST_SWARM)) - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_IMPALE); - events.ScheduleEvent(EVENT_IMPALE, urand(10000, 20000)); + if (events.GetTimeUntilEvent(EVENT_LOCUST) < 5 * IN_MILLISECONDS) break; // don't chain impale tank -> locust swarm + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_IMPALE); + else + EnterEvadeMode(); + + events.ScheduleEvent(EVENT_IMPALE, urand(10 * IN_MILLISECONDS, 20 * IN_MILLISECONDS), 0, PHASE_NORMAL); + 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)) + if(Creature* creatureTarget = ObjectAccessor::GetCreature(*me, target)) + { + creatureTarget->CastSpell(creatureTarget, SPELL_SUMMON_CORPSE_SCARABS_MOB, true, nullptr, nullptr, me->GetGUID()); + creatureTarget->AI()->Talk(EMOTE_SCARAB); + creatureTarget->DespawnOrUnsummon(); + } + } break; case EVENT_LOCUST: - /// @todo Add Text + Talk(EMOTE_LOCUST); DoCast(me, SPELL_LOCUST_SWARM); - DoSummon(NPC_CRYPT_GUARD, GuardSummonPos, 0, TEMPSUMMON_CORPSE_DESPAWN); + 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); + 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); break; - case EVENT_SPAWN_GUARDIAN_NORMAL: - /// @todo Add Text - DoSummon(NPC_CRYPT_GUARD, GuardSummonPos, 0, TEMPSUMMON_CORPSE_DESPAWN); + case EVENT_SPAWN_GUARD: + me->SummonCreatureGroup(GROUP_SINGLE_SPAWN); break; case EVENT_BERSERK: DoCast(me, SPELL_BERSERK, true); @@ -182,13 +229,37 @@ public: } } - DoMeleeAttackIfReady(); + if (events.IsInPhase(PHASE_NORMAL)) + DoMeleeAttackIfReady(); } + private: + GuidSet guardCorpses; }; }; +class at_anubrekhan_entrance : public AreaTriggerScript +{ + public: + at_anubrekhan_entrance() : AreaTriggerScript("at_anubrekhan_entrance") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override + { + InstanceScript* instance = player->GetInstanceScript(); + if (!instance || instance->GetData(DATA_HAD_ANUBREKHAN_GREET) || instance->GetBossState(BOSS_ANUBREKHAN) != NOT_STARTED) + return true; + + if (Creature* anub = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_ANUBREKHAN))) + anub->AI()->Talk(SAY_GREET); + instance->SetData(DATA_HAD_ANUBREKHAN_GREET, 1u); + + return true; + } +}; + void AddSC_boss_anubrekhan() { new boss_anubrekhan(); + + new at_anubrekhan_entrance(); } diff --git a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp index fc0f0e2b833..f0348c408b1 100644 --- a/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp +++ b/src/server/scripts/Northrend/Naxxramas/instance_naxxramas.cpp @@ -125,6 +125,7 @@ class instance_naxxramas : public InstanceMapScript minHorsemenDiedTime = 0; maxHorsemenDiedTime = 0; AbominationCount = 0; + hadAnubRekhanGreet = false; hadFaerlinaGreet = false; CurrentWingTaunt = SAY_KELTHUZAD_FIRST_WING_TAUNT; @@ -135,6 +136,9 @@ class instance_naxxramas : public InstanceMapScript { switch (creature->GetEntry()) { + case NPC_ANUBREKHAN: + AnubRekhanGUID = creature->GetGUID(); + break; case NPC_FAERLINA: FaerlinaGUID = creature->GetGUID(); break; @@ -319,9 +323,14 @@ class instance_naxxramas : public InstanceMapScript case DATA_ABOMINATION_KILLED: AbominationCount = value; break; + case DATA_HAD_ANUBREKHAN_GREET: + hadAnubRekhanGreet = (value == 1u); + break; case DATA_HAD_FAERLINA_GREET: hadFaerlinaGreet = (value == 1u); break; + default: + break; } } @@ -331,6 +340,8 @@ class instance_naxxramas : public InstanceMapScript { case DATA_ABOMINATION_KILLED: return AbominationCount; + case DATA_HAD_ANUBREKHAN_GREET: + return (uint32)hadAnubRekhanGreet; case DATA_HAD_FAERLINA_GREET: return (uint32)hadFaerlinaGreet; default: @@ -344,6 +355,8 @@ class instance_naxxramas : public InstanceMapScript { switch (id) { + case DATA_ANUBREKHAN: + return AnubRekhanGUID; case DATA_FAERLINA: return FaerlinaGUID; case DATA_THANE: @@ -604,6 +617,8 @@ class instance_naxxramas : public InstanceMapScript protected: /* The Arachnid Quarter */ + // Anub'rekhan + ObjectGuid AnubRekhanGUID; // Grand Widow Faerlina ObjectGuid FaerlinaGUID; @@ -640,6 +655,7 @@ class instance_naxxramas : public InstanceMapScript ObjectGuid KelthuzadDoorGUID; ObjectGuid LichKingGUID; uint8 AbominationCount; + bool hadAnubRekhanGreet; bool hadFaerlinaGreet; uint8 CurrentWingTaunt; diff --git a/src/server/scripts/Northrend/Naxxramas/naxxramas.h b/src/server/scripts/Northrend/Naxxramas/naxxramas.h index 6795e2cc337..6289b707411 100644 --- a/src/server/scripts/Northrend/Naxxramas/naxxramas.h +++ b/src/server/scripts/Northrend/Naxxramas/naxxramas.h @@ -46,6 +46,7 @@ enum Data DATA_HEIGAN_ERUPT, DATA_GOTHIK_GATE, DATA_SAPPHIRON_BIRTH, + DATA_HAD_ANUBREKHAN_GREET, DATA_HAD_FAERLINA_GREET, @@ -63,6 +64,7 @@ enum Data enum Data64 { + DATA_ANUBREKHAN, DATA_FAERLINA, DATA_THANE, DATA_LADY, @@ -83,6 +85,7 @@ enum Data64 enum CreaturesIds { + NPC_ANUBREKHAN = 15956, NPC_FAERLINA = 15953, NPC_THANE = 16064, NPC_LADY = 16065, |