aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorrunningnak3d <none@none>2010-10-09 01:54:36 -0600
committerrunningnak3d <none@none>2010-10-09 01:54:36 -0600
commit1cdd1a67001078673c50a58562a5f23489dc8bcb (patch)
tree89b0e630d17efcdf9d983a39cbc8327f92f7fa35 /src
parent7a9a9426a7951dec3dfb9776519a29005b7a227d (diff)
parent8f9660fa0744ba9e821cae42c5b42b697bbe9911 (diff)
Branch merg
--HG-- branch : trunk
Diffstat (limited to 'src')
-rw-r--r--src/server/scripts/Northrend/Ulduar/ulduar/boss_ignis.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/ulduar/boss_razorscale.cpp919
-rw-r--r--src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp105
-rw-r--r--src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h3
4 files changed, 767 insertions, 262 deletions
diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_ignis.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_ignis.cpp
index e9c09d03b21..a51f72e6964 100644
--- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_ignis.cpp
+++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_ignis.cpp
@@ -133,7 +133,7 @@ public:
std::vector<Creature*> triggers;
bool Shattered;
- uint32 SlagPotGUID;
+ uint64 SlagPotGUID;
uint32 EncounterTime;
uint32 ConstructTimer;
diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_razorscale.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_razorscale.cpp
index c4de6b47d22..da17b613336 100644
--- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_razorscale.cpp
+++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_razorscale.cpp
@@ -15,36 +15,141 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+//TODO: Harpoon event is automated needs to be checked
+
/* ScriptData
-SDName: razorscale
-SDAuthor: MaXiMiUS
-SD%Complete: 65
+SDName: Razorscale
+SDAuthor: PrinceCreed
+SD%Complete: 100
EndScriptData */
#include "ScriptPCH.h"
#include "ulduar.h"
-//not in db
-#define SAY_AGGRO -2000000
-#define SAY_KILL -2000001
-#define SAY_PHASE_2_TRANS -2000002
-#define SAY_PHASE_3_TRANS -2000003
-#define EMOTE_BREATH -2000004
+enum Says
+{
+ SAY_GREET = -1603260,
+ SAY_GROUND_PHASE = -1603261,
+ SAY_AGGRO_1 = -1603262,
+ SAY_AGGRO_2 = -1603263,
+ SAY_AGGRO_3 = -1603264,
+ SAY_TURRETS = -1603265,
+ EMOTE_HARPOON = -1603266,
+ EMOTE_BREATH = -1603267,
+ EMOTE_PERMA = -1603268,
+};
+
+#define GOSSIP_ITEM_1 "Activate Harpoones!"
enum Spells
{
- SPELL_FLAMEBUFFET = 64016,
- SPELL_FIREBALL = 62796,
+ SPELL_FLAMEBUFFET = 64016,
+ SPELL_FIREBALL = 62796,
+ SPELL_FLAME_GROUND = 64709,
+ SPELL_WINGBUFFET = 62666,
+ SPELL_FLAMEBREATH = 63317,
+ SPELL_FUSEARMOR = 64771,
+ SPELL_DEVOURING_FLAME = 63236,
+ SPELL_HARPOON = 54933,
+ SPELL_FLAMED = 62696,
+ SPELL_STUN = 9032,
+ SPELL_BERSERK = 47008
+};
+
+const Position PosHarpoon[4] =
+{
+{594.317f, -136.953f, 391.517f, 4.544f},
+{577.449f, -136.953f, 391.517f, 4.877f},
+{607.726f, -146.857f, 391.517f, 4.041f},
+{561.449f, -146.857f, 391.517f, 5.426f}
+};
+
+const Position PosEngSpawn = {591.951f, -95.968f, 391.517f, 0};
+
+const Position PosEngRepair[4] =
+{
+{590.442f, -130.550f, 391.517f, 4.789f},
+{574.850f, -133.687f, 391.517f, 4.252f},
+{606.567f, -143.369f, 391.517f, 4.434f},
+{560.609f, -142.967f, 391.517f, 5.074f}
+};
- SPELL_WINGBUFFET = 62666,
- SPELL_FLAMEBREATH = 63317,
- SPELL_FUSEARMOR = 64771,
- SPELL_DEVOURINGFLAME = 63014
+const Position PosDefSpawn[4] =
+{
+{600.75f, -104.850f, 391.517f, 0},
+{596.38f, -110.262f, 391.517f, 0},
+{566.47f, -103.633f, 391.517f, 0},
+{570.41f, -108.791f, 391.517f, 0}
};
+const Position PosDefCombat[4] =
+{
+{614.975f, -155.138f, 391.517f, 4.154f},
+{609.814f, -204.968f, 391.517f, 5.385f},
+{563.531f, -201.557f, 391.517f, 4.108f},
+{560.231f, -153.677f, 391.517f, 5.403f}
+};
+
+const Position RazorFlight = {588.050f, -251.191f, 470.536f, 1.605f};
+const Position RazorGround = {586.966f, -175.534f, 391.517f, 1.692f};
+
enum Mobs
{
- NPC_DARK_RUNE_SENTINEL = 33846
+ RAZORSCALE = 33186,// ?? why not use instance?
+ NPC_DARK_RUNE_GUARDIAN = 33388,
+ NPC_DARK_RUNE_SENTINEL = 33846,
+ NPC_DARK_RUNE_WATCHER = 33453,
+ MOLE_MACHINE_TRIGGER = 33245,
+ NPC_COMMANDER = 33210,
+ NPC_ENGINEER = 33287,
+ NPC_DEFENDER = 33816,
+ NPC_HARPOON = 33184,
+ GOB_MOLE_MACHINE = 194316
+};
+
+enum DarkRuneSpells
+{
+ // Dark Rune Watcher
+ SPELL_CHAIN_LIGHTNING = 64758,
+ SPELL_LIGHTNING_BOLT = 63809,
+
+ // Dark Rune Guardian
+ SPELL_STORMSTRIKE = 64757,
+
+ // Dark Rune Sentinel
+ SPELL_BATTLE_SHOUT = 46763,
+ SPELL_HEROIC_STRIKE = 45026,
+ SPELL_WHIRLWIND = 63807,
+};
+
+#define ACHIEVEMENT_QUICK_SHAVE RAID_MODE(2919, 2921)
+
+#define ACTION_EVENT_START 1
+#define ACTION_GROUND_PHASE 2
+
+enum Phases
+{
+ PHASE_NULL,
+ PHASE_PERMAGROUND,
+ PHASE_GROUND,
+ PHASE_FLIGHT
+};
+
+enum Events
+{
+ EVENT_NONE,
+ EVENT_BERSERK,
+ EVENT_BREATH,
+ EVENT_BUFFET,
+ EVENT_HARPOON,
+ EVENT_FIREBALL,
+ EVENT_FLIGHT,
+ EVENT_DEVOURING,
+ EVENT_FLAME,
+ EVENT_LAND,
+ EVENT_GROUND,
+ EVENT_FUSE,
+ EVENT_SUMMON
};
class boss_razorscale : public CreatureScript
@@ -59,59 +164,58 @@ public:
struct boss_razorscaleAI : public BossAI
{
- boss_razorscaleAI(Creature *pCreature) : BossAI(pCreature, TYPE_RAZORSCALE) {}
+ boss_razorscaleAI(Creature *pCreature) : BossAI(pCreature, TYPE_RAZORSCALE), phase(PHASE_NULL)
+ {
+ // Do not let Razorscale be affected by Battle Shout buff
+ me->ApplySpellImmune(0, IMMUNITY_ID, (SPELL_BATTLE_SHOUT), true);
+ me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);
+ me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip
+ }
- uint8 Phase;
+ Phases phase;
- uint32 FlameBreathTimer;
- uint32 FuseArmorTimer;
- uint32 DevouringFlameTimer;
- uint32 FlameBuffetTimer;
- uint32 SummonAddsTimer;
- uint32 WingBuffetTimer;
- uint32 FireballTimer;
- //uint32 StunTimer;
- //uint32 CastSpellsTimer;
+ uint32 EnrageTimer;
+ uint32 FlyCount;
- bool InitialSpawn;
- bool IsFlying;
+ Creature* Harpoon[4];
+ bool PermaGround;
+ bool Enraged;
void Reset()
{
- Phase = 1;
-
- FlyPhase(Phase, 0);
-
- FlameBreathTimer = 20000;
- DevouringFlameTimer = 2000;
- FuseArmorTimer = 15000;
- FlameBuffetTimer = 3000;
- SummonAddsTimer = 45000;
- WingBuffetTimer = 17000;
- FireballTimer = 18000;
- //StunTimer = 30000;
- //CastSpellsTimer = 0;
-
- InitialSpawn = true;
- IsFlying = true;
-
- me->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true);
- me->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true);
+ _Reset();
+ me->SetFlying(true);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_PASSIVE);
+ PermaGround = false;
}
void EnterCombat(Unit* /*who*/)
{
- DoScriptText(SAY_AGGRO, me);
- DoZoneInCombat();
+ _EnterCombat();
+ for (uint8 n = 0; n < RAID_MODE(2,4); ++n)
+ Harpoon[n] = me->SummonCreature(NPC_HARPOON, PosHarpoon[n], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 0);
+ me->SetSpeed(MOVE_FLIGHT, 3.0f, true);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ me->SetReactState(REACT_PASSIVE);
+ phase = PHASE_GROUND;
+ events.SetPhase(PHASE_GROUND);
+ FlyCount = 0;
+ EnrageTimer = 15*60*1000; // Enrage in 15 min
+ Enraged = false;
+ events.ScheduleEvent(EVENT_FLIGHT, 0, 0, PHASE_GROUND);
}
void JustDied(Unit* /*Killer*/)
{
- }
+ _JustDied();
- void KilledUnit(Unit * /*victim*/)
- {
- DoScriptText(SAY_KILL, me);
+ if (instance)
+ {
+ // A Quick Shave
+ if (FlyCount <= 2)
+ instance->DoCompleteAchievement(ACHIEVEMENT_QUICK_SHAVE);
+ }
}
void UpdateAI(const uint32 diff)
@@ -119,209 +223,594 @@ public:
if (!UpdateVictim())
return;
- if (me->GetPositionY() > -60 || me->GetPositionX() < 450) // Not Blizzlike, anti-exploit to prevent players from pulling bosses to vehicles.
- {
- me->RemoveAllAuras();
- me->DeleteThreatList();
- me->CombatStop(false);
- me->GetMotionMaster()->MoveTargetedHome();
- }
-
- // Victim is not controlled by a player (should never happen)
if (me->getVictim() && !me->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself())
me->Kill(me->getVictim());
- if (HealthBelowPct(99) && Phase == 1) // TODO: Only land (exit Phase 1) if brought down with harpoon guns! This is important!
+ events.Update(diff);
+
+ if (HealthBelowPct(50) && !PermaGround)
+ EnterPermaGround();
+
+ if (EnrageTimer <= diff && !Enraged)
{
- Phase = 2;
- DoScriptText(SAY_PHASE_2_TRANS, me); // Audio: "Move quickly! She won't remain grounded for long!"
+ DoCast(me, SPELL_BERSERK);
+ Enraged = true;
}
+ else EnrageTimer -= diff;
- if (HealthBelowPct(33) && Phase == 2) // Health under 33%, Razorscale can't fly anymore.
+ if (phase == PHASE_GROUND)
{
- Phase = 3;
- DoScriptText(SAY_PHASE_3_TRANS, me); // "Razorscale lands permanently!"
- // TODO: Cast Devouring Flame on all harpoon guns simultaneously, briefly after Phase 3 starts (lasts until the harpoon guns are destroyed)
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch(eventId)
+ {
+ case EVENT_FLIGHT:
+ phase = PHASE_FLIGHT;
+ events.SetPhase(PHASE_FLIGHT);
+ me->SetFlying(true);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ me->RemoveAllAuras();
+ me->GetMotionMaster()->MovePoint(0,RazorFlight);
+ events.ScheduleEvent(EVENT_FIREBALL, 7000, 0, PHASE_FLIGHT);
+ events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_FLIGHT);
+ events.ScheduleEvent(EVENT_SUMMON, 5000, 0, PHASE_FLIGHT);
+ events.ScheduleEvent(EVENT_GROUND, 75000, 0, PHASE_FLIGHT);
+ ++FlyCount;
+ return;
+ case EVENT_LAND:
+ me->SetFlying(false);
+ me->NearTeleportTo(586.966f, -175.534f, 391.517f, 1.692f);
+ DoCast(me, SPELL_STUN, true);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ if (Creature *pCommander = me->GetCreature(*me, instance->GetData64(DATA_EXP_COMMANDER)))
+ pCommander->AI()->DoAction(ACTION_GROUND_PHASE);
+ events.ScheduleEvent(EVENT_HARPOON, 0, 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_BREATH, 30000, 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_BUFFET, 33000, 0, PHASE_GROUND);
+ events.ScheduleEvent(EVENT_FLIGHT, 35000, 0, PHASE_GROUND);
+ return;
+ case EVENT_HARPOON:
+ for (uint8 n = 0; n < RAID_MODE(2,4); ++n)
+ if (Harpoon[n])
+ Harpoon[n]->CastSpell(me, SPELL_HARPOON, true);
+ events.ScheduleEvent(EVENT_HARPOON, 1500, 0, PHASE_GROUND);
+ return;
+ case EVENT_BREATH:
+ me->MonsterTextEmote(EMOTE_BREATH, 0, true);
+ DoCastAOE(SPELL_FLAMEBREATH);
+ events.CancelEvent(EVENT_HARPOON);
+ events.CancelEvent(EVENT_BREATH);
+ return;
+ case EVENT_BUFFET:
+ DoCastAOE(SPELL_WINGBUFFET);
+ for (uint8 n = 0; n < RAID_MODE(2,4); ++n)
+ if (Harpoon[n])
+ Harpoon[n]->CastSpell(Harpoon[n], SPELL_FLAMED, true);
+ events.CancelEvent(EVENT_BUFFET);
+ return;
+ }
+ }
}
+ if (phase == PHASE_PERMAGROUND)
+ {
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch(eventId)
+ {
+ case EVENT_FLAME:
+ DoCastAOE(SPELL_FLAMEBUFFET);
+ events.ScheduleEvent(EVENT_FLAME, 10000, 0, PHASE_PERMAGROUND);
+ return;
+ case EVENT_BREATH:
+ me->MonsterTextEmote(EMOTE_BREATH, 0, true);
+ DoCastVictim(SPELL_FLAMEBREATH);
+ events.ScheduleEvent(EVENT_BREATH, 20000, 0, PHASE_PERMAGROUND);
+ return;
+ case EVENT_FIREBALL:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
+ DoCast(pTarget, SPELL_FIREBALL);
+ events.ScheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_PERMAGROUND);
+ return;
+ case EVENT_DEVOURING:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
+ DoCast(pTarget, SPELL_DEVOURING_FLAME);
+ events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_PERMAGROUND);
+ return;
+ case EVENT_BUFFET:
+ DoCastAOE(SPELL_WINGBUFFET);
+ events.CancelEvent(EVENT_BUFFET);
+ return;
+ case EVENT_FUSE:
+ DoCastVictim(SPELL_FUSEARMOR);
+ events.ScheduleEvent(EVENT_FUSE, 10000, 0, PHASE_PERMAGROUND);
+ return;
+ }
+ }
- /*
- if (Phase == 2 && CastSpellsTimer > 0) // 5 seconds of spell casting, after stun breaks, during Phase 2
+ DoMeleeAttackIfReady();
+ }
+ else
{
- if (CastSpellsTimer <= diff) // 5 seconds are up
- Phase = 1; // Return to phase 1
- else
- CastSpellsTimer -= diff;
- }*/
+ if (uint32 eventId = events.ExecuteEvent())
+ {
+ switch(eventId)
+ {
+ case EVENT_GROUND:
+ phase = PHASE_GROUND;
+ events.SetPhase(PHASE_GROUND);
+ if (Harpoon[0])
+ Harpoon[0]->MonsterTextEmote(EMOTE_HARPOON, 0, true);
+ me->GetMotionMaster()->MovePoint(0,RazorGround);
+ events.ScheduleEvent(EVENT_LAND, 5500, 0, PHASE_GROUND);
+ return;
+ case EVENT_FIREBALL:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
+ DoCast(pTarget, SPELL_FIREBALL);
+ events.ScheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_FLIGHT);
+ return;
+ case EVENT_DEVOURING:
+ if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
+ DoCast(pTarget, SPELL_DEVOURING_FLAME);
+ events.ScheduleEvent(EVENT_DEVOURING, 10000, 0, PHASE_FLIGHT);
+ return;
+ case EVENT_SUMMON:
+ SummonAdds();
+ events.ScheduleEvent(EVENT_SUMMON, 45000, 0, PHASE_FLIGHT);
+ return;
+ }
+ }
+ }
+ }
+
+ void EnterPermaGround()
+ {
+ me->MonsterTextEmote(EMOTE_PERMA, 0, true);
+ phase = PHASE_PERMAGROUND;
+ events.SetPhase(PHASE_PERMAGROUND);
+ me->SetFlying(false);
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->RemoveAurasDueToSpell(SPELL_STUN);
+ me->SetSpeed(MOVE_FLIGHT, 1.0f, true);
+ PermaGround = true;
+ DoCastAOE(SPELL_FLAMEBREATH);
+ events.ScheduleEvent(EVENT_FLAME, 15000, 0, PHASE_PERMAGROUND);
+ events.RescheduleEvent(EVENT_DEVOURING, 15000, 0, PHASE_PERMAGROUND);
+ events.RescheduleEvent(EVENT_BREATH, 20000, 0, PHASE_PERMAGROUND);
+ events.RescheduleEvent(EVENT_FIREBALL, 3000, 0, PHASE_PERMAGROUND);
+ events.RescheduleEvent(EVENT_DEVOURING, 6000, 0, PHASE_PERMAGROUND);
+ events.RescheduleEvent(EVENT_BUFFET, 2500, 0, PHASE_PERMAGROUND);
+ events.RescheduleEvent(EVENT_FUSE, 5000, 0, PHASE_PERMAGROUND);
+ }
- FlyPhase(Phase, diff);
+ void SummonAdds()
+ {
+ // Adds will come in waves from mole machines. One mole can spawn a Dark Rune Watcher
+ // with 1-2 Guardians, or a lone Sentinel. Up to 4 mole machines can spawn adds at any given time.
+ uint8 random = urand(1,4);
+ for (uint8 i = 0; i < random; ++i)
+ {
+ float x = irand(540.0f, 640.0f); // Safe range is between 500 and 650
+ float y = irand(-230.0f, -195.0f); // Safe range is between -235 and -145
+ float z = 391.5f; // Ground level
+ me->SummonCreature(MOLE_MACHINE_TRIGGER, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN, 10000);
+ }
+ }
- if (Phase >= 2) // Ground Phase (Phase 3 = permanent ground phase)
+ void DoAction(const int32 action)
+ {
+ switch(action)
{
- if (FuseArmorTimer <= diff)
- {
- DoCastVictim(SPELL_FUSEARMOR);
- FuseArmorTimer = 10000;
- } else FuseArmorTimer -= diff;
+ case ACTION_EVENT_START:
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ DoZoneInCombat();
+ break;
+ }
+ }
+ };
- if (WingBuffetTimer <= diff)
- {
- DoCast(SPELL_WINGBUFFET);
- WingBuffetTimer = urand(7000,14000);
- } else WingBuffetTimer -= diff;
+};
- if (FireballTimer <= diff)
- {
- if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
- {
- me->SetInFront(pTarget);
- DoCast(pTarget, SPELL_FIREBALL);
- }
+/*====================================================================================
+====================================================================================*/
- FireballTimer = 18000;
- } else FireballTimer -= diff;
+class npc_expedition_commander : public CreatureScript
+{
+public:
+ npc_expedition_commander() : CreatureScript("npc_expedition_commander") { }
- if (FlameBreathTimer <= diff)
- {
- DoScriptText(EMOTE_BREATH, me); // TODO: "Razorscale takes a deep breath..."
- DoCastVictim(SPELL_FLAMEBREATH);
- FlameBreathTimer = 15000;
- WingBuffetTimer = 0;
- } else FlameBreathTimer -= diff;
+ bool OnGossipSelect(Player* pPlayer, Creature* pCreature, uint32 /*uiSender*/, uint32 uiAction)
+ {
+ pPlayer->PlayerTalkClass->ClearMenus();
+ InstanceScript* pInstance = pCreature->GetInstanceScript();
+ switch(uiAction)
+ {
+ case GOSSIP_ACTION_INFO_DEF:
+ if (pPlayer)
+ pPlayer->CLOSE_GOSSIP_MENU();
+ CAST_AI(npc_expedition_commanderAI, (pCreature->AI()))->uiPhase = 1;
+ break;
+ }
+ return true;
+ }
- if (Phase == 3)
+ bool OnGossipHello(Player* pPlayer, Creature* pCreature)
+ {
+ InstanceScript* pInstance = pCreature->GetInstanceScript();
+ if (pInstance && pInstance->GetBossState(TYPE_RAZORSCALE) == NOT_STARTED && pPlayer)
+ {
+ pPlayer->PrepareGossipMenu(pCreature);
+
+ pPlayer->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT,GOSSIP_ITEM_1,GOSSIP_SENDER_MAIN,GOSSIP_ACTION_INFO_DEF);
+ pPlayer->SEND_GOSSIP_MENU(13853, pCreature->GetGUID());
+ }
+ else pPlayer->SEND_GOSSIP_MENU(13910, pCreature->GetGUID());
+
+ return true;
+ }
+
+ CreatureAI* GetAI(Creature* pCreature) const
+ {
+ return new npc_expedition_commanderAI (pCreature);
+ }
+
+ struct npc_expedition_commanderAI : public ScriptedAI
+ {
+ npc_expedition_commanderAI(Creature* pCreature) : ScriptedAI(pCreature), summons(me)
+ {
+ pInstance = pCreature->GetInstanceScript();
+ greet = false;
+ }
+
+ InstanceScript* pInstance;
+ SummonList summons;
+
+ bool greet;
+ uint32 uiTimer;
+ uint8 uiPhase;
+ Creature* engineer[4];
+ Creature* defender[4];
+
+ void Reset()
+ {
+ uiTimer = 0;
+ uiPhase = 0;
+ greet = false;
+ }
+
+ void MoveInLineOfSight(Unit *who)
+ {
+ if (!greet && me->IsWithinDistInMap(who, 10.0f) && who->GetTypeId() == TYPEID_PLAYER)
+ {
+ DoScriptText(SAY_GREET, me);
+ greet = true;
+ }
+ }
+
+ void JustSummoned(Creature *summon)
+ {
+ summons.Summon(summon);
+ }
+
+ void DoAction(const int32 action)
+ {
+ switch(action)
+ {
+ case ACTION_GROUND_PHASE:
+ DoScriptText(SAY_GROUND_PHASE, me);
+ break;
+ }
+ }
+
+ void UpdateAI(const uint32 uiDiff)
+ {
+ ScriptedAI::UpdateAI(uiDiff);
+ if (uiTimer <= uiDiff)
+ {
+ switch(uiPhase)
{
- if (FlameBuffetTimer <= diff)
- {
- DoScriptText(EMOTE_BREATH, me);
- std::list<Unit*> pTargets;
- SelectTargetList(pTargets, RAID_MODE(3,9), SELECT_TARGET_RANDOM, 100, true);
- uint8 i = 0;
- for (std::list<Unit*>::const_iterator itr = pTargets.begin(); itr != pTargets.end();)
+ case 1:
+ pInstance->SetBossState(TYPE_RAZORSCALE, IN_PROGRESS);
+ summons.DespawnAll();
+ uiTimer = 1000;
+ uiPhase = 2;
+ break;
+ case 2:
+ for (uint8 n = 0; n < RAID_MODE(2,4); ++n)
+ {
+ engineer[n] = me->SummonCreature(NPC_ENGINEER, PosEngSpawn, TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000);
+ engineer[n]->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
+ engineer[n]->SetSpeed(MOVE_RUN, 0.5f);
+ engineer[n]->SetHomePosition(PosEngRepair[n]);
+ engineer[n]->GetMotionMaster()->MoveTargetedHome();
+ }
+ engineer[0]->MonsterYell(SAY_AGGRO_3, LANG_UNIVERSAL, 0);
+ uiPhase = 3;
+ uiTimer = 14000;
+ break;
+ case 3:
+ for (uint8 n = 0; n < 4; ++n)
{
- if (me->HasInArc(M_PI, *itr))
- {
- DoCast(*itr, SPELL_FLAMEBUFFET, true);
- ++i;
- }
- if (++itr == pTargets.end() || i == RAID_MODE(3,9))
- {
- AttackStart(*--itr); // seems to attack targets randomly during perma-ground phase..
- break;
- }
+ defender[n] = me->SummonCreature(NPC_DEFENDER, PosDefSpawn[n], TEMPSUMMON_CORPSE_TIMED_DESPAWN, 3000);
+ defender[n] ->RemoveUnitMovementFlag(MOVEMENTFLAG_WALKING);
+ defender[n] ->SetHomePosition(PosDefCombat[n]);
+ defender[n] ->GetMotionMaster()->MoveTargetedHome();
}
- FlameBuffetTimer = 25000;
- } else FlameBuffetTimer -= diff;
+ uiPhase = 4;
+ break;
+ case 4:
+ for (uint8 n = 0; n < RAID_MODE(2,4); ++n)
+ engineer[n]->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_USESTANDING);
+ for (uint8 n = 0; n < 4; ++n)
+ defender[n]->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_STATE_READY2H);
+ me->MonsterYell(SAY_AGGRO_2, LANG_UNIVERSAL, 0);
+ uiTimer = 16000;
+ uiPhase = 5;
+ break;
+ case 5:
+ if (Creature *pRazorscale = me->GetCreature(*me, pInstance->GetData64(TYPE_RAZORSCALE)))
+ pRazorscale->AI()->DoAction(ACTION_EVENT_START);
+ engineer[0]->MonsterYell(SAY_AGGRO_1, LANG_UNIVERSAL, 0);
+ uiPhase = 6;
+ break;
}
-
- DoMeleeAttackIfReady();
}
- else if (Phase == 1) //Flying Phase
- {
- if (InitialSpawn)
- SummonAdds();
+ else uiTimer -= uiDiff;
+ }
+ };
- InitialSpawn = false;
+};
- if (FireballTimer <= diff)
- {
- if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
- {
- me->SetInFront(pTarget);
- DoCast(pTarget, SPELL_FIREBALL);
- }
- FireballTimer = 18000;
- } else FireballTimer -= diff;
+class npc_mole_machine_trigger : public CreatureScript
+{
+public:
+ npc_mole_machine_trigger() : CreatureScript("npc_mole_machine_trigger") { }
- if (DevouringFlameTimer <= diff)
- {
- if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
- {
- me->SetInFront(pTarget);
- DoCast(pTarget, SPELL_DEVOURINGFLAME);
- }
+ CreatureAI* GetAI(Creature* pCreature) const
+ {
+ return new npc_mole_machine_triggerAI (pCreature);
+ }
+
+ struct npc_mole_machine_triggerAI : public Scripted_NoMovementAI
+ {
+ npc_mole_machine_triggerAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature)
+ {
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED);
+ me->SetVisibility(VISIBILITY_OFF);
+ }
- DevouringFlameTimer = 10000;
- } else DevouringFlameTimer -= diff;
+ GameObject* MoleMachine;
+ uint32 SummonTimer;
- if (SummonAddsTimer <= diff)
- SummonAdds();
- else SummonAddsTimer -= diff;
- }
+ void Reset()
+ {
+ if (MoleMachine = me->SummonGameObject(GOB_MOLE_MACHINE,me->GetPositionX(),me->GetPositionY(),me->GetPositionZ(),urand(0,6),0,0,0,0,300))
+ MoleMachine->SetGoState(GO_STATE_ACTIVE);
+ SummonTimer = 6000;
}
- void SummonAdds()
+ void UpdateAI(const uint32 uiDiff)
{
- // TODO: Adds will come in waves from mole machines. One mole can spawn a Dark Rune Watcher
- // with 1-2 Guardians, or a lone Sentinel. Up to 4 mole machines can spawn adds at any given time.
- uint8 random = urand(1,4);
- for (uint8 i = 0; i < random; ++i)
+ if (!UpdateVictim())
+ return;
+
+ if (SummonTimer <= uiDiff)
{
- if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
+ float x = me->GetPositionX();
+ float y = me->GetPositionY();
+ float z = me->GetPositionZ();
+
+ // One mole can spawn a Dark Rune Watcher with 1-2 Guardians, or a lone Sentinel
+ if (!(rand()%2))
{
- float x = std::max(500.0f, std::min(650.0f, pTarget->GetPositionX() + irand(-20,20))); // Safe range is between 500 and 650
- float y = std::max(-235.0f, std::min(-145.0f, pTarget->GetPositionY() + irand(-20,20))); // Safe range is between -235 and -145
- float z = me->GetBaseMap()->GetHeight(x, y, MAX_HEIGHT); // Ground level
- // TODO: Spawn drillers, then spawn adds 5 seconds later
- if (Creature *pAdd = me->SummonCreature(NPC_DARK_RUNE_SENTINEL, x, y, z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000))
- pAdd->AI()->AttackStart(pTarget);
+ me->SummonCreature(NPC_DARK_RUNE_WATCHER, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000);
+ uint8 random = urand(1,2);
+ for (uint8 i = 0; i < random; ++i)
+ me->SummonCreature(NPC_DARK_RUNE_GUARDIAN, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000);
}
+ else me->SummonCreature(NPC_DARK_RUNE_SENTINEL, x, y, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 3000);
+
+ SummonTimer = 15000;
}
- SummonAddsTimer = 45000;
+ else SummonTimer -= uiDiff;
}
- void FlyPhase(uint8 Phase, const uint32 /*diff*/)
+ void JustSummoned(Creature *summon)
{
- const float x = 587.54f;
- const float y = -174.92f;
- const float GroundLevel = me->GetBaseMap()->GetHeight(x, y, MAX_HEIGHT);
- const float FlightHeight = GroundLevel + 4.0f; // TODO: Fly out of range of attacks (442 is sufficient height for this), minus ~(10*number of harpoon gun chains attached to Razorscale)
+ summon->AI()->DoZoneInCombat();
+ }
+ };
- if (Phase == 1) // Always flying during Phase 1
- IsFlying = true;
+};
- me->SetFlying(IsFlying);
- me->SendMovementFlagUpdate();
- me->SetSpeed(MOVE_WALK, IsFlying ? 7.0f : 2.5f, IsFlying);
- if (Phase == 1) // Flying Phase
+class npc_devouring_flame : public CreatureScript
+{
+public:
+ npc_devouring_flame() : CreatureScript("npc_devouring_flame") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const
+ {
+ return new npc_devouring_flameAI (pCreature);
+ }
+
+ struct npc_devouring_flameAI : public Scripted_NoMovementAI
+ {
+ npc_devouring_flameAI(Creature* pCreature) : Scripted_NoMovementAI(pCreature)
+ {
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED);
+ me->SetDisplayId(11686);
+ }
+
+ void Reset()
+ {
+ DoCast(me, SPELL_FLAME_GROUND);
+ }
+ };
+
+};
+
+
+class npc_darkrune_watcher : public CreatureScript
+{
+public:
+ npc_darkrune_watcher() : CreatureScript("npc_darkrune_watcher") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const
+ {
+ return new npc_darkrune_watcherAI (pCreature);
+ }
+
+ struct npc_darkrune_watcherAI : public ScriptedAI
+ {
+ npc_darkrune_watcherAI(Creature *pCreature) : ScriptedAI(pCreature)
+ {
+ pInstance = pCreature->GetInstanceScript();
+ }
+
+ InstanceScript *pInstance;
+
+ uint32 ChainTimer;
+ uint32 LightTimer;
+
+ void Reset()
+ {
+ ChainTimer = urand(10000, 15000);
+ LightTimer = urand(1000, 3000);
+ }
+
+ void UpdateAI(const uint32 uiDiff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ if (ChainTimer <= uiDiff)
{
- if (me->GetPositionZ() > FlightHeight) // Correct height, stop moving
- me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
- else // Incorrect height
- {
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
- me->GetMotionMaster()->MovePoint(0, x, y, FlightHeight + 0.5f); // Fly to slightly above (x, y, FlightHeight)
- }
+ DoCastVictim(SPELL_CHAIN_LIGHTNING);
+ ChainTimer = urand(10000, 15000);
}
- else // Ground Phases
+ else ChainTimer -= uiDiff;
+
+ if (LightTimer <= uiDiff)
+ {
+ DoCastVictim(SPELL_LIGHTNING_BOLT);
+ LightTimer = urand(5000, 7000);
+ }
+ else LightTimer -= uiDiff;
+
+ DoMeleeAttackIfReady();
+ }
+ };
+
+};
+
+
+class npc_darkrune_guardian : public CreatureScript
+{
+public:
+ npc_darkrune_guardian() : CreatureScript("npc_darkrune_guardian") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const
+ {
+ return new npc_darkrune_guardianAI (pCreature);
+ }
+
+ struct npc_darkrune_guardianAI : public ScriptedAI
+ {
+ npc_darkrune_guardianAI(Creature *pCreature) : ScriptedAI(pCreature)
+ {
+ pInstance = pCreature->GetInstanceScript();
+ }
+
+ InstanceScript *pInstance;
+
+ uint32 StormTimer;
+
+ void Reset()
+ {
+ StormTimer = urand(3000, 6000);
+ }
+
+ void UpdateAI(const uint32 uiDiff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ if (StormTimer <= uiDiff)
+ {
+ DoCastVictim(SPELL_STORMSTRIKE);
+ StormTimer = urand(4000, 8000);
+ }
+ else StormTimer -= uiDiff;
+
+ DoMeleeAttackIfReady();
+ }
+ };
+
+};
+
+
+class npc_darkrune_sentinel : public CreatureScript
+{
+public:
+ npc_darkrune_sentinel() : CreatureScript("npc_darkrune_sentinel") { }
+
+ CreatureAI* GetAI(Creature* pCreature) const
+ {
+ return new npc_darkrune_sentinelAI (pCreature);
+ }
+
+ struct npc_darkrune_sentinelAI : public ScriptedAI
+ {
+ npc_darkrune_sentinelAI(Creature *pCreature) : ScriptedAI(pCreature)
+ {
+ pInstance = pCreature->GetInstanceScript();
+ }
+
+ InstanceScript *pInstance;
+
+ uint32 HeroicTimer;
+ uint32 WhirlTimer;
+ uint32 ShoutTimer;
+
+ void Reset()
+ {
+ HeroicTimer = urand(4000, 8000);
+ WhirlTimer = urand(20000, 25000);
+ ShoutTimer = urand(15000, 30000);
+ }
+
+ void UpdateAI(const uint32 uiDiff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ if (HeroicTimer <= uiDiff)
+ {
+ DoCastVictim(SPELL_HEROIC_STRIKE);
+ HeroicTimer = urand(4000, 6000);
+ }
+ else HeroicTimer -= uiDiff;
+
+ if (WhirlTimer <= uiDiff)
{
- const float CurrentGroundLevel = me->GetBaseMap()->GetHeight(me->GetPositionX(), me->GetPositionY(), MAX_HEIGHT);
- //if (StunTimer == 30000) // Only fly around if not stunned.
- //{
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
- if (IsFlying && me->GetPositionZ() > CurrentGroundLevel) // Fly towards the ground
- me->GetMotionMaster()->MovePoint(0, me->GetPositionX(), me->GetPositionY(), CurrentGroundLevel);
- // TODO: Swoop up just before landing
- else
- IsFlying = false; // Landed, no longer flying
- //}
-
- //if (!IsFlying &&Phase == 2 && CastSpellsTimer == 0 && StunTimer >= diff) // No longer flying, non-permanent ground phase, and not casting spells
- //{
- // TODO: Add stun here. 30 second stun after Razorscale is grounded by harpoon guns
- //StunTimer -= diff;
- //}
- //else if (StunTimer != 30000 && (StunTimer < 0 || Phase == 3)) // Stun is active, and needs to end. Note: Stun breaks instantly if Phase 3 starts
- //{
- // TODO: Remove stun here.
- //DoCast(SPELL_WINGBUFFET); // "Used in the beginning of the phase."
- //WingBuffetTimer = urand(7000,14000);
- //StunTimer = 30000; // Reinitialize the stun timer
- //if (Phase == 2) // Non-permanent ground phase
- // CastSpellsTimer = 5000; // Five seconds of casting before returning to Phase 1
- //}
+ DoCastVictim(SPELL_WHIRLWIND);
+ WhirlTimer = urand(20000, 25000);
}
+ else WhirlTimer -= uiDiff;
+
+ if (ShoutTimer <= uiDiff)
+ {
+ DoCast(me, SPELL_BATTLE_SHOUT);
+ ShoutTimer = urand(30000, 40000);
+ }
+ else ShoutTimer -= uiDiff;
+
+ DoMeleeAttackIfReady();
}
};
@@ -331,4 +820,10 @@ public:
void AddSC_boss_razorscale()
{
new boss_razorscale();
-}
+ new npc_expedition_commander();
+ new npc_mole_machine_trigger();
+ new npc_devouring_flame();
+ new npc_darkrune_watcher();
+ new npc_darkrune_guardian();
+ new npc_darkrune_sentinel();
+} \ No newline at end of file
diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp
index af70b828f23..3b78ce16ec4 100644
--- a/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp
+++ b/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp
@@ -53,6 +53,7 @@ public:
uint64 uiLeviathanGUID;
uint64 uiIgnisGUID;
uint64 uiRazorscaleGUID;
+ uint64 uiExpCommanderGUID;
uint64 uiXT002GUID;
uint64 uiAssemblyGUIDs[3];
uint64 uiKologarnGUID;
@@ -77,6 +78,7 @@ public:
SetBossNumber(MAX_ENCOUNTER);
uiIgnisGUID = 0;
uiRazorscaleGUID = 0;
+ uiExpCommanderGUID = 0;
uiXT002GUID = 0;
uiKologarnGUID = 0;
uiAuriayaGUID = 0;
@@ -123,6 +125,9 @@ public:
case NPC_RAZORSCALE:
uiRazorscaleGUID = pCreature->GetGUID();
break;
+ case NPC_EXPEDITION_COMMANDER:
+ uiExpCommanderGUID = pCreature->GetGUID();
+ return;
case NPC_XT002:
uiXT002GUID = pCreature->GetGUID();
break;
@@ -227,57 +232,57 @@ public:
}
bool SetBossState(uint32 type, EncounterState state)
- {
- if (!InstanceScript::SetBossState(type, state))
- return false;
+ {
+ if (!InstanceScript::SetBossState(type, state))
+ return false;
- switch (type)
+ switch (type)
+ {
+ case TYPE_LEVIATHAN:
+ if (state == IN_PROGRESS)
{
- case TYPE_LEVIATHAN:
- if (state == IN_PROGRESS)
- {
- for (uint8 uiI = 0; uiI < 7; ++uiI)
- HandleGameObject(uiLeviathanDoor[uiI],false);
- }
- else
- {
- for (uint8 uiI = 0; uiI < 7; ++uiI)
- HandleGameObject(uiLeviathanDoor[uiI],true);
- }
- break;
- case TYPE_IGNIS:
- case TYPE_RAZORSCALE:
- case TYPE_XT002:
- case TYPE_ASSEMBLY:
- case TYPE_AURIAYA:
- case TYPE_MIMIRON:
- case TYPE_VEZAX:
- case TYPE_YOGGSARON:
- break;
- case TYPE_KOLOGARN:
- if (state == DONE)
- if (GameObject* pGO = instance->GetGameObject(uiKologarnChestGUID))
- pGO->SetRespawnTime(pGO->GetRespawnDelay());
- break;
- case TYPE_HODIR:
- if (state == DONE)
- if (GameObject* pGO = instance->GetGameObject(uiHodirChestGUID))
- pGO->SetRespawnTime(pGO->GetRespawnDelay());
- break;
- case TYPE_THORIM:
- if (state == DONE)
- if (GameObject* pGO = instance->GetGameObject(uiThorimChestGUID))
- pGO->SetRespawnTime(pGO->GetRespawnDelay());
- break;
- case TYPE_FREYA:
- if (state == DONE)
- if (GameObject* pGO = instance->GetGameObject(uiFreyaChestGUID))
- pGO->SetRespawnTime(pGO->GetRespawnDelay());
- break;
- }
-
- return true;
- }
+ for (uint8 uiI = 0; uiI < 7; ++uiI)
+ HandleGameObject(uiLeviathanDoor[uiI],false);
+ }
+ else
+ {
+ for (uint8 uiI = 0; uiI < 7; ++uiI)
+ HandleGameObject(uiLeviathanDoor[uiI],true);
+ }
+ break;
+ case TYPE_IGNIS:
+ case TYPE_RAZORSCALE:
+ case TYPE_XT002:
+ case TYPE_ASSEMBLY:
+ case TYPE_AURIAYA:
+ case TYPE_MIMIRON:
+ case TYPE_VEZAX:
+ case TYPE_YOGGSARON:
+ break;
+ case TYPE_KOLOGARN:
+ if (state == DONE)
+ if (GameObject* pGO = instance->GetGameObject(uiKologarnChestGUID))
+ pGO->SetRespawnTime(pGO->GetRespawnDelay());
+ break;
+ case TYPE_HODIR:
+ if (state == DONE)
+ if (GameObject* pGO = instance->GetGameObject(uiHodirChestGUID))
+ pGO->SetRespawnTime(pGO->GetRespawnDelay());
+ break;
+ case TYPE_THORIM:
+ if (state == DONE)
+ if (GameObject* pGO = instance->GetGameObject(uiThorimChestGUID))
+ pGO->SetRespawnTime(pGO->GetRespawnDelay());
+ break;
+ case TYPE_FREYA:
+ if (state == DONE)
+ if (GameObject* pGO = instance->GetGameObject(uiFreyaChestGUID))
+ pGO->SetRespawnTime(pGO->GetRespawnDelay());
+ break;
+ }
+
+ return true;
+ }
void SetData(uint32 type, uint32 data)
{
@@ -317,6 +322,8 @@ public:
case TYPE_YOGGSARON: return uiYoggSaronGUID;
case TYPE_ALGALON: return uiAlgalonGUID;
+ // razorscale expedition commander
+ case DATA_EXP_COMMANDER: return uiExpCommanderGUID;
// Assembly of Iron
case DATA_STEELBREAKER: return uiAssemblyGUIDs[0];
case DATA_MOLGEIM: return uiAssemblyGUIDs[1];
diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h
index 8029d661b80..f890355cac3 100644
--- a/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h
+++ b/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h
@@ -43,10 +43,13 @@ enum eTypes
DATA_BRUNDIR = 22,
DATA_RUNEMASTER_MOLGEIM = 23,
DATA_STORMCALLER_BRUNDIR = 24,
+ DATA_EXP_COMMANDER = 25,
+
NPC_LEVIATHAN = 33113,
NPC_IGNIS = 33118,
NPC_RAZORSCALE = 33186,
+ NPC_EXPEDITION_COMMANDER = 33210,
NPC_XT002 = 33293,
NPC_STEELBREAKER = 32867,
NPC_MOLGEIM = 32927,