diff options
author | ccrs <ccrs@users.noreply.github.com> | 2019-06-30 17:50:30 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2021-12-13 00:42:19 +0100 |
commit | bb321ccb02a3bba15e6f3ac4a481fb3ba991c9fe (patch) | |
tree | 8d1607dec5309757898c67a99a01d4d53aab2c6d /src | |
parent | 94599bd32350958cab45129eaf5eef741c4c9971 (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.cpp | 1259 | ||||
-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.cpp | 1536 | ||||
-rw-r--r-- | src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.h | 31 | ||||
-rw-r--r-- | src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp | 18 |
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 |