diff options
Diffstat (limited to 'src')
3 files changed, 1351 insertions, 5 deletions
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 0ae0515a35b..04dd5cda4e4 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -18,7 +18,9 @@ #include "ObjectMgr.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "ScriptedEscortAI.h" #include "SpellAuraEffects.h" +#include "SmartAI.h" #include "icecrown_citadel.h" // Weekly quest support @@ -61,6 +63,33 @@ enum Texts // Rotting Frost Giant EMOTE_DEATH_PLAGUE_WARNING = 0, + + // Sister Svalna + SAY_SVALNA_KILL_CAPTAIN = 1, // happens when she kills a captain + SAY_SVALNA_KILL = 4, + SAY_SVALNA_CAPTAIN_DEATH = 5, // happens when a captain resurrected by her dies + SAY_SVALNA_DEATH = 6, + EMOTE_SVALNA_IMPALE = 7, + EMOTE_SVALNA_BROKEN_SHIELD = 8, + + SAY_CROK_INTRO_1 = 0, // Ready your arms, my Argent Brothers. The Vrykul will protect the Frost Queen with their lives. + SAY_ARNATH_INTRO_2 = 5, // Even dying here beats spending another day collecting reagents for that madman, Finklestein. + SAY_CROK_INTRO_3 = 1, // Enough idle banter! Our champions have arrived - support them as we push our way through the hall! + SAY_SVALNA_EVENT_START = 0, // You may have once fought beside me, Crok, but now you are nothing more than a traitor. Come, your second death approaches! + SAY_CROK_COMBAT_WP_0 = 2, // Draw them back to us, and we'll assist you. + SAY_CROK_COMBAT_WP_1 = 3, // Quickly, push on! + SAY_CROK_FINAL_WP = 4, // Her reinforcements will arrive shortly, we must bring her down quickly! + SAY_SVALNA_RESURRECT_CAPTAINS = 2, // Foolish Crok. You brought my reinforcements with you. Arise, Argent Champions, and serve the Lich King in death! + SAY_CROK_COMBAT_SVALNA = 5, // I'll draw her attacks. Return our brothers to their graves, then help me bring her down! + SAY_SVALNA_AGGRO = 3, // Come, Scourgebane. I'll show the master which of us is truly worthy of the title of "Champion"! + SAY_CAPTAIN_DEATH = 0, + SAY_CAPTAIN_RESURRECTED = 1, + SAY_CAPTAIN_KILL = 2, + SAY_CAPTAIN_SECOND_DEATH = 3, + SAY_CAPTAIN_SURVIVE_TALK = 4, + SAY_CROK_WEAKENING_GAUNTLET = 6, + SAY_CROK_WEAKENING_SVALNA = 7, + SAY_CROK_DEATH = 8, }; enum Spells @@ -79,8 +108,62 @@ enum Spells // Alchemist Adrianna SPELL_HARVEST_BLIGHT_SPECIMEN = 72155, SPELL_HARVEST_BLIGHT_SPECIMEN25 = 72162, + + // Crok Scourgebane + SPELL_ICEBOUND_ARMOR = 70714, + SPELL_SCOURGE_STRIKE = 71488, + SPELL_DEATH_STRIKE = 71489, + + // Sister Svalna + SPELL_CARESS_OF_DEATH = 70078, + SPELL_IMPALING_SPEAR_KILL = 70196, + SPELL_REVIVE_CHAMPION = 70053, + SPELL_UNDEATH = 70089, + SPELL_IMPALING_SPEAR = 71443, + SPELL_AETHER_SHIELD = 71463, + SPELL_HURL_SPEAR = 71466, + + // Captain Arnath + SPELL_DOMINATE_MIND = 14515, + SPELL_FLASH_HEAL_NORMAL = 71595, + SPELL_POWER_WORD_SHIELD_NORMAL = 71548, + SPELL_SMITE_NORMAL = 71546, + SPELL_FLASH_HEAL_UNDEAD = 71782, + SPELL_POWER_WORD_SHIELD_UNDEAD = 71780, + SPELL_SMITE_UNDEAD = 71778, + + // Captain Brandon + SPELL_CRUSADER_STRIKE = 71549, + SPELL_DIVINE_SHIELD = 71550, + SPELL_JUDGEMENT_OF_COMMAND = 71551, + SPELL_HAMMER_OF_BETRAYAL = 71784, + + // Captain Grondel + SPELL_CHARGE = 71553, + SPELL_MORTAL_STRIKE = 71552, + SPELL_SUNDER_ARMOR = 71554, + SPELL_CONFLAGRATION = 71785, + + // Captain Rupert + SPELL_FEL_IRON_BOMB_NORMAL = 71592, + SPELL_MACHINE_GUN_NORMAL = 71594, + SPELL_ROCKET_LAUNCH_NORMAL = 71590, + SPELL_FEL_IRON_BOMB_UNDEAD = 71787, + SPELL_MACHINE_GUN_UNDEAD = 71788, + SPELL_ROCKET_LAUNCH_UNDEAD = 71786, }; +// Helper defines +// Captain Arnath +#define SPELL_FLASH_HEAL (IsUndead ? SPELL_FLASH_HEAL_UNDEAD : SPELL_FLASH_HEAL_NORMAL) +#define SPELL_POWER_WORD_SHIELD (IsUndead ? SPELL_POWER_WORD_SHIELD_UNDEAD : SPELL_POWER_WORD_SHIELD_NORMAL) +#define SPELL_SMITE (IsUndead ? SPELL_SMITE_UNDEAD : SPELL_SMITE_NORMAL) + +// Captain Rupert +#define SPELL_FEL_IRON_BOMB (IsUndead ? SPELL_FEL_IRON_BOMB_UNDEAD : SPELL_FEL_IRON_BOMB_NORMAL) +#define SPELL_MACHINE_GUN (IsUndead ? SPELL_MACHINE_GUN_UNDEAD : SPELL_MACHINE_GUN_NORMAL) +#define SPELL_ROCKET_LAUNCH (IsUndead ? SPELL_ROCKET_LAUNCH_UNDEAD : SPELL_ROCKET_LAUNCH_NORMAL) + enum EventTypes { // Highlord Tirion Fordring (at Light's Hammer) @@ -121,6 +204,43 @@ enum EventTypes // Frost Freeze Trap EVENT_ACTIVATE_TRAP = 28, + // Crok Scourgebane + EVENT_SCOURGE_STRIKE = 29, + EVENT_DEATH_STRIKE = 30, + EVENT_HEALTH_CHECK = 31, + EVENT_CROK_INTRO_3 = 32, + EVENT_START_PATHING = 33, + + // Sister Svalna + EVENT_ARNATH_INTRO_2 = 34, + EVENT_SVALNA_START = 35, + EVENT_SVALNA_RESURRECT = 36, + EVENT_SVALNA_COMBAT = 37, + EVENT_IMPALING_SPEAR = 38, + EVENT_AETHER_SHIELD = 39, + + // Captain Arnath + EVENT_ARNATH_FLASH_HEAL = 40, + EVENT_ARNATH_PW_SHIELD = 41, + EVENT_ARNATH_SMITE = 42, + EVENT_ARNATH_DOMINATE_MIND = 43, + + // Captain Brandon + EVENT_BRANDON_CRUSADER_STRIKE = 44, + EVENT_BRANDON_DIVINE_SHIELD = 45, + EVENT_BRANDON_JUDGEMENT_OF_COMMAND = 46, + EVENT_BRANDON_HAMMER_OF_BETRAYAL = 47, + + // Captain Grondel + EVENT_GRONDEL_CHARGE_CHECK = 48, + EVENT_GRONDEL_MORTAL_STRIKE = 49, + EVENT_GRONDEL_SUNDER_ARMOR = 50, + EVENT_GRONDEL_CONFLAGRATION = 51, + + // Captain Rupert + EVENT_RUPERT_FEL_IRON_BOMB = 52, + EVENT_RUPERT_MACHINE_GUN = 53, + EVENT_RUPERT_ROCKET_LAUNCH = 54, }; enum DataTypesICC @@ -128,6 +248,106 @@ enum DataTypesICC DATA_DAMNED_KILLS = 1, }; +enum Actions +{ + // Sister Svalna + ACTION_KILL_CAPTAIN = 1, + ACTION_START_GAUNTLET = 2, + ACTION_RESURRECT_CAPTAINS = 3, + ACTION_CAPTAIN_DIES = 4, + ACTION_RESET_EVENT = 5, +}; + +class FrostwingVrykulSearcher +{ + public: + FrostwingVrykulSearcher(Creature const* source, float range) : _source(source), _range(range) {} + + bool operator()(Unit* unit) + { + if (!unit->isAlive()) + return false; + + switch (unit->GetEntry()) + { + case NPC_YMIRJAR_BATTLE_MAIDEN: + case NPC_YMIRJAR_DEATHBRINGER: + case NPC_YMIRJAR_FROSTBINDER: + case NPC_YMIRJAR_HUNTRESS: + case NPC_YMIRJAR_WARLORD: + break; + default: + return false; + } + + if (!unit->IsWithinDist(_source, _range, false)) + return false; + + return true; + } + + private: + Creature const* _source; + float _range; +}; + +class FrostwingGauntletRespawner +{ + public: + void operator()(Creature* creature) + { + switch (creature->GetOriginalEntry()) + { + case NPC_YMIRJAR_BATTLE_MAIDEN: + case NPC_YMIRJAR_DEATHBRINGER: + case NPC_YMIRJAR_FROSTBINDER: + case NPC_YMIRJAR_HUNTRESS: + case NPC_YMIRJAR_WARLORD: + break; + case NPC_CROK_SCOURGEBANE: + case NPC_CAPTAIN_ARNATH: + case NPC_CAPTAIN_BRANDON: + case NPC_CAPTAIN_GRONDEL: + case NPC_CAPTAIN_RUPERT: + creature->AI()->DoAction(ACTION_RESET_EVENT); + break; + case NPC_SISTER_SVALNA: + creature->AI()->DoAction(ACTION_RESET_EVENT); + // return, this creature is never dead if event is reset + return; + default: + return; + } + + uint32 corpseDelay = creature->GetCorpseDelay(); + uint32 respawnDelay = creature->GetRespawnDelay(); + creature->SetCorpseDelay(1); + creature->SetRespawnDelay(2); + + if (CreatureData const* data = creature->GetCreatureData()) + creature->SetPosition(data->posX, data->posY, data->posZ, data->orientation); + creature->ForcedDespawn(); + + creature->SetCorpseDelay(corpseDelay); + creature->SetRespawnDelay(respawnDelay); + } +}; + +class CaptainSurviveTalk : public BasicEvent +{ + public: + explicit CaptainSurviveTalk(Creature const& owner) : _owner(owner) { } + + bool Execute(uint64 /*currTime*/, uint32 /*diff*/) + { + _owner.AI()->Talk(SAY_CAPTAIN_SURVIVE_TALK); + return true; + } + + private: + Creature const& _owner; +}; + // at Light's Hammer class npc_highlord_tirion_fordring_lh : public CreatureScript { @@ -475,6 +695,958 @@ class npc_alchemist_adrianna : public CreatureScript } }; +class boss_sister_svalna : public CreatureScript +{ + public: + boss_sister_svalna() : CreatureScript("boss_sister_svalna") { } + + struct boss_sister_svalnaAI : public BossAI + { + boss_sister_svalnaAI(Creature* creature) : BossAI(creature, DATA_SISTER_SVALNA), + _isEventInProgress(false) + { + } + + void InitializeAI() + { + if (!me->isDead()) + Reset(); + + me->SetReactState(REACT_PASSIVE); + } + + void Reset() + { + _Reset(); + me->SetReactState(REACT_DEFENSIVE); + _isEventInProgress = false; + } + + void JustDied(Unit* /*killer*/) + { + _JustDied(); + Talk(SAY_SVALNA_DEATH); + + uint64 delay = 1; + for (uint32 i = 0; i < 4; ++i) + { + if (Creature* crusader = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_CAPTAIN_ARNATH + i))) + { + if (crusader->isAlive() && crusader->GetEntry() == crusader->GetCreatureData()->id) + { + crusader->m_Events.AddEvent(new CaptainSurviveTalk(*crusader), crusader->m_Events.CalculateTime(delay)); + delay += 6000; + } + } + } + } + + void EnterCombat(Unit* /*attacker*/) + { + _EnterCombat(); + if (Creature* crok = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_CROK_SCOURGEBANE))) + crok->AI()->Talk(SAY_CROK_COMBAT_SVALNA); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_1); + events.ScheduleEvent(EVENT_SVALNA_COMBAT, 9000); + events.ScheduleEvent(EVENT_IMPALING_SPEAR, urand(40000, 50000)); + events.ScheduleEvent(EVENT_AETHER_SHIELD, urand(100000, 110000)); + } + + void KilledUnit(Unit* victim) + { + switch (victim->GetTypeId()) + { + case TYPEID_PLAYER: + Talk(SAY_SVALNA_KILL); + break; + case TYPEID_UNIT: + switch (victim->GetEntry()) + { + case NPC_CAPTAIN_ARNATH: + case NPC_CAPTAIN_BRANDON: + case NPC_CAPTAIN_GRONDEL: + case NPC_CAPTAIN_RUPERT: + Talk(SAY_SVALNA_KILL_CAPTAIN); + break; + default: + break; + } + break; + default: + break; + } + } + + void JustReachedHome() + { + _JustReachedHome(); + me->SetReactState(REACT_PASSIVE); + } + + void DoAction(int32 const action) + { + switch (action) + { + case ACTION_KILL_CAPTAIN: + me->CastCustomSpell(SPELL_CARESS_OF_DEATH, SPELLVALUE_MAX_TARGETS, 1, me, true); + break; + case ACTION_START_GAUNTLET: + me->setActive(true); + _isEventInProgress = true; + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE); + events.ScheduleEvent(EVENT_SVALNA_START, 25000); + break; + case ACTION_RESURRECT_CAPTAINS: + events.ScheduleEvent(EVENT_SVALNA_RESURRECT, 7000); + break; + case ACTION_CAPTAIN_DIES: + Talk(SAY_SVALNA_CAPTAIN_DEATH); + break; + case ACTION_RESET_EVENT: + me->setActive(false); + Reset(); + break; + default: + break; + } + } + + void SpellHit(Unit* caster, SpellEntry const* spell) + { + if (spell->Id == SPELL_HURL_SPEAR && me->HasAura(SPELL_AETHER_SHIELD)) + { + me->RemoveAurasDueToSpell(SPELL_AETHER_SHIELD); + Talk(EMOTE_SVALNA_BROKEN_SHIELD, caster->GetGUID()); + } + } + + void SpellHitTarget(Unit* target, SpellEntry const* spell) + { + switch (spell->Id) + { + case SPELL_REVIVE_CHAMPION: + if (!_isEventInProgress) + break; + _isEventInProgress = false; + me->setActive(false); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE | UNIT_FLAG_PASSIVE); + break; + case SPELL_IMPALING_SPEAR_KILL: + me->Kill(target); + break; + case SPELL_IMPALING_SPEAR: + if (TempSummon* summon = target->SummonCreature(NPC_IMPALING_SPEAR, *target)) + { + Talk(EMOTE_SVALNA_IMPALE, target->GetGUID()); + summon->SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_UNK1 | 0x4000); + summon->CastCustomSpell(VEHICLE_SPELL_RIDE_HARDCODED, SPELLVALUE_BASE_POINT0, 1, target, false); + } + break; + default: + break; + } + } + + void UpdateAI(uint32 const diff) + { + if (!UpdateVictim() && !_isEventInProgress) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SVALNA_START: + Talk(SAY_SVALNA_EVENT_START); + break; + case EVENT_SVALNA_RESURRECT: + Talk(SAY_SVALNA_RESURRECT_CAPTAINS); + me->CastSpell(me, SPELL_REVIVE_CHAMPION, false); + break; + case EVENT_SVALNA_COMBAT: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_ATTACKABLE_1); + me->SetReactState(REACT_DEFENSIVE); + Talk(SAY_SVALNA_AGGRO); + break; + case EVENT_IMPALING_SPEAR: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, -SPELL_IMPALING_SPEAR)) + DoCast(target, SPELL_IMPALING_SPEAR); + events.ScheduleEvent(EVENT_IMPALING_SPEAR, urand(20000, 25000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + bool _isEventInProgress; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<boss_sister_svalnaAI>(creature); + } +}; + +class npc_crok_scourgebane : public CreatureScript +{ + public: + npc_crok_scourgebane() : CreatureScript("npc_crok_scourgebane") { } + + struct npc_crok_scourgebaneAI : public npc_escortAI + { + npc_crok_scourgebaneAI(Creature* creature) : npc_escortAI(creature), + _instance(creature->GetInstanceScript()), _respawnTime(creature->GetRespawnDelay()), + _corpseDelay(creature->GetCorpseDelay()) + { + SetDespawnAtEnd(false); + SetDespawnAtFar(false); + _isEventActive = false; + _isEventDone = false; + _didUnderTenPercentText = false; + } + + void Reset() + { + _events.Reset(); + _events.ScheduleEvent(EVENT_SCOURGE_STRIKE, urand(7500, 12500)); + _events.ScheduleEvent(EVENT_DEATH_STRIKE, urand(25000, 30000)); + me->SetReactState(REACT_DEFENSIVE); + _didUnderTenPercentText = false; + _wipeCheckTimer = 1000; + } + + void DoAction(int32 const action) + { + if (action == ACTION_START_GAUNTLET) + { + if (_isEventDone || !me->isAlive()) + return; + + _isEventActive = true; + _isEventDone = true; + // Load Grid with Sister Svalna + me->GetMap()->LoadGrid(4356.71f, 2484.33f); + if (Creature* svalna = me->FindNearestCreature(NPC_SISTER_SVALNA, 333.0f, true)) + svalna->AI()->DoAction(ACTION_START_GAUNTLET); + Talk(SAY_CROK_INTRO_1); + _events.ScheduleEvent(EVENT_ARNATH_INTRO_2, 7000); + _events.ScheduleEvent(EVENT_CROK_INTRO_3, 14000); + _events.ScheduleEvent(EVENT_START_PATHING, 37000); + me->setActive(true); + for (uint32 i = 0; i < 4; ++i) + if (Creature* crusader = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_CAPTAIN_ARNATH + i))) + crusader->AI()->DoAction(ACTION_START_GAUNTLET); + } + else if (action == ACTION_RESET_EVENT) + { + _isEventActive = false; + _isEventDone = false; + me->setActive(false); + _aliveTrash.clear(); + _currentWPid = 0; + } + } + + void SetGUID(uint64 const& guid, int32 type/* = 0*/) + { + if (type == ACTION_VRYKUL_DEATH) + { + _aliveTrash.erase(guid); + if (_aliveTrash.empty()) + { + SetEscortPaused(false); + if (_currentWPid == 4 && _isEventActive) + { + _isEventActive = false; + me->setActive(false); + Talk(SAY_CROK_FINAL_WP); + if (Creature* svalna = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_SISTER_SVALNA))) + svalna->AI()->DoAction(ACTION_RESURRECT_CAPTAINS); + } + } + } + } + + void WaypointReached(uint32 waypointId) + { + switch (waypointId) + { + // pause pathing until trash pack is cleared + case 0: + Talk(SAY_CROK_COMBAT_WP_0); + if (!_aliveTrash.empty()) + SetEscortPaused(true); + break; + case 1: + Talk(SAY_CROK_COMBAT_WP_1); + if (!_aliveTrash.empty()) + SetEscortPaused(true); + break; + case 4: + if (_aliveTrash.empty() && _isEventActive) + { + _isEventActive = false; + me->setActive(false); + Talk(SAY_CROK_FINAL_WP); + if (Creature* svalna = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_SISTER_SVALNA))) + svalna->AI()->DoAction(ACTION_RESURRECT_CAPTAINS); + } + break; + default: + break; + } + } + + void WaypointStart(uint32 waypointId) + { + _currentWPid = waypointId; + switch (waypointId) + { + case 0: + case 1: + case 4: + { + // get spawns by home position + float minY = 2600.0f; + float maxY = 2650.0f; + if (waypointId == 1) + { + minY -= 50.0f; + maxY -= 50.0f; + // at waypoints 1 and 2 she kills one captain + if (Creature* svalna = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_SISTER_SVALNA))) + svalna->AI()->DoAction(ACTION_KILL_CAPTAIN); + } + else if (waypointId == 4) + { + minY -= 100.0f; + maxY -= 100.0f; + } + + // get all nearby vrykul + std::list<Creature*> temp; + FrostwingVrykulSearcher check(me, 80.0f); + Trinity::CreatureListSearcher<FrostwingVrykulSearcher> searcher(me, temp, check); + me->VisitNearbyGridObject(80.0f, searcher); + + _aliveTrash.clear(); + for (std::list<Creature*>::iterator itr = temp.begin(); itr != temp.end(); ++itr) + if ((*itr)->GetHomePosition().GetPositionY() < maxY && (*itr)->GetHomePosition().GetPositionY() > minY) + _aliveTrash.insert((*itr)->GetGUID()); + break; + } + // at waypoints 1 and 2 she kills one captain + case 2: + if (Creature* svalna = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_SISTER_SVALNA))) + svalna->AI()->DoAction(ACTION_KILL_CAPTAIN); + break; + default: + break; + } + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) + { + // check wipe + if (!_wipeCheckTimer) + { + _wipeCheckTimer = 1000; + Player* player = NULL; + Trinity::AnyPlayerInObjectRangeCheck check(me, 60.0f); + Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(me, player, check); + me->VisitNearbyWorldObject(60.0f, searcher); + // wipe + if (!player) + { + damage *= 100; + if (damage >= me->GetHealth()) + { + FrostwingGauntletRespawner respawner; + Trinity::CreatureWorker<FrostwingGauntletRespawner> worker(me, respawner); + me->VisitNearbyGridObject(333.0f, worker); + Talk(SAY_CROK_DEATH); + } + return; + } + } + + if (HealthBelowPct(10)) + { + if (!_didUnderTenPercentText) + { + _didUnderTenPercentText = true; + if (_isEventActive) + Talk(SAY_CROK_WEAKENING_GAUNTLET); + else + Talk(SAY_CROK_WEAKENING_SVALNA); + } + + damage = 0; + DoCast(me, SPELL_ICEBOUND_ARMOR); + _events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000); + } + } + + void UpdateEscortAI(uint32 const diff) + { + if (_wipeCheckTimer <= diff) + _wipeCheckTimer = 0; + else + _wipeCheckTimer -= diff; + + if (!UpdateVictim() && !_isEventActive) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STAT_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ARNATH_INTRO_2: + if (Creature* arnath = ObjectAccessor::GetCreature(*me, _instance->GetData64(DATA_CAPTAIN_ARNATH))) + arnath->AI()->Talk(SAY_ARNATH_INTRO_2); + break; + case EVENT_CROK_INTRO_3: + Talk(SAY_CROK_INTRO_3); + break; + case EVENT_START_PATHING: + Start(true, true); + break; + case EVENT_SCOURGE_STRIKE: + DoCastVictim(SPELL_SCOURGE_STRIKE); + _events.ScheduleEvent(EVENT_SCOURGE_STRIKE, urand(10000, 14000)); + break; + case EVENT_DEATH_STRIKE: + if (HealthBelowPct(20)) + DoCastVictim(SPELL_DEATH_STRIKE); + _events.ScheduleEvent(EVENT_DEATH_STRIKE, urand(5000, 10000)); + break; + case EVENT_HEALTH_CHECK: + if (HealthAbovePct(15)) + { + me->RemoveAurasDueToSpell(SPELL_ICEBOUND_ARMOR); + _didUnderTenPercentText = false; + } + else + { + me->DealHeal(me, me->CountPctFromMaxHealth(5)); + _events.ScheduleEvent(EVENT_HEALTH_CHECK, 1000); + } + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + bool CanAIAttack(Unit const* target) const + { + // do not see targets inside Frostwing Halls when we are not there + return (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f); + } + + private: + EventMap _events; + std::set<uint64> _aliveTrash; + InstanceScript* _instance; + uint32 _currentWPid; + uint32 _wipeCheckTimer; + uint32 const _respawnTime; + uint32 const _corpseDelay; + bool _isEventActive; + bool _isEventDone; + bool _didUnderTenPercentText; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_crok_scourgebaneAI>(creature); + } +}; + +struct npc_argent_captainAI : public ScriptedAI +{ + public: + npc_argent_captainAI(Creature* creature) : ScriptedAI(creature), Instance(creature->GetInstanceScript()), _firstDeath(true) + { + FollowAngle = PET_FOLLOW_ANGLE; + FollowDist = PET_FOLLOW_DIST; + IsUndead = false; + } + + void JustDied(Unit* /*killer*/) + { + if (_firstDeath) + { + _firstDeath = false; + Talk(SAY_CAPTAIN_DEATH); + } + else + Talk(SAY_CAPTAIN_SECOND_DEATH); + } + + void KilledUnit(Unit* victim) + { + if (victim->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_CAPTAIN_KILL); + } + + void DoAction(int32 const action) + { + if (action == ACTION_START_GAUNTLET) + { + if (Creature* crok = ObjectAccessor::GetCreature(*me, Instance->GetData64(DATA_CROK_SCOURGEBANE))) + { + me->SetReactState(REACT_DEFENSIVE); + FollowAngle = me->GetAngle(crok) + me->GetOrientation(); + FollowDist = me->GetDistance2d(crok); + me->GetMotionMaster()->MoveFollow(crok, FollowDist, FollowAngle, MOTION_SLOT_IDLE); + } + + me->setActive(true); + } + else if (action == ACTION_RESET_EVENT) + { + _firstDeath = true; + } + } + + void EnterCombat(Unit* /*target*/) + { + me->SetHomePosition(*me); + if (IsUndead) + DoZoneInCombat(); + } + + bool CanAIAttack(Unit const* target) const + { + // do not see targets inside Frostwing Halls when we are not there + return (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f); + } + + void EnterEvadeMode() + { + // not yet following + if (me->GetMotionMaster()->GetMotionSlotType(MOTION_SLOT_IDLE) != TARGETED_MOTION_TYPE || IsUndead) + { + ScriptedAI::EnterEvadeMode(); + return; + } + + if (!_EnterEvadeMode()) + return; + + if (!me->GetVehicle()) + { + me->GetMotionMaster()->Clear(false); + if (Creature* crok = ObjectAccessor::GetCreature(*me, Instance->GetData64(DATA_CROK_SCOURGEBANE))) + me->GetMotionMaster()->MoveFollow(crok, FollowDist, FollowAngle, MOTION_SLOT_IDLE); + } + + Reset(); + } + + void SpellHit(Unit* /*caster*/, SpellEntry const* spell) + { + if (spell->Id == SPELL_REVIVE_CHAMPION && !IsUndead) + { + IsUndead = true; + me->setDeathState(JUST_ALIVED); + uint32 newEntry = 0; + switch (me->GetEntry()) + { + case NPC_CAPTAIN_ARNATH: + newEntry = NPC_CAPTAIN_ARNATH_UNDEAD; + break; + case NPC_CAPTAIN_BRANDON: + newEntry = NPC_CAPTAIN_BRANDON_UNDEAD; + break; + case NPC_CAPTAIN_GRONDEL: + newEntry = NPC_CAPTAIN_GRONDEL_UNDEAD; + break; + case NPC_CAPTAIN_RUPERT: + newEntry = NPC_CAPTAIN_RUPERT_UNDEAD; + break; + default: + return; + } + + Talk(SAY_CAPTAIN_RESURRECTED); + me->UpdateEntry(newEntry, Instance->GetData(DATA_TEAM_IN_INSTANCE), me->GetCreatureData()); + DoCast(me, SPELL_UNDEATH, true); + } + } + + protected: + EventMap Events; + InstanceScript* Instance; + float FollowAngle; + float FollowDist; + bool IsUndead; + + private: + bool _firstDeath; +}; + +class npc_captain_arnath : public CreatureScript +{ + public: + npc_captain_arnath() : CreatureScript("npc_captain_arnath") { } + + struct npc_captain_arnathAI : public npc_argent_captainAI + { + npc_captain_arnathAI(Creature* creature) : npc_argent_captainAI(creature) + { + } + + void Reset() + { + Events.Reset(); + Events.ScheduleEvent(EVENT_ARNATH_FLASH_HEAL, urand(4000, 7000)); + Events.ScheduleEvent(EVENT_ARNATH_PW_SHIELD, urand(8000, 14000)); + Events.ScheduleEvent(EVENT_ARNATH_SMITE, urand(3000, 6000)); + if (Is25ManRaid() && IsUndead) + Events.ScheduleEvent(EVENT_ARNATH_DOMINATE_MIND, urand(22000, 27000)); + } + + 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_ARNATH_FLASH_HEAL: + if (Creature* target = FindFriendlyCreature()) + DoCast(target, SPELL_FLASH_HEAL); + Events.ScheduleEvent(EVENT_ARNATH_FLASH_HEAL, urand(6000, 9000)); + break; + case EVENT_ARNATH_PW_SHIELD: + { + std::list<Creature*> targets = DoFindFriendlyMissingBuff(40.0f, SPELL_POWER_WORD_SHIELD); + std::list<Creature*>::iterator itr = targets.begin(); + std::advance(itr, urand(0, targets.size() - 1)); + DoCast(*itr, SPELL_POWER_WORD_SHIELD); + Events.ScheduleEvent(EVENT_ARNATH_PW_SHIELD, urand(15000, 20000)); + break; + } + case EVENT_ARNATH_SMITE: + DoCastVictim(SPELL_SMITE); + Events.ScheduleEvent(EVENT_ARNATH_SMITE, urand(4000, 7000)); + break; + case EVENT_ARNATH_DOMINATE_MIND: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true)) + DoCast(target, SPELL_DOMINATE_MIND); + Events.ScheduleEvent(EVENT_ARNATH_DOMINATE_MIND, urand(28000, 37000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + Creature* FindFriendlyCreature() const + { + Creature* target = NULL; + Trinity::MostHPMissingInRange u_check(me, 60.0f, 0); + Trinity::CreatureLastSearcher<Trinity::MostHPMissingInRange> searcher(me, target, u_check); + me->VisitNearbyGridObject(60.0f, searcher); + return target; + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_captain_arnathAI>(creature); + } +}; + +class npc_captain_brandon : public CreatureScript +{ + public: + npc_captain_brandon() : CreatureScript("npc_captain_brandon") { } + + struct npc_captain_brandonAI : public npc_argent_captainAI + { + npc_captain_brandonAI(Creature* creature) : npc_argent_captainAI(creature) + { + } + + void Reset() + { + Events.Reset(); + Events.ScheduleEvent(EVENT_BRANDON_CRUSADER_STRIKE, urand(6000, 10000)); + Events.ScheduleEvent(EVENT_BRANDON_DIVINE_SHIELD, 500); + Events.ScheduleEvent(EVENT_BRANDON_JUDGEMENT_OF_COMMAND, urand(8000, 13000)); + if (IsUndead) + Events.ScheduleEvent(EVENT_BRANDON_HAMMER_OF_BETRAYAL, urand(25000, 30000)); + } + + 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_BRANDON_CRUSADER_STRIKE: + DoCastVictim(SPELL_CRUSADER_STRIKE); + Events.ScheduleEvent(EVENT_BRANDON_CRUSADER_STRIKE, urand(6000, 12000)); + break; + case EVENT_BRANDON_DIVINE_SHIELD: + if (HealthBelowPct(20)) + DoCast(me, SPELL_DIVINE_SHIELD); + Events.ScheduleEvent(EVENT_BRANDON_DIVINE_SHIELD, 500); + break; + case EVENT_BRANDON_JUDGEMENT_OF_COMMAND: + DoCastVictim(SPELL_JUDGEMENT_OF_COMMAND); + Events.ScheduleEvent(EVENT_BRANDON_JUDGEMENT_OF_COMMAND, urand(8000, 13000)); + break; + case EVENT_BRANDON_HAMMER_OF_BETRAYAL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true)) + DoCast(target, SPELL_HAMMER_OF_BETRAYAL); + Events.ScheduleEvent(EVENT_BRANDON_HAMMER_OF_BETRAYAL, urand(45000, 60000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_captain_brandonAI>(creature); + } +}; + +class npc_captain_grondel : public CreatureScript +{ + public: + npc_captain_grondel() : CreatureScript("npc_captain_grondel") { } + + struct npc_captain_grondelAI : public npc_argent_captainAI + { + npc_captain_grondelAI(Creature* creature) : npc_argent_captainAI(creature) + { + } + + void Reset() + { + Events.Reset(); + Events.ScheduleEvent(EVENT_GRONDEL_CHARGE_CHECK, 500); + Events.ScheduleEvent(EVENT_GRONDEL_MORTAL_STRIKE, urand(8000, 14000)); + Events.ScheduleEvent(EVENT_GRONDEL_SUNDER_ARMOR, urand(3000, 12000)); + if (IsUndead) + Events.ScheduleEvent(EVENT_GRONDEL_CONFLAGRATION, urand(12000, 17000)); + } + + 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_GRONDEL_CHARGE_CHECK: + if (CanCast(me->getVictim(), sSpellStore.LookupEntry(SPELL_CHARGE))) + DoCastVictim(SPELL_CHARGE); + Events.ScheduleEvent(EVENT_GRONDEL_CHARGE_CHECK, 500); + break; + case EVENT_GRONDEL_MORTAL_STRIKE: + DoCastVictim(SPELL_MORTAL_STRIKE); + Events.ScheduleEvent(EVENT_GRONDEL_MORTAL_STRIKE, urand(10000, 15000)); + break; + case EVENT_GRONDEL_SUNDER_ARMOR: + DoCastVictim(SPELL_SUNDER_ARMOR); + Events.ScheduleEvent(EVENT_GRONDEL_SUNDER_ARMOR, urand(5000, 17000)); + break; + case EVENT_GRONDEL_CONFLAGRATION: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_CONFLAGRATION); + Events.ScheduleEvent(EVENT_GRONDEL_CONFLAGRATION, urand(10000, 15000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_captain_grondelAI>(creature); + } +}; + +class npc_captain_rupert : public CreatureScript +{ + public: + npc_captain_rupert() : CreatureScript("npc_captain_rupert") { } + + struct npc_captain_rupertAI : public npc_argent_captainAI + { + npc_captain_rupertAI(Creature* creature) : npc_argent_captainAI(creature) + { + } + + void Reset() + { + Events.Reset(); + Events.ScheduleEvent(EVENT_RUPERT_FEL_IRON_BOMB, urand(15000, 20000)); + Events.ScheduleEvent(EVENT_RUPERT_MACHINE_GUN, urand(25000, 30000)); + Events.ScheduleEvent(EVENT_RUPERT_ROCKET_LAUNCH, urand(10000, 15000)); + } + + 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_RUPERT_FEL_IRON_BOMB: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_FEL_IRON_BOMB); + Events.ScheduleEvent(EVENT_RUPERT_FEL_IRON_BOMB, urand(15000, 20000)); + break; + case EVENT_RUPERT_MACHINE_GUN: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) + DoCast(target, SPELL_MACHINE_GUN); + Events.ScheduleEvent(EVENT_RUPERT_MACHINE_GUN, urand(25000, 30000)); + break; + case EVENT_RUPERT_ROCKET_LAUNCH: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1)) + DoCast(target, SPELL_ROCKET_LAUNCH); + Events.ScheduleEvent(EVENT_RUPERT_ROCKET_LAUNCH, urand(10000, 15000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return GetIcecrownCitadelAI<npc_captain_rupertAI>(creature); + } +}; + +class npc_frostwing_vrykul : public CreatureScript +{ + public: + npc_frostwing_vrykul() : CreatureScript("npc_frostwing_vrykul") { } + + struct npc_frostwing_vrykulAI : public SmartAI + { + npc_frostwing_vrykulAI(Creature* creature) : SmartAI(creature) + { + } + + bool CanAIAttack(Unit const* target) const + { + // do not see targets inside Frostwing Halls when we are not there + return (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f) && SmartAI::CanAIAttack(target); + } + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_frostwing_vrykulAI(creature); + } +}; + +class npc_impaling_spear : public CreatureScript +{ + public: + npc_impaling_spear() : CreatureScript("npc_impaling_spear") { } + + struct npc_impaling_spearAI : public CreatureAI + { + npc_impaling_spearAI(Creature* creature) : CreatureAI(creature) + { + } + + void Reset() + { + me->SetReactState(REACT_PASSIVE); + _vehicleCheckTimer = 500; + } + + void UpdateAI(uint32 const diff) + { + if (_vehicleCheckTimer <= diff) + { + _vehicleCheckTimer = 500; + if (!me->GetVehicle()) + me->DespawnOrUnsummon(100); + } + else + _vehicleCheckTimer -= diff; + } + + uint32 _vehicleCheckTimer; + }; + + CreatureAI* GetAI(Creature* creature) const + { + return new npc_impaling_spearAI(creature); + } +}; + class DeathPlagueTargetSelector { public: @@ -595,6 +1767,70 @@ class spell_icc_harvest_blight_specimen : public SpellScriptLoader } }; +class AliveCheck +{ + public: + bool operator()(Unit* unit) + { + return unit->isAlive(); + } +}; + +class spell_svalna_revive_champion : public SpellScriptLoader +{ + public: + spell_svalna_revive_champion() : SpellScriptLoader("spell_svalna_revive_champion") { } + + class spell_svalna_revive_champion_SpellScript : public SpellScript + { + PrepareSpellScript(spell_svalna_revive_champion_SpellScript); + + void RemoveAliveTarget(std::list<Unit*>& unitList) + { + unitList.remove_if(AliveCheck()); + Trinity::RandomResizeList(unitList, 2); + } + + void Register() + { + OnUnitTargetSelect += SpellUnitTargetFn(spell_svalna_revive_champion_SpellScript::RemoveAliveTarget, EFFECT_0, TARGET_UNIT_AREA_ENTRY_DST); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_svalna_revive_champion_SpellScript(); + } +}; + +class spell_svalna_remove_spear : public SpellScriptLoader +{ + public: + spell_svalna_remove_spear() : SpellScriptLoader("spell_svalna_remove_spear") { } + + class spell_svalna_remove_spear_SpellScript : public SpellScript + { + PrepareSpellScript(spell_svalna_remove_spear_SpellScript); + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + if (Creature* target = GetHitCreature()) + target->DespawnOrUnsummon(); + } + + void Register() + { + OnEffect += SpellEffectFn(spell_svalna_remove_spear_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const + { + return new spell_svalna_remove_spear_SpellScript(); + } +}; + class at_icc_saurfang_portal : public AreaTriggerScript { public: @@ -624,6 +1860,7 @@ class at_icc_saurfang_portal : public AreaTriggerScript instant = !instant; } } + return true; } }; @@ -656,15 +1893,41 @@ class at_icc_start_blood_quickening : public AreaTriggerScript } }; +class at_icc_start_frostwing_gauntlet : public AreaTriggerScript +{ + public: + at_icc_start_frostwing_gauntlet() : AreaTriggerScript("at_icc_start_frostwing_gauntlet") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) + { + if (InstanceScript* instance = player->GetInstanceScript()) + if (Creature* crok = ObjectAccessor::GetCreature(*player, instance->GetData64(DATA_CROK_SCOURGEBANE))) + crok->AI()->DoAction(ACTION_START_GAUNTLET); + return true; + } +}; + void AddSC_icecrown_citadel() { new npc_highlord_tirion_fordring_lh(); new npc_rotting_frost_giant(); new npc_frost_freeze_trap(); new npc_alchemist_adrianna(); + new boss_sister_svalna(); + new npc_crok_scourgebane(); + new npc_captain_arnath(); + new npc_captain_brandon(); + new npc_captain_grondel(); + new npc_captain_rupert(); + new npc_frostwing_vrykul(); + new npc_impaling_spear(); new spell_frost_giant_death_plague(); new spell_icc_harvest_blight_specimen(); + new spell_trigger_spell_from_caster("spell_svalna_caress_of_death", SPELL_IMPALING_SPEAR_KILL); + new spell_svalna_revive_champion(); + new spell_svalna_remove_spear(); new at_icc_saurfang_portal(); new at_icc_shutdown_traps(); new at_icc_start_blood_quickening(); + new at_icc_start_frostwing_gauntlet(); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h index f46de1a6cd7..137ac32df24 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h @@ -24,7 +24,7 @@ #define ICCScriptName "instance_icecrown_citadel" -uint32 const EncounterCount = 12; +uint32 const EncounterCount = 13; uint32 const WeeklyNPCs = 9; uint32 const MaxHeroicAttempts = 50; // Defined in boss_sindragosa.cpp @@ -64,12 +64,13 @@ enum DataTypes DATA_PROFESSOR_PUTRICIDE = 6, DATA_BLOOD_PRINCE_COUNCIL = 7, DATA_BLOOD_QUEEN_LANA_THEL = 8, - DATA_VALITHRIA_DREAMWALKER = 9, - DATA_SINDRAGOSA = 10, - DATA_THE_LICH_KING = 11, + DATA_SISTER_SVALNA = 9, + DATA_VALITHRIA_DREAMWALKER = 10, + DATA_SINDRAGOSA = 11, + DATA_THE_LICH_KING = 12, // Additional data - DATA_SAURFANG_EVENT_NPC = 12, + DATA_SAURFANG_EVENT_NPC = 34, DATA_BONED_ACHIEVEMENT = 13, DATA_OOZE_DANCE_ACHIEVEMENT = 14, DATA_PUTRICIDE_TABLE = 15, @@ -86,6 +87,11 @@ enum DataTypes 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, }; enum CreaturesIds @@ -186,6 +192,34 @@ enum CreaturesIds // Blood-Queen Lana'thel NPC_BLOOD_QUEEN_LANA_THEL = 37955, + // Frostwing Halls gauntlet event + NPC_CROK_SCOURGEBANE = 37129, + NPC_CAPTAIN_ARNATH = 37122, + NPC_CAPTAIN_BRANDON = 37123, + NPC_CAPTAIN_GRONDEL = 37124, + NPC_CAPTAIN_RUPERT = 37125, + NPC_CAPTAIN_ARNATH_UNDEAD = 37491, + NPC_CAPTAIN_BRANDON_UNDEAD = 37493, + NPC_CAPTAIN_GRONDEL_UNDEAD = 37494, + NPC_CAPTAIN_RUPERT_UNDEAD = 37495, + NPC_YMIRJAR_BATTLE_MAIDEN = 37132, + NPC_YMIRJAR_DEATHBRINGER = 38125, + NPC_YMIRJAR_FROSTBINDER = 37127, + NPC_YMIRJAR_HUNTRESS = 37134, + NPC_YMIRJAR_WARLORD = 37133, + NPC_SISTER_SVALNA = 37126, + NPC_IMPALING_SPEAR = 38248, + + // Valithria Dreamwalker + NPC_VALITHRIA_DREAMWALKER = 36789, + NPC_GREEN_DRAGON_COMBAT_TRIGGER = 38752, + NPC_RISEN_ARCHMAGE = 37868, + NPC_BLAZING_SKELETON = 36791, + NPC_SUPPRESSER = 37863, + NPC_BLISTERING_ZOMBIE = 37934, + NPC_GLUTTONOUS_ABOMINATION = 37886, + NPC_THE_LICH_KING_VALITHRIA = 16980, + // Sindragosa NPC_SINDRAGOSA = 36853, NPC_SPINESTALKER = 37534, @@ -305,6 +339,9 @@ enum SharedActions // Blood-Queen Lana'thel ACTION_KILL_MINCHAR = -379550, + // Frostwing Halls gauntlet event + ACTION_VRYKUL_DEATH = 37129, + // Sindragosa ACTION_START_FROSTWYRM = -368530, ACTION_TRIGGER_ASPHYXIATION = -368531, diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index 7f00fa08ad7..f537a70d61e 100755 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -38,6 +38,7 @@ DoorData const doorData[] = {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 }, @@ -101,6 +102,9 @@ class instance_icecrown_citadel : public InstanceMapScript memset(BloodCouncilGUIDs, 0, 3*sizeof(uint64)); BloodCouncilControllerGUID = 0; BloodQueenLanaThelGUID = 0; + CrokScourgebaneGUID = 0; + memset(CrokCaptainGUIDs, 0, 4 * sizeof(uint64)); + SisterSvalnaGUID = 0; SindragosaGUID = 0; SpinestalkerGUID = 0; RimefangGUID = 0; @@ -221,6 +225,19 @@ class instance_icecrown_citadel : public InstanceMapScript case NPC_BLOOD_QUEEN_LANA_THEL: BloodQueenLanaThelGUID = creature->GetGUID(); break; + case NPC_CROK_SCOURGEBANE: + CrokScourgebaneGUID = creature->GetGUID(); + break; + // we can only do this because there are no gaps in their entries + case NPC_CAPTAIN_ARNATH: + case NPC_CAPTAIN_BRANDON: + case NPC_CAPTAIN_GRONDEL: + case NPC_CAPTAIN_RUPERT: + CrokCaptainGUIDs[creature->GetEntry()-NPC_CAPTAIN_ARNATH] = creature->GetGUID(); + break; + case NPC_SISTER_SVALNA: + SisterSvalnaGUID = creature->GetGUID(); + break; case NPC_SINDRAGOSA: SindragosaGUID = creature->GetGUID(); break; @@ -278,6 +295,23 @@ class instance_icecrown_citadel : public InstanceMapScript ColdflameJetGUIDs.erase(creature->GetGUID()); } + void OnCreatureDeath(Creature* creature) + { + switch (creature->GetEntry()) + { + case NPC_YMIRJAR_BATTLE_MAIDEN: + case NPC_YMIRJAR_DEATHBRINGER: + case NPC_YMIRJAR_FROSTBINDER: + case NPC_YMIRJAR_HUNTRESS: + case NPC_YMIRJAR_WARLORD: + if (Creature* crok = instance->GetCreature(CrokScourgebaneGUID)) + crok->AI()->SetGUID(creature->GetGUID(), ACTION_VRYKUL_DEATH); + break; + default: + break; + } + } + void OnGameObjectCreate(GameObject* go) { switch (go->GetEntry()) @@ -466,6 +500,15 @@ class instance_icecrown_citadel : public InstanceMapScript 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]; + case DATA_SISTER_SVALNA: + return SisterSvalnaGUID; default: break; } @@ -1011,6 +1054,9 @@ class instance_icecrown_citadel : public InstanceMapScript uint64 BloodCouncilGUIDs[3]; uint64 BloodCouncilControllerGUID; uint64 BloodQueenLanaThelGUID; + uint64 CrokScourgebaneGUID; + uint64 CrokCaptainGUIDs[4]; + uint64 SisterSvalnaGUID; uint64 SindragosaGUID; uint64 SpinestalkerGUID; uint64 RimefangGUID; |
