diff options
author | Shauren <shauren.trinity@gmail.com> | 2011-05-20 22:20:11 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2011-05-20 22:20:11 +0200 |
commit | 0ab5cdef2e1b700c60fbe3c807206c3369b7fc1a (patch) | |
tree | 6a7ba51e49a34e24ff33b25f0b1fde622b717289 /src | |
parent | 3d620db0c18135fc5d750f591f0e779231ee17aa (diff) |
Scripts/Icecrown Citadel:
* Added Valithria Dreamwalker script
* Fixed Mutated Abomination on heroic mode at Professor Putricide
* Fixed saving heroic attempts to db
Diffstat (limited to 'src')
7 files changed, 1484 insertions, 55 deletions
diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 482b8f51c73..969294733d5 100755 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -476,6 +476,7 @@ void AddSC_boss_rotface(); void AddSC_boss_professor_putricide(); void AddSC_boss_blood_prince_council(); void AddSC_boss_blood_queen_lana_thel(); +void AddSC_boss_valithria_dreamwalker(); void AddSC_boss_sindragosa(); void AddSC_icecrown_citadel_teleport(); void AddSC_instance_icecrown_citadel(); @@ -1171,6 +1172,7 @@ void AddNorthrendScripts() AddSC_boss_professor_putricide(); AddSC_boss_blood_prince_council(); AddSC_boss_blood_queen_lana_thel(); + AddSC_boss_valithria_dreamwalker(); AddSC_boss_sindragosa(); AddSC_icecrown_citadel_teleport(); AddSC_instance_icecrown_citadel(); diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 8d98ae1a5a9..5791d311281 100755 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -4099,6 +4099,24 @@ void SpellMgr::LoadSpellCustomAttr() spellInfo->AreaGroupId = 0; ++count; break; + case 70588: // Suppression + case 70602: // Corruption + spellInfo->AttributesEx |= SPELL_ATTR1_STACK_FOR_DIFF_CASTERS; + ++count; + break; + case 70715: // Column of Frost (visual marker) + spellInfo->DurationIndex = 32; // 6 seconds (missing) + ++count; + break; + case 71085: // Mana Void (periodic aura) + spellInfo->DurationIndex = 9; // 30 seconds (missing) + ++count; + break; + case 70936: // Summon Suppressor + spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; + spellInfo->EffectImplicitTargetB[0] = 0; + ++count; + break; case 71357: // Order Whelp spellInfo->EffectRadiusIndex[0] = 22; ++count; diff --git a/src/server/scripts/Northrend/CMakeLists.txt b/src/server/scripts/Northrend/CMakeLists.txt index 79f36fe3763..88e551cd6b6 100644 --- a/src/server/scripts/Northrend/CMakeLists.txt +++ b/src/server/scripts/Northrend/CMakeLists.txt @@ -165,6 +165,7 @@ set(scripts_STAT_SRCS Northrend/IcecrownCitadel/boss_professor_putricide.cpp Northrend/IcecrownCitadel/boss_blood_prince_council.cpp Northrend/IcecrownCitadel/boss_blood_queen_lana_thel.cpp + Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp Northrend/IcecrownCitadel/boss_sindragosa.cpp Northrend/zuldrak.cpp Northrend/icecrown.cpp diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 2844376fe21..af5d50fc11c 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -932,6 +932,34 @@ class spell_putricide_slime_puddle : public SpellScriptLoader } }; +// this is here only because on retail you dont actually enter HEROIC mode for ICC +class spell_putricide_slime_puddle_aura : public SpellScriptLoader +{ + public: + spell_putricide_slime_puddle_aura() : SpellScriptLoader("spell_putricide_slime_puddle_aura") { } + + class spell_putricide_slime_puddle_aura_SpellScript : public SpellScript + { + PrepareSpellScript(spell_putricide_slime_puddle_aura_SpellScript); + + void ReplaceAura() + { + if (Unit* target = GetHitUnit()) + GetCaster()->AddAura((GetCaster()->GetMap()->GetSpawnMode() & 1) ? 72456 : 70346, target); + } + + void Register() + { + OnHit += SpellHitFn(spell_putricide_slime_puddle_aura_SpellScript::ReplaceAura); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_putricide_slime_puddle_aura_SpellScript(); + } +}; + class spell_putricide_unstable_experiment : public SpellScriptLoader { public: @@ -1516,6 +1544,7 @@ void AddSC_boss_professor_putricide() new spell_putricide_ooze_channel(); new spell_putricide_expunged_gas(); new spell_putricide_slime_puddle(); + new spell_putricide_slime_puddle_aura(); new spell_putricide_unstable_experiment(); new spell_putricide_ooze_summon(); new spell_putricide_ooze_eruption_searcher(); diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp new file mode 100644 index 00000000000..d99b5395a74 --- /dev/null +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_valithria_dreamwalker.cpp @@ -0,0 +1,1324 @@ +/* + * Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ObjectMgr.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellAuraEffects.h" +#include "Cell.h" +#include "CellImpl.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" +#include "icecrown_citadel.h" + +enum Texts +{ + // The Lich King + SAY_LICH_KING_INTRO = 0, + + // Valithria Dreamwalker + SAY_VALITHRIA_ENTER_COMBAT = 0, + SAY_VALITHRIA_DREAM_PORTAL = 1, + SAY_VALITHRIA_75_PERCENT = 2, + SAY_VALITHRIA_25_PERCENT = 3, + SAY_VALITHRIA_DEATH = 4, + SAY_VALITHRIA_PLAYER_DEATH = 5, + SAY_VALITHRIA_BERSERK = 6, + SAY_VALITHRIA_SUCCESS = 7, +}; + +enum Spells +{ + // Valithria Dreamwalker + SPELL_COPY_DAMAGE = 71948, + SPELL_DREAM_PORTAL_VISUAL_PRE = 71304, + SPELL_NIGHTMARE_PORTAL_VISUAL_PRE = 71986, + SPELL_NIGHTMARE_CLOUD = 71970, + SPELL_NIGHTMARE_CLOUD_VISUAL = 71939, + SPELL_PRE_SUMMON_DREAM_PORTAL = 72224, + SPELL_PRE_SUMMON_NIGHTMARE_PORTAL = 72480, + SPELL_SUMMON_DREAM_PORTAL = 71305, + SPELL_SUMMON_NIGHTMARE_PORTAL = 71987, + SPELL_DREAMWALKERS_RAGE = 71189, + SPELL_DREAM_SLIP = 71196, + SPELL_ACHIEVEMENT_CHECK = 72706, + SPELL_CLEAR_ALL = 71721, + SPELL_AWARD_REPUTATION_BOSS_KILL = 73843, + SPELL_CORRUPTION_VALITHRIA = 70904, + + // The Lich King + SPELL_TIMER_GLUTTONOUS_ABOMINATION = 70915, + SPELL_TIMER_SUPPRESSER = 70912, + SPELL_TIMER_BLISTERING_ZOMBIE = 70914, + SPELL_TIMER_RISEN_ARCHMAGE = 70916, + SPELL_TIMER_BLAZING_SKELETON = 70913, + SPELL_SUMMON_SUPPRESSER = 70936, + SPELL_RECENTLY_SPAWNED = 72954, + SPELL_SPAWN_CHEST = 71207, + + // Risen Archmage + SPELL_CORRUPTION = 70602, + SPELL_FROSTBOLT_VOLLEY = 70759, + SPELL_MANA_VOID = 71179, + SPELL_COLUMN_OF_FROST = 70704, + SPELL_COLUMN_OF_FROST_DAMAGE = 70702, + + // Blazing Skeleton + SPELL_FIREBALL = 70754, + SPELL_LEY_WASTE = 69325, + + // Suppresser + SPELL_SUPPRESSION = 70588, + + // Blistering Zombie + SPELL_ACID_BURST = 70744, + + // Gluttonous Abomination + SPELL_GUT_SPRAY = 70633, + SPELL_ROT_WORM_SPAWNER = 70675, + + // Dream Cloud + SPELL_EMERALD_VIGOR = 70873, + + // Nightmare Cloud + SPELL_TWISTED_NIGHTMARE = 71941, +}; + +#define SUMMON_PORTAL RAID_MODE<uint32>(SPELL_PRE_SUMMON_DREAM_PORTAL, SPELL_PRE_SUMMON_DREAM_PORTAL, \ + SPELL_PRE_SUMMON_NIGHTMARE_PORTAL, SPELL_PRE_SUMMON_NIGHTMARE_PORTAL) + +#define EMERALD_VIGOR RAID_MODE<uint32>(SPELL_EMERALD_VIGOR, SPELL_EMERALD_VIGOR, \ + SPELL_TWISTED_NIGHTMARE, SPELL_TWISTED_NIGHTMARE) + +enum Events +{ + // Valithria Dreamwalker + EVENT_INTRO_TALK = 1, + EVENT_BERSERK, + EVENT_DREAM_PORTAL, + EVENT_DREAM_SLIP, + + // The Lich King + EVENT_GLUTTONOUS_ABOMINATION_SUMMONER, + EVENT_SUPPRESSER_SUMMONER, + EVENT_BLISTERING_ZOMBIE_SUMMONER, + EVENT_RISEN_ARCHMAGE_SUMMONER, + EVENT_BLAZING_SKELETON_SUMMONER, + + // Risen Archmage + EVENT_FROSTBOLT_VOLLEY, + EVENT_MANA_VOID, + EVENT_COLUMN_OF_FROST, + + // Blazing Skeleton + EVENT_FIREBALL, + EVENT_LEY_WASTE, + + // Suppresser + EVENT_SUPPRESSION, + + // Gluttonous Abomination + EVENT_GUT_SPRAY, + + // Dream Cloud + // Nightmare Cloud + EVENT_CHECK_PLAYER, + EVENT_EXPLODE, +}; + +enum Actions +{ + ACTION_ENTER_COMBAT = 1, + MISSED_PORTALS = 2, + ACTION_DEATH = 3, +}; + +Position const ValithriaSpawnPos = {4210.813f, 2484.443f, 364.9558f, 0.01745329f}; + +class RisenArchmageCheck +{ + public: + // look for all permanently spawned Risen Archmages that are not yet in combat + bool operator()(Creature* creature) + { + return creature->isAlive() && creature->GetEntry() == NPC_RISEN_ARCHMAGE && + creature->GetDBTableGUIDLow() && !creature->isInCombat(); + } +}; + +struct ManaVoidSelector : public std::unary_function<Unit*, bool> +{ + explicit ManaVoidSelector(WorldObject const* source) : _source(source) { } + + bool operator()(Unit* unit) const + { + return unit->getPowerType() == POWER_MANA && _source->GetDistance(unit) > 15.0f; + } + + WorldObject const* _source; +}; + +class DelayedCastEvent : public BasicEvent +{ + public: + DelayedCastEvent(Creature* trigger, uint32 spellId, uint64 originalCaster, uint32 despawnTime) : _trigger(trigger), _spellId(spellId), _originalCaster(originalCaster), _despawnTime(despawnTime) + { + } + + bool Execute(uint64 /*time*/, uint32 /*diff*/) + { + _trigger->CastSpell(_trigger, _spellId, false, NULL, NULL, _originalCaster); + if (_despawnTime) + _trigger->DespawnOrUnsummon(_despawnTime); + return true; + } + + private: + Creature* _trigger; + uint64 _originalCaster; + uint32 _spellId; + uint32 _despawnTime; +}; + +class AuraRemoveEvent : public BasicEvent +{ + public: + AuraRemoveEvent(Creature* trigger, uint32 spellId) : _trigger(trigger), _spellId(spellId) + { + } + + bool Execute(uint64 /*time*/, uint32 /*diff*/) + { + _trigger->RemoveAurasDueToSpell(_spellId); + return true; + } + + private: + Creature* _trigger; + uint32 _spellId; +}; + +class SummonTargetSelector +{ + public: + bool operator()(Unit* unit) const + { + return unit->HasAura(SPELL_RECENTLY_SPAWNED); + } +}; + +class ValithriaDespawner : public BasicEvent +{ + public: + explicit ValithriaDespawner(Creature* creature) : _creature(creature) + { + } + + bool Execute(uint64 /*currTime*/, uint32 /*diff*/) + { + Trinity::CreatureWorker<ValithriaDespawner> worker(_creature, *this); + _creature->VisitNearbyGridObject(333.0f, worker); + return true; + } + + void operator()(Creature* creature) const + { + switch (creature->GetEntry()) + { + case NPC_VALITHRIA_DREAMWALKER: + if (InstanceScript* instance = creature->GetInstanceScript()) + instance->SendEncounterUnit(ENCOUNTER_FRAME_REMOVE, creature); + break; + case NPC_BLAZING_SKELETON: + case NPC_SUPPRESSER: + case NPC_BLISTERING_ZOMBIE: + case NPC_GLUTTONOUS_ABOMINATION: + case NPC_MANA_VOID: + case NPC_COLUMN_OF_FROST: + creature->DespawnOrUnsummon(); + return; + case NPC_RISEN_ARCHMAGE: + if (!creature->GetDBTableGUIDLow()) + { + creature->DespawnOrUnsummon(); + return; + } + creature->Respawn(true); + break; + default: + return; + } + + uint32 corpseDelay = creature->GetCorpseDelay(); + uint32 respawnDelay = creature->GetRespawnDelay(); + creature->SetCorpseDelay(1); + creature->SetRespawnDelay(10); + + if (CreatureData const* data = creature->GetCreatureData()) + creature->SetPosition(data->posX, data->posY, data->posZ, data->orientation); + creature->ForcedDespawn(); + + creature->SetCorpseDelay(corpseDelay); + creature->SetRespawnDelay(respawnDelay); + } + + private: + Creature* _creature; +}; + +class boss_valithria_dreamwalker : public CreatureScript +{ + public: + boss_valithria_dreamwalker() : CreatureScript("boss_valithria_dreamwalker") { } + + struct boss_valithria_dreamwalkerAI : public ScriptedAI + { + boss_valithria_dreamwalkerAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()), _portalCount(RAID_MODE<uint32>(3, 8, 3, 8)) + { + } + + void InitializeAI() + { + if (CreatureData const* data = sObjectMgr->GetCreatureData(me->GetDBTableGUIDLow())) + if (data->curhealth) + _spawnHealth = data->curhealth; + } + + void Reset() + { + me->SetHealth(_spawnHealth); + me->SetReactState(REACT_PASSIVE); + me->LoadCreaturesAddon(true); + _instance->SendEncounterUnit(ENCOUNTER_FRAME_REMOVE, me); + _missedPortals = 0; + _under25PercentTalkDone = false; + _over75PercentTalkDone = false; + _justDied = false; + } + + void AttackStart(Unit* /*target*/) + { + } + + void DoAction(int32 const action) + { + if (action != ACTION_ENTER_COMBAT) + return; + + DoCast(me, SPELL_COPY_DAMAGE); + _instance->SendEncounterUnit(ENCOUNTER_FRAME_ADD, me); + _events.ScheduleEvent(EVENT_INTRO_TALK, 15000); + _events.ScheduleEvent(EVENT_DREAM_PORTAL, urand(45000, 48000)); + if (IsHeroic()) + _events.ScheduleEvent(EVENT_BERSERK, 420000); + } + + void HealReceived(Unit* /*healer*/, uint32& heal) + { + // encounter complete + if (me->HealthAbovePctHealed(100, heal)) + { + Talk(SAY_VALITHRIA_SUCCESS); + me->RemoveAurasDueToSpell(SPELL_CORRUPTION_VALITHRIA); + DoCast(me, SPELL_ACHIEVEMENT_CHECK); + DoCast(me, SPELL_DREAMWALKERS_RAGE); + _events.ScheduleEvent(EVENT_DREAM_SLIP, 3500); + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VALITHRIA_LICH_KING))) + lichKing->AI()->EnterEvadeMode(); + } + else if (!_over75PercentTalkDone && me->HealthAbovePctHealed(75, heal)) + { + _over75PercentTalkDone = true; + Talk(SAY_VALITHRIA_75_PERCENT); + } + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) + { + if (me->HealthBelowPctDamaged(25, damage)) + { + if (!_under25PercentTalkDone) + { + _under25PercentTalkDone = true; + Talk(SAY_VALITHRIA_25_PERCENT); + } + + if (damage > me->GetHealth() && !_justDied) + { + _justDied = true; + Talk(SAY_VALITHRIA_DEATH); + _instance->SendEncounterUnit(ENCOUNTER_FRAME_REMOVE, me); + if (Creature* trigger = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VALITHRIA_TRIGGER))) + trigger->AI()->DoAction(ACTION_DEATH); + } + } + } + + void SpellHit(Unit* /*caster*/, SpellEntry const* spell) + { + if (spell->Id == SPELL_DREAM_SLIP) + { + DoCast(me, SPELL_CLEAR_ALL); + DoCast(me, SPELL_AWARD_REPUTATION_BOSS_KILL); + // this display id was found in sniff instead of the one on aura + me->SetDisplayId(11686); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->DespawnOrUnsummon(4000); + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VALITHRIA_LICH_KING))) + lichKing->CastSpell(lichKing, SPELL_SPAWN_CHEST, false); + + if (Creature* trigger = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VALITHRIA_TRIGGER))) + me->Kill(trigger); + } + } + + void JustSummoned(Creature* summon) + { + if (summon->GetEntry() == NPC_DREAM_PORTAL_PRE_EFFECT) + { + summon->m_Events.AddEvent(new DelayedCastEvent(summon, SPELL_SUMMON_DREAM_PORTAL, me->GetGUID(), 6000), summon->m_Events.CalculateTime(15000)); + summon->m_Events.AddEvent(new AuraRemoveEvent(summon, SPELL_DREAM_PORTAL_VISUAL_PRE), summon->m_Events.CalculateTime(15000)); + } + else if (summon->GetEntry() == NPC_NIGHTMARE_PORTAL_PRE_EFFECT) + { + summon->m_Events.AddEvent(new DelayedCastEvent(summon, SPELL_SUMMON_NIGHTMARE_PORTAL, me->GetGUID(), 6000), summon->m_Events.CalculateTime(15000)); + summon->m_Events.AddEvent(new AuraRemoveEvent(summon, SPELL_NIGHTMARE_PORTAL_VISUAL_PRE), summon->m_Events.CalculateTime(15000)); + } + } + + void SummonedCreatureDespawn(Creature* summon) + { + if (summon->GetEntry() == NPC_DREAM_PORTAL || summon->GetEntry() == NPC_NIGHTMARE_PORTAL) + if (summon->AI()->GetData(MISSED_PORTALS)) + ++_missedPortals; + } + + void UpdateAI(uint32 const diff) + { + // does not enter combat + if (_instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) != IN_PROGRESS) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_INTRO_TALK: + Talk(SAY_VALITHRIA_ENTER_COMBAT); + break; + case EVENT_BERSERK: + Talk(SAY_VALITHRIA_BERSERK); + break; + case EVENT_DREAM_PORTAL: + if (!IsHeroic()) + Talk(SAY_VALITHRIA_DREAM_PORTAL); + for (uint32 i = 0; i < _portalCount; ++i) + DoCast(me, SUMMON_PORTAL); + _events.ScheduleEvent(EVENT_DREAM_PORTAL, urand(45000, 48000)); + break; + case EVENT_DREAM_SLIP: + DoCast(me, SPELL_DREAM_SLIP); + break; + default: + break; + } + } + } + + uint32 GetData(uint32 type) + { + if (type == MISSED_PORTALS) + return _missedPortals; + + return 0; + } + + private: + EventMap _events; + InstanceScript* _instance; + uint32 _spawnHealth; + uint32 const _portalCount; + uint32 _missedPortals; + bool _under25PercentTalkDone; + bool _over75PercentTalkDone; + bool _justDied; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<boss_valithria_dreamwalkerAI>(creature); + } +}; + +class npc_green_dragon_combat_trigger : public CreatureScript +{ + public: + npc_green_dragon_combat_trigger() : CreatureScript("npc_green_dragon_combat_trigger") { } + + struct npc_green_dragon_combat_triggerAI : public BossAI + { + npc_green_dragon_combat_triggerAI(Creature* creature) : BossAI(creature, DATA_VALITHRIA_DREAMWALKER) + { + } + + void Reset() + { + _Reset(); + me->SetReactState(REACT_PASSIVE); + } + + void EnterCombat(Unit* /*target*/) + { + me->setActive(true); + DoZoneInCombat(); + instance->SetBossState(DATA_VALITHRIA_DREAMWALKER, IN_PROGRESS); + if (Creature* valithria = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_VALITHRIA_DREAMWALKER))) + valithria->AI()->DoAction(ACTION_ENTER_COMBAT); + } + + void AttackStart(Unit* target) + { + if (target->GetEntry() != NPC_VALITHRIA_DREAMWALKER) + BossAI::AttackStart(target); + } + + void JustReachedHome() + { + BossAI::JustReachedHome(); + DoAction(ACTION_DEATH); + } + + void DoAction(int32 const action) + { + if (action == ACTION_DEATH) + { + instance->SetBossState(DATA_VALITHRIA_DREAMWALKER, FAIL); + me->m_Events.AddEvent(new ValithriaDespawner(me), me->m_Events.CalculateTime(5000)); + } + } + + void UpdateAI(uint32 const /*diff*/) + { + UpdateVictim(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_green_dragon_combat_triggerAI>(creature); + } +}; + +class npc_the_lich_king_controller : public CreatureScript +{ + public: + npc_the_lich_king_controller() : CreatureScript("npc_the_lich_king_controller") { } + + struct npc_the_lich_king_controllerAI : public ScriptedAI + { + npc_the_lich_king_controllerAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + } + + void Reset() + { + _events.Reset(); + _events.ScheduleEvent(EVENT_GLUTTONOUS_ABOMINATION_SUMMONER, 5000); + _events.ScheduleEvent(EVENT_SUPPRESSER_SUMMONER, 10000); + _events.ScheduleEvent(EVENT_BLISTERING_ZOMBIE_SUMMONER, 15000); + _events.ScheduleEvent(EVENT_RISEN_ARCHMAGE_SUMMONER, 20000); + _events.ScheduleEvent(EVENT_BLAZING_SKELETON_SUMMONER, 30000); + me->SetReactState(REACT_PASSIVE); + } + + void JustReachedHome() + { + me->setActive(false); + } + + void EnterCombat(Unit* /*target*/) + { + Talk(SAY_LICH_KING_INTRO); + me->setActive(true); + } + + void JustSummoned(Creature* summon) + { + // must not be in dream phase + summon->SetPhaseMask((summon->GetPhaseMask() & ~0x10), true); + } + + 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_GLUTTONOUS_ABOMINATION_SUMMONER: + DoCast(me, SPELL_TIMER_GLUTTONOUS_ABOMINATION); + break; + case EVENT_SUPPRESSER_SUMMONER: + DoCast(me, SPELL_TIMER_SUPPRESSER); + break; + case EVENT_BLISTERING_ZOMBIE_SUMMONER: + DoCast(me, SPELL_TIMER_BLISTERING_ZOMBIE); + break; + case EVENT_RISEN_ARCHMAGE_SUMMONER: + DoCast(me, SPELL_TIMER_RISEN_ARCHMAGE); + break; + case EVENT_BLAZING_SKELETON_SUMMONER: + DoCast(me, SPELL_TIMER_BLAZING_SKELETON); + break; + default: + break; + } + } + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_the_lich_king_controllerAI(creature); + } +}; + +class npc_risen_archmage : public CreatureScript +{ + public: + npc_risen_archmage() : CreatureScript("npc_risen_archmage") { } + + struct npc_risen_archmageAI : public ScriptedAI + { + npc_risen_archmageAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + } + + bool CanAIAttack(Unit const* target) const + { + return target->GetEntry() != NPC_VALITHRIA_DREAMWALKER; + } + + void Reset() + { + _events.Reset(); + _events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, urand(5000, 15000)); + _events.ScheduleEvent(EVENT_MANA_VOID, urand(20000, 25000)); + _events.ScheduleEvent(EVENT_COLUMN_OF_FROST, urand(10000, 20000)); + _canCallEnterCombat = true; + } + + void EnterCombat(Unit* /*target*/) + { + me->FinishSpell(CURRENT_CHANNELED_SPELL, false); + if (me->GetDBTableGUIDLow() && _canCallEnterCombat) + { + std::list<Creature*> archmages; + RisenArchmageCheck check; + Trinity::CreatureListSearcher<RisenArchmageCheck> searcher(me, archmages, check); + me->VisitNearbyGridObject(100.0f, searcher); + for (std::list<Creature*>::iterator itr = archmages.begin(); itr != archmages.end(); ++itr) + (*itr)->AI()->DoAction(ACTION_ENTER_COMBAT); + + if (Creature* lichKing = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VALITHRIA_LICH_KING))) + lichKing->AI()->DoZoneInCombat(); + + if (Creature* trigger = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VALITHRIA_TRIGGER))) + trigger->AI()->DoZoneInCombat(); + } + } + + void DoAction(int32 const action) + { + if (action != ACTION_ENTER_COMBAT) + return; + + _canCallEnterCombat = false; + DoZoneInCombat(); + _canCallEnterCombat = true; + } + + void JustSummoned(Creature* summon) + { + if (summon->GetEntry() == NPC_COLUMN_OF_FROST) + summon->m_Events.AddEvent(new DelayedCastEvent(summon, SPELL_COLUMN_OF_FROST_DAMAGE, 0, 8000), summon->m_Events.CalculateTime(2000)); + else if (summon->GetEntry() == NPC_MANA_VOID) + summon->DespawnOrUnsummon(36000); + } + + void UpdateAI(uint32 const diff) + { + if (!me->isInCombat()) + if (me->GetDBTableGUIDLow()) + if (!me->GetCurrentSpell(CURRENT_CHANNELED_SPELL)) + DoCast(me, SPELL_CORRUPTION); + + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FROSTBOLT_VOLLEY: + DoCast(me, SPELL_FROSTBOLT_VOLLEY); + _events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, urand(8000, 15000)); + break; + case EVENT_MANA_VOID: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, ManaVoidSelector(me))) + DoCast(target, SPELL_MANA_VOID); + _events.ScheduleEvent(EVENT_MANA_VOID, urand(20000, 25000)); + break; + case EVENT_COLUMN_OF_FROST: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, -10.0f, true)) + DoCast(target, SPELL_COLUMN_OF_FROST); + _events.ScheduleEvent(EVENT_COLUMN_OF_FROST, urand(15000, 25000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + InstanceScript* _instance; + bool _canCallEnterCombat; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_risen_archmageAI>(creature); + } +}; + +class npc_blazing_skeleton : public CreatureScript +{ + public: + npc_blazing_skeleton() : CreatureScript("npc_blazing_skeleton") { } + + struct npc_blazing_skeletonAI : public ScriptedAI + { + npc_blazing_skeletonAI(Creature* creature) : ScriptedAI(creature) + { + } + + void Reset() + { + _events.Reset(); + _events.ScheduleEvent(EVENT_FIREBALL, urand(2000, 4000)); + _events.ScheduleEvent(EVENT_LEY_WASTE, urand(15000, 20000)); + } + + 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_FIREBALL: + if (!me->IsWithinMeleeRange(me->getVictim())) + DoCastVictim(SPELL_FIREBALL); + _events.ScheduleEvent(EVENT_FIREBALL, urand(2000, 4000)); + break; + case EVENT_LEY_WASTE: + DoCast(me, SPELL_LEY_WASTE); + _events.ScheduleEvent(EVENT_LEY_WASTE, urand(15000, 20000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_blazing_skeletonAI>(creature); + } +}; + +class npc_suppresser : public CreatureScript +{ + public: + npc_suppresser() : CreatureScript("npc_suppresser") { } + + struct npc_suppresserAI : public ScriptedAI + { + npc_suppresserAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + } + + void Reset() + { + _events.Reset(); + _events.ScheduleEvent(EVENT_SUPPRESSION, urand(10000, 15000)); + me->SetReactState(REACT_PASSIVE); + } + + void IsSummonedBy(Unit* /*summoner*/) + { + if (Creature* valithria = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_VALITHRIA_DREAMWALKER))) + AttackStart(valithria); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + // this code will never be reached while channeling + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SUPPRESSION: + DoCast(me, SPELL_SUPPRESSION); + _events.ScheduleEvent(EVENT_SUPPRESSION, 5000); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + InstanceScript* const _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_suppresserAI>(creature); + } +}; + +class npc_blistering_zombie : public CreatureScript +{ + public: + npc_blistering_zombie() : CreatureScript("npc_blistering_zombie") { } + + struct npc_blistering_zombieAI : public ScriptedAI + { + npc_blistering_zombieAI(Creature* creature) : ScriptedAI(creature) + { + } + + void JustDied(Unit* killer) + { + DoCast(me, SPELL_ACID_BURST, true); + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim()) + return; + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_blistering_zombieAI>(creature); + } +}; + +class npc_gluttonous_abomination : public CreatureScript +{ + public: + npc_gluttonous_abomination() : CreatureScript("npc_gluttonous_abomination") { } + + struct npc_gluttonous_abominationAI : public ScriptedAI + { + npc_gluttonous_abominationAI(Creature* creature) : ScriptedAI(creature) + { + } + + void Reset() + { + _events.Reset(); + _events.ScheduleEvent(EVENT_GUT_SPRAY, urand(10000, 13000)); + } + + void JustDied(Unit* /*killer*/) + { + DoCast(me, SPELL_ROT_WORM_SPAWNER, true); + } + + 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_GUT_SPRAY: + DoCast(me, SPELL_GUT_SPRAY); + _events.ScheduleEvent(EVENT_GUT_SPRAY, urand(10000, 13000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_gluttonous_abominationAI>(creature); + } +}; + +class npc_dream_portal : public CreatureScript +{ + public: + npc_dream_portal() : CreatureScript("npc_dream_portal") { } + + struct npc_dream_portalAI : public CreatureAI + { + npc_dream_portalAI(Creature* creature) : CreatureAI(creature), + _used(false) + { + } + + void DoAction(int32 const action) + { + if (action != EVENT_SPELLCLICK) + return; + + _used = true; + me->DespawnOrUnsummon(); + } + + uint32 GetData(uint32 type) + { + return (type == MISSED_PORTALS && _used) ? 0 : 1; + } + + void UpdateAI(uint32 const /*diff*/) + { + UpdateVictim(); + } + + private: + bool _used; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_dream_portalAI>(creature); + } +}; + +class npc_dream_cloud : public CreatureScript +{ + public: + npc_dream_cloud() : CreatureScript("npc_dream_cloud") { } + + struct npc_dream_cloudAI : public ScriptedAI + { + npc_dream_cloudAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + } + + void Reset() + { + _events.Reset(); + _events.ScheduleEvent(EVENT_CHECK_PLAYER, 1000); + me->SetCorpseDelay(0); // remove corpse immediately + me->LoadCreaturesAddon(true); + } + + void UpdateAI(uint32 const diff) + { + // trigger + if (_instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) != IN_PROGRESS) + return; + + _events.Update(diff); + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CHECK_PLAYER: + { + Player* player = NULL; + Trinity::AnyPlayerInObjectRangeCheck check(me, 5.0f); + Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(me, player, check); + me->VisitNearbyWorldObject(7.5f, searcher); + _events.ScheduleEvent(player ? EVENT_EXPLODE : EVENT_CHECK_PLAYER, 1000); + break; + } + case EVENT_EXPLODE: + me->GetMotionMaster()->MoveIdle(); + // must use originalCaster the same for all clouds to allow stacking + me->CastSpell(me, EMERALD_VIGOR, false, NULL, NULL, _instance->GetData64(DATA_VALITHRIA_DREAMWALKER)); + me->ForcedDespawn(100); + break; + default: + break; + } + } + } + + private: + EventMap _events; + InstanceScript* _instance; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_dream_cloudAI>(creature); + } +}; + +class spell_dreamwalker_mana_void : public SpellScriptLoader +{ + public: + spell_dreamwalker_mana_void() : SpellScriptLoader("spell_dreamwalker_mana_void") { } + + class spell_dreamwalker_mana_void_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dreamwalker_mana_void_AuraScript); + + void PeriodicTick(AuraEffect const* aurEff) + { + // first 3 ticks have amplitude 1 second + // remaining tick every 500ms + if (aurEff->GetTickNumber() <= 5) + if (!(aurEff->GetTickNumber() & 1)) + PreventDefaultAction(); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_dreamwalker_mana_void_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_dreamwalker_mana_void_AuraScript(); + } +}; + +class spell_dreamwalker_decay_periodic_timer : public SpellScriptLoader +{ + public: + spell_dreamwalker_decay_periodic_timer() : SpellScriptLoader("spell_dreamwalker_decay_periodic_timer") { } + + class spell_dreamwalker_decay_periodic_timer_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dreamwalker_decay_periodic_timer_AuraScript); + + bool Load() + { + _decayRate = GetId() != SPELL_TIMER_BLAZING_SKELETON ? 1000 : 5000; + return true; + } + + void DecayPeriodicTimer(AuraEffect* aurEff) + { + int32 timer = aurEff->GetPeriodicTimer(); + if (timer <= 5) + return; + + aurEff->SetPeriodicTimer(timer - _decayRate); + } + + void Register() + { + OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(spell_dreamwalker_decay_periodic_timer_AuraScript::DecayPeriodicTimer, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + + int32 _decayRate; + }; + + AuraScript* GetAuraScript() const + { + return new spell_dreamwalker_decay_periodic_timer_AuraScript(); + } +}; + +class spell_dreamwalker_summoner : public SpellScriptLoader +{ + public: + spell_dreamwalker_summoner() : SpellScriptLoader("spell_dreamwalker_summoner") { } + + class spell_dreamwalker_summoner_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dreamwalker_summoner_SpellScript); + + void FilterTargets(std::list<Unit*>& targets) + { + targets.remove_if(SummonTargetSelector()); + if (targets.empty()) + return; + + std::list<Unit*>::iterator itr = targets.begin(); + std::advance(itr, urand(0, targets.size() - 1)); + Unit* target = *itr; + targets.clear(); + targets.push_back(target); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_dreamwalker_summoner_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_AREA_ENTRY_SRC); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_dreamwalker_summoner_SpellScript(); + } +}; + +class spell_dreamwalker_summon_suppresser : public SpellScriptLoader +{ + public: + spell_dreamwalker_summon_suppresser() : SpellScriptLoader("spell_dreamwalker_summon_suppresser") { } + + class spell_dreamwalker_summon_suppresser_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dreamwalker_summon_suppresser_AuraScript); + + void PeriodicTick(AuraEffect const* aurEff) + { + PreventDefaultAction(); + Unit* caster = GetCaster(); + if (!caster) + return; + + std::list<Creature*> summoners; + GetCreatureListWithEntryInGrid(summoners, caster, 22515, 100.0f); + summoners.remove_if(SummonTargetSelector()); + Trinity::RandomResizeList(summoners, 2); + if (summoners.empty()) + return; + + for (uint32 i = 0; i < 3; ++i) + caster->CastSpell(summoners.front(), SPELL_SUMMON_SUPPRESSER, true); + for (uint32 i = 0; i < 3; ++i) + caster->CastSpell(summoners.back(), SPELL_SUMMON_SUPPRESSER, true); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_dreamwalker_summon_suppresser_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + + int32 _decayRate; + }; + + AuraScript* GetAuraScript() const + { + return new spell_dreamwalker_summon_suppresser_AuraScript(); + } +}; + +class spell_dreamwalker_summon_dream_portal : public SpellScriptLoader +{ + public: + spell_dreamwalker_summon_dream_portal() : SpellScriptLoader("spell_dreamwalker_summon_dream_portal") { } + + class spell_dreamwalker_summon_dream_portal_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dreamwalker_summon_dream_portal_SpellScript); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + if (!GetHitUnit()) + return; + + uint32 spellId = RAND<uint32>(71301, 72220, 72223, 72225); + GetHitUnit()->CastSpell(GetHitUnit(), spellId, true); + } + + void Register() + { + OnEffect += SpellEffectFn(spell_dreamwalker_summon_dream_portal_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_dreamwalker_summon_dream_portal_SpellScript(); + } +}; + +class spell_dreamwalker_summon_nightmare_portal : public SpellScriptLoader +{ + public: + spell_dreamwalker_summon_nightmare_portal() : SpellScriptLoader("spell_dreamwalker_summon_nightmare_portal") { } + + class spell_dreamwalker_summon_nightmare_portal_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dreamwalker_summon_nightmare_portal_SpellScript); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + if (!GetHitUnit()) + return; + + uint32 spellId = RAND<uint32>(71977, 72481, 72482, 72483); + GetHitUnit()->CastSpell(GetHitUnit(), spellId, true); + } + + void Register() + { + OnEffect += SpellEffectFn(spell_dreamwalker_summon_nightmare_portal_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_dreamwalker_summon_nightmare_portal_SpellScript(); + } +}; + +class spell_dreamwalker_nightmare_cloud : public SpellScriptLoader +{ + public: + spell_dreamwalker_nightmare_cloud() : SpellScriptLoader("spell_dreamwalker_nightmare_cloud") { } + + class spell_dreamwalker_nightmare_cloud_AuraScript : public AuraScript + { + PrepareAuraScript(spell_dreamwalker_nightmare_cloud_AuraScript); + + bool Load() + { + _instance = GetOwner()->GetInstanceScript(); + return _instance != NULL; + } + + void PeriodicTick(AuraEffect const* /*aurEff*/) + { + if (_instance->GetBossState(DATA_VALITHRIA_DREAMWALKER) != IN_PROGRESS) + PreventDefaultAction(); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_dreamwalker_nightmare_cloud_AuraScript::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + + InstanceScript* _instance; + }; + + AuraScript* GetAuraScript() const + { + return new spell_dreamwalker_nightmare_cloud_AuraScript(); + } +}; + +class achievement_portal_jockey : public AchievementCriteriaScript +{ + public: + achievement_portal_jockey() : AchievementCriteriaScript("achievement_portal_jockey") { } + + bool OnCheck(Player* /*source*/, Unit* target) + { + return target && !target->GetAI()->GetData(MISSED_PORTALS); + } +}; + +void AddSC_boss_valithria_dreamwalker() +{ + new boss_valithria_dreamwalker(); + new npc_green_dragon_combat_trigger(); + new npc_the_lich_king_controller(); + new npc_risen_archmage(); + new npc_blazing_skeleton(); + new npc_suppresser(); + new npc_blistering_zombie(); + new npc_gluttonous_abomination(); + new npc_dream_portal(); + new npc_dream_cloud(); + new spell_dreamwalker_mana_void(); + new spell_dreamwalker_decay_periodic_timer(); + new spell_dreamwalker_summoner(); + new spell_dreamwalker_summon_suppresser(); + new spell_dreamwalker_summon_dream_portal(); + new spell_dreamwalker_summon_nightmare_portal(); + new spell_dreamwalker_nightmare_cloud(); + new achievement_portal_jockey(); +} diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h index 137ac32df24..9453610a034 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h @@ -27,6 +27,8 @@ uint32 const EncounterCount = 13; uint32 const WeeklyNPCs = 9; uint32 const MaxHeroicAttempts = 50; + +extern Position const ValithriaSpawnPos; // Defined in boss_sindragosa.cpp extern Position const SindragosaSpawnPos; @@ -70,28 +72,30 @@ enum DataTypes DATA_THE_LICH_KING = 12, // Additional data - DATA_SAURFANG_EVENT_NPC = 34, - DATA_BONED_ACHIEVEMENT = 13, - DATA_OOZE_DANCE_ACHIEVEMENT = 14, - DATA_PUTRICIDE_TABLE = 15, - DATA_NAUSEA_ACHIEVEMENT = 16, - DATA_ORB_WHISPERER_ACHIEVEMENT = 17, - DATA_PRINCE_KELESETH_GUID = 18, - DATA_PRINCE_TALDARAM_GUID = 19, - DATA_PRINCE_VALANAR_GUID = 20, - DATA_BLOOD_PRINCES_CONTROL = 21, - DATA_SINDRAGOSA_FROSTWYRMS = 22, - DATA_SPINESTALKER = 23, - DATA_RIMEFANG = 24, - DATA_COLDFLAME_JETS = 25, - DATA_TEAM_IN_INSTANCE = 26, - DATA_BLOOD_QUICKENING_STATE = 27, - DATA_HEROIC_ATTEMPTS = 28, - DATA_CROK_SCOURGEBANE = 29, - DATA_CAPTAIN_ARNATH = 30, - DATA_CAPTAIN_BRANDON = 31, - DATA_CAPTAIN_GRONDEL = 32, - DATA_CAPTAIN_RUPERT = 33, + DATA_SAURFANG_EVENT_NPC = 13, + DATA_BONED_ACHIEVEMENT = 14, + DATA_OOZE_DANCE_ACHIEVEMENT = 15, + DATA_PUTRICIDE_TABLE = 16, + DATA_NAUSEA_ACHIEVEMENT = 17, + DATA_ORB_WHISPERER_ACHIEVEMENT = 18, + DATA_PRINCE_KELESETH_GUID = 19, + DATA_PRINCE_TALDARAM_GUID = 20, + DATA_PRINCE_VALANAR_GUID = 21, + DATA_BLOOD_PRINCES_CONTROL = 22, + DATA_SINDRAGOSA_FROSTWYRMS = 23, + DATA_SPINESTALKER = 24, + DATA_RIMEFANG = 25, + DATA_COLDFLAME_JETS = 26, + DATA_TEAM_IN_INSTANCE = 27, + DATA_BLOOD_QUICKENING_STATE = 28, + DATA_HEROIC_ATTEMPTS = 29, + DATA_CROK_SCOURGEBANE = 30, + DATA_CAPTAIN_ARNATH = 31, + DATA_CAPTAIN_BRANDON = 32, + DATA_CAPTAIN_GRONDEL = 33, + DATA_CAPTAIN_RUPERT = 34, + DATA_VALITHRIA_TRIGGER = 35, + DATA_VALITHRIA_LICH_KING = 36, }; enum CreaturesIds @@ -218,7 +222,13 @@ enum CreaturesIds NPC_SUPPRESSER = 37863, NPC_BLISTERING_ZOMBIE = 37934, NPC_GLUTTONOUS_ABOMINATION = 37886, + NPC_MANA_VOID = 38068, + NPC_COLUMN_OF_FROST = 37918, NPC_THE_LICH_KING_VALITHRIA = 16980, + NPC_DREAM_PORTAL_PRE_EFFECT = 38186, + NPC_NIGHTMARE_PORTAL_PRE_EFFECT = 38429, + NPC_DREAM_PORTAL = 37945, + NPC_NIGHTMARE_PORTAL = 38430, // Sindragosa NPC_SINDRAGOSA = 36853, @@ -275,6 +285,10 @@ enum GameObjectsIds // Valithria Dreamwalker GO_GREEN_DRAGON_BOSS_ENTRANCE = 201375, GO_GREEN_DRAGON_BOSS_EXIT = 201374, + GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_01 = 201380, + GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_02 = 201381, + GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_03 = 201382, + GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_04 = 201383, // Sindragosa GO_SINDRAGOSA_ENTRANCE_DOOR = 201373, diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index f537a70d61e..048def7a120 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -25,28 +25,32 @@ DoorData const doorData[] = { - {GO_LORD_MARROWGAR_S_ENTRANCE, DATA_LORD_MARROWGAR, DOOR_TYPE_ROOM, BOUNDARY_N }, - {GO_ICEWALL, DATA_LORD_MARROWGAR, DOOR_TYPE_PASSAGE, BOUNDARY_NONE}, - {GO_DOODAD_ICECROWN_ICEWALL02, DATA_LORD_MARROWGAR, DOOR_TYPE_PASSAGE, BOUNDARY_NONE}, - {GO_ORATORY_OF_THE_DAMNED_ENTRANCE, DATA_LADY_DEATHWHISPER, DOOR_TYPE_ROOM, BOUNDARY_N }, - {GO_SAURFANG_S_DOOR, DATA_DEATHBRINGER_SAURFANG, DOOR_TYPE_PASSAGE, BOUNDARY_NONE}, - {GO_ORANGE_PLAGUE_MONSTER_ENTRANCE, DATA_FESTERGUT, DOOR_TYPE_ROOM, BOUNDARY_E }, - {GO_GREEN_PLAGUE_MONSTER_ENTRANCE, DATA_ROTFACE, DOOR_TYPE_ROOM, BOUNDARY_E }, - {GO_SCIENTIST_ENTRANCE, DATA_PROFESSOR_PUTRICIDE, DOOR_TYPE_ROOM, BOUNDARY_E }, - {GO_CRIMSON_HALL_DOOR, DATA_BLOOD_PRINCE_COUNCIL, DOOR_TYPE_ROOM, BOUNDARY_S }, - {GO_BLOOD_ELF_COUNCIL_DOOR, DATA_BLOOD_PRINCE_COUNCIL, DOOR_TYPE_PASSAGE, BOUNDARY_W }, - {GO_BLOOD_ELF_COUNCIL_DOOR_RIGHT, DATA_BLOOD_PRINCE_COUNCIL, DOOR_TYPE_PASSAGE, BOUNDARY_E }, - {GO_DOODAD_ICECROWN_BLOODPRINCE_DOOR_01, DATA_BLOOD_QUEEN_LANA_THEL, DOOR_TYPE_ROOM, BOUNDARY_S }, - {GO_DOODAD_ICECROWN_GRATE_01, DATA_BLOOD_QUEEN_LANA_THEL, DOOR_TYPE_PASSAGE, BOUNDARY_NONE}, - {GO_GREEN_DRAGON_BOSS_ENTRANCE, DATA_SISTER_SVALNA, DOOR_TYPE_PASSAGE, BOUNDARY_S }, - {GO_GREEN_DRAGON_BOSS_ENTRANCE, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_ROOM, BOUNDARY_N }, - {GO_GREEN_DRAGON_BOSS_EXIT, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_PASSAGE, BOUNDARY_S }, - {GO_SINDRAGOSA_ENTRANCE_DOOR, DATA_SINDRAGOSA, DOOR_TYPE_ROOM, BOUNDARY_S }, - {GO_SINDRAGOSA_SHORTCUT_ENTRANCE_DOOR, DATA_SINDRAGOSA, DOOR_TYPE_PASSAGE, BOUNDARY_E }, - {GO_SINDRAGOSA_SHORTCUT_EXIT_DOOR, DATA_SINDRAGOSA, DOOR_TYPE_PASSAGE, BOUNDARY_NONE}, - {GO_ICE_WALL, DATA_SINDRAGOSA, DOOR_TYPE_ROOM, BOUNDARY_SE }, - {GO_ICE_WALL, DATA_SINDRAGOSA, DOOR_TYPE_ROOM, BOUNDARY_SW }, - {0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE} // END + {GO_LORD_MARROWGAR_S_ENTRANCE, DATA_LORD_MARROWGAR, DOOR_TYPE_ROOM, BOUNDARY_N }, + {GO_ICEWALL, DATA_LORD_MARROWGAR, DOOR_TYPE_PASSAGE, BOUNDARY_NONE}, + {GO_DOODAD_ICECROWN_ICEWALL02, DATA_LORD_MARROWGAR, DOOR_TYPE_PASSAGE, BOUNDARY_NONE}, + {GO_ORATORY_OF_THE_DAMNED_ENTRANCE, DATA_LADY_DEATHWHISPER, DOOR_TYPE_ROOM, BOUNDARY_N }, + {GO_SAURFANG_S_DOOR, DATA_DEATHBRINGER_SAURFANG, DOOR_TYPE_PASSAGE, BOUNDARY_NONE}, + {GO_ORANGE_PLAGUE_MONSTER_ENTRANCE, DATA_FESTERGUT, DOOR_TYPE_ROOM, BOUNDARY_E }, + {GO_GREEN_PLAGUE_MONSTER_ENTRANCE, DATA_ROTFACE, DOOR_TYPE_ROOM, BOUNDARY_E }, + {GO_SCIENTIST_ENTRANCE, DATA_PROFESSOR_PUTRICIDE, DOOR_TYPE_ROOM, BOUNDARY_E }, + {GO_CRIMSON_HALL_DOOR, DATA_BLOOD_PRINCE_COUNCIL, DOOR_TYPE_ROOM, BOUNDARY_S }, + {GO_BLOOD_ELF_COUNCIL_DOOR, DATA_BLOOD_PRINCE_COUNCIL, DOOR_TYPE_PASSAGE, BOUNDARY_W }, + {GO_BLOOD_ELF_COUNCIL_DOOR_RIGHT, DATA_BLOOD_PRINCE_COUNCIL, DOOR_TYPE_PASSAGE, BOUNDARY_E }, + {GO_DOODAD_ICECROWN_BLOODPRINCE_DOOR_01, DATA_BLOOD_QUEEN_LANA_THEL, DOOR_TYPE_ROOM, BOUNDARY_S }, + {GO_DOODAD_ICECROWN_GRATE_01, DATA_BLOOD_QUEEN_LANA_THEL, DOOR_TYPE_PASSAGE, BOUNDARY_NONE}, + {GO_GREEN_DRAGON_BOSS_ENTRANCE, DATA_SISTER_SVALNA, DOOR_TYPE_PASSAGE, BOUNDARY_S }, + {GO_GREEN_DRAGON_BOSS_ENTRANCE, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_ROOM, BOUNDARY_N }, + {GO_GREEN_DRAGON_BOSS_EXIT, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_PASSAGE, BOUNDARY_S }, + {GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_01, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_N }, + {GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_02, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_S }, + {GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_03, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_N }, + {GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_04, DATA_VALITHRIA_DREAMWALKER, DOOR_TYPE_SPAWN_HOLE, BOUNDARY_S }, + {GO_SINDRAGOSA_ENTRANCE_DOOR, DATA_SINDRAGOSA, DOOR_TYPE_ROOM, BOUNDARY_S }, + {GO_SINDRAGOSA_SHORTCUT_ENTRANCE_DOOR, DATA_SINDRAGOSA, DOOR_TYPE_PASSAGE, BOUNDARY_E }, + {GO_SINDRAGOSA_SHORTCUT_EXIT_DOOR, DATA_SINDRAGOSA, DOOR_TYPE_PASSAGE, BOUNDARY_NONE}, + {GO_ICE_WALL, DATA_SINDRAGOSA, DOOR_TYPE_ROOM, BOUNDARY_SE }, + {GO_ICE_WALL, DATA_SINDRAGOSA, DOOR_TYPE_ROOM, BOUNDARY_SW }, + {0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE},// END }; // this doesnt have to only store questgivers, also can be used for related quest spawns @@ -105,6 +109,9 @@ class instance_icecrown_citadel : public InstanceMapScript CrokScourgebaneGUID = 0; memset(CrokCaptainGUIDs, 0, 4 * sizeof(uint64)); SisterSvalnaGUID = 0; + ValithriaDreamwalkerGUID = 0; + ValithriaLichKingGUID = 0; + ValithriaTriggerGUID = 0; SindragosaGUID = 0; SpinestalkerGUID = 0; RimefangGUID = 0; @@ -238,6 +245,15 @@ class instance_icecrown_citadel : public InstanceMapScript case NPC_SISTER_SVALNA: SisterSvalnaGUID = creature->GetGUID(); break; + case NPC_VALITHRIA_DREAMWALKER: + ValithriaDreamwalkerGUID = creature->GetGUID(); + break; + case NPC_THE_LICH_KING_VALITHRIA: + ValithriaLichKingGUID = creature->GetGUID(); + break; + case NPC_GREEN_DRAGON_COMBAT_TRIGGER: + ValithriaTriggerGUID = creature->GetGUID(); + break; case NPC_SINDRAGOSA: SindragosaGUID = creature->GetGUID(); break; @@ -330,12 +346,20 @@ class instance_icecrown_citadel : public InstanceMapScript case GO_DOODAD_ICECROWN_GRATE_01: case GO_GREEN_DRAGON_BOSS_ENTRANCE: case GO_GREEN_DRAGON_BOSS_EXIT: + case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_02: + case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_03: case GO_SINDRAGOSA_ENTRANCE_DOOR: case GO_SINDRAGOSA_SHORTCUT_ENTRANCE_DOOR: case GO_SINDRAGOSA_SHORTCUT_EXIT_DOOR: case GO_ICE_WALL: AddDoor(go, true); break; + // these 2 gates are functional only on 25man modes + case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_01: + case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_04: + if (instance->GetSpawnMode() & 1) + AddDoor(go, true); + break; case GO_LADY_DEATHWHISPER_ELEVATOR: LadyDeathwisperElevatorGUID = go->GetGUID(); if (GetBossState(DATA_LADY_DEATHWHISPER) == DONE) @@ -428,6 +452,10 @@ class instance_icecrown_citadel : public InstanceMapScript case GO_DOODAD_ICECROWN_GRATE_01: case GO_GREEN_DRAGON_BOSS_ENTRANCE: case GO_GREEN_DRAGON_BOSS_EXIT: + case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_01: + case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_02: + case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_03: + case GO_DOODAD_ICECROWN_ROOSTPORTCULLIS_04: case GO_SINDRAGOSA_ENTRANCE_DOOR: case GO_SINDRAGOSA_SHORTCUT_ENTRANCE_DOOR: case GO_SINDRAGOSA_SHORTCUT_EXIT_DOOR: @@ -494,21 +522,27 @@ class instance_icecrown_citadel : public InstanceMapScript return BloodCouncilControllerGUID; case DATA_BLOOD_QUEEN_LANA_THEL: return BloodQueenLanaThelGUID; - case DATA_SINDRAGOSA: - return SindragosaGUID; - case DATA_SPINESTALKER: - return SpinestalkerGUID; - case DATA_RIMEFANG: - return RimefangGUID; case DATA_CROK_SCOURGEBANE: return CrokScourgebaneGUID; case DATA_CAPTAIN_ARNATH: case DATA_CAPTAIN_BRANDON: case DATA_CAPTAIN_GRONDEL: case DATA_CAPTAIN_RUPERT: - return CrokCaptainGUIDs[type-DATA_CAPTAIN_ARNATH]; + return CrokCaptainGUIDs[type - DATA_CAPTAIN_ARNATH]; case DATA_SISTER_SVALNA: return SisterSvalnaGUID; + case DATA_VALITHRIA_DREAMWALKER: + return ValithriaDreamwalkerGUID; + case DATA_VALITHRIA_LICH_KING: + return ValithriaLichKingGUID; + case DATA_VALITHRIA_TRIGGER: + return ValithriaTriggerGUID; + case DATA_SINDRAGOSA: + return SindragosaGUID; + case DATA_SPINESTALKER: + return SpinestalkerGUID; + case DATA_RIMEFANG: + return RimefangGUID; default: break; } @@ -611,6 +645,8 @@ class instance_icecrown_citadel : public InstanceMapScript } break; case DATA_VALITHRIA_DREAMWALKER: + if (state == DONE && sPoolMgr->IsSpawnedObject<Quest>(WeeklyQuestData[8].questId[instance->GetSpawnMode() & 1])) + instance->SummonCreature(NPC_VALITHRIA_DREAMWALKER_QUEST, ValithriaSpawnPos); break; case DATA_SINDRAGOSA: HandleGameObject(FrostwingSigilGUID, state != DONE); @@ -959,8 +995,8 @@ class instance_icecrown_citadel : public InstanceMapScript OUT_SAVE_INST_DATA; std::ostringstream saveStream; - saveStream << "I C " << GetBossSaveData() << ColdflameJetsState - << " " << BloodQuickeningState << " " << BloodQuickeningMinutes; + saveStream << "I C " << GetBossSaveData() << HeroicAttempts << " " + << ColdflameJetsState << " " << BloodQuickeningState << " " << BloodQuickeningMinutes; OUT_SAVE_INST_DATA_COMPLETE; return saveStream.str(); @@ -992,10 +1028,12 @@ class instance_icecrown_citadel : public InstanceMapScript SetBossState(i, EncounterState(tmpState)); } + loadStream >> HeroicAttempts; + uint32 temp = 0; loadStream >> temp; ColdflameJetsState = temp ? DONE : NOT_STARTED; - temp = 0; + loadStream >> temp; BloodQuickeningState = temp ? DONE : NOT_STARTED; // DONE means finished (not success/fail) loadStream >> BloodQuickeningMinutes; @@ -1057,6 +1095,9 @@ class instance_icecrown_citadel : public InstanceMapScript uint64 CrokScourgebaneGUID; uint64 CrokCaptainGUIDs[4]; uint64 SisterSvalnaGUID; + uint64 ValithriaDreamwalkerGUID; + uint64 ValithriaLichKingGUID; + uint64 ValithriaTriggerGUID; uint64 SindragosaGUID; uint64 SpinestalkerGUID; uint64 RimefangGUID; @@ -1067,7 +1108,7 @@ class instance_icecrown_citadel : public InstanceMapScript uint32 SpinestalkerTrashCount; uint32 RimefangTrashCount; uint32 BloodQuickeningState; - uint16 HeroicAttempts; + uint32 HeroicAttempts; uint16 BloodQuickeningMinutes; bool IsBonedEligible; bool IsOozeDanceEligible; |