aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorccrs <ccrs@users.noreply.github.com>2019-06-30 17:50:30 +0200
committerShauren <shauren.trinity@gmail.com>2021-12-13 00:42:19 +0100
commitbb321ccb02a3bba15e6f3ac4a481fb3ba991c9fe (patch)
tree8d1607dec5309757898c67a99a01d4d53aab2c6d /src
parent94599bd32350958cab45129eaf5eef741c4c9971 (diff)
Scripts/ICC: move Sister Svalna to her own file
I've almost guttered her, so lets try it more gently this time (cherry picked from commit 1eb2aef1791df5942b3760162d5180cb0bdb51ec)
Diffstat (limited to 'src')
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/boss_sister_svalna.cpp1259
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/go_icecrown_citadel_teleport.cpp (renamed from src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp)8
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp1536
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h31
-rw-r--r--src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp18
5 files changed, 1386 insertions, 1466 deletions
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_sister_svalna.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_sister_svalna.cpp
new file mode 100644
index 00000000000..ac517013fc8
--- /dev/null
+++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_sister_svalna.cpp
@@ -0,0 +1,1259 @@
+/*
+ * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
+ *
+ * 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 "icecrown_citadel.h"
+#include "CellImpl.h"
+#include "InstanceScript.h"
+#include "GridNotifiersImpl.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
+#include "ScriptedEscortAI.h"
+#include "SmartAI.h"
+#include "SpellScript.h"
+#include "VehicleDefines.h"
+
+enum ICCSisterSvalnaTexts
+{
+ 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 ICCSisterSvalnaSpells
+{
+ // 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,
+ SPELL_DIVINE_SURGE = 71465,
+
+ // 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,
+};
+
+enum ICCSisterSvalnaTimedEventIds
+{
+ // Crok Scourgebane
+ EVENT_SCOURGE_STRIKE = 1,
+ EVENT_DEATH_STRIKE,
+ EVENT_HEALTH_CHECK,
+ EVENT_CROK_INTRO_3,
+ EVENT_START_PATHING,
+
+ // Sister Svalna
+ EVENT_ARNATH_INTRO_2,
+ EVENT_SVALNA_START,
+ EVENT_SVALNA_RESURRECT,
+ EVENT_SVALNA_COMBAT,
+ EVENT_IMPALING_SPEAR,
+ EVENT_AETHER_SHIELD,
+
+ // Captain Arnath
+ EVENT_ARNATH_FLASH_HEAL,
+ EVENT_ARNATH_PW_SHIELD,
+ EVENT_ARNATH_SMITE,
+ EVENT_ARNATH_DOMINATE_MIND,
+
+ // Captain Brandon
+ EVENT_BRANDON_CRUSADER_STRIKE,
+ EVENT_BRANDON_DIVINE_SHIELD,
+ EVENT_BRANDON_JUDGEMENT_OF_COMMAND,
+ EVENT_BRANDON_HAMMER_OF_BETRAYAL,
+
+ // Captain Grondel
+ EVENT_GRONDEL_CHARGE_CHECK,
+ EVENT_GRONDEL_MORTAL_STRIKE,
+ EVENT_GRONDEL_SUNDER_ARMOR,
+ EVENT_GRONDEL_CONFLAGRATION,
+
+ // Captain Rupert
+ EVENT_RUPERT_FEL_IRON_BOMB,
+ EVENT_RUPERT_MACHINE_GUN,
+ EVENT_RUPERT_ROCKET_LAUNCH,
+};
+
+enum ICCSisterSvalnaActions
+{
+ ACTION_KILL_CAPTAIN = 1,
+ ACTION_START_GAUNTLET,
+ ACTION_RESURRECT_CAPTAINS,
+ ACTION_CAPTAIN_DIES,
+ ACTION_RESET_EVENT
+};
+
+enum ICCSisterSvalnaMovePoints
+{
+ POINT_SVALNA_LAND = 1
+};
+
+// 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)
+
+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->UpdatePosition(data->spawnPoint);
+
+ creature->DespawnOrUnsummon();
+ creature->SetCorpseDelay(corpseDelay);
+ creature->SetRespawnDelay(respawnDelay);
+ }
+};
+
+class CaptainSurviveTalk : public BasicEvent
+{
+public:
+ explicit CaptainSurviveTalk(Creature const* owner) : _owner(owner) { }
+
+ bool Execute(uint64 /*currTime*/, uint32 /*diff*/) override
+ {
+ _owner->AI()->Talk(SAY_CAPTAIN_SURVIVE_TALK);
+ return true;
+ }
+
+private:
+ Creature const* _owner;
+};
+
+struct boss_sister_svalna : public BossAI
+{
+ boss_sister_svalna(Creature* creature) : BossAI(creature, DATA_SISTER_SVALNA), _isEventInProgress(false) { }
+
+ void InitializeAI() override
+ {
+ if (!me->isDead())
+ Reset();
+
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ void Reset() override
+ {
+ _Reset();
+ me->SetReactState(REACT_DEFENSIVE);
+ _isEventInProgress = false;
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ Talk(SAY_SVALNA_DEATH);
+
+ uint64 delay = 1;
+ for (uint8 itr = 0; itr < 4; ++itr)
+ {
+ if (Creature* crusader = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_CAPTAIN_ARNATH + itr)))
+ {
+ if (crusader->IsAlive() && crusader->GetEntry() == crusader->GetCreatureData()->id)
+ {
+ crusader->m_Events.AddEvent(new CaptainSurviveTalk(crusader), crusader->m_Events.CalculateTime(delay));
+ delay += 6000;
+ }
+ }
+ }
+ }
+
+ void JustEngagedWith(Unit* /*attacker*/) override
+ {
+ _JustEngagedWith();
+ if (Creature* crok = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_CROK_SCOURGEBANE)))
+ crok->AI()->Talk(SAY_CROK_COMBAT_SVALNA);
+ DoCastSelf(SPELL_DIVINE_SURGE, true);
+ events.ScheduleEvent(EVENT_SVALNA_COMBAT, 9s);
+ events.ScheduleEvent(EVENT_IMPALING_SPEAR, 40s, 50s);
+ events.ScheduleEvent(EVENT_AETHER_SHIELD, 100s, 110s);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ 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() override
+ {
+ _JustReachedHome();
+ me->SetReactState(REACT_PASSIVE);
+ me->SetDisableGravity(false);
+ me->SetHover(false);
+ }
+
+ void DoAction(int32 action) override
+ {
+ switch (action)
+ {
+ case ACTION_KILL_CAPTAIN:
+ DoCastSelf(SPELL_CARESS_OF_DEATH, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellMod(SPELLVALUE_MAX_TARGETS, 1));
+ break;
+ case ACTION_START_GAUNTLET:
+ me->setActive(true);
+ me->SetFarVisible(true);
+ _isEventInProgress = true;
+ me->SetImmuneToAll(true);
+ events.ScheduleEvent(EVENT_SVALNA_START, 25s);
+ break;
+ case ACTION_RESURRECT_CAPTAINS:
+ events.ScheduleEvent(EVENT_SVALNA_RESURRECT, 7s);
+ break;
+ case ACTION_CAPTAIN_DIES:
+ Talk(SAY_SVALNA_CAPTAIN_DEATH);
+ break;
+ case ACTION_RESET_EVENT:
+ me->setActive(false);
+ me->SetFarVisible(false);
+ Reset();
+ break;
+ default:
+ break;
+ }
+ }
+
+ void SpellHit(Unit* caster, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_HURL_SPEAR && me->HasAura(SPELL_AETHER_SHIELD))
+ {
+ me->RemoveAurasDueToSpell(SPELL_AETHER_SHIELD);
+ Talk(EMOTE_SVALNA_BROKEN_SHIELD, caster);
+ }
+ }
+
+ void MovementInform(uint32 type, uint32 id) override
+ {
+ if (type != EFFECT_MOTION_TYPE || id != POINT_SVALNA_LAND)
+ return;
+
+ _isEventInProgress = false;
+ me->setActive(false);
+ me->SetFarVisible(false);
+ me->SetImmuneToAll(false);
+ me->SetDisableGravity(false);
+ me->SetHover(false);
+ }
+
+ void SpellHitTarget(Unit* target, SpellInfo const* spell) override
+ {
+ switch (spell->Id)
+ {
+ case SPELL_IMPALING_SPEAR_KILL:
+ Unit::Kill(me, target);
+ break;
+ case SPELL_IMPALING_SPEAR:
+ if (TempSummon* summon = target->SummonCreature(NPC_IMPALING_SPEAR, *target))
+ {
+ Talk(EMOTE_SVALNA_IMPALE, target);
+ CastSpellExtraArgs args;
+ args.AddSpellBP0(1);
+ summon->CastSpell(target, VEHICLE_SPELL_RIDE_HARDCODED, args);
+ summon->AddUnitFlag2(UnitFlags2(UNIT_FLAG2_UNK1 | UNIT_FLAG2_ALLOW_ENEMY_INTERACT));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() && !_isEventInProgress)
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_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);
+ DoCast(me, SPELL_REVIVE_CHAMPION, false);
+ break;
+ case EVENT_SVALNA_COMBAT:
+ me->SetReactState(REACT_DEFENSIVE);
+ Talk(SAY_SVALNA_AGGRO);
+ break;
+ case EVENT_IMPALING_SPEAR:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, true, -SPELL_IMPALING_SPEAR))
+ {
+ DoCast(me, SPELL_AETHER_SHIELD);
+ DoCast(target, SPELL_IMPALING_SPEAR);
+ }
+ events.ScheduleEvent(EVENT_IMPALING_SPEAR, 20s, 25s);
+ break;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+private:
+ bool _isEventInProgress;
+};
+
+struct npc_crok_scourgebane : public EscortAI
+{
+ npc_crok_scourgebane(Creature* creature) : EscortAI(creature), _instance(creature->GetInstanceScript()), _respawnTime(creature->GetRespawnDelay()), _corpseDelay(creature->GetCorpseDelay())
+ {
+ Initialize();
+ SetDespawnAtEnd(false);
+ SetDespawnAtFar(false);
+ _isEventActive = false;
+ _isEventDone = _instance->GetBossState(DATA_SISTER_SVALNA) == DONE;
+ _currentWPid = 0;
+ }
+
+ void Initialize()
+ {
+ _didUnderTenPercentText = false;
+ _wipeCheckTimer = 1000;
+ }
+
+ void Reset() override
+ {
+ _events.Reset();
+ _events.ScheduleEvent(EVENT_SCOURGE_STRIKE, urand(7500, 12500));
+ _events.ScheduleEvent(EVENT_DEATH_STRIKE, 25s, 30s);
+ me->SetReactState(REACT_DEFENSIVE);
+ Initialize();
+ }
+
+ void DoAction(int32 action) override
+ {
+ 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 = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SISTER_SVALNA)))
+ 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, 35s);
+ me->setActive(true);
+ me->SetFarVisible(true);
+
+ for (uint32 itr = 0; itr < 4; ++itr)
+ if (Creature* crusader = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_CAPTAIN_ARNATH + itr)))
+ crusader->AI()->DoAction(ACTION_START_GAUNTLET);
+ }
+ else if (action == ACTION_RESET_EVENT)
+ {
+ _isEventActive = false;
+ _isEventDone = _instance->GetBossState(DATA_SISTER_SVALNA) == DONE;
+ me->setActive(false);
+ me->SetFarVisible(false);
+ _aliveTrash.clear();
+ _currentWPid = 0;
+ }
+ }
+
+ void SetGUID(ObjectGuid const& guid, int32 id) override
+ {
+ if (id == ACTION_VRYKUL_DEATH)
+ {
+ _aliveTrash.erase(guid);
+ if (_aliveTrash.empty())
+ {
+ SetEscortPaused(false);
+ if (_currentWPid == 4 && _isEventActive)
+ {
+ _isEventActive = false;
+ me->setActive(false);
+ me->SetFarVisible(false);
+ Talk(SAY_CROK_FINAL_WP);
+ if (Creature* svalna = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SISTER_SVALNA)))
+ svalna->AI()->DoAction(ACTION_RESURRECT_CAPTAINS);
+ }
+ }
+ }
+ }
+
+ void WaypointReached(uint32 waypointId, uint32 /*pathId*/) override
+ {
+ switch (waypointId)
+ {
+ case 0: // pause pathing until trash pack is cleared
+ me->SetImmuneToNPC(false);
+ 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);
+ me->SetFarVisible(false);
+ Talk(SAY_CROK_FINAL_WP);
+ if (Creature* svalna = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SISTER_SVALNA)))
+ svalna->AI()->DoAction(ACTION_RESURRECT_CAPTAINS);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ void WaypointStarted(uint32 waypointId, uint32 /*pathId*/) override
+ {
+ _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->GetGuidData(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);
+ Cell::VisitGridObjects(me, searcher, 80.0f);
+
+ _aliveTrash.clear();
+ for (auto 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->GetGuidData(DATA_SISTER_SVALNA)))
+ svalna->AI()->DoAction(ACTION_KILL_CAPTAIN);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage) override
+ {
+ // check wipe
+ if (!_wipeCheckTimer)
+ {
+ _wipeCheckTimer = 1000;
+ Player* player = nullptr;
+ Trinity::AnyPlayerInObjectRangeCheck check(me, 60.0f);
+ Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(me, player, check);
+ Cell::VisitWorldObjects(me, searcher, 60.0f);
+ // wipe
+ if (!player)
+ {
+ damage *= 100;
+ if (damage >= me->GetHealth())
+ {
+ FrostwingGauntletRespawner respawner;
+ Trinity::CreatureWorker<FrostwingGauntletRespawner> worker(me, respawner);
+ Cell::VisitGridObjects(me, worker, 333.0f);
+ 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, 1s);
+ }
+ }
+
+ void UpdateEscortAI(uint32 diff) override
+ {
+ if (_wipeCheckTimer <= diff)
+ _wipeCheckTimer = 0;
+ else
+ _wipeCheckTimer -= diff;
+
+ if (!UpdateVictim() && !_isEventActive)
+ return;
+
+ _events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = _events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_ARNATH_INTRO_2:
+ if (Creature* arnath = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(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, 10s, 14s);
+ break;
+ case EVENT_DEATH_STRIKE:
+ if (HealthBelowPct(20))
+ DoCastVictim(SPELL_DEATH_STRIKE);
+ _events.ScheduleEvent(EVENT_DEATH_STRIKE, 5s, 10s);
+ break;
+ case EVENT_HEALTH_CHECK:
+ if (HealthAbovePct(15))
+ {
+ me->RemoveAurasDueToSpell(SPELL_ICEBOUND_ARMOR);
+ _didUnderTenPercentText = false;
+ }
+ else
+ {
+ // looks totally hacky to me
+ me->ModifyHealth(me->CountPctFromMaxHealth(5));
+ _events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ bool CanAIAttack(Unit const* target) const override
+ {
+ // do not see targets inside Frostwing Halls when we are not there
+ return (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f);
+ }
+
+private:
+ EventMap _events;
+ GuidSet _aliveTrash;
+ InstanceScript* _instance;
+ uint32 _currentWPid;
+ uint32 _wipeCheckTimer;
+ uint32 const _respawnTime;
+ uint32 const _corpseDelay;
+ bool _isEventActive;
+ bool _isEventDone;
+ bool _didUnderTenPercentText;
+};
+
+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*/) override
+ {
+ if (_firstDeath)
+ {
+ _firstDeath = false;
+ Talk(SAY_CAPTAIN_DEATH);
+ }
+ else
+ Talk(SAY_CAPTAIN_SECOND_DEATH);
+ }
+
+ void KilledUnit(Unit* victim) override
+ {
+ if (victim->GetTypeId() == TYPEID_PLAYER)
+ Talk(SAY_CAPTAIN_KILL);
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_START_GAUNTLET)
+ {
+ if (Creature* crok = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_CROK_SCOURGEBANE)))
+ {
+ me->SetReactState(REACT_DEFENSIVE);
+ FollowAngle = me->GetAbsoluteAngle(crok) + me->GetOrientation();
+ FollowDist = me->GetDistance2d(crok);
+ me->GetMotionMaster()->MoveFollow(crok, FollowDist, FollowAngle, MOTION_SLOT_DEFAULT);
+ }
+
+ me->setActive(true);
+ me->SetFarVisible(true);
+ }
+ else if (action == ACTION_RESET_EVENT)
+ {
+ _firstDeath = true;
+ }
+ }
+
+ void JustEngagedWith(Unit* /*target*/) override
+ {
+ me->SetHomePosition(*me);
+ if (IsUndead)
+ DoZoneInCombat();
+ }
+
+ bool CanAIAttack(Unit const* target) const override
+ {
+ // do not see targets inside Frostwing Halls when we are not there
+ return (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f);
+ }
+
+ void EnterEvadeMode(EvadeReason why) override
+ {
+ // not yet following
+ if (me->GetMotionMaster()->GetCurrentMovementGeneratorType(MOTION_SLOT_DEFAULT) != FOLLOW_MOTION_TYPE || IsUndead)
+ {
+ ScriptedAI::EnterEvadeMode(why);
+ return;
+ }
+
+ if (!_EnterEvadeMode(why))
+ return;
+
+ if (!me->GetVehicle())
+ {
+ me->GetMotionMaster()->Clear();
+ if (Creature* crok = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_CROK_SCOURGEBANE)))
+ me->GetMotionMaster()->MoveFollow(crok, FollowDist, FollowAngle, MOTION_SLOT_DEFAULT);
+ }
+
+ Reset();
+ }
+
+ void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
+ {
+ if (spell->Id == SPELL_REVIVE_CHAMPION && !IsUndead)
+ {
+ IsUndead = true;
+ me->setDeathState(JUST_RESPAWNED);
+ 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, me->GetCreatureData());
+ DoCast(me, SPELL_UNDEATH, true);
+ }
+ }
+
+protected:
+ EventMap Events;
+ InstanceScript* instance;
+ float FollowAngle;
+ float FollowDist;
+ bool IsUndead;
+
+private:
+ bool _firstDeath;
+};
+
+struct npc_captain_arnath : public npc_argent_captainAI
+{
+ npc_captain_arnath(Creature* creature) : npc_argent_captainAI(creature)
+ {
+ }
+
+ void Reset() override
+ {
+ Events.Reset();
+ Events.ScheduleEvent(EVENT_ARNATH_FLASH_HEAL, 4s, 7s);
+ Events.ScheduleEvent(EVENT_ARNATH_PW_SHIELD, 8s, 14s);
+ Events.ScheduleEvent(EVENT_ARNATH_SMITE, 3s, 6s);
+ if (Is25ManRaid() && IsUndead)
+ Events.ScheduleEvent(EVENT_ARNATH_DOMINATE_MIND, 22s, 27s);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ Events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_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, 6s, 9s);
+ break;
+ case EVENT_ARNATH_PW_SHIELD:
+ {
+ std::list<Creature*> targets = DoFindFriendlyMissingBuff(40.0f, SPELL_POWER_WORD_SHIELD);
+ DoCast(Trinity::Containers::SelectRandomContainerElement(targets), SPELL_POWER_WORD_SHIELD);
+ Events.ScheduleEvent(EVENT_ARNATH_PW_SHIELD, 15s, 20s);
+ break;
+ }
+ case EVENT_ARNATH_SMITE:
+ DoCastVictim(SPELL_SMITE);
+ Events.ScheduleEvent(EVENT_ARNATH_SMITE, 4s, 7s);
+ 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, 28s, 37s);
+ break;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+private:
+ Creature* FindFriendlyCreature() const
+ {
+ Creature* target = nullptr;
+ Trinity::MostHPMissingInRange u_check(me, 60.0f, 0);
+ Trinity::CreatureLastSearcher<Trinity::MostHPMissingInRange> searcher(me, target, u_check);
+ Cell::VisitGridObjects(me, searcher, 60.0f);
+ return target;
+ }
+};
+
+struct npc_captain_brandon : public npc_argent_captainAI
+{
+ npc_captain_brandon(Creature* creature) : npc_argent_captainAI(creature)
+ {
+ }
+
+ void Reset() override
+ {
+ Events.Reset();
+ Events.ScheduleEvent(EVENT_BRANDON_CRUSADER_STRIKE, 6s, 10s);
+ Events.ScheduleEvent(EVENT_BRANDON_DIVINE_SHIELD, 500ms);
+ Events.ScheduleEvent(EVENT_BRANDON_JUDGEMENT_OF_COMMAND, 8s, 13s);
+ if (IsUndead)
+ Events.ScheduleEvent(EVENT_BRANDON_HAMMER_OF_BETRAYAL, 25s, 30s);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ Events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = Events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_BRANDON_CRUSADER_STRIKE:
+ DoCastVictim(SPELL_CRUSADER_STRIKE);
+ Events.ScheduleEvent(EVENT_BRANDON_CRUSADER_STRIKE, 6s, 12s);
+ break;
+ case EVENT_BRANDON_DIVINE_SHIELD:
+ if (HealthBelowPct(20))
+ DoCast(me, SPELL_DIVINE_SHIELD);
+ Events.ScheduleEvent(EVENT_BRANDON_DIVINE_SHIELD, 500ms);
+ break;
+ case EVENT_BRANDON_JUDGEMENT_OF_COMMAND:
+ DoCastVictim(SPELL_JUDGEMENT_OF_COMMAND);
+ Events.ScheduleEvent(EVENT_BRANDON_JUDGEMENT_OF_COMMAND, 8s, 13s);
+ 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, 45s, 60s);
+ break;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+};
+
+struct npc_captain_grondel : public npc_argent_captainAI
+{
+ npc_captain_grondel(Creature* creature) : npc_argent_captainAI(creature)
+ {
+ }
+
+ void Reset() override
+ {
+ Events.Reset();
+ Events.ScheduleEvent(EVENT_GRONDEL_CHARGE_CHECK, 500ms);
+ Events.ScheduleEvent(EVENT_GRONDEL_MORTAL_STRIKE, 8s, 14s);
+ Events.ScheduleEvent(EVENT_GRONDEL_SUNDER_ARMOR, 3s, 12s);
+ if (IsUndead)
+ Events.ScheduleEvent(EVENT_GRONDEL_CONFLAGRATION, 12s, 17s);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ Events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = Events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_GRONDEL_CHARGE_CHECK:
+ DoCastVictim(SPELL_CHARGE);
+ Events.ScheduleEvent(EVENT_GRONDEL_CHARGE_CHECK, 500ms);
+ break;
+ case EVENT_GRONDEL_MORTAL_STRIKE:
+ DoCastVictim(SPELL_MORTAL_STRIKE);
+ Events.ScheduleEvent(EVENT_GRONDEL_MORTAL_STRIKE, 10s, 15s);
+ break;
+ case EVENT_GRONDEL_SUNDER_ARMOR:
+ DoCastVictim(SPELL_SUNDER_ARMOR);
+ Events.ScheduleEvent(EVENT_GRONDEL_SUNDER_ARMOR, 5s, 17s);
+ 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, 10s, 15s);
+ break;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+};
+
+struct npc_captain_rupert : public npc_argent_captainAI
+{
+ npc_captain_rupert(Creature* creature) : npc_argent_captainAI(creature)
+ {
+ }
+
+ void Reset() override
+ {
+ Events.Reset();
+ Events.ScheduleEvent(EVENT_RUPERT_FEL_IRON_BOMB, 15s, 20s);
+ Events.ScheduleEvent(EVENT_RUPERT_MACHINE_GUN, 25s, 30s);
+ Events.ScheduleEvent(EVENT_RUPERT_ROCKET_LAUNCH, 10s, 15s);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim())
+ return;
+
+ Events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_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, 15s, 20s);
+ 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, 25s, 30s);
+ 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, 10s, 15s);
+ break;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+};
+
+struct npc_frostwing_vrykul : public SmartAI
+{
+ npc_frostwing_vrykul(Creature* creature) : SmartAI(creature)
+ {
+ }
+
+ bool CanAIAttack(Unit const* target) const override
+ {
+ // do not see targets inside Frostwing Halls when we are not there
+ return (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f) && SmartAI::CanAIAttack(target);
+ }
+};
+
+struct npc_impaling_spear : public CreatureAI
+{
+ npc_impaling_spear(Creature* creature) : CreatureAI(creature)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ _vehicleCheckTimer = 500;
+ }
+
+ void Reset() override
+ {
+ me->SetReactState(REACT_PASSIVE);
+ Initialize();
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (_vehicleCheckTimer <= diff)
+ {
+ _vehicleCheckTimer = 500;
+ if (!me->GetVehicle())
+ me->DespawnOrUnsummon(100);
+ }
+ else
+ _vehicleCheckTimer -= diff;
+ }
+
+private:
+ uint32 _vehicleCheckTimer;
+};
+
+class ICCSvalnaAliveCheck
+{
+public:
+ bool operator()(WorldObject* object) const
+ {
+ if (Unit* unit = object->ToUnit())
+ return unit->IsAlive();
+ return true;
+ }
+};
+
+class spell_svalna_revive_champion : public SpellScript
+{
+ PrepareSpellScript(spell_svalna_revive_champion);
+
+ void RemoveAliveTarget(std::list<WorldObject*>& targets)
+ {
+ targets.remove_if(ICCSvalnaAliveCheck());
+ Trinity::Containers::RandomResize(targets, 2);
+ }
+
+ void Land(SpellEffIndex /*effIndex*/)
+ {
+ Creature* caster = GetCaster()->ToCreature();
+ if (!caster)
+ return;
+
+ Position pos = caster->GetNearPosition(5.0f, 0.0f);
+ //pos.m_positionZ = caster->GetBaseMap()->GetHeight(caster->GetPhaseMask(), pos.GetPositionX(), pos.GetPositionY(), caster->GetPositionZ(), true, 50.0f);
+ //pos.m_positionZ += 0.05f;
+ caster->SetHomePosition(pos);
+ caster->GetMotionMaster()->MoveLand(POINT_SVALNA_LAND, pos);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_svalna_revive_champion::RemoveAliveTarget, EFFECT_0, TARGET_UNIT_DEST_AREA_ENTRY);
+ OnEffectHit += SpellEffectFn(spell_svalna_revive_champion::Land, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+class spell_svalna_remove_spear : public SpellScript
+{
+ PrepareSpellScript(spell_svalna_remove_spear);
+
+ void HandleScript(SpellEffIndex effIndex)
+ {
+ PreventHitDefaultEffect(effIndex);
+ if (Creature* target = GetHitCreature())
+ {
+ if (Unit* vehicle = target->GetVehicleBase())
+ vehicle->RemoveAurasDueToSpell(SPELL_IMPALING_SPEAR);
+ target->DespawnOrUnsummon(1);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_svalna_remove_spear::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+};
+
+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*/) override
+ {
+ if (InstanceScript* instance = player->GetInstanceScript())
+ if (Creature* crok = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_CROK_SCOURGEBANE)))
+ crok->AI()->DoAction(ACTION_START_GAUNTLET);
+ return true;
+ }
+};
+
+void AddSC_boss_sister_svalna()
+{
+ RegisterIcecrownCitadelCreatureAI(boss_sister_svalna);
+ RegisterIcecrownCitadelCreatureAI(npc_crok_scourgebane);
+ RegisterIcecrownCitadelCreatureAI(npc_captain_arnath);
+ RegisterIcecrownCitadelCreatureAI(npc_captain_brandon);
+ RegisterIcecrownCitadelCreatureAI(npc_captain_grondel);
+ RegisterIcecrownCitadelCreatureAI(npc_captain_rupert);
+ RegisterIcecrownCitadelCreatureAI(npc_frostwing_vrykul);
+ RegisterIcecrownCitadelCreatureAI(npc_impaling_spear);
+ new spell_trigger_spell_from_caster("spell_svalna_caress_of_death", SPELL_IMPALING_SPEAR_KILL);
+ RegisterSpellScript(spell_svalna_revive_champion);
+ RegisterSpellScript(spell_svalna_remove_spear);
+ new at_icc_start_frostwing_gauntlet();
+}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp b/src/server/scripts/Northrend/IcecrownCitadel/go_icecrown_citadel_teleport.cpp
index 97d4696ca68..fab08ce3181 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel_teleport.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/go_icecrown_citadel_teleport.cpp
@@ -97,11 +97,11 @@ class at_frozen_throne_teleport : public AreaTriggerScript
}
if (InstanceScript* instance = player->GetInstanceScript())
- if (instance->GetBossState(DATA_PROFESSOR_PUTRICIDE) == DONE &&
- instance->GetBossState(DATA_BLOOD_QUEEN_LANA_THEL) == DONE &&
- instance->GetBossState(DATA_SINDRAGOSA) == DONE &&
- instance->GetBossState(DATA_THE_LICH_KING) != IN_PROGRESS)
+ {
+ if (instance->GetBossState(DATA_PROFESSOR_PUTRICIDE) == DONE && instance->GetBossState(DATA_BLOOD_QUEEN_LANA_THEL) == DONE &&
+ instance->GetBossState(DATA_SINDRAGOSA) == DONE && instance->GetBossState(DATA_THE_LICH_KING) != IN_PROGRESS)
player->CastSpell(player, FROZEN_THRONE_TELEPORT, true);
+ }
return true;
}
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp
index f59134a2715..5dcdaba4e64 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp
@@ -17,288 +17,152 @@
#include "icecrown_citadel.h"
#include "CellImpl.h"
-#include "GameObject.h"
#include "GameObjectAI.h"
#include "GridNotifiersImpl.h"
#include "InstanceScript.h"
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "PassiveAI.h"
-#include "ScriptedEscortAI.h"
-#include "SmartAI.h"
-#include "SpellInfo.h"
+#include "ScriptedCreature.h"
#include "SpellScript.h"
-#include "TemporarySummon.h"
-#include "VehicleDefines.h"
-
-// Weekly quest support
-// * Deprogramming (DONE)
-// * Securing the Ramparts (DONE)
-// * Residue Rendezvous (DONE)
-// * Blood Quickening (DONE)
-// * Respite for a Tormented Soul
enum ICCTexts
{
// Highlord Tirion Fordring (at Light's Hammer)
- SAY_TIRION_INTRO_1 = 0,
- SAY_TIRION_INTRO_2 = 1,
- SAY_TIRION_INTRO_3 = 2,
- SAY_TIRION_INTRO_4 = 3,
- SAY_TIRION_INTRO_H_5 = 4,
- SAY_TIRION_INTRO_A_5 = 5,
+ SAY_TIRION_INTRO_1 = 0,
+ SAY_TIRION_INTRO_2 = 1,
+ SAY_TIRION_INTRO_3 = 2,
+ SAY_TIRION_INTRO_4 = 3,
+ SAY_TIRION_INTRO_H_5 = 4,
+ SAY_TIRION_INTRO_A_5 = 5,
// The Lich King (at Light's Hammer)
- SAY_LK_INTRO_1 = 0,
- SAY_LK_INTRO_2 = 1,
- SAY_LK_INTRO_3 = 2,
- SAY_LK_INTRO_4 = 3,
- SAY_LK_INTRO_5 = 4,
+ SAY_LK_INTRO_1 = 0,
+ SAY_LK_INTRO_2 = 1,
+ SAY_LK_INTRO_3 = 2,
+ SAY_LK_INTRO_4 = 3,
+ SAY_LK_INTRO_5 = 4,
// Highlord Bolvar Fordragon (at Light's Hammer)
- SAY_BOLVAR_INTRO_1 = 0,
+ SAY_BOLVAR_INTRO_1 = 0,
// High Overlord Saurfang (at Light's Hammer)
- SAY_SAURFANG_INTRO_1 = 15,
- SAY_SAURFANG_INTRO_2 = 16,
- SAY_SAURFANG_INTRO_3 = 17,
- SAY_SAURFANG_INTRO_4 = 18,
+ SAY_SAURFANG_INTRO_1 = 15,
+ SAY_SAURFANG_INTRO_2 = 16,
+ SAY_SAURFANG_INTRO_3 = 17,
+ SAY_SAURFANG_INTRO_4 = 18,
// Muradin Bronzebeard (at Light's Hammer)
- SAY_MURADIN_INTRO_1 = 13,
- SAY_MURADIN_INTRO_2 = 14,
- SAY_MURADIN_INTRO_3 = 15,
+ SAY_MURADIN_INTRO_1 = 13,
+ SAY_MURADIN_INTRO_2 = 14,
+ SAY_MURADIN_INTRO_3 = 15,
// Deathbound Ward
- SAY_TRAP_ACTIVATE = 0,
+ SAY_TRAP_ACTIVATE = 0,
// 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,
+ EMOTE_DEATH_PLAGUE_WARNING = 0,
};
enum ICCSpells
{
// Rotting Frost Giant
- SPELL_DEATH_PLAGUE = 72879,
- SPELL_DEATH_PLAGUE_AURA = 72865,
- SPELL_RECENTLY_INFECTED = 72884,
- SPELL_DEATH_PLAGUE_KILL = 72867,
- SPELL_STOMP = 64652,
- SPELL_ARCTIC_BREATH = 72848,
+ SPELL_DEATH_PLAGUE = 72879,
+ SPELL_DEATH_PLAGUE_AURA = 72865,
+ SPELL_RECENTLY_INFECTED = 72884,
+ SPELL_DEATH_PLAGUE_KILL = 72867,
+ SPELL_STOMP = 64652,
+ SPELL_ARCTIC_BREATH = 72848,
// Frost Freeze Trap
- SPELL_COLDFLAME_JETS = 70460,
+ SPELL_COLDFLAME_JETS = 70460,
// Alchemist Adrianna
- SPELL_HARVEST_BLIGHT_SPECIMEN = 72155,
+ 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,
- SPELL_DIVINE_SURGE = 71465,
-
- // 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,
-
// Invisible Stalker (Float, Uninteractible, LargeAOI)
- SPELL_SOUL_MISSILE = 72585,
+ SPELL_SOUL_MISSILE = 72585,
// Empowering Blood Orb
- SPELL_EMPOWERED_BLOOD_2 = 70232,
- SPELL_EMPOWERED_BLOOD_3 = 70304,
- SPELL_EMPOWERED_BLOOD_4 = 70320,
- SPELL_ORB_CONTROLLER_ACTIVE = 70293,
+ SPELL_EMPOWERED_BLOOD_2 = 70232,
+ SPELL_EMPOWERED_BLOOD_3 = 70304,
+ SPELL_EMPOWERED_BLOOD_4 = 70320,
+ SPELL_ORB_CONTROLLER_ACTIVE = 70293,
// Darkfallen Generic
- SPELL_BLOOD_ORB_VISUAL = 72099,
- SPELL_SIPHON_ESSENCE = 70299,
+ SPELL_BLOOD_ORB_VISUAL = 72099,
+ SPELL_SIPHON_ESSENCE = 70299,
// Darkfallen Blood Knight
- SPELL_VAMPIRIC_AURA = 71736,
- SPELL_BLOOD_MIRROR = 70450,
- SPELL_BLOOD_MIRROR_2 = 70451,
+ SPELL_VAMPIRIC_AURA = 71736,
+ SPELL_BLOOD_MIRROR = 70450,
+ SPELL_BLOOD_MIRROR_2 = 70451,
SPELL_BLOOD_MIRROR_DAMAGE_SHARE = 70445,
- SPELL_UNHOLY_STRIKE = 70437,
+ SPELL_UNHOLY_STRIKE = 70437,
// Darkfallen Noble
- SPELL_SHADOW_BOLT = 72960,
- SPELL_CHAINS_OF_SHADOW = 72960,
+ SPELL_SHADOW_BOLT = 72960,
+ SPELL_CHAINS_OF_SHADOW = 72960,
// Darkfallen Archmage
- SPELL_FIREBALL = 70409,
- SPELL_AMPLIFY_MAGIC = 70408,
- SPELL_BLAST_WAVE = 70407,
- SPELL_POLYMORPH_ALLY = 72106,
- SPELL_POLYMORPH = 70410,
+ SPELL_FIREBALL = 70409,
+ SPELL_AMPLIFY_MAGIC = 70408,
+ SPELL_BLAST_WAVE = 70407,
+ SPELL_POLYMORPH_ALLY = 72106,
+ SPELL_POLYMORPH = 70410,
// Darkfallen Advisor
- SPELL_LICH_SLAP = 72057,
- SPELL_SHROUD_OF_SPELL_WARDING = 72066,
+ SPELL_LICH_SLAP = 72057,
+ SPELL_SHROUD_OF_SPELL_WARDING = 72066,
// Vampiric Fiend
- SPELL_DISEASE_CLOUD = 41290,
- SPELL_LEECHING_ROOT = 70671,
+ SPELL_DISEASE_CLOUD = 41290,
+ SPELL_LEECHING_ROOT = 70671,
// Darkfallen Tactician
- SPELL_SHADOWSTEP = 70431,
- SPELL_BLOOD_SAP = 70432
+ SPELL_SHADOWSTEP = 70431,
+ SPELL_BLOOD_SAP = 70432
};
-// 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 ICCEventTypes
+enum ICCTimedEventIds
{
- // Highlord Tirion Fordring (at Light's Hammer)
- // The Lich King (at Light's Hammer)
- // Highlord Bolvar Fordragon (at Light's Hammer)
- // High Overlord Saurfang (at Light's Hammer)
- // Muradin Bronzebeard (at Light's Hammer)
- EVENT_TIRION_INTRO_2 = 1,
- EVENT_TIRION_INTRO_3 = 2,
- EVENT_TIRION_INTRO_4 = 3,
- EVENT_TIRION_INTRO_5 = 4,
- EVENT_LK_INTRO_1 = 5,
- EVENT_TIRION_INTRO_6 = 6,
- EVENT_LK_INTRO_2 = 7,
- EVENT_LK_INTRO_3 = 8,
- EVENT_LK_INTRO_4 = 9,
- EVENT_BOLVAR_INTRO_1 = 10,
- EVENT_LK_INTRO_5 = 11,
- EVENT_SAURFANG_INTRO_1 = 12,
- EVENT_TIRION_INTRO_H_7 = 13,
- EVENT_SAURFANG_INTRO_2 = 14,
- EVENT_SAURFANG_INTRO_3 = 15,
- EVENT_SAURFANG_INTRO_4 = 16,
- EVENT_SAURFANG_RUN = 17,
- EVENT_MURADIN_INTRO_1 = 18,
- EVENT_MURADIN_INTRO_2 = 19,
- EVENT_MURADIN_INTRO_3 = 20,
- EVENT_TIRION_INTRO_A_7 = 21,
- EVENT_MURADIN_INTRO_4 = 22,
- EVENT_MURADIN_INTRO_5 = 23,
- EVENT_MURADIN_RUN = 24,
+ // Light's Hammer RP
+ EVENT_TIRION_INTRO_2 = 1,
+ EVENT_TIRION_INTRO_3,
+ EVENT_TIRION_INTRO_4,
+ EVENT_TIRION_INTRO_5,
+ EVENT_LK_INTRO_1,
+ EVENT_TIRION_INTRO_6,
+ EVENT_LK_INTRO_2,
+ EVENT_LK_INTRO_3,
+ EVENT_LK_INTRO_4,
+ EVENT_BOLVAR_INTRO_1,
+ EVENT_LK_INTRO_5,
+ EVENT_SAURFANG_INTRO_1,
+ EVENT_TIRION_INTRO_H_7,
+ EVENT_SAURFANG_INTRO_2,
+ EVENT_SAURFANG_INTRO_3,
+ EVENT_SAURFANG_INTRO_4,
+ EVENT_SAURFANG_RUN,
+ EVENT_MURADIN_INTRO_1,
+ EVENT_MURADIN_INTRO_2,
+ EVENT_MURADIN_INTRO_3,
+ EVENT_TIRION_INTRO_A_7,
+ EVENT_MURADIN_INTRO_4,
+ EVENT_MURADIN_INTRO_5,
+ EVENT_MURADIN_RUN,
// Rotting Frost Giant
- EVENT_DEATH_PLAGUE = 25,
- EVENT_STOMP = 26,
- EVENT_ARCTIC_BREATH = 27,
+ EVENT_DEATH_PLAGUE,
+ EVENT_STOMP,
+ EVENT_ARCTIC_BREATH,
// 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,
+ EVENT_ACTIVATE_TRAP,
// Invisible Stalker (Float, Uninteractible, LargeAOI)
- EVENT_SOUL_MISSILE = 55,
+ EVENT_SOUL_MISSILE,
};
enum ICCDataTypes
@@ -309,15 +173,9 @@ enum ICCDataTypes
enum ICCActions
{
- // Sister Svalna
- ACTION_KILL_CAPTAIN = 1,
- ACTION_START_GAUNTLET = 2,
- ACTION_RESURRECT_CAPTAINS = 3,
- ACTION_CAPTAIN_DIES = 4,
- ACTION_RESET_EVENT = 5,
- ACTION_SIPHON_INTERRUPTED = 6,
- ACTION_EVADE = 7,
- ACTION_COMBAT = 8
+ ACTION_SIPHON_INTERRUPTED = 1,
+ ACTION_EVADE,
+ ACTION_COMBAT
};
enum ICCEventIds
@@ -330,99 +188,8 @@ enum ICCEventIds
enum ICCMisc
{
- POINT_LAND = 1,
- ICC_BUFF_MENUID_ALLY = 11204,
- ICC_BUFF_MENUID_HORDE = 11207
-};
-
-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->UpdatePosition(data->spawnPoint);
- creature->DespawnOrUnsummon();
-
- creature->SetCorpseDelay(corpseDelay);
- creature->SetRespawnDelay(respawnDelay);
- }
-};
-
-class CaptainSurviveTalk : public BasicEvent
-{
- public:
- explicit CaptainSurviveTalk(Creature const& owner) : _owner(owner) { }
-
- bool Execute(uint64 /*currTime*/, uint32 /*diff*/) override
- {
- _owner.AI()->Talk(SAY_CAPTAIN_SURVIVE_TALK);
- return true;
- }
-
- private:
- Creature const& _owner;
+ GOSSIP_MENUID_ALLY = 11204,
+ GOSSIP_MENUID_HORDE = 11207
};
// at Light's Hammer
@@ -791,1003 +558,6 @@ 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() override
- {
- if (!me->isDead())
- Reset();
-
- me->SetReactState(REACT_PASSIVE);
- }
-
- void Reset() override
- {
- _Reset();
- me->SetReactState(REACT_DEFENSIVE);
- _isEventInProgress = false;
- }
-
- void JustDied(Unit* /*killer*/) override
- {
- _JustDied();
- Talk(SAY_SVALNA_DEATH);
-
- uint64 delay = 1;
- for (uint32 i = 0; i < 4; ++i)
- {
- if (Creature* crusader = ObjectAccessor::GetCreature(*me, instance->GetGuidData(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 JustEngagedWith(Unit* /*attacker*/) override
- {
- _JustEngagedWith();
- if (Creature* crok = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_CROK_SCOURGEBANE)))
- crok->AI()->Talk(SAY_CROK_COMBAT_SVALNA);
- DoCastSelf(SPELL_DIVINE_SURGE, true);
- events.ScheduleEvent(EVENT_SVALNA_COMBAT, 9s);
- events.ScheduleEvent(EVENT_IMPALING_SPEAR, 40s, 50s);
- events.ScheduleEvent(EVENT_AETHER_SHIELD, urand(100000, 110000));
- }
-
- void KilledUnit(Unit* victim) override
- {
- 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() override
- {
- _JustReachedHome();
- me->SetReactState(REACT_PASSIVE);
- me->SetDisableGravity(false);
- me->SetHover(false);
- }
-
- void DoAction(int32 action) override
- {
- switch (action)
- {
- case ACTION_KILL_CAPTAIN:
- DoCastSelf(SPELL_CARESS_OF_DEATH, CastSpellExtraArgs(TRIGGERED_FULL_MASK).AddSpellMod(SPELLVALUE_MAX_TARGETS, 1));
- break;
- case ACTION_START_GAUNTLET:
- me->setActive(true);
- me->SetFarVisible(true);
- _isEventInProgress = true;
- me->SetImmuneToAll(true);
- events.ScheduleEvent(EVENT_SVALNA_START, 25s);
- break;
- case ACTION_RESURRECT_CAPTAINS:
- events.ScheduleEvent(EVENT_SVALNA_RESURRECT, 7s);
- break;
- case ACTION_CAPTAIN_DIES:
- Talk(SAY_SVALNA_CAPTAIN_DEATH);
- break;
- case ACTION_RESET_EVENT:
- me->setActive(false);
- me->SetFarVisible(false);
- Reset();
- break;
- default:
- break;
- }
- }
-
- void SpellHit(Unit* caster, SpellInfo const* spell) override
- {
- if (spell->Id == SPELL_HURL_SPEAR && me->HasAura(SPELL_AETHER_SHIELD))
- {
- me->RemoveAurasDueToSpell(SPELL_AETHER_SHIELD);
- Talk(EMOTE_SVALNA_BROKEN_SHIELD, caster);
- }
- }
-
- void MovementInform(uint32 type, uint32 id) override
- {
- if (type != EFFECT_MOTION_TYPE || id != POINT_LAND)
- return;
-
- _isEventInProgress = false;
- me->setActive(false);
- me->SetFarVisible(false);
- me->SetImmuneToAll(false);
- me->SetDisableGravity(false);
- me->SetHover(false);
- }
-
- void SpellHitTarget(Unit* target, SpellInfo const* spell) override
- {
- switch (spell->Id)
- {
- case SPELL_IMPALING_SPEAR_KILL:
- Unit::Kill(me, target);
- break;
- case SPELL_IMPALING_SPEAR:
- if (TempSummon* summon = target->SummonCreature(NPC_IMPALING_SPEAR, *target))
- {
- Talk(EMOTE_SVALNA_IMPALE, target);
- CastSpellExtraArgs args;
- args.AddSpellBP0(1);
- summon->CastSpell(target, VEHICLE_SPELL_RIDE_HARDCODED, args);
- summon->AddUnitFlag2(UnitFlags2(UNIT_FLAG2_UNK1 | UNIT_FLAG2_ALLOW_ENEMY_INTERACT));
- }
- break;
- default:
- break;
- }
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim() && !_isEventInProgress)
- return;
-
- events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_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->SetReactState(REACT_DEFENSIVE);
- Talk(SAY_SVALNA_AGGRO);
- break;
- case EVENT_IMPALING_SPEAR:
- if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1, 0.0f, true, true, -SPELL_IMPALING_SPEAR))
- {
- DoCast(me, SPELL_AETHER_SHIELD);
- DoCast(target, SPELL_IMPALING_SPEAR);
- }
- events.ScheduleEvent(EVENT_IMPALING_SPEAR, 20s, 25s);
- break;
- default:
- break;
- }
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
- }
-
- DoMeleeAttackIfReady();
- }
-
- private:
- bool _isEventInProgress;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- 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 EscortAI
- {
- npc_crok_scourgebaneAI(Creature* creature) : EscortAI(creature),
- _instance(creature->GetInstanceScript()), _respawnTime(creature->GetRespawnDelay()),
- _corpseDelay(creature->GetCorpseDelay())
- {
- Initialize();
- SetDespawnAtEnd(false);
- SetDespawnAtFar(false);
- _isEventActive = false;
- _isEventDone = _instance->GetBossState(DATA_SISTER_SVALNA) == DONE;
- _currentWPid = 0;
- }
-
- void Initialize()
- {
- _didUnderTenPercentText = false;
- _wipeCheckTimer = 1000;
- }
-
- void Reset() override
- {
- _events.Reset();
- _events.ScheduleEvent(EVENT_SCOURGE_STRIKE, urand(7500, 12500));
- _events.ScheduleEvent(EVENT_DEATH_STRIKE, 25s, 30s);
- me->SetReactState(REACT_DEFENSIVE);
- Initialize();
- }
-
- void DoAction(int32 action) override
- {
- 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 = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SISTER_SVALNA)))
- 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, 35s);
- me->setActive(true);
- me->SetFarVisible(true);
- for (uint32 i = 0; i < 4; ++i)
- if (Creature* crusader = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_CAPTAIN_ARNATH + i)))
- crusader->AI()->DoAction(ACTION_START_GAUNTLET);
- }
- else if (action == ACTION_RESET_EVENT)
- {
- _isEventActive = false;
- _isEventDone = _instance->GetBossState(DATA_SISTER_SVALNA) == DONE;
- me->setActive(false);
- me->SetFarVisible(false);
- _aliveTrash.clear();
- _currentWPid = 0;
- }
- }
-
- void SetGUID(ObjectGuid const& guid, int32 id) override
- {
- if (id == ACTION_VRYKUL_DEATH)
- {
- _aliveTrash.erase(guid);
- if (_aliveTrash.empty())
- {
- SetEscortPaused(false);
- if (_currentWPid == 4 && _isEventActive)
- {
- _isEventActive = false;
- me->setActive(false);
- me->SetFarVisible(false);
- Talk(SAY_CROK_FINAL_WP);
- if (Creature* svalna = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SISTER_SVALNA)))
- svalna->AI()->DoAction(ACTION_RESURRECT_CAPTAINS);
- }
- }
- }
- }
-
- void WaypointReached(uint32 waypointId, uint32 /*pathId*/) override
- {
- switch (waypointId)
- {
- // pause pathing until trash pack is cleared
- case 0:
- me->SetImmuneToNPC(false);
- 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);
- me->SetFarVisible(false);
- Talk(SAY_CROK_FINAL_WP);
- if (Creature* svalna = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_SISTER_SVALNA)))
- svalna->AI()->DoAction(ACTION_RESURRECT_CAPTAINS);
- }
- break;
- default:
- break;
- }
- }
-
- void WaypointStarted(uint32 waypointId, uint32 /*pathId*/) override
- {
- _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->GetGuidData(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);
- Cell::VisitGridObjects(me, searcher, 80.0f);
-
- _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->GetGuidData(DATA_SISTER_SVALNA)))
- svalna->AI()->DoAction(ACTION_KILL_CAPTAIN);
- break;
- default:
- break;
- }
- }
-
- void DamageTaken(Unit* /*attacker*/, uint32& damage) override
- {
- // check wipe
- if (!_wipeCheckTimer)
- {
- _wipeCheckTimer = 1000;
- Player* player = nullptr;
- Trinity::AnyPlayerInObjectRangeCheck check(me, 60.0f);
- Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(me, player, check);
- Cell::VisitWorldObjects(me, searcher, 60.0f);
- // wipe
- if (!player)
- {
- damage *= 100;
- if (damage >= me->GetHealth())
- {
- FrostwingGauntletRespawner respawner;
- Trinity::CreatureWorker<FrostwingGauntletRespawner> worker(me, respawner);
- Cell::VisitGridObjects(me, worker, 333.0f);
- 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, 1s);
- }
- }
-
- void UpdateEscortAI(uint32 diff) override
- {
- if (_wipeCheckTimer <= diff)
- _wipeCheckTimer = 0;
- else
- _wipeCheckTimer -= diff;
-
- if (!UpdateVictim() && !_isEventActive)
- return;
-
- _events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- while (uint32 eventId = _events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_ARNATH_INTRO_2:
- if (Creature* arnath = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(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, 10s, 14s);
- break;
- case EVENT_DEATH_STRIKE:
- if (HealthBelowPct(20))
- DoCastVictim(SPELL_DEATH_STRIKE);
- _events.ScheduleEvent(EVENT_DEATH_STRIKE, 5s, 10s);
- break;
- case EVENT_HEALTH_CHECK:
- if (HealthAbovePct(15))
- {
- me->RemoveAurasDueToSpell(SPELL_ICEBOUND_ARMOR);
- _didUnderTenPercentText = false;
- }
- else
- {
- // looks totally hacky to me
- me->ModifyHealth(me->CountPctFromMaxHealth(5));
- _events.ScheduleEvent(EVENT_HEALTH_CHECK, 1s);
- }
- break;
- default:
- break;
- }
- }
-
- DoMeleeAttackIfReady();
- }
-
- bool CanAIAttack(Unit const* target) const override
- {
- // do not see targets inside Frostwing Halls when we are not there
- return (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f);
- }
-
- private:
- EventMap _events;
- GuidSet _aliveTrash;
- InstanceScript* _instance;
- uint32 _currentWPid;
- uint32 _wipeCheckTimer;
- uint32 const _respawnTime;
- uint32 const _corpseDelay;
- bool _isEventActive;
- bool _isEventDone;
- bool _didUnderTenPercentText;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- 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*/) override
- {
- if (_firstDeath)
- {
- _firstDeath = false;
- Talk(SAY_CAPTAIN_DEATH);
- }
- else
- Talk(SAY_CAPTAIN_SECOND_DEATH);
- }
-
- void KilledUnit(Unit* victim) override
- {
- if (victim->GetTypeId() == TYPEID_PLAYER)
- Talk(SAY_CAPTAIN_KILL);
- }
-
- void DoAction(int32 action) override
- {
- if (action == ACTION_START_GAUNTLET)
- {
- if (Creature* crok = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_CROK_SCOURGEBANE)))
- {
- me->SetReactState(REACT_DEFENSIVE);
- FollowAngle = me->GetAbsoluteAngle(crok) + me->GetOrientation();
- FollowDist = me->GetDistance2d(crok);
- me->GetMotionMaster()->MoveFollow(crok, FollowDist, FollowAngle, MOTION_SLOT_DEFAULT);
- }
-
- me->setActive(true);
- me->SetFarVisible(true);
- }
- else if (action == ACTION_RESET_EVENT)
- {
- _firstDeath = true;
- }
- }
-
- void JustEngagedWith(Unit* /*target*/) override
- {
- me->SetHomePosition(*me);
- if (IsUndead)
- DoZoneInCombat();
- }
-
- bool CanAIAttack(Unit const* target) const override
- {
- // do not see targets inside Frostwing Halls when we are not there
- return (me->GetPositionY() > 2660.0f) == (target->GetPositionY() > 2660.0f);
- }
-
- void EnterEvadeMode(EvadeReason why) override
- {
- // not yet following
- if (me->GetMotionMaster()->GetCurrentMovementGeneratorType(MOTION_SLOT_DEFAULT) != FOLLOW_MOTION_TYPE || IsUndead)
- {
- ScriptedAI::EnterEvadeMode(why);
- return;
- }
-
- if (!_EnterEvadeMode(why))
- return;
-
- if (!me->GetVehicle())
- {
- me->GetMotionMaster()->Clear();
- if (Creature* crok = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_CROK_SCOURGEBANE)))
- me->GetMotionMaster()->MoveFollow(crok, FollowDist, FollowAngle, MOTION_SLOT_DEFAULT);
- }
-
- Reset();
- }
-
- void SpellHit(Unit* /*caster*/, SpellInfo const* spell) override
- {
- if (spell->Id == SPELL_REVIVE_CHAMPION && !IsUndead)
- {
- IsUndead = true;
- me->setDeathState(JUST_RESPAWNED);
- 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, 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() override
- {
- Events.Reset();
- Events.ScheduleEvent(EVENT_ARNATH_FLASH_HEAL, 4s, 7s);
- Events.ScheduleEvent(EVENT_ARNATH_PW_SHIELD, 8s, 14s);
- Events.ScheduleEvent(EVENT_ARNATH_SMITE, 3s, 6s);
- if (Is25ManRaid() && IsUndead)
- Events.ScheduleEvent(EVENT_ARNATH_DOMINATE_MIND, 22s, 27s);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- Events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_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, 6s, 9s);
- break;
- case EVENT_ARNATH_PW_SHIELD:
- {
- std::list<Creature*> targets = DoFindFriendlyMissingBuff(40.0f, SPELL_POWER_WORD_SHIELD);
- DoCast(Trinity::Containers::SelectRandomContainerElement(targets), SPELL_POWER_WORD_SHIELD);
- Events.ScheduleEvent(EVENT_ARNATH_PW_SHIELD, 15s, 20s);
- break;
- }
- case EVENT_ARNATH_SMITE:
- DoCastVictim(SPELL_SMITE);
- Events.ScheduleEvent(EVENT_ARNATH_SMITE, 4s, 7s);
- 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, 28s, 37s);
- break;
- default:
- break;
- }
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
- }
-
- DoMeleeAttackIfReady();
- }
-
- private:
- Creature* FindFriendlyCreature() const
- {
- Creature* target = nullptr;
- Trinity::MostHPMissingInRange u_check(me, 60.0f, 0);
- Trinity::CreatureLastSearcher<Trinity::MostHPMissingInRange> searcher(me, target, u_check);
- Cell::VisitGridObjects(me, searcher, 60.0f);
- return target;
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- 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() override
- {
- Events.Reset();
- Events.ScheduleEvent(EVENT_BRANDON_CRUSADER_STRIKE, 6s, 10s);
- Events.ScheduleEvent(EVENT_BRANDON_DIVINE_SHIELD, 500ms);
- Events.ScheduleEvent(EVENT_BRANDON_JUDGEMENT_OF_COMMAND, 8s, 13s);
- if (IsUndead)
- Events.ScheduleEvent(EVENT_BRANDON_HAMMER_OF_BETRAYAL, 25s, 30s);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- Events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- while (uint32 eventId = Events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_BRANDON_CRUSADER_STRIKE:
- DoCastVictim(SPELL_CRUSADER_STRIKE);
- Events.ScheduleEvent(EVENT_BRANDON_CRUSADER_STRIKE, 6s, 12s);
- break;
- case EVENT_BRANDON_DIVINE_SHIELD:
- if (HealthBelowPct(20))
- DoCast(me, SPELL_DIVINE_SHIELD);
- Events.ScheduleEvent(EVENT_BRANDON_DIVINE_SHIELD, 500ms);
- break;
- case EVENT_BRANDON_JUDGEMENT_OF_COMMAND:
- DoCastVictim(SPELL_JUDGEMENT_OF_COMMAND);
- Events.ScheduleEvent(EVENT_BRANDON_JUDGEMENT_OF_COMMAND, 8s, 13s);
- 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, 45s, 60s);
- break;
- default:
- break;
- }
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- 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() override
- {
- Events.Reset();
- Events.ScheduleEvent(EVENT_GRONDEL_CHARGE_CHECK, 500ms);
- Events.ScheduleEvent(EVENT_GRONDEL_MORTAL_STRIKE, 8s, 14s);
- Events.ScheduleEvent(EVENT_GRONDEL_SUNDER_ARMOR, 3s, 12s);
- if (IsUndead)
- Events.ScheduleEvent(EVENT_GRONDEL_CONFLAGRATION, 12s, 17s);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- Events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
-
- while (uint32 eventId = Events.ExecuteEvent())
- {
- switch (eventId)
- {
- case EVENT_GRONDEL_CHARGE_CHECK:
- DoCastVictim(SPELL_CHARGE);
- Events.ScheduleEvent(EVENT_GRONDEL_CHARGE_CHECK, 500ms);
- break;
- case EVENT_GRONDEL_MORTAL_STRIKE:
- DoCastVictim(SPELL_MORTAL_STRIKE);
- Events.ScheduleEvent(EVENT_GRONDEL_MORTAL_STRIKE, 10s, 15s);
- break;
- case EVENT_GRONDEL_SUNDER_ARMOR:
- DoCastVictim(SPELL_SUNDER_ARMOR);
- Events.ScheduleEvent(EVENT_GRONDEL_SUNDER_ARMOR, 5s, 17s);
- 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, 10s, 15s);
- break;
- default:
- break;
- }
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- 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() override
- {
- Events.Reset();
- Events.ScheduleEvent(EVENT_RUPERT_FEL_IRON_BOMB, 15s, 20s);
- Events.ScheduleEvent(EVENT_RUPERT_MACHINE_GUN, 25s, 30s);
- Events.ScheduleEvent(EVENT_RUPERT_ROCKET_LAUNCH, 10s, 15s);
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (!UpdateVictim())
- return;
-
- Events.Update(diff);
-
- if (me->HasUnitState(UNIT_STATE_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, 15s, 20s);
- 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, 25s, 30s);
- 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, 10s, 15s);
- break;
- default:
- break;
- }
-
- if (me->HasUnitState(UNIT_STATE_CASTING))
- return;
- }
-
- DoMeleeAttackIfReady();
- }
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- 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 override
- {
- // 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 override
- {
- return GetIcecrownCitadelAI<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)
- {
- Initialize();
- }
-
- void Initialize()
- {
- _vehicleCheckTimer = 500;
- }
-
- void Reset() override
- {
- me->SetReactState(REACT_PASSIVE);
- Initialize();
- }
-
- void UpdateAI(uint32 diff) override
- {
- if (_vehicleCheckTimer <= diff)
- {
- _vehicleCheckTimer = 500;
- if (!me->GetVehicle())
- me->DespawnOrUnsummon(100);
- }
- else
- _vehicleCheckTimer -= diff;
- }
-
- uint32 _vehicleCheckTimer;
- };
-
- CreatureAI* GetAI(Creature* creature) const override
- {
- return GetIcecrownCitadelAI<npc_impaling_spearAI>(creature);
- }
-};
-
class npc_arthas_teleport_visual : public CreatureScript
{
public:
@@ -1844,17 +614,17 @@ struct npc_entrance_faction_leader : public ScriptedAI
bool GossipSelect(Player* /*player*/, uint32 menuId, uint32 /*gossipListId*/) override
{
- if (menuId == ICC_BUFF_MENUID_ALLY || menuId == ICC_BUFF_MENUID_HORDE)
+ if (menuId == GOSSIP_MENUID_ALLY || menuId == GOSSIP_MENUID_HORDE)
if (InstanceScript* instance = me->GetInstanceScript())
instance->SetData(DATA_FACTION_BUFF, 0);
return false;
}
};
-class MinionSearch
+class ICCOrbControllerMinionSearch
{
public:
- MinionSearch(Unit* owner, bool checkCasting) : _owner(owner), _checkCasting(checkCasting) { }
+ ICCOrbControllerMinionSearch(Unit* owner, bool checkCasting) : _owner(owner), _checkCasting(checkCasting) { }
bool operator()(Creature* target) const
{
@@ -1880,7 +650,7 @@ private:
bool _checkCasting;
};
-std::vector<uint32> DarkFallensEmotes =
+static std::vector<uint32> const DarkFallensEmotes =
{
EMOTE_ONESHOT_TALK,
EMOTE_ONESHOT_EXCLAMATION,
@@ -1899,8 +669,8 @@ struct npc_icc_orb_controller : public ScriptedAI
_scheduler.Schedule(1s, [this](TaskContext /*initialize*/)
{
std::vector<Creature*> creatures;
- MinionSearch check(me, false);
- Trinity::CreatureListSearcher<MinionSearch> searcher(me, creatures, check);
+ ICCOrbControllerMinionSearch check(me, false);
+ Trinity::CreatureListSearcher<ICCOrbControllerMinionSearch> searcher(me, creatures, check);
Cell::VisitGridObjects(me, searcher, 10.0f);
if (creatures.empty())
@@ -2026,8 +796,8 @@ struct DarkFallenAI : public ScriptedAI
if (roll_chance_i(20))
{
std::vector<Creature*> creatures;
- MinionSearch check(me, true);
- Trinity::CreatureListSearcher<MinionSearch> searcher(me, creatures, check);
+ ICCOrbControllerMinionSearch check(me, true);
+ Trinity::CreatureListSearcher<ICCOrbControllerMinionSearch> searcher(me, creatures, check);
Cell::VisitGridObjects(me, searcher, 10.0f);
if (!creatures.empty())
{
@@ -2660,90 +1430,6 @@ class spell_icc_harvest_blight_specimen : public SpellScriptLoader
}
};
-class AliveCheck
-{
- public:
- bool operator()(WorldObject* object) const
- {
- if (Unit* unit = object->ToUnit())
- return unit->IsAlive();
- return true;
- }
-};
-
-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<WorldObject*>& targets)
- {
- targets.remove_if(AliveCheck());
- Trinity::Containers::RandomResize(targets, 2);
- }
-
- void Land(SpellEffIndex /*effIndex*/)
- {
- Creature* caster = GetCaster()->ToCreature();
- if (!caster)
- return;
-
- Position pos = caster->GetNearPosition(5.0f, 0.0f);
- //pos.m_positionZ = caster->GetBaseMap()->GetHeight(caster->GetPhases(), pos.GetPositionX(), pos.GetPositionY(), caster->GetPositionZ(), true, 50.0f);
- //pos.m_positionZ += 0.05f;
- caster->SetHomePosition(pos);
- caster->GetMotionMaster()->MoveLand(POINT_LAND, pos);
- }
-
- void Register() override
- {
- OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_svalna_revive_champion_SpellScript::RemoveAliveTarget, EFFECT_0, TARGET_UNIT_DEST_AREA_ENTRY);
- OnEffectHit += SpellEffectFn(spell_svalna_revive_champion_SpellScript::Land, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- 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())
- {
- if (Unit* vehicle = target->GetVehicleBase())
- vehicle->RemoveAurasDueToSpell(SPELL_IMPALING_SPEAR);
- target->DespawnOrUnsummon(1);
- }
- }
-
- void Register() override
- {
- OnEffectHitTarget += SpellEffectFn(spell_svalna_remove_spear_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
- }
- };
-
- SpellScript* GetSpellScript() const override
- {
- return new spell_svalna_remove_spear_SpellScript();
- }
-};
-
// 72585 - Soul Missile
class spell_icc_soul_missile : public SpellScriptLoader
{
@@ -2877,34 +1563,12 @@ 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*/) override
- {
- if (InstanceScript* instance = player->GetInstanceScript())
- if (Creature* crok = ObjectAccessor::GetCreature(*player, instance->GetGuidData(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 npc_arthas_teleport_visual();
RegisterIcecrownCitadelCreatureAI(npc_entrance_faction_leader);
RegisterIcecrownCitadelCreatureAI(npc_icc_orb_controller);
@@ -2924,12 +1588,8 @@ void AddSC_icecrown_citadel()
new spell_icc_sprit_alarm();
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 spell_icc_soul_missile();
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 4ac39246b7b..7704fffea75 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
+++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h
@@ -21,24 +21,10 @@
#include "CreatureAIImpl.h"
#include "ScriptMgr.h"
-struct Position;
-enum TriggerCastFlags : uint32;
-
#define ICCScriptName "instance_icecrown_citadel"
-#define DataHeader "IC"
+#define DataHeader "IC"
uint32 const EncounterCount = 13;
-uint32 const WeeklyNPCs = 9;
-uint32 const MaxHeroicAttempts = 50;
-
-// Defined in boss_valithria_dreamwalker.cpp
-extern Position const ValithriaSpawnPos;
-// Defined in boss_sindragosa.cpp
-extern Position const SindragosaSpawnPos;
-// Defined in boss_the_lich_king.cpp
-extern Position const TerenasSpawn;
-extern Position const TerenasSpawnHeroic;
-extern Position const SpiritWardenSpawn;
// Shared spells used by more than one script
enum ICSharedSpells
@@ -547,6 +533,21 @@ enum ICAreaIds
AREA_ICECROWN_CITADEL = 4812
};
+struct Position;
+enum TriggerCastFlags : uint32;
+
+// Defined in boss_valithria_dreamwalker.cpp
+extern Position const ValithriaSpawnPos;
+// Defined in boss_sindragosa.cpp
+extern Position const SindragosaSpawnPos;
+// Defined in boss_the_lich_king.cpp
+extern Position const TerenasSpawn;
+extern Position const TerenasSpawnHeroic;
+extern Position const SpiritWardenSpawn;
+
+uint32 const WeeklyNPCs = 9;
+uint32 const MaxHeroicAttempts = 50;
+
class spell_trigger_spell_from_caster : public SpellScriptLoader
{
public:
diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
index 4fccd61d53e..0dc66d1c9df 100644
--- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
+++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp
@@ -110,15 +110,15 @@ struct WeeklyQuest
// when changing the content, remember to update SetData, DATA_BLOOD_QUICKENING_STATE case for NPC_ALRIN_THE_AGILE index
WeeklyQuest const WeeklyQuestData[WeeklyNPCs] =
{
- {NPC_INFILTRATOR_MINCHAR, {QUEST_DEPROGRAMMING_10, QUEST_DEPROGRAMMING_25 }}, // Deprogramming
- {NPC_KOR_KRON_LIEUTENANT, {QUEST_SECURING_THE_RAMPARTS_10, QUEST_SECURING_THE_RAMPARTS_25 }}, // Securing the Ramparts
- {NPC_ROTTING_FROST_GIANT_10, {QUEST_SECURING_THE_RAMPARTS_10, QUEST_SECURING_THE_RAMPARTS_25 }}, // Securing the Ramparts
- {NPC_ROTTING_FROST_GIANT_25, {QUEST_SECURING_THE_RAMPARTS_10, QUEST_SECURING_THE_RAMPARTS_25 }}, // Securing the Ramparts
- {NPC_ALCHEMIST_ADRIANNA, {QUEST_RESIDUE_RENDEZVOUS_10, QUEST_RESIDUE_RENDEZVOUS_25 }}, // Residue Rendezvous
- {NPC_ALRIN_THE_AGILE, {QUEST_BLOOD_QUICKENING_10, QUEST_BLOOD_QUICKENING_25 }}, // Blood Quickening
- {NPC_INFILTRATOR_MINCHAR_BQ, {QUEST_BLOOD_QUICKENING_10, QUEST_BLOOD_QUICKENING_25 }}, // Blood Quickening
- {NPC_MINCHAR_BEAM_STALKER, {QUEST_BLOOD_QUICKENING_10, QUEST_BLOOD_QUICKENING_25 }}, // Blood Quickening
- {NPC_VALITHRIA_DREAMWALKER_QUEST, {QUEST_RESPITE_FOR_A_TORNMENTED_SOUL_10, QUEST_RESPITE_FOR_A_TORNMENTED_SOUL_25}} // Respite for a Tormented Soul
+ { NPC_INFILTRATOR_MINCHAR, { QUEST_DEPROGRAMMING_10, QUEST_DEPROGRAMMING_25 } }, // Deprogramming
+ { NPC_KOR_KRON_LIEUTENANT, { QUEST_SECURING_THE_RAMPARTS_10, QUEST_SECURING_THE_RAMPARTS_25 } }, // Securing the Ramparts
+ { NPC_ROTTING_FROST_GIANT_10, { QUEST_SECURING_THE_RAMPARTS_10, QUEST_SECURING_THE_RAMPARTS_25 } }, // Securing the Ramparts
+ { NPC_ROTTING_FROST_GIANT_25, { QUEST_SECURING_THE_RAMPARTS_10, QUEST_SECURING_THE_RAMPARTS_25 } }, // Securing the Ramparts
+ { NPC_ALCHEMIST_ADRIANNA, { QUEST_RESIDUE_RENDEZVOUS_10, QUEST_RESIDUE_RENDEZVOUS_25 } }, // Residue Rendezvous
+ { NPC_ALRIN_THE_AGILE, { QUEST_BLOOD_QUICKENING_10, QUEST_BLOOD_QUICKENING_25 } }, // Blood Quickening
+ { NPC_INFILTRATOR_MINCHAR_BQ, { QUEST_BLOOD_QUICKENING_10, QUEST_BLOOD_QUICKENING_25 } }, // Blood Quickening
+ { NPC_MINCHAR_BEAM_STALKER, { QUEST_BLOOD_QUICKENING_10, QUEST_BLOOD_QUICKENING_25 } }, // Blood Quickening
+ { NPC_VALITHRIA_DREAMWALKER_QUEST, { QUEST_RESPITE_FOR_A_TORNMENTED_SOUL_10, QUEST_RESPITE_FOR_A_TORNMENTED_SOUL_25 } } // Respite for a Tormented Soul
};
// NPCs spawned at Light's Hammer on Lich King dead