aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLopin <davca.hr@seznam.cz>2011-05-19 15:09:06 +0200
committerSupabad <Supabad.trinity@gmail.com>2011-05-19 15:09:06 +0200
commit9a7720e1845fe094ff1c7f05f5096394932dcb32 (patch)
tree9b79cfb3e109cb80d4ed3119799d798da7cddfdb /src
parentfb4913da3d900cc35bf3a636bd60dd1dafefd9de (diff)
Scripts/Ulduar: Add script for Hodir encounter.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/game/Scripting/ScriptLoader.cpp2
-rw-r--r--src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp969
-rw-r--r--src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp72
-rw-r--r--src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h28
4 files changed, 1016 insertions, 55 deletions
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp
index 3b896ce192b..482b8f51c73 100755
--- a/src/server/game/Scripting/ScriptLoader.cpp
+++ b/src/server/game/Scripting/ScriptLoader.cpp
@@ -424,6 +424,7 @@ void AddSC_boss_assembly_of_iron();
void AddSC_boss_general_vezax();
void AddSC_ulduar_teleporter();
void AddSC_boss_mimiron();
+void AddSC_boss_hodir();
void AddSC_instance_ulduar();
void AddSC_boss_keleseth(); //Utgarde Keep
void AddSC_boss_skarvald_dalronn();
@@ -1118,6 +1119,7 @@ void AddNorthrendScripts()
AddSC_boss_kologarn();
AddSC_ulduar_teleporter();
AddSC_boss_mimiron();
+ AddSC_boss_hodir();
AddSC_instance_ulduar();
AddSC_boss_keleseth(); //Utgarde Keep
AddSC_boss_skarvald_dalronn();
diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp
index 902305dacc1..3a6a4803fc0 100644
--- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp
+++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_hodir.cpp
@@ -19,73 +19,964 @@
#include "ScriptedCreature.h"
#include "ulduar.h"
-enum Yells
+/* #TODO: Achievements
+ Storm Cloud (Shaman ability)
+ Destroying of Toasty Fires
+*/
+
+enum HodirYells
{
- SAY_AGGRO = -1603210,
- SAY_SLAY_1 = -1603211,
- SAY_SLAY_2 = -1603212,
- SAY_FLASH_FREEZE = -1603213,
- SAY_STALACTITE = -1603214,
- SAY_DEATH = -1603215,
- SAY_BERSERK = -1603216,
- SAY_YS_HELP = -1603217,
- SAY_HARD_MODE_MISSED = -1603218,
+ SAY_AGGRO = -1603210,
+ SAY_SLAY_1 = -1603211,
+ SAY_SLAY_2 = -1603212,
+ SAY_FLASH_FREEZE = -1603213,
+ SAY_STALACTITE = -1603214,
+ SAY_DEATH = -1603215,
+ SAY_BERSERK = -1603216,
+ SAY_YS_HELP = -1603217,
+ SAY_HARD_MODE_FAILED = -1603218,
+
+ EMOTE_FREEZE = -1603209,
+ EMOTE_BLOWS = -1603219,
};
-class boss_hodir : public CreatureScript
+enum HodirSpells
{
-public:
- boss_hodir() : CreatureScript("boss_hodir") { }
+ // Hodir
+ SPELL_FROZEN_BLOWS = 62478,
+ SPELL_FLASH_FREEZE = 61968,
+ SPELL_FLASH_FREEZE_VISUAL = 62148,
+ SPELL_BITING_COLD = 62038,
+ SPELL_BITING_COLD_TRIGGERED = 62039, // Needed for Achievement Getting Cold In Here
+ SPELL_BITING_COLD_DAMAGE = 62188,
+ SPELL_FREEZE = 62469,
+ SPELL_ICICLE = 62234,
+ SPELL_ICICLE_SNOWDRIFT = 62462,
+ SPELL_BLOCK_OF_ICE = 61969, // Player + Helper
+ SPELL_SUMMON_FLASH_FREEZE_HELPER = 61989, // Helper
+ SPELL_SUMMON_BLOCK_OF_ICE = 61970, // Player + Helper
+ SPELL_FLASH_FREEZE_HELPER = 61990, // Helper
+ SPELL_FLASH_FREEZE_KILL = 62226,
+ SPELL_ICICLE_FALL = 69428,
+ SPELL_FALL_DAMAGE = 62236,
+ SPELL_FALL_SNOWDRIFT = 62460,
+ SPELL_BERSERK = 47008,
+ SPELL_ICE_SHARD = 62457,
+ SPELL_ICE_SHARD_HIT = 65370,
- CreatureAI* GetAI(Creature* pCreature) const
- {
- return new boss_hodirAI(pCreature);
- }
+ // Druids
+ SPELL_WRATH = 62793,
+ SPELL_STARLIGHT = 62807,
- struct boss_hodirAI : public BossAI
- {
- boss_hodirAI(Creature *pCreature) : BossAI(pCreature, TYPE_HODIR)
+ // Shamans
+ SPELL_LAVA_BURST = 61924,
+ SPELL_STORM_CLOUD = 65123,
+
+ // Mages
+ SPELL_FIREBALL = 61909,
+ SPELL_CONJURE_FIRE = 62823,
+ SPELL_MELT_ICE = 64528,
+ SPELL_SINGED = 62821,
+
+ // Priests
+ SPELL_SMITE = 61923,
+ SPELL_GREATER_HEAL = 62809,
+ SPELL_DISPEL_MAGIC = 63499,
+};
+
+enum HodirNPC
+{
+ NPC_ICE_BLOCK = 32938,
+ NPC_FLASH_FREEZE = 32926,
+ NPC_SNOWPACKED_ICICLE = 33174,
+ NPC_ICICLE = 33169,
+ NPC_ICICLE_SNOWDRIFT = 33173,
+};
+
+enum HodirGameObjects
+{
+ GO_TOASTY_FIRE = 194300,
+ GO_SNOWDRIFT = 194173,
+};
+
+enum HodirEvents
+{
+ // Hodir
+ EVENT_FREEZE = 1,
+ EVENT_FLASH_FREEZE = 2,
+ EVENT_FLASH_FREEZE_EFFECT = 3,
+ EVENT_ICICLE = 4,
+ EVENT_BLOWS = 5,
+ EVENT_RARE_CACHE = 6,
+ EVENT_BERSERK = 7,
+
+ // Priest
+ EVENT_HEAL = 8,
+ EVENT_DISPEL_MAGIC = 9,
+
+ // Shaman
+ EVENT_STORM_CLOUD = 10,
+
+ // Druid
+ EVENT_STARLIGHT = 11,
+
+ // Mage
+ EVENT_CONJURE_FIRE = 12,
+ EVENT_MELT_ICE = 13,
+};
+
+enum HodirActions
+{
+ ACTION_I_HAVE_THE_COOLEST_FRIENDS = 1,
+ ACTION_CHEESE_THE_FREEZE = 2,
+};
+
+#define ACHIEVEMENT_CHEESE_THE_FREEZE RAID_MODE(2961, 2962)
+#define ACHIEVEMENT_GETTING_COLD_IN_HERE RAID_MODE(2967, 2968)
+#define ACHIEVEMENT_THIS_CACHE_WAS_RARE RAID_MODE(3182, 3184)
+#define ACHIEVEMENT_COOLEST_FRIENDS RAID_MODE(2963, 2965)
+#define FRIENDS_COUNT RAID_MODE(4, 8)
+#define DATA_GETTING_COLD_IN_HERE 29672968 // 2967, 2968 are achievement IDs
+
+const Position SummonPositions[8] =
+{
+ { 1983.75f, -243.36f, 432.767f, 1.57f }, // Field Medic Penny && Battle-Priest Eliza
+ { 1999.90f, -230.49f, 432.767f, 1.57f }, // Eivi Nightfeather && Tor Greycloud
+ { 2010.06f, -243.45f, 432.767f, 1.57f }, // Elementalist Mahfuun && Spiritwalker Tara
+ { 2021.12f, -236.65f, 432.767f, 1.57f }, // Missy Flamecuffs && Amira Blazeweaver
+ { 2028.10f, -244.66f, 432.767f, 1.57f }, // Field Medic Jessi && Battle-Priest Gina
+ { 2014.18f, -232.80f, 432.767f, 1.57f }, // Ellie Nightfeather && Kar Greycloud
+ { 1992.90f, -237.54f, 432.767f, 1.57f }, // Elementalist Avuun && Spiritwalker Yona
+ { 1976.60f, -233.53f, 432.767f, 1.57f }, // Sissy Flamecuffs && Veesha Blazeweaver
+};
+
+uint32 Entry[8] =
+{
+ 32897, 33325, 33328, 32893, 33326, 32901, 32900, 33327,
+};
+
+class npc_flash_freeze : public CreatureScript
+{
+ public:
+ npc_flash_freeze() : CreatureScript("npc_flash_freeze") { }
+
+ struct npc_flash_freezeAI : public ScriptedAI
{
- }
+ npc_flash_freezeAI(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = me->GetInstanceScript();
+ me->SetDisplayId(me->GetCreatureInfo()->Modelid2);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED);
+ }
+
+ InstanceScript* instance;
- void Reset()
+ uint64 targetGUID;
+ uint32 checkDespawnTimer;
+
+ void Reset()
+ {
+ targetGUID = 0;
+ checkDespawnTimer = 1000;
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim() || me->getVictim()->HasAura(SPELL_BLOCK_OF_ICE) || me->getVictim()->HasAura(SPELL_FLASH_FREEZE_HELPER))
+ return;
+
+ if (checkDespawnTimer <= diff)
+ {
+ if (Unit* target = ObjectAccessor::GetUnit(*me, targetGUID))
+ if (!target->isAlive())
+ me->DisappearAndDie();
+ checkDespawnTimer = 2500;
+ }
+ else
+ checkDespawnTimer -= diff;
+ }
+
+ void IsSummonedBy(Unit* summoner)
+ {
+ targetGUID = summoner->GetGUID();
+ me->SetInCombatWith(summoner);
+ me->AddThreat(summoner, 250.0f);
+ if (Unit* target = ObjectAccessor::GetUnit(*me, targetGUID))
+ {
+ DoCast(target, SPELL_BLOCK_OF_ICE, true);
+ // Prevents to have Ice Block on other place than target is
+ me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation());
+ if (target->GetTypeId() == TYPEID_PLAYER)
+ if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(TYPE_HODIR) : 0))
+ Hodir->AI()->DoAction(ACTION_CHEESE_THE_FREEZE);
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
{
- _Reset();
+ return new npc_flash_freezeAI(creature);
}
+};
- void KilledUnit(Unit * /*victim*/)
+class npc_ice_block : public CreatureScript
+{
+ public:
+ npc_ice_block() : CreatureScript("npc_ice_block") { }
+
+ struct npc_ice_blockAI : public ScriptedAI
{
- DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me);
- }
+ npc_ice_blockAI(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = me->GetInstanceScript();
+ me->SetDisplayId(me->GetCreatureInfo()->Modelid2);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED);
+ targetGUID = 0;
+ }
+
+ InstanceScript* instance;
+
+ uint64 targetGUID;
+
+ void IsSummonedBy(Unit* summoner)
+ {
+ targetGUID = summoner->GetGUID();
+ summoner->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED);
+ me->SetInCombatWith(summoner);
+ me->AddThreat(summoner, 250.0f);
+ summoner->AddThreat(me, 250.0f);
+ if (Creature* target = ObjectAccessor::GetCreature(*me, targetGUID))
+ {
+ DoCast(target, SPELL_FLASH_FREEZE_HELPER, true);
+ // Prevents to have Ice Block on other place than target is
+ me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation());
+ }
+ }
- void JustDied(Unit * /*victim*/)
+ void DamageTaken(Unit* who, uint32& damage)
+ {
+ if (Creature* Helper = ObjectAccessor::GetCreature(*me, targetGUID))
+ {
+ Helper->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_STUNNED | UNIT_FLAG_PACIFIED);
+
+ if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(TYPE_HODIR) : 0))
+ {
+ if (!Hodir->isInCombat())
+ {
+ Hodir->SetReactState(REACT_AGGRESSIVE);
+ Hodir->AI()->DoZoneInCombat();
+ Hodir->AI()->AttackStart(who);
+ }
+
+ Helper->AI()->AttackStart(Hodir);
+ }
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
{
- DoScriptText(SAY_DEATH, me);
- _JustDied();
+ return new npc_ice_blockAI(creature);
}
+};
+
+class boss_hodir : public CreatureScript
+{
+ public:
+ boss_hodir() : CreatureScript("boss_hodir") { }
+
+ struct boss_hodirAI : public BossAI
+ {
+ boss_hodirAI(Creature* creature) : BossAI(creature, TYPE_HODIR)
+ {
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ uint32 gettingColdInHereTimer;
+
+ bool gettingColdInHere;
+ bool cheeseTheFreeze;
+ bool iHaveTheCoolestFriends;
+ bool iCouldSayThatThisCacheWasRare;
+
+ void Reset()
+ {
+ _Reset();
+ me->SetReactState(REACT_PASSIVE);
+
+ for (uint8 n = 0; n < FRIENDS_COUNT; ++n)
+ if (Creature* FrozenHelper = me->SummonCreature(Entry[n], SummonPositions[n], TEMPSUMMON_MANUAL_DESPAWN))
+ FrozenHelper->CastSpell(FrozenHelper, SPELL_SUMMON_FLASH_FREEZE_HELPER, true);
+ }
+
+ void EnterCombat(Unit* who)
+ {
+ _EnterCombat();
+ DoScriptText(SAY_AGGRO, me);
+ DoCast(me, SPELL_BITING_COLD, true);
+
+ gettingColdInHereTimer = 1000;
+ gettingColdInHere = true;
+ cheeseTheFreeze = true;
+ iHaveTheCoolestFriends = true;
+ iCouldSayThatThisCacheWasRare = true;
+
+ events.ScheduleEvent(EVENT_ICICLE, 2000);
+ events.ScheduleEvent(EVENT_FREEZE, 25000);
+ events.ScheduleEvent(EVENT_BLOWS, urand(60000, 65000));
+ events.ScheduleEvent(EVENT_FLASH_FREEZE, 45000);
+ events.ScheduleEvent(EVENT_RARE_CACHE, 180000);
+ events.ScheduleEvent(EVENT_BERSERK, 480000);
+ }
+
+ void KilledUnit(Unit* who)
+ {
+ if (!urand(0, 3))
+ DoScriptText(RAND(SAY_SLAY_1, SAY_SLAY_2), me);
+ }
+
+ void DamageTaken(Unit* who, uint32& damage)
+ {
+ if (damage >= me->GetHealth())
+ {
+ damage = 0;
+ _JustDied();
+ DoScriptText(SAY_DEATH, me);
+
+ me->RemoveAllAuras();
+ me->RemoveAllAttackers();
+ me->AttackStop();
+ me->SetReactState(REACT_PASSIVE);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_DISABLE_MOVE);
+ me->InterruptNonMeleeSpells(true);
+ me->StopMoving();
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveIdle();
+ me->SetControlled(true, UNIT_STAT_STUNNED);
+ me->CombatStop(true);
+
+ me->setFaction(35);
+ me->DespawnOrUnsummon(10000);
+ }
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_FREEZE:
+ DoCastAOE(SPELL_FREEZE);
+ events.ScheduleEvent(EVENT_FREEZE, urand(30000, 45000));
+ break;
+ case EVENT_ICICLE:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_ICICLE);
+ events.ScheduleEvent(EVENT_ICICLE, RAID_MODE(5500, 3500));
+ break;
+ case EVENT_FLASH_FREEZE:
+ DoScriptText(SAY_FLASH_FREEZE, me);
+ DoScriptText(EMOTE_FREEZE, me);
+ for (uint8 n = 0; n < RAID_MODE(2, 3); ++n)
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ target->CastSpell(target, SPELL_ICICLE_SNOWDRIFT, true);
+ DoCast(SPELL_FLASH_FREEZE);
+ events.DelayEvents(9000);
+ events.ScheduleEvent(EVENT_FLASH_FREEZE_EFFECT, 500);
+ break;
+ case EVENT_FLASH_FREEZE_EFFECT:
+ {
+ std::list<Creature*> IcicleSnowdriftList;
+ GetCreatureListWithEntryInGrid(IcicleSnowdriftList, me, NPC_SNOWPACKED_ICICLE, 100.0f);
+ for (std::list<Creature*>::iterator itr = IcicleSnowdriftList.begin(); itr != IcicleSnowdriftList.end(); ++itr)
+ (*itr)->CastSpell(me, SPELL_FLASH_FREEZE_VISUAL, true);
+ FlashFreeze();
+ events.CancelEvent(EVENT_FLASH_FREEZE_EFFECT);
+ events.ScheduleEvent(EVENT_FLASH_FREEZE, urand(25000, 35000));
+ break;
+ }
+ case EVENT_BLOWS:
+ DoScriptText(SAY_STALACTITE, me);
+ DoScriptText(EMOTE_BLOWS, me);
+ DoCast(me, SPELL_FROZEN_BLOWS);
+ events.ScheduleEvent(EVENT_BLOWS, urand(60000, 65000));
+ break;
+ case EVENT_RARE_CACHE:
+ DoScriptText(SAY_HARD_MODE_FAILED, me);
+ iCouldSayThatThisCacheWasRare = false;
+ events.CancelEvent(EVENT_RARE_CACHE);
+ break;
+ case EVENT_BERSERK:
+ DoScriptText(SAY_BERSERK, me);
+ DoCast(me, SPELL_BERSERK, true);
+ events.CancelEvent(EVENT_BERSERK);
+ break;
+ }
+ }
+
+ if (gettingColdInHereTimer <= diff && gettingColdInHere)
+ {
+ std::list<HostileReference*> ThreatList = me->getThreatManager().getThreatList();
+ for (std::list<HostileReference*>::const_iterator itr = ThreatList.begin(); itr != ThreatList.end(); ++itr)
+ if (Unit* target = ObjectAccessor::GetUnit(*me, (*itr)->getUnitGuid()))
+ if (Aura* BitingColdAura = target->GetAura(SPELL_BITING_COLD_TRIGGERED))
+ if (target->GetTypeId() == TYPEID_PLAYER && BitingColdAura->GetStackAmount() > 2)
+ me->AI()->SetData(DATA_GETTING_COLD_IN_HERE, 0);
+ gettingColdInHereTimer = 1000;
+ }
+ else
+ gettingColdInHereTimer -= diff;
- void EnterCombat(Unit* /*pWho*/)
+ DoMeleeAttackIfReady();
+ }
+
+ void DoAction(const int32 action)
+ {
+ switch (action)
+ {
+ case ACTION_I_HAVE_THE_COOLEST_FRIENDS:
+ iHaveTheCoolestFriends = false;
+ break;
+ case ACTION_CHEESE_THE_FREEZE:
+ cheeseTheFreeze = false;
+ break;
+ default:
+ break;
+ }
+ }
+
+ void FlashFreeze()
+ {
+ std::list<Unit*> TargetList;
+ Trinity::AnyUnfriendlyUnitInObjectRangeCheck checker(me, me, 150.0f);
+ Trinity::UnitListSearcher<Trinity::AnyUnfriendlyUnitInObjectRangeCheck> searcher(me, TargetList, checker);
+ me->VisitNearbyObject(100.0f, searcher);
+ for (std::list<Unit*>::iterator itr = TargetList.begin(); itr != TargetList.end(); ++itr)
+ {
+ Unit* target = *itr;
+ if (!target || !target->isAlive() || GetClosestCreatureWithEntry(target, NPC_SNOWPACKED_ICICLE, 5.0f))
+ continue;
+
+ if (target->HasAura(SPELL_FLASH_FREEZE_HELPER) || target->HasAura(SPELL_BLOCK_OF_ICE))
+ {
+ me->CastSpell(target, SPELL_FLASH_FREEZE_KILL, true);
+ continue;
+ }
+
+ target->CastSpell(target, SPELL_SUMMON_BLOCK_OF_ICE, true);
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new boss_hodirAI (creature);
+ };
+};
+
+class npc_icicle : public CreatureScript
+{
+ public:
+ npc_icicle() : CreatureScript("npc_icicle") { }
+
+ struct npc_icicleAI : public ScriptedAI
+ {
+ npc_icicleAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetDisplayId(me->GetCreatureInfo()->Modelid1);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_PACIFIED | UNIT_FLAG_NOT_SELECTABLE);
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ uint32 icicleTimer;
+
+ void Reset()
+ {
+ icicleTimer = 2500;
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (icicleTimer <= diff)
+ {
+ if (me->GetEntry() == NPC_ICICLE_SNOWDRIFT)
+ {
+ DoCast(me, SPELL_FALL_SNOWDRIFT);
+ DoCast(me, SPELL_ICICLE_FALL);
+ }
+ else if (me->GetEntry() == NPC_ICICLE)
+ {
+ DoCast(me, SPELL_ICICLE_FALL);
+ DoCast(me, SPELL_FALL_DAMAGE, true);
+ }
+ icicleTimer = 10000;
+ }
+ else
+ icicleTimer -= diff;
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_icicleAI(creature);
+ };
+};
+
+class npc_snowpacked_icicle : public CreatureScript
+{
+ public:
+ npc_snowpacked_icicle() : CreatureScript("npc_snowpacked_icicle") { }
+
+ struct npc_snowpacked_icicleAI : public ScriptedAI
{
- DoScriptText(SAY_AGGRO, me);
- _EnterCombat();
+ npc_snowpacked_icicleAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetDisplayId(me->GetCreatureInfo()->Modelid2);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED);
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ uint32 despawnTimer;
+
+ void Reset()
+ {
+ despawnTimer = 12000;
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (despawnTimer <= diff)
+ {
+ if (GameObject* Snowdrift = me->FindNearestGameObject(GO_SNOWDRIFT, 2.0f))
+ me->RemoveGameObject(Snowdrift, true);
+ me->DespawnOrUnsummon();
+ }
+ else
+ despawnTimer -= diff;
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_snowpacked_icicleAI(creature);
+ };
+};
+
+class npc_hodir_priest : public CreatureScript
+{
+ public:
+ npc_hodir_priest() : CreatureScript("npc_hodir_priest") { }
+
+ struct npc_hodir_priestAI : public ScriptedAI
+ {
+ npc_hodir_priestAI(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = me->GetInstanceScript();
+ }
+
+ void Reset()
+ {
+ events.Reset();
+ events.ScheduleEvent(EVENT_HEAL, urand(4000, 8000));
+ events.ScheduleEvent(EVENT_DISPEL_MAGIC, urand(15000, 20000));
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED))
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ if (HealthBelowPct(30))
+ DoCast(me, SPELL_GREATER_HEAL);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_HEAL:
+ DoCastAOE(SPELL_GREATER_HEAL);
+ events.ScheduleEvent(EVENT_HEAL, urand(7500, 10000));
+ break;
+ case EVENT_DISPEL_MAGIC:
+ {
+ std::list<Unit*> TargetList;
+ Trinity::AnyFriendlyUnitInObjectRangeCheck checker(me, me, 30.0f);
+ Trinity::UnitListSearcher<Trinity::AnyFriendlyUnitInObjectRangeCheck> searcher(me, TargetList, checker);
+ me->VisitNearbyObject(30.0f, searcher);
+ for (std::list<Unit*>::iterator itr = TargetList.begin(); itr != TargetList.end(); ++itr)
+ if ((*itr)->HasAura(SPELL_FREEZE))
+ DoCast(*itr, SPELL_DISPEL_MAGIC, true);
+ events.ScheduleEvent(EVENT_DISPEL_MAGIC, urand(15000, 20000));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ DoSpellAttackIfReady(SPELL_SMITE);
+ }
+
+ void JustDied(Unit* who)
+ {
+ if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(TYPE_HODIR) : 0))
+ Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS);
+ }
+
+ private:
+ InstanceScript* instance;
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_hodir_priestAI(creature);
+ };
+};
+
+class npc_hodir_shaman : public CreatureScript
+{
+ public:
+ npc_hodir_shaman() : CreatureScript("npc_hodir_shaman") { }
+
+ struct npc_hodir_shamanAI : public ScriptedAI
+ {
+ npc_hodir_shamanAI(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = me->GetInstanceScript();
+ }
+
+ void Reset()
+ {
+ events.Reset();
+ events.ScheduleEvent(EVENT_STORM_CLOUD, urand(10000, 12500));
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED))
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_STORM_CLOUD:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true))
+ DoCast(target, SPELL_STORM_CLOUD, true);
+ events.ScheduleEvent(EVENT_STORM_CLOUD, urand(15000, 20000));
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoSpellAttackIfReady(SPELL_LAVA_BURST);
+ }
+
+ void JustDied(Unit* who)
+ {
+ if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(TYPE_HODIR) : 0))
+ Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS);
+ }
+
+ private:
+ InstanceScript* instance;
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_hodir_shamanAI(creature);
+ };
+};
+
+class npc_hodir_druid : public CreatureScript
+{
+ public:
+ npc_hodir_druid() : CreatureScript("npc_hodir_druid") { }
+
+ struct npc_hodir_druidAI : public ScriptedAI
+ {
+ npc_hodir_druidAI(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = me->GetInstanceScript();
+ }
+
+ void Reset()
+ {
+ events.Reset();
+ events.ScheduleEvent(EVENT_STARLIGHT, urand(15000, 17500));
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED))
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_STARLIGHT:
+ DoCast(me, SPELL_STARLIGHT, true);
+ events.ScheduleEvent(EVENT_STARLIGHT, urand(25000, 35000));
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoSpellAttackIfReady(SPELL_WRATH);
+ }
+
+ void JustDied(Unit* who)
+ {
+ if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(TYPE_HODIR) : 0))
+ Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS);
+ }
+
+ private:
+ InstanceScript* instance;
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_hodir_druidAI(creature);
+ };
+};
+
+class npc_hodir_mage : public CreatureScript
+{
+ public:
+ npc_hodir_mage() : CreatureScript("npc_hodir_mage") { }
+
+ struct npc_hodir_mageAI : public ScriptedAI
+ {
+ npc_hodir_mageAI(Creature* creature) : ScriptedAI(creature)
+ {
+ instance = me->GetInstanceScript();
+ }
+
+ void Reset()
+ {
+ events.Reset();
+ events.ScheduleEvent(EVENT_CONJURE_FIRE, urand(10000, 12500));
+ events.ScheduleEvent(EVENT_MELT_ICE, 5000);
+ }
+
+ void UpdateAI(uint32 const diff)
+ {
+ if (!UpdateVictim() || me->HasUnitState(UNIT_STAT_STUNNED) || me->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_STUNNED))
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STAT_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_CONJURE_FIRE:
+ DoCast(me, SPELL_CONJURE_FIRE, true);
+ events.ScheduleEvent(EVENT_CONJURE_FIRE, urand(35000, 40000));
+ break;
+ case EVENT_MELT_ICE:
+ if (Creature* FlashFreeze = me->FindNearestCreature(NPC_FLASH_FREEZE, 50.0f, true))
+ DoCast(FlashFreeze, SPELL_MELT_ICE, true);
+ events.ScheduleEvent(EVENT_MELT_ICE, urand(10000, 15000));
+ break;
+ }
+ }
+
+ DoSpellAttackIfReady(SPELL_FIREBALL);
+ }
+
+ void JustDied(Unit* who)
+ {
+ if (Creature* Hodir = ObjectAccessor::GetCreature(*me, instance ? instance->GetData64(TYPE_HODIR) : 0))
+ Hodir->AI()->DoAction(ACTION_I_HAVE_THE_COOLEST_FRIENDS);
+ }
+
+ private:
+ InstanceScript* instance;
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_hodir_mageAI(creature);
+ };
+};
+
+class npc_toasty_fire : public CreatureScript
+{
+ public:
+ npc_toasty_fire() : CreatureScript("npc_toasty_fire") { }
+
+ struct npc_toasty_fireAI : public ScriptedAI
+ {
+ npc_toasty_fireAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetDisplayId(me->GetCreatureInfo()->Modelid2);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE | UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED);
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ void Reset()
+ {
+ DoCast(me, SPELL_SINGED, true);
+ }
+
+ void SpellHit(Unit* who, const SpellEntry* spell)
+ {
+ if (spell->Id == SPELL_BLOCK_OF_ICE || spell->Id == SPELL_ICE_SHARD || spell->Id == SPELL_ICE_SHARD_HIT)
+ {
+ if (GameObject* ToastyFire = me->FindNearestGameObject(GO_TOASTY_FIRE, 1.0f))
+ me->RemoveGameObject(ToastyFire, true);
+ me->DespawnOrUnsummon();
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_toasty_fireAI(creature);
+ };
+};
+
+class spell_biting_cold : public SpellScriptLoader
+{
+ public:
+ spell_biting_cold() : SpellScriptLoader("spell_biting_cold") { }
+
+ class spell_biting_cold_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_biting_cold_AuraScript);
+
+ void HandleEffectPeriodic(AuraEffect const* aurEff)
+ {
+ Unit* caster = GetCaster();
+ Unit* target = GetTarget();
+ bool found = false;
+
+ if (!caster || !target)
+ return;
+
+ for (TargetList::iterator itr = listOfTargets.begin(); itr != listOfTargets.end(); ++itr)
+ {
+ if (itr->first != target->GetGUID())
+ return;
+
+ if (itr->second >= 4)
+ {
+ target->CastSpell(target, SPELL_BITING_COLD_TRIGGERED, true);
+ itr->second = 1;
+ }
+ else
+ {
+ if (target->isMoving())
+ itr->second = 1;
+ else
+ itr->second++;
+ }
+ found = true;
+ break;
+ }
+
+ if (!found)
+ listOfTargets.push_back(std::make_pair(target->GetGUID(), 1));
+ }
+
+ void Register()
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_biting_cold_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+
+ private:
+ typedef std::list< std::pair<uint64, uint8> > TargetList;
+ TargetList listOfTargets;
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_biting_cold_AuraScript();
}
+};
+
+class spell_biting_cold_dot : public SpellScriptLoader
+{
+public:
+ spell_biting_cold_dot() : SpellScriptLoader("spell_biting_cold_dot") { }
+
+ class spell_biting_cold_dot_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_biting_cold_dot_AuraScript);
- void UpdateAI(const uint32 diff)
+ void HandleEffectPeriodic(AuraEffect const* aurEff)
{
- if (!UpdateVictim())
+ Unit* caster = GetCaster();
+ if (!caster)
return;
- //SPELLS TODO:
- //
- DoMeleeAttackIfReady();
+ int32 damage = int32(200 * pow(2.0f, GetStackAmount()));
+ caster->CastCustomSpell(caster, SPELL_BITING_COLD_DAMAGE, &damage, NULL, NULL, true);
- EnterEvadeIfOutOfCombatArea(diff);
+ if (caster->isMoving())
+ caster->RemoveAuraFromStack(SPELL_BITING_COLD_TRIGGERED);
+ }
+
+ void Register()
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_biting_cold_dot_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
}
};
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_biting_cold_dot_AuraScript();
+ }
};
void AddSC_boss_hodir()
{
new boss_hodir();
-}
+ new npc_icicle();
+ new npc_snowpacked_icicle();
+ new npc_hodir_priest();
+ new npc_hodir_shaman();
+ new npc_hodir_druid();
+ new npc_hodir_mage();
+ new npc_toasty_fire();
+ new npc_ice_block();
+ new npc_flash_freeze();
+ new spell_biting_cold();
+ new spell_biting_cold_dot();
+} \ 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 5cc635f4f02..71c5d927c65 100644
--- a/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp
+++ b/src/server/scripts/Northrend/Ulduar/ulduar/instance_ulduar.cpp
@@ -39,7 +39,7 @@ public:
struct instance_ulduar_InstanceMapScript : public InstanceScript
{
- instance_ulduar_InstanceMapScript(InstanceMap* map) : InstanceScript(map) {}
+ instance_ulduar_InstanceMapScript(InstanceMap* map) : InstanceScript(map) { }
uint32 uiEncounter[MAX_ENCOUNTER];
std::string m_strInstData;
@@ -73,6 +73,8 @@ public:
uint64 uiHodirChestGUID;
uint64 uiFreyaChestGUID;
+ uint32 TeamInInstance;
+
std::set<uint64> mRubbleSpawns;
void Initialize()
@@ -103,6 +105,7 @@ public:
uiFreyaChestGUID = 0;
uiLeviathanGateGUID = 0;
uiVezaxDoorGUID = 0;
+ TeamInInstance = 0;
memset(uiEncounter, 0, sizeof(uiEncounter));
memset(uiAssemblyGUIDs, 0, sizeof(uiAssemblyGUIDs));
@@ -120,9 +123,23 @@ public:
return false;
}
+ void OnPlayerEnter(Player* player)
+ {
+ if (!TeamInInstance)
+ TeamInInstance = player->GetTeam();
+ }
+
void OnCreatureCreate(Creature* creature)
{
- switch(creature->GetEntry())
+ if (!TeamInInstance)
+ {
+ Map::PlayerList const& Players = instance->GetPlayers();
+ if (!Players.isEmpty())
+ if (Player* player = Players.begin()->getSource())
+ TeamInInstance = player->GetTeam();
+ }
+
+ switch (creature->GetEntry())
{
case NPC_LEVIATHAN:
uiLeviathanGUID = creature->GetGUID();
@@ -199,13 +216,46 @@ public:
case NPC_ALGALON:
uiAlgalonGUID = creature->GetGUID();
break;
+ // Hodir's Helper NPCs
+ case NPC_EIVI_NIGHTFEATHER:
+ if (TeamInInstance == HORDE)
+ creature->UpdateEntry(NPC_TOR_GREYCLOUD, HORDE);
+ break;
+ case NPC_ELLIE_NIGHTFEATHER:
+ if (TeamInInstance == HORDE)
+ creature->UpdateEntry(NPC_KAR_GREYCLOUD, HORDE);
+ break;
+ case NPC_ELEMENTALIST_MAHFUUN:
+ if (TeamInInstance == HORDE)
+ creature->UpdateEntry(NPC_SPIRITWALKER_TARA, HORDE);
+ break;
+ case NPC_ELEMENTALIST_AVUUN:
+ if (TeamInInstance == HORDE)
+ creature->UpdateEntry(NPC_SPIRITWALKER_YONA, HORDE);
+ break;
+ case NPC_MISSY_FLAMECUFFS:
+ if (TeamInInstance == HORDE)
+ creature->UpdateEntry(NPC_AMIRA_BLAZEWEAVER, HORDE);
+ break;
+ case NPC_SISSY_FLAMECUFFS:
+ if (TeamInInstance == HORDE)
+ creature->UpdateEntry(NPC_VEESHA_BLAZEWEAVER, HORDE);
+ break;
+ case NPC_FIELD_MEDIC_PENNY:
+ if (TeamInInstance == HORDE)
+ creature->UpdateEntry(NPC_BATTLE_PRIEST_ELIZA, HORDE);
+ break;
+ case NPC_FIELD_MEDIC_JESSI:
+ if (TeamInInstance == HORDE)
+ creature->UpdateEntry(NPC_BATTLE_PRIEST_GINA, HORDE);
+ break;
}
}
void OnGameObjectCreate(GameObject* go)
{
- switch(go->GetEntry())
+ switch (go->GetEntry())
{
case GO_KOLOGARN_CHEST_HERO:
case GO_KOLOGARN_CHEST:
@@ -221,7 +271,7 @@ public:
break;
case GO_THORIM_CHEST_HERO:
case GO_THORIM_CHEST:
- uiThorimChestGUID =go->GetGUID();
+ uiThorimChestGUID = go->GetGUID();
break;
case GO_HODIR_CHEST_HERO:
case GO_HODIR_CHEST:
@@ -276,22 +326,22 @@ public:
void ProcessEvent(GameObject* /*go*/, uint32 eventId)
{
// Flame Leviathan's Tower Event triggers
- Creature* pFlameLeviathan = instance->GetCreature(uiLeviathanGUID);
+ Creature* FlameLeviathan = instance->GetCreature(uiLeviathanGUID);
- if (pFlameLeviathan && pFlameLeviathan->isAlive()) //No leviathan, no event triggering ;)
- switch(eventId)
+ if (FlameLeviathan && FlameLeviathan->isAlive()) //No leviathan, no event triggering ;)
+ switch (eventId)
{
case EVENT_TOWER_OF_STORM_DESTROYED:
- pFlameLeviathan->AI()->DoAction(1);
+ FlameLeviathan->AI()->DoAction(1);
break;
case EVENT_TOWER_OF_FROST_DESTROYED:
- pFlameLeviathan->AI()->DoAction(2);
+ FlameLeviathan->AI()->DoAction(2);
break;
case EVENT_TOWER_OF_FLAMES_DESTROYED:
- pFlameLeviathan->AI()->DoAction(3);
+ FlameLeviathan->AI()->DoAction(3);
break;
case EVENT_TOWER_OF_LIFE_DESTROYED:
- pFlameLeviathan->AI()->DoAction(4);
+ FlameLeviathan->AI()->DoAction(4);
break;
}
}
diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h
index 7580d97186f..e83d388c4a9 100644
--- a/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h
+++ b/src/server/scripts/Northrend/Ulduar/ulduar/ulduar.h
@@ -18,7 +18,7 @@
#ifndef DEF_ULDUAR_H
#define DEF_ULDUAR_H
-enum eTypes
+enum UlduarTypes
{
MAX_ENCOUNTER = 15,
@@ -51,7 +51,7 @@ enum eTypes
DATA_RIGHT_ARM,
};
-enum eNPCs
+enum UlduarNPCs
{
NPC_LEVIATHAN = 33113,
NPC_IGNIS = 33118,
@@ -81,9 +81,27 @@ enum eNPCs
NPC_LEVIATHAN_MKII = 33432,
NPC_VX_001 = 33651,
NPC_AERIAL_COMMAND_UNIT = 33670,
+
+ // Hodir's Helper NPCs
+ NPC_TOR_GREYCLOUD = 32941,
+ NPC_KAR_GREYCLOUD = 33333,
+ NPC_EIVI_NIGHTFEATHER = 33325,
+ NPC_ELLIE_NIGHTFEATHER = 32901,
+ NPC_SPIRITWALKER_TARA = 33332,
+ NPC_SPIRITWALKER_YONA = 32950,
+ NPC_ELEMENTALIST_MAHFUUN = 33328,
+ NPC_ELEMENTALIST_AVUUN = 32900,
+ NPC_AMIRA_BLAZEWEAVER = 33331,
+ NPC_VEESHA_BLAZEWEAVER = 32946,
+ NPC_MISSY_FLAMECUFFS = 32893,
+ NPC_SISSY_FLAMECUFFS = 33327,
+ NPC_BATTLE_PRIEST_ELIZA = 32948,
+ NPC_BATTLE_PRIEST_GINA = 33330,
+ NPC_FIELD_MEDIC_PENNY = 32897,
+ NPC_FIELD_MEDIC_JESSI = 33326,
};
-enum eGameObjects
+enum UlduarGameObjects
{
GO_KOLOGARN_CHEST_HERO = 195047,
GO_KOLOGARN_CHEST = 195046,
@@ -106,7 +124,7 @@ enum eGameObjects
GO_RAZOR_BROKEN_HARPOON = 194565,
};
-enum eTowerEvents
+enum UlduarTowerEvents
{
EVENT_TOWER_OF_STORM_DESTROYED = 21031,
EVENT_TOWER_OF_FROST_DESTROYED = 21032,
@@ -114,7 +132,7 @@ enum eTowerEvents
EVENT_TOWER_OF_LIFE_DESTROYED = 21030
};
-enum eAchievementCriteria
+enum UlduarAchievementCriteria
{
ACHIEVEMENT_UNBROKEN_10 = 10044, // Leviathan
ACHIEVEMENT_UNBROKEN_25 = 10045,