Scripts/Naxxramas: Anub'rekhan encounter cleanup.

- Cleaned up events behavior to use phases instead of weird checks for auras.
- Cleaned up Crypt Guard despawn behavior, they should no longer despawn instantly upon death.
- Moved initial greeting from MoveInLineOfSight hack to proper areatrigger script.
- Fixed Crypt Guard respawn behaviour to prevent pulling them before Anub'rekhan has fully reset.
- Fixed Crypt Guard aggro behaviour to call for help on aggro. This prevents pulling the initial pair of Crypt Guards without engaging the boss.
- Added missing boss emotes.
- Code style cleanup.

(cherry picked from commit 91de0322bb)

# Conflicts:
#	src/server/scripts/Northrend/Naxxramas/boss_anubrekhan.cpp
This commit is contained in:
treeston
2015-09-30 12:14:45 +02:00
committed by MitchesD
parent d94e5d17e7
commit 6d14c4871f
4 changed files with 185 additions and 69 deletions

View File

@@ -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));
}
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);
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;
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_SPAWN_GUARDIAN_NORMAL:
/// @todo Add Text
DoSummon(NPC_CRYPT_GUARD, GuardSummonPos, 0, TEMPSUMMON_CORPSE_DESPAWN);
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_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();
}

View File

@@ -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;

View File

@@ -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,