diff --git a/sql/updates/world/2016_07_02_01_world.sql b/sql/updates/world/2016_07_02_01_world.sql
new file mode 100644
index 00000000000..e978c3af88a
--- /dev/null
+++ b/sql/updates/world/2016_07_02_01_world.sql
@@ -0,0 +1,277 @@
+-- The Vortex Pinnacle
+UPDATE `instance_template` SET `script` = 'instance_vortex_pinnacle' WHERE `map` = 657;
+
+UPDATE `creature_template` SET `mechanic_immune_mask` = 617299839 WHERE `entry` IN (43878, 43873, 43875);
+
+-- Script names
+UPDATE `creature_template` SET `ScriptName` = 'boss_grand_vizier_ertan' WHERE `entry` = 43878;
+UPDATE `creature_template` SET `ScriptName` = 'boss_altairus' WHERE `entry` = 43873;
+UPDATE `creature_template` SET `ScriptName` = 'boss_asaad' WHERE `entry` = 43875;
+
+UPDATE `creature_template` SET `ScriptName` = 'npc_lurking_tempest' WHERE `entry` = 45704;
+UPDATE `creature_template` SET `ScriptName` = 'npc_ertans_vortex' WHERE `entry` = 46007;
+UPDATE `creature_template` SET `ScriptName` = 'npc_slipstream' WHERE `entry` = 45455;
+UPDATE `creature_template` SET `ScriptName` = 'npc_slipstream_landing_zone' WHERE `entry` = 45504;
+UPDATE `creature_template` SET `ScriptName` = 'npc_young_storm_dragon' WHERE `entry` = 45919;
+UPDATE `creature_template` SET `ScriptName` = 'npc_air_current' WHERE `entry` = 47305;
+UPDATE `creature_template` SET `ScriptName` = 'npc_grounding_field' WHERE `entry` = 47085;
+UPDATE `creature_template` SET `ScriptName` = 'npc_skyfall' WHERE `entry` = 45981;
+UPDATE `creature_template` SET `ScriptName` = 'npc_skyfall_star' WHERE `entry` = 45932;
+UPDATE `creature_template` SET `ScriptName` = 'npc_unstable_grounding_field' WHERE `entry` = 46492;
+UPDATE `creature_template` SET `ScriptName` = 'npc_storm_target' WHERE `entry` = 46387;
+UPDATE `creature_template` SET `ScriptName` = 'npc_asaad_grounding_field' WHERE `entry` = 47000;
+
+DELETE FROM `spell_script_names` WHERE `spell_id` IN (84978, 84989, 85395, 85396, 85017);
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(84978, 'spell_slipstream'),
+(84989, 'spell_slipstream'),
+(85395, 'spell_slipstream'),
+(85396, 'spell_slipstream'),
+(85017, 'spell_slipstream');
+
+DELETE FROM `spell_script_names` WHERE `spell_id` IN (85294, 85291, 85267, 86493, 85281, 86456, 86284, 86311, 86299, 85084, 88276, 88282, 88772, 88322, 87726, 87850, 87854);
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(85294, 'spell_lurk_search'),
+(85291, 'spell_lurk_search_check'),
+(85267, 'spell_feign_death'),
+(86493, 'spell_lurk_search_check'),
+(85281, 'spell_lurk_ressurect'),
+(86456, 'spell_lurk_search_victim'),
+(86284, 'spell_storms_edge'),
+(86311, 'spell_storms_edge'),
+(86299, 'spell_storms_edge_script'),
+(85084, 'spell_howling_gale'),
+(88276, 'spell_call_the_wind'),
+(88282, 'spell_upwind_of_altairus'),
+(88772, 'spell_call_the_wind_channel'),
+(88322, 'spell_chilling_breath'),
+(87726, 'spell_grounding_field'),
+(87850, 'spell_skyfall'),
+(87854, 'spell_arcane_barrage');
+
+-- Asaad spell script names
+DELETE FROM `spell_script_names` WHERE `spell_id` IN (86632, 86926, 86921, 86923, 86925, 87517, 87553, 93994);
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(86632, 'spell_sots_targeting'),
+(86926, 'spell_sots_trigger'),
+(86921, 'spell_storm_rune_beam'),
+(86923, 'spell_storm_rune_beam'),
+(86925, 'spell_storm_rune_beam'),
+(87517, 'spell_grounding_field_visual_beams'),
+(87553, 'spell_supremacy_of_the_storm'),
+(93994, 'spell_supremacy_of_the_storm');
+
+-- Spell condition
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` IN (86284, 86299, 88276, 88772, 87724, 87726, 87850, 86632, 86926, 86911, 86981, 87328);
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
+(13, 1, 86284, 0, 0, 35, 0, 1, 25, 3, 0, 0, 0, '', 'Storm''s Edge targets must be further than 25 yards'),
+(13, 1, 86299, 0, 0, 31, 0, 3, 46007, 0, 0, 0, 0, '', 'Call The Wind targets NPC_ERTANS_VORTEX'),
+(13, 1, 88276, 0, 0, 31, 0, 3, 47305, 0, 0, 0, 0, '', 'Call The Wind EFFECT_0 can only hit NPC_AIR_CURRENT'),
+(13, 1, 88772, 0, 0, 31, 0, 3, 47305, 0, 0, 0, 0, '', 'Call The Wind targets NPC_AIR_CURRENT'),
+(13, 1, 88772, 0, 0, 1, 0, 88244, 0, 0, 0, 0, 0, '', 'Call The Wind target must have Call The Wind aura'),
+(13, 1, 87724, 0, 0, 1, 0, 87721, 0, 0, 0, 0, 0, '', 'Prism Beam EFFECT_0 target must have SPELL_BEAM_A aura'),
+(13, 2, 87724, 0, 0, 1, 0, 87722, 0, 0, 0, 0, 0, '', 'Prism Beam EFFECT_1 target must have SPELL_BEAM_B aura'),
+(13, 4, 87724, 0, 0, 1, 0, 87723, 0, 0, 0, 0, 0, '', 'Prism Beam EFFECT_2 target must have SPELL_BEAM_C aura'),
+(13, 1, 87726, 0, 0, 31, 0, 3, 45926, 0, 0, 0, 0, '', 'Grounding Field can target npc Servant of Asaad'),
+(13, 1, 87726, 0, 1, 31, 0, 3, 45928, 0, 0, 0, 0, '', 'Grounding Field can target npc Executor of the Caliph'),
+(13, 1, 87726, 0, 2, 31, 0, 3, 45930, 0, 0, 0, 0, '', 'Grounding Field can target npc Minister of Air'),
+(13, 1, 87726, 0, 3, 31, 0, 3, 45935, 0, 0, 0, 0, '', 'Grounding Field can target npc Temple Adept'),
+(13, 1, 87850, 0, 0, 31, 0, 3, 52019, 0, 0, 0, 0, '', 'Skyfall targets NPC_SKYFALL_STAR'),
+(13, 1, 86632, 0, 0, 31, 0, 3, 46387, 0, 0, 0, 0, '', 'SOTS Targeting targets NPC_STORM_TARGET'),
+(13, 1, 86926, 0, 0, 31, 0, 3, 43875, 0, 0, 0, 0, '', 'SOTS Trigger targets BOSS_ASAAD'),
+(13, 1, 86911, 0, 0, 31, 0, 3, 46492, 0, 0, 0, 0, '', 'Unstable Grounding Field targets NPC_UNSTABLE_GROUNDING_FIELD'),
+(13, 1, 86981, 0, 0, 31, 0, 3, 46387, 0, 0, 0, 0, '', 'Storm Rune Beam AA targets NPC_STORM_TARGET'),
+(13, 1, 87328, 0, 0, 31, 0, 3, 47000, 0, 0, 0, 0, '', 'Supremacy of the Storm targets NPC_ASAAD_GROUNDING_FIELD');
+
+
+-- Lurking Tempest
+DELETE FROM `creature_template_addon` WHERE `entry` = 45704;
+
+DELETE FROM `creature_text` WHERE `entry` = 45704;
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(45704, 0, 0, '%s realizes it''s been spotted and quickly plays dead!', 16, 0, 100, 0, 0, 0, 0, 0, 'Lurking Tempest to Lurking Tempest');
+
+
+-- Grand Vizier Ertan
+UPDATE `creature_template` SET `difficulty_entry_1` = 43879 WHERE `entry` = 43878;
+UPDATE `creature_template` SET `minlevel` = 87, `maxlevel` = 87, `exp` = 3, `faction` = 16, `speed_walk` = 1.6, `speed_run` = 1.71429, `unit_class` = 2, `unit_flags` = 32832, `ManaModifier` = 2, `flags_extra` = 1 WHERE `entry` = 43879;
+
+-- Grand Vizier Ertan texts
+DELETE FROM `creature_text` WHERE `entry` = 43878;
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(43878, 0, 0, 'Filthy beasts! Your presence in Skywall will not be tolerated!', 14, 0, 100, 0, 0, 20876, 0, 0, 'Grand Vizier Ertan to Player'),
+(43878, 1, 0, '%s retracts her cyclone shield!', 41, 0, 100, 0, 0, 0, 47800, 0, 'Grand Vizier Ertan');
+
+-- Grand Vizier Ertan loot
+UPDATE `creature_template` SET `lootid` = 43878 WHERE `entry` = 43878;
+UPDATE `creature_template` SET `lootid` = 43879 WHERE `entry` = 43879;
+
+DELETE FROM `creature_loot_template` WHERE `Entry` IN (43878, 43879);
+INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(43878, 1, 43410, 100, 0, 1, 0, 1, 1, 'Grand Vizier Ertan N - Reference Loot'),
+(43879, 1, 43411, 100, 0, 1, 0, 1, 1, 'Grand Vizier Ertan H - Reference Loot'),
+(43878, 65660, 0, 100, 1, 1, 0, 1, 1, 'Grand Vizier Ertan N - Quest Item'),
+(43879, 65660, 0, 100, 1, 1, 0, 1, 1, 'Grand Vizier Ertan H - Quest Item');
+
+DELETE FROM `reference_loot_template` WHERE `Entry` IN (43410, 43411);
+INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(43410, 55830, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43410, 55831, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43410, 55832, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43410, 55833, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43410, 55834, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43411, 56356, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43411, 56357, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43411, 56358, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43411, 56359, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43411, 56360, 0, 0, 0, 1, 1, 1, 1, NULL);
+
+-- Ertan's Vortex.
+UPDATE `creature_template` SET `flags_extra` = 128 WHERE `entry` = 46007;
+
+-- Slipstream
+UPDATE `creature_template` SET `InhabitType` = 7 WHERE `entry` IN (45455, 45504);
+UPDATE `creature_template` SET `unit_flags` = 33554432 WHERE `entry` = 45504;
+
+DELETE FROM `npc_spellclick_spells` WHERE `npc_entry` = 45455;
+INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `cast_flags`, `user_type`) VALUES
+(45455, 84965, 1, 0);
+
+DELETE FROM `creature_template_addon` WHERE `entry` = 45455;
+INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES
+(45455, 0, 0, 0, 1, 0, '85021');
+
+-- Young Storm Dragon
+UPDATE `creature_template` SET `InhabitType` = 7 WHERE `entry` = 45919;
+
+DELETE FROM `creature_template_addon` WHERE `entry` = 45919;
+INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES
+(45919, 0, 0, 0, 1, 0, '88192');
+
+-- Howling Gale
+DELETE FROM `creature_template_addon` WHERE `entry` = 45572;
+INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES
+(45572, 0, 0, 0, 1, 0, '85084');
+
+-- Altairus
+UPDATE `creature_template` SET `difficulty_entry_1` = 43874, `InhabitType` = 7 WHERE `entry` = 43873;
+UPDATE `creature_template` SET `minlevel` = 87, `maxlevel` = 87, `exp` = 3, `faction` = 16, `speed_walk` = 1.6, `speed_run` = 1.71429, `unit_flags` = 32832, `InhabitType` = 7, `HoverHeight` = 10.125, `flags_extra` = 1 WHERE `entry` = 43874;
+
+-- Altairus texts
+DELETE FROM `creature_text` WHERE `entry` = 43873;
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(43873, 0, 0, 'The wind abruptly shifts direction at %s'' command!', 41, 0, 100, 0, 0, 0, 0, 0, 'Altairus');
+
+-- Altairus loot
+UPDATE `creature_template` SET `lootid` = 43873 WHERE `entry` = 43873;
+UPDATE `creature_template` SET `lootid` = 43874 WHERE `entry` = 43874;
+
+DELETE FROM `creature_loot_template` WHERE `Entry` IN (43873, 43874);
+INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(43873, 1, 43412, 100, 0, 1, 0, 1, 1, 'Altairus N - Reference Loot'),
+(43874, 1, 43413, 100, 0, 1, 0, 1, 1, 'Altairus H - Reference Loot'),
+(43873, 63040, 0, 1, 0, 1, 0, 1, 1, 'Altairus N - Mount Drop'),
+(43874, 63040, 0, 1, 0, 1, 0, 1, 1, 'Altairus H - Mount Drop');
+
+DELETE FROM `reference_loot_template` WHERE `Entry` IN (43412, 43413);
+INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(43412, 55835, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43412, 55838, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43412, 55839, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43412, 55840, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43412, 55841, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43413, 56361, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43413, 56362, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43413, 56363, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43413, 56364, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43413, 56365, 0, 0, 0, 1, 1, 1, 1, NULL);
+
+-- Invisible Stalker (Cataclysm Boss, Ignore Combat)
+UPDATE `creature_template` SET `flags_extra` = 128 WHERE `entry` = 42844;
+DELETE FROM `creature_template_addon` WHERE `entry` = 42844;
+INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES
+(42844, 0, 0, 0, 1, 0, '88350');
+
+-- Air Current
+UPDATE `creature_template` SET `InhabitType` = 7, `flags_extra` = 128 WHERE `entry` = 47305;
+
+-- Twister
+UPDATE `creature_template` SET `flags_extra` = 128 WHERE `entry` = 47342;
+DELETE FROM `creature_template_addon` WHERE `entry` = 47342;
+INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES
+(47342, 0, 0, 0, 1, 0, '88313');
+
+
+-- Zephyr
+UPDATE `creature_template` SET `speed_walk` = 4, `speed_run` = 12, `flags_extra` = 128 WHERE `entry` = 45991;
+DELETE FROM `creature_template_addon` WHERE `entry` = 45991;
+INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES
+(45991, 0, 0, 0, 1, 0, '85734');
+DELETE FROM `waypoint_data` WHERE `id` IN (4599100, 4599101);
+INSERT INTO `waypoint_data` (`id`, `point`, `position_x`, `position_y`, `position_z`, `orientation`, `delay`, `move_type`, `action`, `action_chance`, `wpguid`) VALUES
+(4599100, 1, -1050.74, 429.649, 651.2561, 0, 0, 0, 0, 100, 0),
+(4599100, 2, -1025.79, 446.358, 657.6731, 0, 0, 0, 0, 100, 0),
+(4599100, 3, -1021.287, 474.0407, 664.598, 0, 0, 0, 0, 100, 0),
+(4599100, 4, -1036.114, 495.2139, 670.9863, 0, 0, 0, 0, 100, 0),
+(4599100, 5, -1059.67, 498.865, 677.6423, 0, 0, 0, 0, 100, 0),
+(4599100, 6, -1077.17, 485.951, 683.4588, 0, 0, 0, 0, 100, 0),
+(4599100, 7, -1080.06, 466.3477, 688.7894, 0, 0, 0, 0, 100, 0),
+(4599100, 8, -1069.01, 452.476, 693.6293, 0, 0, 0, 0, 100, 0),
+(4599100, 9, -1053.397, 450.5248, 698.0431, 0, 0, 0, 45991, 100, 0),
+(4599101, 1, -781.4438, 491.1446, 698.0991, 0, 0, 0, 0, 100, 0),
+(4599101, 2, -765.677, 487.116, 693.6418, 0, 0, 0, 0, 100, 0),
+(4599101, 3, -756.743, 472.135, 688.8555, 0, 0, 0, 0, 100, 0),
+(4599101, 4, -762.127, 453.059, 683.3886, 0, 0, 0, 0, 100, 0),
+(4599101, 5, -780.924, 442.635, 677.577, 0, 0, 0, 0, 100, 0),
+(4599101, 6, -803.446, 449.476, 670.8987, 0, 0, 0, 0, 100, 0),
+(4599101, 7, -815.382, 471.972, 664.5117, 0, 0, 0, 0, 100, 0),
+(4599101, 8, -807.351, 498.323, 657.6155, 0, 0, 0, 0, 100, 0),
+(4599101, 9, -780.9688, 511.8101, 651.2169, 0, 0, 0, 45991, 100, 0);
+DELETE FROM `waypoint_scripts` WHERE `id` = 45991;
+INSERT INTO `waypoint_scripts` (`id`, `delay`, `command`, `datalong`, `datalong2`, `dataint`, `x`, `y`, `z`, `o`, `guid`) VALUES
+(45991, 0, 18, 0, 0, 0, 0, 0, 0, 0, 891);
+
+-- Grounding Field and Skyfall Star inhabit type correction
+UPDATE `creature_template` SET `InhabitType` = 7 WHERE `entry` IN (47085, 45932);
+
+-- Asaad
+UPDATE `creature_template` SET `difficulty_entry_1` = 43876, `InhabitType` = 7 WHERE `entry` = 43875;
+UPDATE `creature_template` SET `minlevel` = 87, `maxlevel` = 87, `exp` = 3, `faction` = 16, `speed_walk` = 1.6, `speed_run` = 1.71429, `unit_class` = 2, `unit_flags` = 32832, `ManaModifier` = 2, `flags_extra` = 1 WHERE `entry` = 43876;
+
+-- Asaad texts
+DELETE FROM `creature_text` WHERE `entry` = 43875;
+INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
+(43875, 0, 0, 'YOU tread upon the sacrosanct! Mortals have no place amidst the clouds.', 14, 0, 100, 0, 0, 20867, 0, 0, 'Asaad to Player'),
+(43875, 1, 0, 'Al''Akir, your servant calls for aid!', 14, 0, 100, 0, 0, 20869, 0, 0, 'Asaad'),
+(43875, 2, 0, '%s conjures a temporary grounding field!', 41, 0, 100, 0, 0, 20869, 0, 0, 'Asaad'),
+(43875, 3, 0, 'The winds take me!', 14, 0, 100, 0, 0, 20870, 0, 0, 'Asaad to Player');
+
+-- Asaad loot
+UPDATE `creature_template` SET `lootid` = 43875 WHERE `entry` = 43875;
+UPDATE `creature_template` SET `lootid` = 43876 WHERE `entry` = 43876;
+
+DELETE FROM `creature_loot_template` WHERE `Entry` IN (43875, 43876);
+INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(43875, 1, 43414, 100, 0, 1, 0, 2, 2, 'Asaad N - Reference Loot'),
+(43876, 1, 43415, 100, 0, 1, 0, 2, 2, 'Asaad H - Reference Loot'),
+(43876, 52078, 0, 100, 0, 1, 0, 1, 1, 'Asaad H - Chaos Orb');
+
+DELETE FROM `reference_loot_template` WHERE `Entry` IN (43414, 43415);
+INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES
+(43414, 55842, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43414, 55844, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43414, 55845, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43414, 55846, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43414, 55847, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43414, 55848, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43414, 55849, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43414, 55850, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43414, 55851, 0, 0, 0, 1, 1, 1, 1, NULL),
+(43414, 55852, 0, 0, 0, 1, 1, 1, 1, NULL);
+
+-- Grounding Field inhabit type correction
+UPDATE `creature_template` SET `InhabitType` = 7 WHERE `entry` IN (47000);
+
+-- Set CREATURE_FLAG_EXTRA_TRIGGER to Storm Target, Unstable Grounding Field and Grounding Field.
+UPDATE `creature_template` SET `flags_extra` = 128 WHERE `entry` IN (46387, 46492, 47000);
+--
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 5c0ebf8eb73..694ecd4c0bb 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3753,6 +3753,27 @@ void SpellMgr::LoadSpellInfoCorrections()
case 95285: // Teleport (from Slabhide to entrance)
spellInfo->Effects[EFFECT_0].TargetB = SpellImplicitTargetInfo(TARGET_DEST_DB);
break;
+ // Vortex of Pinnacle spells
+ case 85085: // Howling Gale
+ spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_5_YARDS);
+ break;
+ case 85159: // Howling Gale
+ spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(84); // To-do: Enum this radius entry - EFFECT_RADIUS_17_YARDS.
+ break;
+ // Altairus
+ case 88282: // Upwind of Altairus
+ spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS);
+ break;
+ case 88314: // Twisting Winds
+ spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_3_YARDS);
+ spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_3_YARDS);
+ break;
+ // Grounding Field
+ case 87721: // Beam A
+ case 87722: // Beam B
+ case 87723: // Beam C
+ spellInfo->Effects[EFFECT_0].TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY);
+ break;
// Halls Of Origination spells
// Temple Guardian Anhuur
case 76606: // Disable Beacon Beams L
diff --git a/src/server/scripts/Kalimdor/VortexPinnacle/boss_altairus.cpp b/src/server/scripts/Kalimdor/VortexPinnacle/boss_altairus.cpp
new file mode 100644
index 00000000000..3860ddf3402
--- /dev/null
+++ b/src/server/scripts/Kalimdor/VortexPinnacle/boss_altairus.cpp
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2008-2016 TrinityCore
+ *
+ * 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 .
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "Player.h"
+#include "vortex_pinnacle.h"
+
+enum Spells
+{
+ SPELL_CALL_THE_WIND = 88276, // targets 47305 in hook
+ SPELL_CHILLING_BREATH = 88322,
+
+ // Invisible Stalker
+ SPELL_CALL_THE_WIND_CHANNEL = 88772, // visual channeling targeting Air Current
+
+ // Air Current
+ SPELL_CALL_THE_WIND_AURA = 88244, // periodically triggers upwind
+ SPELL_UPWIND_OF_ALTAIRUS = 88282,
+ SPELL_DOWNWIND_OF_ALTAIRUS = 88286,
+
+ // Twister
+ SPELL_TWISTER_AURA = 88313,
+};
+
+enum NPCs
+{
+ NPC_INVISIBLE_STALKER = 42844,
+ NPC_AIR_CURRENT = 47305,
+ NPC_TWISTER = 47342,
+};
+
+enum Texts
+{
+ SAY_CALL_THE_WIND = 0,
+};
+
+enum Events
+{
+ EVENT_NONE,
+ EVENT_CALL_THE_WIND,
+ EVENT_CHILLING_BREATH,
+
+ // Air Current
+ EVENT_SET_FACING,
+ EVENT_CAST_VISUAL,
+
+ // Twister
+ EVENT_MOVE_RANDOM,
+};
+
+enum Actions
+{
+ ACTION_CALL_THE_WIND,
+};
+
+enum Points
+{
+ POINT_RANDOM,
+ POINT_TWISTER_MAX = 24,
+};
+
+const Position InvisibleStalkerPos = { -1216.12f, 64.026f, 734.2573f };
+
+const Position TwisterSpawnPoints[POINT_TWISTER_MAX] = {
+ { -1226.936f, 58.03993f, 734.2574f },
+ { -1250.604f, 78.47916f, 729.8842f },
+ { -1255.609f, 63.03125f, 729.05f },
+ { -1235.368f, 85.2691f, 732.747f },
+ { -1245.059f, 61.33333f, 732.6014f },
+ { -1237.84f, 72.69965f, 734.2705f },
+ { -1190.684f, 69.16666f, 734.2564f },
+ { -1194.172f, 54.2066f, 734.2574f },
+ { -1215.405f, 65.88541f, 734.2574f },
+ { -1236.722f, 48.6632f, 734.2571f },
+ { -1193.104f, 82.77431f, 737.7465f },
+ { -1210.278f, 80.68056f, 734.2574f },
+ { -1202.799f, 68.46702f, 734.2574f },
+ { -1224.179f, 76.04688f, 734.2574f },
+ { -1244.069f, 92.11979f, 729.0458f },
+ { -1211.163f, 53.77778f, 734.2574f },
+ { -1198.332f, 106.1181f, 740.7894f },
+ { -1203.602f, 93.05209f, 738.5089f },
+ { -1242.745f, 37.7257f, 734.257f },
+ { -1219.642f, 93.82291f, 737.8855f },
+ { -1223.229f, 40.89063f, 734.2574f },
+ { -1211.016f, 105.4375f, 740.8424f },
+ { -1189.568f, 95.77604f, 740.8668f },
+ { -1204.863f, 40.49826f, 734.2564f },
+};
+
+// TO-DO:
+// - Fix hovering with disabled gravity. Altairus falls down every time position is updated.
+// - Add argument to MoveRandom() to manually set i_nextMoveTime in "RandomMovementGenerator.h". This npc needs i_nextMoveTime = 1000.
+
+class boss_altairus : public CreatureScript
+{
+ public:
+ boss_altairus() : CreatureScript("boss_altairus") { }
+
+ struct boss_altairusAI : public BossAI
+ {
+ boss_altairusAI(Creature* creature) : BossAI(creature, DATA_ALTAIRUS)
+ {
+ //me->SetHover(true);
+ //me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
+ }
+
+ void Reset() override
+ {
+ _Reset();
+
+ events.ScheduleEvent(EVENT_CALL_THE_WIND, 6000);
+ events.ScheduleEvent(EVENT_CHILLING_BREATH, 15000);
+ }
+
+ void EnterCombat(Unit* /*target*/) override
+ {
+ _EnterCombat();
+
+ me->SummonCreature(NPC_INVISIBLE_STALKER, InvisibleStalkerPos);
+
+ if (IsHeroic())
+ for (int8 i = 0; i < POINT_TWISTER_MAX; i++)
+ if (Creature* twister = me->SummonCreature(NPC_TWISTER, TwisterSpawnPoints[i]))
+ twister->GetMotionMaster()->MoveRandom(10.0f);
+ }
+
+ 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_CALL_THE_WIND:
+ DoCast(me, SPELL_CALL_THE_WIND);
+ Talk(SAY_CALL_THE_WIND);
+ events.ScheduleEvent(EVENT_CALL_THE_WIND, 20500);
+ break;
+ case EVENT_CHILLING_BREATH:
+ if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
+ DoCast(target, SPELL_CHILLING_BREATH);
+ events.ScheduleEvent(EVENT_CHILLING_BREATH, 13000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 47305 - Air Current
+class npc_air_current : public CreatureScript
+{
+public:
+ npc_air_current() : CreatureScript("npc_air_current") { }
+
+ struct npc_air_currentAI : public ScriptedAI
+ {
+ npc_air_currentAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetDisableGravity(true);
+ }
+
+ void SpellHit(Unit* /*unit*/, const SpellInfo* spellInfo) override
+ {
+ if (spellInfo->Id != SPELL_CALL_THE_WIND)
+ return;
+
+ DoCast(me, SPELL_CALL_THE_WIND_AURA);
+
+ events.ScheduleEvent(EVENT_SET_FACING, 400);
+ events.ScheduleEvent(EVENT_CAST_VISUAL, 1600);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (events.Empty())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SET_FACING:
+ if (Creature* invisibleStalker = me->FindNearestCreature(NPC_INVISIBLE_STALKER, 100.0f))
+ {
+ invisibleStalker->CastStop();
+ invisibleStalker->SetFacingToObject(me);
+ }
+ break;
+ case EVENT_CAST_VISUAL:
+ if (Creature* invisibleStalker = me->FindNearestCreature(NPC_INVISIBLE_STALKER, 100.0f))
+ invisibleStalker->CastSpell(me, SPELL_CALL_THE_WIND_CHANNEL);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 88276 - Call The Wind
+class spell_call_the_wind : public SpellScriptLoader
+{
+public:
+ spell_call_the_wind() : SpellScriptLoader("spell_call_the_wind") { }
+
+ class spell_call_the_wind_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_call_the_wind_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_CALL_THE_WIND_AURA))
+ return false;
+ return true;
+ }
+
+ void FilterTargets(std::list& targets)
+ {
+ if (targets.empty())
+ return;
+
+ targets.remove_if(Trinity::UnitAuraCheck(true, SPELL_CALL_THE_WIND_AURA));
+ Trinity::Containers::RandomResizeList(targets, 1);
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_CALL_THE_WIND_AURA);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_call_the_wind_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ OnEffectHitTarget += SpellEffectFn(spell_call_the_wind_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_call_the_wind_SpellScript();
+ }
+};
+
+// 88282 - Upwind of Altairus
+class spell_upwind_of_altairus : public SpellScriptLoader
+{
+public:
+ spell_upwind_of_altairus() : SpellScriptLoader("spell_upwind_of_altairus") { }
+
+ class spell_upwind_of_altairus_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_upwind_of_altairus_SpellScript);
+
+ void GetDistance()
+ {
+ Unit* caster = GetCaster();
+ if (InstanceScript* instance = caster->GetInstanceScript())
+ if (Creature* altairus = instance->GetCreature(DATA_ALTAIRUS))
+ upwindDistance = caster->GetExactDist(altairus);
+ }
+
+ void CheckDistance(SpellEffIndex /*effIndex*/)
+ {
+ Unit* target = GetHitUnit();
+ if (GetCaster()->GetExactDist(target) < upwindDistance)
+ {
+ // Upwind of Altairus (applied by default effects)
+ if (target->HasAura(SPELL_DOWNWIND_OF_ALTAIRUS))
+ target->RemoveAurasDueToSpell(SPELL_DOWNWIND_OF_ALTAIRUS);
+ }
+ else
+ {
+ // Downwind of Altairus
+ PreventHitDefaultEffect(EFFECT_0);
+ PreventHitDefaultEffect(EFFECT_1);
+ if (target->HasAura(SPELL_UPWIND_OF_ALTAIRUS))
+ target->RemoveAurasDueToSpell(SPELL_UPWIND_OF_ALTAIRUS);
+ target->CastSpell(target, SPELL_DOWNWIND_OF_ALTAIRUS, true);
+ }
+ }
+
+ void Register() override
+ {
+ BeforeCast += SpellCastFn(spell_upwind_of_altairus_SpellScript::GetDistance);
+ OnEffectHitTarget += SpellEffectFn(spell_upwind_of_altairus_SpellScript::CheckDistance, EFFECT_0, SPELL_EFFECT_APPLY_AURA);
+ }
+
+ private:
+ float upwindDistance;
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_upwind_of_altairus_SpellScript();
+ }
+};
+
+// 88772 - Call the Wind (visual, channeling on Air Current with Call The Wind aura)
+class spell_call_the_wind_channel : public SpellScriptLoader
+{
+public:
+ spell_call_the_wind_channel() : SpellScriptLoader("spell_call_the_wind_channel") { }
+
+ class spell_call_the_wind_channel_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_call_the_wind_channel_AuraScript);
+
+ void RemoveCallTheWindAura(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Creature* creature = GetOwner()->ToCreature())
+ creature->RemoveAurasDueToSpell(SPELL_CALL_THE_WIND_AURA);
+ }
+
+ void Register() override
+ {
+ OnEffectRemove += AuraEffectRemoveFn(spell_call_the_wind_channel_AuraScript::RemoveCallTheWindAura, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_call_the_wind_channel_AuraScript();
+ }
+};
+
+// 88322 - Chilling Breath
+class spell_chilling_breath : public SpellScriptLoader
+{
+public:
+ spell_chilling_breath() : SpellScriptLoader("spell_chilling_breath") { }
+
+ class spell_chilling_breath_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_chilling_breath_SpellScript);
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->CastSpell(GetHitUnit(), uint32(GetEffectValue()));
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_chilling_breath_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_chilling_breath_SpellScript();
+ }
+};
+
+void AddSC_boss_altairus()
+{
+ new boss_altairus();
+ new npc_air_current();
+ new spell_call_the_wind();
+ new spell_upwind_of_altairus();
+ new spell_call_the_wind_channel();
+ new spell_chilling_breath();
+}
diff --git a/src/server/scripts/Kalimdor/VortexPinnacle/boss_asaad.cpp b/src/server/scripts/Kalimdor/VortexPinnacle/boss_asaad.cpp
new file mode 100644
index 00000000000..b288e1482ea
--- /dev/null
+++ b/src/server/scripts/Kalimdor/VortexPinnacle/boss_asaad.cpp
@@ -0,0 +1,775 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore
+ *
+ * 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 .
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "ObjectAccessor.h"
+#include "Player.h"
+#include "vortex_pinnacle.h"
+
+enum Spells
+{
+ SPELL_SUMMON_SKYFALL_STAR = 96260, // summons 52019
+ SPELL_CHAIN_LIGHTNING = 87622,
+ SPELL_SOTS_TARGETING = 86632,
+ SPELL_STATIC_CLING = 87618,
+
+ SPELL_UNSTABLE_GROUNDING_FIELD = 86911, // 20 sec channel, visual
+ SPELL_SUPREMACY_OF_THE_STORM_TELEPORT = 87328,
+ SPELL_SUPREMACY_OF_THE_STORM = 86930,
+
+ // Skyfall Star
+ SPELL_ARCANE_BARRAGE_AURA = 87845,
+
+ // Storm Target
+ SPELL_SOTS_SUMMON = 86658,
+
+ // Unstable Grounding Field
+ SPELL_SOTS_TRIGGER = 86926,
+ SPELL_STORM_RUNE_BEAM_AA = 86981,
+ SPELL_STORM_RUNE_BEAM_A = 86921,
+ SPELL_STORM_RUNE_BEAM_B = 86923,
+ SPELL_STORM_RUNE_BEAM_C = 86925,
+ SPELL_STORM_SUMMON_GROUNDING_FIELD = 87518,
+
+ // Grounding Field
+ SPELL_GROUNDING_FIELD_VISUAL_BEAMS = 87517,
+};
+
+enum NPCs
+{
+ NPC_SKYFALL_STAR = 52019,
+ NPC_STORM_TARGET = 46387,
+ NPC_UNSTABLE_GROUNDING_FIELD = 46492,
+};
+
+enum Texts
+{
+ SAY_AGGRO = 0,
+ SAY_SOTS_EMOTE = 1,
+ SAY_SOTS = 2,
+ SAY_DEATH = 3,
+};
+
+enum Actions
+{
+ ACTION_NONE,
+ ACTION_SOTS_TARGET,
+ ACTION_SUPREMACY_OF_THE_STORM,
+};
+
+enum Events
+{
+ EVENT_NONE,
+ EVENT_SUMMON_SKYFALL_STAR,
+ EVENT_CHAIN_LIGHTNING,
+ EVENT_STATIC_CLING,
+ EVENT_SOTS,
+ EVENT_SOTS_START,
+ EVENT_SOTS_END,
+ EVENT_ATTACK,
+
+ // Storm Target
+ EVENT_SOTS_SUMMON,
+
+ // Unstable Grounding Field npc
+ EVENT_STORM_ASSAD_CHANNEL,
+ EVENT_STORM_RUNE_BEAM_AA,
+ EVENT_STORM_MOVE_B,
+ EVENT_STORM_MOVE_C,
+ EVENT_STORM_MOVE_A,
+ EVENT_STORM_ASAAD_TELEPORT,
+
+ // Grounding Field npc
+ EVENT_GROUNDING_FIELD_VISUAL_BEAMS,
+};
+
+enum Points
+{
+ POINT_STORM_A,
+ POINT_STORM_B,
+ POINT_STORM_C,
+};
+
+uint32 const StormTargetPositions = 39;
+Position const StormTargetPositionData[StormTargetPositions] =
+{
+ { -633.771f, 490.976f, 646.7143f, 3.141593f }, // 56889
+ { -625.688f, 501.934f, 646.7143f, 3.141593f }, // 56890
+ { -620.226f, 490.892f, 646.7143f, 3.141593f }, // 56891
+
+ { -649.906f, 494.905f, 646.7143f, 3.141593f }, // 56892
+ { -643.214f, 503.953f, 646.7143f, 3.141593f }, // 56893
+ { -640.542f, 487.474f, 646.7143f, 3.141593f }, // 56894
+
+ { -637.839f, 516.186f, 646.7143f, 1.099557f }, // 56895
+ { -634.068f, 507.51f, 646.7143f, 1.099557f }, // 56896
+ { -650.894f, 509.323f, 646.7143f, 1.099557f }, // 56897
+
+ { -637.01f, 530.09f, 646.7143f, 1.099557f }, // 56898
+ { -632.167f, 521.153f, 646.7143f, 1.099557f }, // 56899
+ { -646.939f, 519.566f, 646.7143f, 1.099557f }, // 56900
+
+ { -628.512f, 516.988f, 646.7143f, 1.099557f }, // 56901
+ { -622.184f, 507.908f, 646.7143f, 1.099557f }, // 56902
+ { -633.148f, 499.762f, 646.7143f, 1.099557f }, // 56903
+
+ { -615.528f, 515.944f, 646.7143f, 1.099557f }, // 56904
+ { -609.41f, 504.675f, 646.7143f, 1.099557f }, // 56905
+ { -618.748f, 501.946f, 646.7143f, 1.099557f }, // 56906
+
+ { -600.986f, 522.576f, 646.7143f, 1.099557f }, // 56907
+ { -594.96f, 507.582f, 646.7143f, 1.099557f }, // 56908
+ { -605.094f, 509.141f, 646.7143f, 1.099557f }, // 56909
+
+ { -617.269f, 521.168f, 646.7143f, 0.0f }, // 56910
+ { -606.75f, 530.002f, 646.7143f, 0.0f }, // 56911
+ { -608.832f, 515.175f, 646.7143f, 0.0f }, // 56912
+
+ { -627.957f, 529.927f, 646.7143f, 0.0f }, // 56913
+ { -616.997f, 530.564f, 646.7143f, 0.0f }, // 56914
+ { -621.91f, 517.644f, 646.7143f, 0.0f }, // 56915
+
+ { -604.839f, 485.186f, 646.7143f, 3.141593f }, // 56916
+ { -616.885f, 496.186f, 646.7143f, 3.141593f }, // 56917
+ { -606.833f, 500.078f, 646.7143f, 3.141593f }, // 56918
+
+ { -600.387f, 482.604f, 646.7143f, 3.141593f }, // 56919
+ { -602.899f, 497.245f, 646.7143f, 3.141593f }, // 56920
+ { -592.599f, 500.392f, 646.7143f, 3.141593f }, // 56921
+
+ { -622.946f, 483.113f, 646.7143f, 3.141593f }, // 56922
+ { -613.104f, 488.776f, 646.7143f, 3.141593f }, // 56923
+ { -606.915f, 477.097f, 646.7143f, 3.141593f }, // 56924
+
+ { -640.717f, 480.623f, 646.7143f, 3.141593f }, // 56925
+ { -627.049f, 486.917f, 646.7143f, 3.141593f }, // 56926
+ { -623.059f, 476.104f, 646.7143f, 3.141593f }, // 56927
+};
+
+class boss_asaad : public CreatureScript
+{
+ public:
+ boss_asaad() : CreatureScript("boss_asaad") { }
+
+ struct boss_asaadAI : public BossAI
+ {
+ boss_asaadAI(Creature* creature) : BossAI(creature, DATA_ASAAD) { }
+
+ void Reset() override
+ {
+ _Reset();
+
+ me->SetReactState(REACT_AGGRESSIVE);
+
+ events.ScheduleEvent(EVENT_SUMMON_SKYFALL_STAR, 11000);
+ events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 14500);
+ events.ScheduleEvent(EVENT_SOTS, 18000);
+ if (IsHeroic())
+ events.ScheduleEvent(EVENT_STATIC_CLING, 10800);
+ }
+
+ void EnterCombat(Unit* /*target*/) override
+ {
+ _EnterCombat();
+
+ Talk(SAY_AGGRO);
+
+ // Spawn Storm Targets
+ for (uint32 i = 0; i < StormTargetPositions; i++)
+ if (Creature* stormTarget = me->SummonCreature(NPC_STORM_TARGET, StormTargetPositionData[i]))
+ stormTargetGUIDs.push_back(stormTarget->GetGUID());
+ }
+
+ void JustSummoned(Creature* creature) override
+ {
+ if (creature->GetEntry() == NPC_SKYFALL_STAR)
+ {
+ creature->SetReactState(REACT_PASSIVE);
+ creature->SetInCombatWithZone();
+ creature->CastSpell(creature, SPELL_ARCANE_BARRAGE_AURA);
+ }
+
+ BossAI::JustSummoned(creature);
+ }
+
+ void SpellHitTarget(Unit* target, const SpellInfo* spellInfo) override
+ {
+ if (spellInfo->Id != SPELL_SOTS_TARGETING || target->GetEntry() != NPC_STORM_TARGET)
+ return;
+
+ stormTargetA = target->ToCreature();
+
+ for (uint32 i = 0; i < StormTargetPositions; i++)
+ {
+ if (stormTargetGUIDs[i] != target->GetGUID())
+ continue;
+
+ stormTargetB = ObjectAccessor::GetCreature(*me, stormTargetGUIDs[i % 3 == 0 ? i + 1 : (i % 3 == 1 ? i - 1 : i - 2)]);
+ stormTargetC = ObjectAccessor::GetCreature(*me, stormTargetGUIDs[i % 3 == 0 ? i + 2 : (i % 3 == 1 ? i + 1 : i - 1)]);
+
+ ASSERT(stormTargetB);
+ ASSERT(stormTargetC);
+ break;
+ }
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action != ACTION_SUPREMACY_OF_THE_STORM)
+ return;
+
+ me->CastStop();
+ me->SetDisableGravity(true);
+ DoCast(me, SPELL_SUPREMACY_OF_THE_STORM_TELEPORT);
+ DoCast(me, SPELL_SUPREMACY_OF_THE_STORM);
+ events.ScheduleEvent(EVENT_SOTS_END, 6000);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ Talk(SAY_DEATH);
+
+ _JustDied();
+ }
+
+ 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_STATIC_CLING:
+ DoCast(me, SPELL_STATIC_CLING);
+ events.ScheduleEvent(EVENT_STATIC_CLING, 16000);
+ break;
+ case EVENT_SUMMON_SKYFALL_STAR:
+ DoCast(me, SPELL_SUMMON_SKYFALL_STAR);
+ events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 14500);
+ break;
+ case EVENT_CHAIN_LIGHTNING:
+ DoCast(me, SPELL_CHAIN_LIGHTNING);
+ events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 14500);
+ break;
+ case EVENT_SOTS:
+ Talk(SAY_SOTS_EMOTE);
+ events.Reset();
+ events.ScheduleEvent(EVENT_SOTS_START, 200);
+ events.ScheduleEvent(EVENT_SOTS, 45800);
+ break;
+ case EVENT_SOTS_START:
+ me->SetReactState(REACT_PASSIVE);
+ me->AttackStop();
+ Talk(SAY_SOTS);
+ DoCast(me, SPELL_SOTS_TARGETING);
+ break;
+ case EVENT_SOTS_END:
+ ResetStormTargets();
+ me->SetDisableGravity(false);
+ events.ScheduleEvent(EVENT_ATTACK, 2000);
+ break;
+ case EVENT_ATTACK:
+ me->SetReactState(REACT_AGGRESSIVE);
+ events.ScheduleEvent(EVENT_CHAIN_LIGHTNING, 100);
+ events.ScheduleEvent(EVENT_STATIC_CLING, 2000);
+ events.ScheduleEvent(EVENT_SUMMON_SKYFALL_STAR, 3500);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ Creature* GetSelectedStormTarget(uint32 point)
+ {
+ if (point == POINT_STORM_A)
+ return stormTargetA;
+ if (point == POINT_STORM_B)
+ return stormTargetB;
+ if (point == POINT_STORM_C)
+ return stormTargetC;
+ return NULL;
+ }
+
+ Position GetTriangleCenterPosition()
+ {
+ Position pos;
+ pos.m_positionX = (stormTargetA->GetPositionX() + stormTargetB->GetPositionX() + stormTargetC->GetPositionX()) / 3;
+ pos.m_positionY = (stormTargetA->GetPositionY() + stormTargetB->GetPositionY() + stormTargetC->GetPositionY()) / 3;
+ pos.m_positionZ = stormTargetA->GetPositionZ() + 8.0f;
+ return pos;
+ }
+
+ void ResetStormTargets()
+ {
+ stormTargetA->CastStop();
+ stormTargetB->CastStop();
+ stormTargetC->CastStop();
+ }
+
+ private:
+ GuidVector stormTargetGUIDs;
+ Creature* stormTargetA;
+ Creature* stormTargetB;
+ Creature* stormTargetC;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+typedef boss_asaad::boss_asaadAI AsaadAI;
+
+// 46387 - Storm Target
+class npc_storm_target : public CreatureScript
+{
+public:
+ npc_storm_target() : CreatureScript("npc_storm_target") { }
+
+ struct npc_storm_targetAI : public ScriptedAI
+ {
+ npc_storm_targetAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void DoAction(int32 action) override
+ {
+ if (action != ACTION_SOTS_TARGET)
+ return;
+
+ events.ScheduleEvent(EVENT_SOTS_SUMMON, 400);
+ }
+
+ void JustSummoned(Creature* creature) override
+ {
+ if (InstanceScript* instance = me->GetInstanceScript())
+ if (Creature* asaad = instance->GetCreature(DATA_ASAAD))
+ ENSURE_AI(AsaadAI, asaad->AI())->JustSummoned(creature);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (events.Empty())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SOTS_SUMMON:
+ DoCast(me, SPELL_SOTS_SUMMON);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 46492 - Unstable Grounding Field
+class npc_unstable_grounding_field : public CreatureScript
+{
+public:
+ npc_unstable_grounding_field() : CreatureScript("npc_unstable_grounding_field") { }
+
+ struct npc_unstable_grounding_fieldAI : public ScriptedAI
+ {
+ npc_unstable_grounding_fieldAI(Creature* creature) : ScriptedAI(creature)
+ {
+ if (InstanceScript* instance = me->GetInstanceScript())
+ if (Creature* asaad = instance->GetCreature(DATA_ASAAD))
+ asaadAI = CAST_AI(AsaadAI, asaad->AI());
+
+ me->SetWalk(true);
+ events.ScheduleEvent(EVENT_STORM_ASSAD_CHANNEL, 400);
+ }
+
+ void MovementInform(uint32 movementType, uint32 pointId) override
+ {
+ if (movementType != POINT_MOTION_TYPE)
+ return;
+
+ switch (pointId)
+ {
+ case POINT_STORM_B:
+ if (Creature* stormTargetB = asaadAI->GetSelectedStormTarget(POINT_STORM_B))
+ stormTargetB->CastSpell((Unit*)NULL, SPELL_STORM_RUNE_BEAM_A);
+ events.ScheduleEvent(EVENT_STORM_MOVE_C, 1200);
+ break;
+ case POINT_STORM_C:
+ if (Creature* stormTargetB = asaadAI->GetSelectedStormTarget(POINT_STORM_C))
+ stormTargetB->CastSpell((Unit*)NULL, SPELL_STORM_RUNE_BEAM_B);
+ events.ScheduleEvent(EVENT_STORM_MOVE_A, 1200);
+ break;
+ case POINT_STORM_A:
+ {
+ if (Creature* stormTargetB = asaadAI->GetSelectedStormTarget(POINT_STORM_A))
+ stormTargetB->CastSpell((Unit*)NULL, SPELL_STORM_RUNE_BEAM_C);
+
+ DoCast(me, SPELL_STORM_SUMMON_GROUNDING_FIELD);
+ Position pos = asaadAI->GetTriangleCenterPosition();
+ me->CastSpell(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), SPELL_STORM_SUMMON_GROUNDING_FIELD, true);
+ events.ScheduleEvent(EVENT_STORM_ASAAD_TELEPORT, 500);
+ break;
+ }
+ default:
+ break;
+ }
+ };
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (events.Empty())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_STORM_ASSAD_CHANNEL:
+ DoCast(me, SPELL_SOTS_TRIGGER);
+ events.ScheduleEvent(EVENT_STORM_RUNE_BEAM_AA, 400);
+ break;
+ case EVENT_STORM_RUNE_BEAM_AA:
+ DoCast(me, SPELL_STORM_RUNE_BEAM_AA);
+ events.ScheduleEvent(EVENT_STORM_MOVE_B, 800);
+ break;
+ case EVENT_STORM_MOVE_B:
+ if (Creature* stormTargetB = asaadAI->GetSelectedStormTarget(POINT_STORM_B))
+ me->GetMotionMaster()->MovePoint(POINT_STORM_B, stormTargetB->GetPosition());
+ break;
+ case EVENT_STORM_MOVE_C:
+ DoCast(me, SPELL_STORM_RUNE_BEAM_B);
+ if (Creature* stormTargetC = asaadAI->GetSelectedStormTarget(POINT_STORM_C))
+ me->GetMotionMaster()->MovePoint(POINT_STORM_C, stormTargetC->GetPosition());
+ break;
+ case EVENT_STORM_MOVE_A:
+ me->CastStop();
+ DoCast(me, SPELL_STORM_RUNE_BEAM_C);
+ if (Creature* stormTargetA = asaadAI->GetSelectedStormTarget(POINT_STORM_A))
+ me->GetMotionMaster()->MovePoint(POINT_STORM_A, stormTargetA->GetPosition());
+ break;
+ case EVENT_STORM_ASAAD_TELEPORT:
+ asaadAI->DoAction(ACTION_SUPREMACY_OF_THE_STORM);
+ me->DespawnOrUnsummon(700);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ AsaadAI* asaadAI;
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 47000 - Grounding Field
+class npc_asaad_grounding_field : public CreatureScript
+{
+public:
+ npc_asaad_grounding_field() : CreatureScript("npc_asaad_grounding_field") { }
+
+ struct npc_asaad_grounding_fieldAI : public ScriptedAI
+ {
+ npc_asaad_grounding_fieldAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetDisableGravity(true);
+ events.ScheduleEvent(EVENT_GROUNDING_FIELD_VISUAL_BEAMS, 500);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (events.Empty())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_GROUNDING_FIELD_VISUAL_BEAMS:
+ DoCast(me, SPELL_GROUNDING_FIELD_VISUAL_BEAMS);
+ me->DespawnOrUnsummon(6000);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 86632 - SOTS Targeting
+class spell_sots_targeting : public SpellScriptLoader
+{
+public:
+ spell_sots_targeting() : SpellScriptLoader("spell_sots_targeting") { }
+
+ class spell_sots_targeting_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_sots_targeting_SpellScript);
+
+ void SelectRandom(std::list& targets)
+ {
+ Trinity::Containers::RandomResizeList(targets, 1);
+ }
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ if (Creature* creature = GetHitCreature())
+ creature->GetAI()->DoAction(ACTION_SOTS_TARGET);
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sots_targeting_SpellScript::SelectRandom, EFFECT_0, TARGET_UNIT_DEST_AREA_ENTRY);
+ OnEffectHitTarget += SpellEffectFn(spell_sots_targeting_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_sots_targeting_SpellScript();
+ }
+};
+
+// 86926 - SOTS Trigger (makes Asaad channel Unstable Grounding Field)
+class spell_sots_trigger : public SpellScriptLoader
+{
+public:
+ spell_sots_trigger() : SpellScriptLoader("spell_sots_trigger") { }
+
+ class spell_sots_trigger_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_sots_trigger_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_UNSTABLE_GROUNDING_FIELD))
+ return false;
+ return true;
+ }
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_UNSTABLE_GROUNDING_FIELD, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_sots_trigger_SpellScript::HandleScriptEffect, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_sots_trigger_SpellScript();
+ }
+};
+
+// 86981 - Storm Rune Beam AA
+// 86921 - Storm Rune Beam A
+// 86923 - Storm Rune Beam B
+// 86925 - Storm Rune Beam C
+class spell_storm_rune_beam : public SpellScriptLoader
+{
+public:
+ spell_storm_rune_beam() : SpellScriptLoader("spell_storm_rune_beam") { }
+
+ class spell_storm_rune_beam_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_storm_rune_beam_SpellScript);
+
+ void SetTarget(WorldObject*& target)
+ {
+ InstanceScript* instance = GetCaster()->GetInstanceScript();
+ if (!instance)
+ return;
+
+ Creature* asaad = instance->GetCreature(DATA_ASAAD);
+ if (!asaad)
+ return;
+
+ switch (GetSpellInfo()->Id)
+ {
+ case SPELL_STORM_RUNE_BEAM_AA:
+ case SPELL_STORM_RUNE_BEAM_A:
+ target = ENSURE_AI(AsaadAI, asaad->AI())->GetSelectedStormTarget(POINT_STORM_A);
+ break;
+ case SPELL_STORM_RUNE_BEAM_B:
+ target = ENSURE_AI(AsaadAI, asaad->AI())->GetSelectedStormTarget(POINT_STORM_B);
+ break;
+ case SPELL_STORM_RUNE_BEAM_C:
+ target = ENSURE_AI(AsaadAI, asaad->AI())->GetSelectedStormTarget(POINT_STORM_C);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void Register() override
+ {
+ OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_storm_rune_beam_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_storm_rune_beam_SpellScript();
+ }
+};
+
+// 87517 - Grounding Field Visual Beams
+class spell_grounding_field_visual_beams : public SpellScriptLoader
+{
+public:
+ spell_grounding_field_visual_beams() : SpellScriptLoader("spell_grounding_field_visual_beams") { }
+
+ class spell_grounding_field_visual_beams_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_grounding_field_visual_beams_SpellScript);
+
+ void SetTargetA(WorldObject*& target)
+ {
+ target = GetStormTarget(POINT_STORM_A);
+ }
+
+ void SetTargetB(WorldObject*& target)
+ {
+ target = GetStormTarget(POINT_STORM_B);
+ }
+
+ void SetTargetC(WorldObject*& target)
+ {
+ target = GetStormTarget(POINT_STORM_C);
+ }
+
+ void Register() override
+ {
+ OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_grounding_field_visual_beams_SpellScript::SetTargetA, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
+ OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_grounding_field_visual_beams_SpellScript::SetTargetB, EFFECT_1, TARGET_UNIT_NEARBY_ENTRY);
+ OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_grounding_field_visual_beams_SpellScript::SetTargetC, EFFECT_2, TARGET_UNIT_NEARBY_ENTRY);
+ }
+
+ private:
+ Creature* GetStormTarget(uint32 point)
+ {
+ if (InstanceScript* instance = GetCaster()->GetInstanceScript())
+ if (Creature* asaad = instance->GetCreature(DATA_ASAAD))
+ return ENSURE_AI(AsaadAI, asaad->AI())->GetSelectedStormTarget(point);
+ return NULL;
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_grounding_field_visual_beams_SpellScript();
+ }
+};
+
+// 87553/93994 - Supremacy of the Storm (massive aoe damage)
+class spell_supremacy_of_the_storm : public SpellScriptLoader
+{
+public:
+ spell_supremacy_of_the_storm() : SpellScriptLoader("spell_supremacy_of_the_storm") { }
+
+ class spell_supremacy_of_the_storm_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_supremacy_of_the_storm_SpellScript);
+
+ void FilterTargets(std::list& targets)
+ {
+ InstanceScript* instance = GetCaster()->GetInstanceScript();
+ if (!instance)
+ return;
+
+ Creature* asaad = instance->GetCreature(DATA_ASAAD);
+ if (!asaad)
+ return;
+
+ AsaadAI* asaadAI = CAST_AI(AsaadAI, asaad->AI());
+
+ if (Creature* stormTargetA = asaadAI->GetSelectedStormTarget(POINT_STORM_A))
+ if (Creature* stormTargetB = asaadAI->GetSelectedStormTarget(POINT_STORM_B))
+ if (Creature* stormTargetC = asaadAI->GetSelectedStormTarget(POINT_STORM_C))
+ targets.remove_if(TargetInTriangleCheck(false, stormTargetA->GetPosition(), stormTargetB->GetPosition(), stormTargetC->GetPosition()));
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_supremacy_of_the_storm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_supremacy_of_the_storm_SpellScript();
+ }
+};
+
+void AddSC_boss_asaad()
+{
+ new boss_asaad();
+ new npc_storm_target();
+ new npc_unstable_grounding_field();
+ new npc_asaad_grounding_field();
+ new spell_sots_targeting();
+ new spell_sots_trigger();
+ new spell_storm_rune_beam();
+ new spell_grounding_field_visual_beams();
+ new spell_supremacy_of_the_storm();
+}
diff --git a/src/server/scripts/Kalimdor/VortexPinnacle/boss_grand_vizier_ertan.cpp b/src/server/scripts/Kalimdor/VortexPinnacle/boss_grand_vizier_ertan.cpp
new file mode 100644
index 00000000000..c9fb42a6af1
--- /dev/null
+++ b/src/server/scripts/Kalimdor/VortexPinnacle/boss_grand_vizier_ertan.cpp
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore
+ *
+ * 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 .
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellScript.h"
+#include "Player.h"
+#include "vortex_pinnacle.h"
+
+enum Spells
+{
+ SPELL_STORMS_EDGE_AURA = 86295,
+ SPELL_LIGHTNING_BOLT = 86331,
+ SPELL_SUMMON_TEMPEST = 86340,
+ SPELL_STORMS_EDGE_VISUAL = 86329,
+ SPELL_STORMS_EDGE_CYCLONE_SHIELD_AURA = 86310, // periodically triggers 86311
+
+ // Ertan's Vortex
+ SPELL_CYCLONE_SHIELD = 86267,
+ SPELL_CYCLONE_SHIELD_TRIGGER = 86292,
+
+ SPELL_STORMS_EDGE_SCRIPT = 86299, // targets closest cyclone and makes it cast SPELL_STORMS_EDGE_DAMAGE on caster
+// SPELL_STORMS_EDGE_DAMAGE = 86309,
+};
+
+enum NPCs
+{
+ NPC_ERTANS_VORTEX = 46007,
+};
+
+enum Texts
+{
+ SAY_AGGRO = 0,
+ SAY_STORMS_EDGE = 1,
+};
+
+enum Actions
+{
+ ACTION_STORMS_EDGE,
+};
+
+enum Events
+{
+ EVENT_NONE,
+ EVENT_SUMMON_TEMPEST,
+ EVENT_STORMS_EDGE_SPAWN,
+ EVENT_STORMS_EDGE,
+ EVENT_STORMS_EDGE_AURA,
+ EVENT_STORMS_EDGE_END,
+
+ // Ertan's Vortex
+ EVENT_MOVE_POINT,
+};
+
+enum Points
+{
+ POINT_ERTANS_VORTEX_S = 0,
+ POINT_ERTANS_VORTEX_SW = 1,
+ POINT_ERTANS_VORTEX_W = 2,
+ POINT_ERTANS_VORTEX_NW = 3,
+ POINT_ERTANS_VORTEX_N = 4,
+ POINT_ERTANS_VORTEX_NE = 5,
+ POINT_ERTANS_VORTEX_E = 6,
+ POINT_ERTANS_VORTEX_SE = 7,
+ POINT_ERTANS_VORTEX_MAX = 8,
+ POINT_NONE,
+};
+
+const Position ErtansVortexPoints[POINT_ERTANS_VORTEX_MAX] =
+{
+ { -744.889f, 3.98611f, 635.6728f }, // South
+ { -737.552f, 21.592f, 635.6728f }, // South-West
+ { -719.802f, 28.8351f, 635.6728f }, // West
+ { -702.144f, 21.9878f, 635.6728f }, // North-West
+ { -694.911f, 4.16493f, 635.6728f }, // North
+ { -702.212f, -13.6806f, 635.6728f }, // North-East
+ { -719.934f, -20.9497f, 635.6728f }, // East
+ { -737.649f, -13.5347f, 635.6728f }, // South-East
+};
+
+const Position ErtansVortexMiddlePoints[POINT_ERTANS_VORTEX_MAX] =
+{
+ { -724.3819f, 2.915083f, 635.6728f }, // South
+ { -724.0161f, 6.648534f, 635.6728f }, // South-West
+ { -721.1381f, 9.082433f, 635.6728f }, // West
+ { -716.7177f, 8.423817f, 635.6728f }, // North-West
+ { -714.6548f, 5.146466f, 635.6728f }, // North
+ { -715.2417f, 1.857746f, 635.6728f }, // North-East
+ { -718.2345f, -0.4830246f, 635.6728f }, // East
+ { -721.9816f, -0.05864143f, 635.6728f }, // South-East
+};
+
+class boss_grand_vizier_ertan : public CreatureScript
+{
+ public:
+ boss_grand_vizier_ertan() : CreatureScript("boss_grand_vizier_ertan") { }
+
+ struct boss_grand_vizier_ertanAI : public BossAI
+ {
+ boss_grand_vizier_ertanAI(Creature* creature) : BossAI(creature, DATA_GRAND_VIZIER_ERTAN)
+ {
+ me->SetDisableGravity(true);
+ SetCombatMovement(false);
+ }
+
+ void Reset() override
+ {
+ _Reset();
+
+ // Should have, but gets stuck in evade mode...
+ //me->AddUnitState(UNIT_STATE_ROOT);
+
+ events.ScheduleEvent(EVENT_STORMS_EDGE_SPAWN, 400);
+ events.ScheduleEvent(EVENT_STORMS_EDGE, 23000);
+ if (IsHeroic())
+ events.ScheduleEvent(EVENT_SUMMON_TEMPEST, 17000);
+ }
+
+ void EnterCombat(Unit* /*target*/) override
+ {
+ _EnterCombat();
+
+ SummonErtansVortexes();
+ DoCast(me, SPELL_STORMS_EDGE_AURA);
+ Talk(SAY_AGGRO);
+ }
+
+ 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_SUMMON_TEMPEST:
+ DoCast(me, SPELL_SUMMON_TEMPEST);
+ events.ScheduleEvent(EVENT_SUMMON_TEMPEST, 17000);
+ break;
+ case EVENT_STORMS_EDGE:
+ {
+ DoCast(me, SPELL_STORMS_EDGE_VISUAL);
+ EntryCheckPredicate pred(NPC_ERTANS_VORTEX);
+ summons.DoAction(ACTION_STORMS_EDGE, pred);
+ Talk(SAY_STORMS_EDGE);
+ events.ScheduleEvent(EVENT_STORMS_EDGE_AURA, 3000);
+ events.ScheduleEvent(EVENT_STORMS_EDGE, 32000);
+ break;
+ }
+ case EVENT_STORMS_EDGE_AURA:
+ me->RemoveAurasDueToSpell(SPELL_STORMS_EDGE_AURA);
+ DoCast(me, SPELL_STORMS_EDGE_CYCLONE_SHIELD_AURA);
+ events.ScheduleEvent(EVENT_STORMS_EDGE_END, 6000);
+ break;
+ case EVENT_STORMS_EDGE_END:
+ me->RemoveAurasDueToSpell(SPELL_STORMS_EDGE_CYCLONE_SHIELD_AURA);
+ DoCast(me, SPELL_STORMS_EDGE_AURA);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoSpellAttackIfReady(SPELL_LIGHTNING_BOLT);
+ }
+
+ private:
+ void SummonErtansVortexes() // Summons Ertan's Vortex at each point and makes them move to the next point
+ {
+ for (int8 i = 0; i < POINT_ERTANS_VORTEX_MAX; i++)
+ {
+ if (Creature* ertansVortex = me->SummonCreature(NPC_ERTANS_VORTEX, ErtansVortexPoints[i]))
+ {
+ if (i == POINT_ERTANS_VORTEX_SE)
+ ertansVortex->GetMotionMaster()->MovePoint(POINT_ERTANS_VORTEX_S, ErtansVortexPoints[POINT_ERTANS_VORTEX_S]);
+ else
+ ertansVortex->GetMotionMaster()->MovePoint(i + 1, ErtansVortexPoints[i + 1]);
+ }
+ }
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 46007 - Ertan's Vortex
+class npc_ertans_vortex : public CreatureScript
+{
+public:
+ npc_ertans_vortex() : CreatureScript("npc_ertans_vortex") { }
+
+ struct npc_ertans_vortexAI : public ScriptedAI
+ {
+ npc_ertans_vortexAI(Creature* creature) : ScriptedAI(creature)
+ {
+ currentPointId = 0;
+ DoCast(me, SPELL_CYCLONE_SHIELD);
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action != ACTION_STORMS_EDGE)
+ return;
+
+ me->GetMotionMaster()->MovePoint(POINT_NONE, ErtansVortexMiddlePoints[currentPointId]);
+ events.ScheduleEvent(EVENT_MOVE_POINT, 9000);
+ }
+
+ void MovementInform(uint32 movementType, uint32 pointId) override
+ {
+ if (movementType != POINT_MOTION_TYPE || pointId == POINT_NONE)
+ return;
+
+ if (pointId < POINT_ERTANS_VORTEX_SE)
+ currentPointId = pointId + 1;
+ else
+ currentPointId = POINT_ERTANS_VORTEX_S;
+
+ events.ScheduleEvent(EVENT_MOVE_POINT, 1);
+ };
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (events.Empty())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_MOVE_POINT:
+ me->GetMotionMaster()->MovePoint(currentPointId, ErtansVortexPoints[currentPointId]);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ uint32 currentPointId;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 86284 - Storm's Edge (targets players outside cyclone ring/further than 25 yards and makes them cast 86299)
+// 86311 - Storm's Edge (targets all players and makes them cast 86299)
+class spell_storms_edge : public SpellScriptLoader
+{
+public:
+ spell_storms_edge() : SpellScriptLoader("spell_storms_edge") { }
+
+ class spell_storms_edge_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_storms_edge_SpellScript);
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetHitUnit(), SPELL_STORMS_EDGE_SCRIPT, true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_storms_edge_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_storms_edge_SpellScript();
+ }
+};
+
+// 86299 - Storm's Edge (targets closest Ertan's Vortex and makes it cast 86309 on caster)
+class spell_storms_edge_script : public SpellScriptLoader
+{
+public:
+ spell_storms_edge_script() : SpellScriptLoader("spell_storms_edge_script") { }
+
+ class spell_storms_edge_script_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_storms_edge_script_SpellScript);
+
+ void HandleScript(SpellEffIndex /*effIndex*/)
+ {
+ GetHitUnit()->CastSpell(GetCaster(), uint32(GetEffectValue()), true);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_storms_edge_script_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_storms_edge_script_SpellScript();
+ }
+};
+
+void AddSC_boss_grand_vizier_ertan()
+{
+ new boss_grand_vizier_ertan();
+ new npc_ertans_vortex();
+ new spell_storms_edge();
+ new spell_storms_edge_script();
+}
diff --git a/src/server/scripts/Kalimdor/VortexPinnacle/instance_vortex_pinnacle.cpp b/src/server/scripts/Kalimdor/VortexPinnacle/instance_vortex_pinnacle.cpp
new file mode 100644
index 00000000000..522fe5f5cc0
--- /dev/null
+++ b/src/server/scripts/Kalimdor/VortexPinnacle/instance_vortex_pinnacle.cpp
@@ -0,0 +1,230 @@
+/*
+* Copyright (C) 2008-2015 TrinityCore
+*
+* 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 .
+*/
+
+#include "ScriptMgr.h"
+#include "Player.h"
+#include "CreatureGroups.h"
+#include "Vehicle.h"
+#include "InstanceScript.h"
+#include "vortex_pinnacle.h"
+
+#define MAX_ENCOUNTER 3
+
+/* The Vortex Pinnacle encounters:
+0 - Grand Vizier Ertan
+1 - Altairus
+2 - Asaad
+*/
+
+struct Slipstream
+{
+ uint32 entry;
+ uint32 vehicleId;
+ Position position;
+ uint32 data;
+ uint32 bossData; // boss that has to die/be dead for Slipstream to spawn
+};
+
+Slipstream const SlipstreamData[Slipstreams] =
+{
+ // Grand Vizier Ertan Slipstreams
+ { NPC_SLIPSTREAM, 1111, { -775.517f, -70.9323f, 640.3123f, 0.0f }, DATA_SLIPSTREAM_1, DATA_GRAND_VIZIER_ERTAN },
+ { NPC_SLIPSTREAM, 1112, { -848.227f, -68.724f, 654.2203f, 0.0f }, DATA_SLIPSTREAM_2, DATA_GRAND_VIZIER_ERTAN },
+ { NPC_SLIPSTREAM, 1113, { -844.885f, -205.135f, 660.7083f, 0.0f }, DATA_SLIPSTREAM_3, DATA_GRAND_VIZIER_ERTAN },
+ // Grand Vizier Ertan Slipstream Landing Zone
+ { NPC_SLIPSTREAM_LANDING_ZONE, 1114, { -906.08f, -176.514f, 664.5053f, 2.86234f }, 0, DATA_GRAND_VIZIER_ERTAN },
+ // Altairus Slipstreams
+ { NPC_SLIPSTREAM, 1111, { -1190.88f, 125.203f, 737.6243f, 0.0f }, DATA_SLIPSTREAM_4, DATA_ALTAIRUS },
+ { NPC_SLIPSTREAM, 1112, { -1138.55f, 178.524f, 711.4943f, 0.0f }, DATA_SLIPSTREAM_5, DATA_ALTAIRUS },
+ { NPC_SLIPSTREAM, 1149, { -1245.21f, 230.986f, 690.6083f, 0.0f }, DATA_SLIPSTREAM_6, DATA_ALTAIRUS },
+ { NPC_SLIPSTREAM, 1150, { -1282.07f, 344.856f, 660.9873f, 0.0f }, DATA_SLIPSTREAM_7, DATA_ALTAIRUS },
+ { NPC_SLIPSTREAM, 1113, { -1229.64f, 412.26f, 641.2933f, 0.0f }, DATA_SLIPSTREAM_8, DATA_ALTAIRUS },
+ // Altairus Slipstream Landing Zone
+ { NPC_SLIPSTREAM_LANDING_ZONE, 1114, { -1193.67f, 472.835f, 634.8653f, 0.5061455f }, 0, DATA_ALTAIRUS },
+ // Asaad Slipstream
+ { NPC_SLIPSTREAM, 1551, { -746.9566f, 529.1406f, 644.8316f, 0.0f }, DATA_SLIPSTREAM_9, DATA_ASAAD },
+ // Entrance Slipstreams
+ { NPC_SLIPSTREAM, 1305, { -310.4583f, -29.74479f, 625.0833f, 0.0f }, DATA_SLIPSTREAM_10, DATA_GRAND_VIZIER_ERTAN },
+ { NPC_SLIPSTREAM, 1306, { -382.441f, 42.31597f, 625.0833f, 0.0f }, DATA_SLIPSTREAM_11, DATA_ALTAIRUS },
+};
+
+Position const SouthZephyrSummonLocation = { -1070.639f, 432.2814f, 647.0389f, 6.15166f };
+Position const NorthZephyrSummonLocation = { -781.4438f, 491.1446f, 698.0991f, 0.3193802f };
+
+Position const FirstPrismGroundingFieldTop = { -1008.997f, 474.3663f, 708.1033f, 0.0f };
+Position const FirstPrismGroundingFieldPoints[PrismGroundingFieldPoints] =
+{
+ { -990.934f, 466.7552f, 700.0436f, 0.0f },
+ { -1021.677f, 461.6684f, 700.1023f, 0.0f },
+ { -1016.434f, 492.8455f, 700.0325f, 0.0f },
+};
+
+Position const SecondPrismGroundingFieldTop = { -829.7674f, 477.9531f, 708.1063f, 4.328416f };
+Position const SecondPrismGroundingFieldPoints[PrismGroundingFieldPoints] =
+{
+ { -851.3368f, 469.3629f, 700.0286f, 4.328416f },
+ { -820.2327f, 468.5017f, 700.1062f, 4.328416f },
+ { -821.4792f, 500.3004f, 700.0289f, 4.328416f },
+};
+
+ObjectData const creatureData[] =
+{
+ { NPC_ALTAIRUS, DATA_ALTAIRUS },
+ { NPC_ASAAD, DATA_ASAAD },
+ { 0, 0 }
+};
+
+class instance_vortex_pinnacle : public InstanceMapScript
+{
+ public:
+ instance_vortex_pinnacle() : InstanceMapScript(SCScriptName, 657) { }
+
+ struct instance_vortex_pinnacle_InstanceScript : public InstanceScript
+ {
+ instance_vortex_pinnacle_InstanceScript(Map* map) : InstanceScript(map)
+ {
+ SetHeaders(DataHeader);
+ SetBossNumber(MAX_ENCOUNTER);
+ LoadObjectData(creatureData, nullptr);
+
+ CheckSlipstreams();
+ SummonGroundingFieldPrism(FirstPrismGroundingFieldTop, FirstPrismGroundingFieldPoints);
+ SummonGroundingFieldPrism(SecondPrismGroundingFieldTop, SecondPrismGroundingFieldPoints);
+
+ events.ScheduleEvent(EVENT_SUMMON_ZEPHYRS, 0);
+ }
+
+ void OnCreatureCreate(Creature* creature) override
+ {
+ switch (creature->GetEntry())
+ {
+ case NPC_HOWLING_GALE:
+ creature->SetReactState(REACT_PASSIVE);
+ break;
+ default:
+ break;
+ }
+
+ InstanceScript::OnCreatureCreate(creature);
+ }
+
+
+ bool SetBossState(uint32 type, EncounterState state) override
+ {
+ InstanceScript::SetBossState(type, state);
+
+ // Spawn Slipstreams
+ if (state == DONE)
+ SummonSlipstreams(type);
+
+ return true;
+ }
+
+ void Update(uint32 diff) override
+ {
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SUMMON_ZEPHYRS: // Summon Zephyrs every 10 seconds. There is no sniff data about trigger npc or spells that would handle summoning.
+ if (TempSummon* zephyr = instance->SummonCreature(NPC_ZEPHYR, SouthZephyrSummonLocation))
+ zephyr->GetMotionMaster()->MovePath(PATH_ZEPHYR_SOUTH, false);
+ if (TempSummon* zephyr = instance->SummonCreature(NPC_ZEPHYR, NorthZephyrSummonLocation))
+ zephyr->GetMotionMaster()->MovePath(PATH_ZEPHYR_NORTH, false);
+ events.ScheduleEvent(EVENT_SUMMON_ZEPHYRS, 10000);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ // Check which Slipstreams can be spawned on script init
+ void CheckSlipstreams()
+ {
+ if (GetBossState(DATA_GRAND_VIZIER_ERTAN) == DONE)
+ SummonSlipstreams(DATA_GRAND_VIZIER_ERTAN);
+ if (GetBossState(DATA_ALTAIRUS) == DONE)
+ SummonSlipstreams(DATA_ALTAIRUS);
+ if (GetBossState(DATA_ASAAD) == DONE)
+ SummonSlipstreams(DATA_ASAAD);
+ }
+
+ // Spawns Slipstreams belonging bossType
+ void SummonSlipstreams(uint32 bossType)
+ {
+ for (uint8 i = 0; i < Slipstreams; ++i)
+ {
+ if (SlipstreamData[i].bossData != bossType)
+ continue;
+
+ TempSummon* summon = instance->SummonCreature(SlipstreamData[i].entry, SlipstreamData[i].position);
+ if (!summon)
+ continue;
+
+ AddObject(summon, SlipstreamData[i].data, true);
+
+ if (SlipstreamData[i].data == DATA_SLIPSTREAM_1 || SlipstreamData[i].data == DATA_SLIPSTREAM_4 ||
+ SlipstreamData[i].data == DATA_SLIPSTREAM_10 || SlipstreamData[i].data == DATA_SLIPSTREAM_11)
+ {
+ summon->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ summon->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
+ }
+
+ WorldPacket data(SMSG_PLAYER_VEHICLE_DATA, summon->GetPackGUID().size() + 4);
+ data << summon->GetPackGUID();
+ data << uint32(SlipstreamData[i].vehicleId);
+ summon->SendMessageToSet(&data, true);
+ }
+ }
+
+ // Spawns Grounding Field prism
+ void SummonGroundingFieldPrism(Position positionTop, const Position positionPoints[PrismGroundingFieldPoints])
+ {
+ // Spawn lower three grounding fields
+ TempSummon* points[PrismGroundingFieldPoints];
+ for (uint32 i = 0; i < PrismGroundingFieldPoints; i++)
+ points[i] = instance->SummonCreature(NPC_GROUNDING_FIELD, positionPoints[i]);
+
+ // If all three grounding fields spawned, cast beams and spawn the upper grounding field
+ if (points[0] && points[1] && points[2])
+ {
+ points[1]->CastSpell(points[0], SPELL_BEAM_A, true);
+ points[2]->CastSpell(points[1], SPELL_BEAM_B, true);
+ points[0]->CastSpell(points[2], SPELL_BEAM_C, true);
+
+ if (TempSummon* top = instance->SummonCreature(NPC_GROUNDING_FIELD, positionTop))
+ top->ToCreature()->GetAI()->DoAction(ACTION_GROUNDING_FIELD_TOP);
+ }
+ }
+
+ EventMap events;
+ };
+
+ InstanceScript* GetInstanceScript(InstanceMap* map) const override
+ {
+ return new instance_vortex_pinnacle_InstanceScript(map);
+ }
+};
+
+void AddSC_instance_vortex_pinnacle()
+{
+ new instance_vortex_pinnacle();
+}
diff --git a/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.cpp b/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.cpp
new file mode 100644
index 00000000000..40e0e176d1e
--- /dev/null
+++ b/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.cpp
@@ -0,0 +1,1005 @@
+/*
+ * Copyright (C) 2008-2015 TrinityCore
+ *
+ * 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 .
+ */
+
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "ObjectGuid.h"
+#include "SpellScript.h"
+#include "Player.h"
+#include "Vehicle.h"
+#include "vortex_pinnacle.h"
+
+enum Texts
+{
+ SAY_FEIGN_DEATH = 0,
+};
+
+enum Spells
+{
+ // Lurking Tempest
+ SPELL_LIGHTNING_BOLT = 89105,
+ SPELL_LURK = 85467, // dummy aura while not playing dead
+ SPELL_LURK_SEARCH = 85294, // periodically triggers either SPELL_LURK_CHECK or SPELL_FEIGN_DEATH_CHECK
+ SPELL_LURK_CHECK = 85291,
+ SPELL_FEIGN_DEATH = 85267,
+ SPELL_FEIGN_DEATH_CHECK = 86493,
+ SPELL_LURK_RESSURECT = 85281, // 1250 ms duration, on remove SPELL_LURK (85467) is cast
+ SPELL_LURK_FIND_VICTIM = 86456,
+
+ // Young Storm Dragon
+ SPELL_HEALING_WELL = 88201,
+ SPELL_CHILLING_BLAST = 88194,
+
+ // Howling Gale
+ SPELL_HOWLING_GALE_VISUAL = 85086,
+ SPELL_HOWLING_GALE_KNOCKBACK = 85159,
+ SPELL_HOWLING_GALE_VISUAL_2 = 85137,
+ SPELL_HOWLING_GALE_KNOCKBACK_2 = 85085,
+
+ // Slipstream (spells Slipstream npcs cast on passenger to make it enter next Slipstream)
+ SPELL_SLIPSTREAM_SPELLCLICK = 84965, // spellclick
+ SPELL_SLIPSTREAM_FIRST = 84980, // Cast on passenger by Slipstream 1 and 4.
+ SPELL_SLIPSTREAM_FIRST_CONTROL_VEHICLE_AURA = 84978, // Triggered by SPELL_SLIPSTREAM_FIRST. Targets closest NPC_SLIPSTREAM.
+ SPELL_SLIPSTREAM_SECOND = 84988, // Cast on passenger by Slipstream 2 and 5.
+ SPELL_SLIPSTREAM_SECOND_CONTROL_VEHICLE_AURA = 84989, // Triggered by SPELL_SLIPSTREAM_SECOND. Targets second closest NPC_SLIPSTREAM.
+ SPELL_SLIPSTREAM_THIRD = 85394, // Cast on passenger by Slipstream 6.
+ SPELL_SLIPSTREAM_THIRD_CONTROL_VEHICLE_AURA = 85395, // Triggered by SPELL_SLIPSTREAM_THIRD. Unknown how it targets next NPC_SLIPSTREAM.
+ SPELL_SLIPSTREAM_FORTH = 85397, // Cast on passenger by Slipstream 7.
+ SPELL_SLIPSTREAM_FORTH_CONTROL_VEHICLE_AURA = 85396, // Triggered by SPELL_SLIPSTREAM_FORTH. Unknown how it targets next NPC_SLIPSTREAM.
+ SPELL_SLIPSTREAM_LAST = 85016, // Cast on passenger by Slipstream 3 and 8.
+ SPELL_SLIPSTREAM_LAST_CONTROL_VEHICLE_AURA = 85017, // Triggered by SPELL_SLIPSTREAM_LAST. Targets NPC_SLIPSTREAM_LANDING_ZONE.
+
+ // No one sniffed using Slipstreams at entrance, I guess they take you to Slipstream Landing Zone directly, but need spell IDs.
+ // Possible spell IDs named 'Slipstream': 87742 Jet Stream??, 89498, 89500, 95911
+// SPELL_SLIPSTREAM_LEFT = 0,
+// SPELL_SLIPSTREAM_RIGHT = 0,
+
+ // Slipstream Landing Zone
+ SPELL_GENERIC_EJECT_ALL_PASSENGERS = 79737, // Generic Eject All Passengers - Always Allow
+
+ // Grounding Field
+ SPELL_PRISM_BEAMS = 87724,
+ SPELL_GROUNDING_FIELD = 87725,
+
+ // Skyfall npc
+ SPELL_SKYFALL_VISUAL = 85719,
+ SPELL_SKYFALL = 87850,
+
+ // Skyfall Star npc
+ SPELL_ARCANE_BARRAGE = 87845,
+};
+
+enum NPCs
+{
+ NPC_SKYFALL = 45981,
+ NPC_SKYFALL_STAR = 52019,
+};
+
+enum Events
+{
+ EVENT_NONE,
+
+ // Young Storm Dragon
+ EVENT_TAKEOFF,
+ EVENT_ATTACK,
+ EVENT_HEALING_WELL,
+ EVENT_CHILLING_BLAST,
+
+ // Grounding Field
+ EVENT_CAST_PRISM_BEAMS,
+
+ // Skyfall Star
+ EVENT_FLY_RANDOM,
+};
+
+enum Points
+{
+ POINT_NONE,
+
+ POINT_RANDOM,
+};
+
+// TO-DO:
+// - Grounding Field npc (47085) is broken somewhere, it won't load script assigned in DB. They are summoned in
+// SummonGroundingFieldPrism() void (instance_vortex_pinnacle.cpp), same like Slipstream which acts just fine.
+
+// 45704 - Lurking Tempest
+class npc_lurking_tempest : public CreatureScript
+{
+public:
+ npc_lurking_tempest() : CreatureScript("npc_lurking_tempest") { }
+
+ struct npc_lurking_tempestAI : public ScriptedAI
+ {
+ npc_lurking_tempestAI(Creature* creature) : ScriptedAI(creature)
+ {
+ ertan = false;
+ SetCombatMovement(false);
+ }
+
+ void Reset() override
+ {
+ // Should have, but gets stuck in evade mode...
+ //me->AddUnitState(UNIT_STATE_ROOT);
+ DoCast(me, SPELL_LURK);
+ }
+
+ void IsSummonedBy(Unit* summoner) override
+ {
+ if (Creature* creature = summoner->ToCreature())
+ ertan = (creature->GetEntry() == NPC_GRAND_VIZIER_ERTAN);
+ }
+
+ void MoveInLineOfSight(Unit* who) override
+ {
+ if (!me->IsInCombat() && me->IsWithinDist(who, ertan ? 100.0f : 45.0f) && me->IsValidAttackTarget(who))
+ AttackStart(who);
+ }
+
+ void EnterCombat(Unit* /*target*/) override
+ {
+ DoCast(me, SPELL_LURK_SEARCH);
+ }
+
+ void SpellHit(Unit* /*unit*/, const SpellInfo* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_FEIGN_DEATH)
+ Talk(SAY_FEIGN_DEATH);
+ }
+
+ void UpdateAI(uint32 /*diff*/) override
+ {
+ if (!me->HasAura(SPELL_LURK) || !UpdateVictim())
+ return;
+
+ // Just stop combat when target is far away.
+ if (!ertan && !me->IsWithinDistInMap(me->GetVictim(), 45.0f))
+ {
+ me->DeleteThreatList();
+ me->CombatStop(true);
+ return;
+ }
+
+ DoSpellAttackIfReady(SPELL_LIGHTNING_BOLT);
+ }
+
+ private:
+ bool ertan; // Is it summoned by Grand Vizier Ertan?
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 45455 - Slipstream
+class npc_slipstream : public CreatureScript
+{
+public:
+ npc_slipstream() : CreatureScript("npc_slipstream") { }
+
+ struct npc_slipstreamAI : public ScriptedAI
+ {
+ npc_slipstreamAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetDisableGravity(true);
+ me->SetExtraUnitMovementFlags(MOVEMENTFLAG2_NO_STRAFE | MOVEMENTFLAG2_NO_JUMPING);
+ }
+
+ void PassengerBoarded(Unit* who, int8 /*seatId*/, bool apply) override
+ {
+ if (!apply)
+ return;
+
+ if (me->HasAura(SPELL_SLIPSTREAM_SPELLCLICK))
+ DoCast(who, SPELL_SLIPSTREAM_FIRST);
+ else if (me->HasAura(SPELL_SLIPSTREAM_FIRST_CONTROL_VEHICLE_AURA))
+ DoCast(who, SPELL_SLIPSTREAM_SECOND);
+ else if (me->HasAura(SPELL_SLIPSTREAM_SECOND_CONTROL_VEHICLE_AURA))
+ DoCast(who, SPELL_SLIPSTREAM_THIRD);
+ else if (me->HasAura(SPELL_SLIPSTREAM_THIRD_CONTROL_VEHICLE_AURA))
+ DoCast(who, SPELL_SLIPSTREAM_FORTH);
+ else if (me->HasAura(SPELL_SLIPSTREAM_FORTH_CONTROL_VEHICLE_AURA))
+ DoCast(who, SPELL_SLIPSTREAM_LAST);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 45504 - Slipstream Landing Zone (can be converted to SAI later, whatever masters say)
+class npc_slipstream_landing_zone : public CreatureScript
+{
+public:
+ npc_slipstream_landing_zone() : CreatureScript("npc_slipstream_landing_zone") { }
+
+ struct npc_slipstream_landing_zoneAI : public ScriptedAI
+ {
+ npc_slipstream_landing_zoneAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetDisableGravity(true);
+ me->SetExtraUnitMovementFlags(MOVEMENTFLAG2_NO_STRAFE | MOVEMENTFLAG2_NO_JUMPING);
+ }
+
+ void PassengerBoarded(Unit* /*who*/, int8 /*seatId*/, bool apply) override
+ {
+ if (!apply)
+ return;
+
+ if (me->HasAura(SPELL_SLIPSTREAM_LAST_CONTROL_VEHICLE_AURA))
+ DoCast(me, SPELL_GENERIC_EJECT_ALL_PASSENGERS);
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 45919 - Young Storm Dragon
+class npc_young_storm_dragon : public CreatureScript
+{
+public:
+ npc_young_storm_dragon() : CreatureScript("npc_young_storm_dragon") { }
+
+ struct npc_young_storm_dragonAI : public ScriptedAI
+ {
+ npc_young_storm_dragonAI(Creature* creature) : ScriptedAI(creature) { }
+
+ void Reset() override
+ {
+ me->SetCanFly(false);
+ me->SetDisableGravity(false);
+ me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
+
+ events.Reset();
+ events.ScheduleEvent(EVENT_HEALING_WELL, 1);
+ events.ScheduleEvent(EVENT_TAKEOFF, 3000);
+ events.ScheduleEvent(EVENT_ATTACK, 6000);
+ }
+
+ void EnterCombat(Unit* /*target*/) override
+ {
+ me->SetReactState(REACT_PASSIVE);
+
+ me->GetMotionMaster()->MovementExpired();
+ me->GetMotionMaster()->Clear(true);
+ me->StopMoving();
+ //me->GetMotionMaster()->MoveIdle();
+ }
+
+ 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_TAKEOFF:
+ {
+ me->SetCanFly(true);
+ me->SetDisableGravity(true);
+ me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER);
+ Position pos = me->GetPosition();
+ pos.m_positionZ += 10.0f;
+ me->GetMotionMaster()->MoveTakeoff(0, pos);
+ break;
+ }
+ case EVENT_ATTACK:
+ me->SetReactState(REACT_AGGRESSIVE);
+ events.RescheduleEvent(EVENT_CHILLING_BLAST, 14000);
+ events.RescheduleEvent(EVENT_HEALING_WELL, 15000);
+ break;
+ case EVENT_CHILLING_BLAST:
+ DoCastVictim(SPELL_CHILLING_BLAST);
+ events.ScheduleEvent(EVENT_CHILLING_BLAST, 14000);
+ break;
+ case EVENT_HEALING_WELL:
+ DoCast(me, SPELL_HEALING_WELL);
+ events.ScheduleEvent(EVENT_HEALING_WELL, 15000);
+ break;
+ default:
+ break;
+ }
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 47085 - Grounding Field
+class npc_grounding_field : public CreatureScript
+{
+public:
+ npc_grounding_field() : CreatureScript("npc_grounding_field") { }
+
+ struct npc_grounding_fieldAI : public ScriptedAI
+ {
+ npc_grounding_fieldAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetDisableGravity(true);
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action != ACTION_GROUNDING_FIELD_TOP)
+ return;
+
+ DoCast(me, SPELL_GROUNDING_FIELD);
+ events.ScheduleEvent(EVENT_CAST_PRISM_BEAMS, 5000);
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (events.Empty())
+ return;
+
+ events.Update(diff);
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_CAST_PRISM_BEAMS:
+ me->CastStop();
+ DoCast(me, SPELL_PRISM_BEAMS);
+ events.ScheduleEvent(EVENT_CAST_PRISM_BEAMS, 5000);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 45981 - Skyfall
+// TO-DO: Script despawn.
+class npc_skyfall : public CreatureScript
+{
+public:
+ npc_skyfall() : CreatureScript("npc_skyfall") { }
+
+ struct npc_skyfallAI : public ScriptedAI
+ {
+ npc_skyfallAI(Creature* creature) : ScriptedAI(creature)
+ {
+ me->SetDisableGravity(true);
+ }
+
+ void Reset()
+ {
+ me->AddUnitState(UNIT_STATE_ROOT);
+ me->SetReactState(REACT_AGGRESSIVE);
+ DoCast(me, SPELL_SKYFALL_VISUAL);
+ }
+
+ void EnterCombat(Unit* /*target*/) override
+ {
+ me->SetReactState(REACT_PASSIVE);
+ DoCast(me, SPELL_SKYFALL);
+ }
+
+ void UpdateAI(uint32 /*diff*/) override
+ {
+ if (!me->FindNearestCreature(NPC_SKYFALL, 100.0f))
+ me->DespawnOrUnsummon();
+ }
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 45932 - Skyfall Star
+class npc_skyfall_star : public CreatureScript
+{
+public:
+ npc_skyfall_star() : CreatureScript("npc_skyfall_star") { }
+
+ struct npc_skyfall_starAI : public CreatureAI
+ {
+ npc_skyfall_starAI(Creature* creature) : CreatureAI(creature)
+ {
+ me->SetDisableGravity(true);
+ }
+
+ void Reset() override
+ {
+ me->SetReactState(REACT_AGGRESSIVE);
+ }
+
+ void EnterCombat(Unit* /*target*/) override
+ {
+ me->SetReactState(REACT_PASSIVE);
+ DoCast(me, SPELL_ARCANE_BARRAGE);
+ events.ScheduleEvent(EVENT_FLY_RANDOM, 0);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ me->DespawnOrUnsummon();
+ }
+
+ void MovementInform(uint32 movementType, uint32 pointId) override
+ {
+ if (movementType == POINT_MOTION_TYPE || pointId == POINT_RANDOM)
+ events.ScheduleEvent(EVENT_FLY_RANDOM, 1000);
+ };
+
+ void UpdateAI(uint32 diff) override
+ {
+ if (!UpdateVictim() || events.Empty())
+ return;
+
+ events.Update(diff);
+
+ uint32 eventId = events.ExecuteEvent();
+ if (!eventId || eventId != EVENT_FLY_RANDOM)
+ return;
+
+ // Fly to random near position.
+ Position pos = me->GetRandomNearPosition(10.0f);
+ pos.m_positionZ += frand(4.0f, 6.0f);
+ me->GetMotionMaster()->MovePoint(POINT_RANDOM, pos);
+ }
+
+ private:
+ EventMap events;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const override
+ {
+ return GetInstanceAI(creature);
+ }
+};
+
+// 85294 - Lurk Search
+class spell_lurk_search : public SpellScriptLoader
+{
+public:
+ spell_lurk_search() : SpellScriptLoader("spell_lurk_search") { }
+
+ class spell_lurk_search_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_lurk_search_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_LURK_CHECK))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_FEIGN_DEATH_CHECK))
+ return false;
+ return true;
+ }
+
+ void HandlePeriodic(AuraEffect const* /*aurEff*/)
+ {
+ Creature* owner = GetOwner()->ToCreature();
+ if (!owner)
+ return;
+
+ if (owner->HasAura(SPELL_LURK))
+ {
+ if (owner->IsInCombat())
+ owner->CastSpell(owner, SPELL_LURK_CHECK, true);
+ }
+ else if (owner->HasAura(SPELL_FEIGN_DEATH))
+ owner->CastSpell(owner, SPELL_FEIGN_DEATH_CHECK, true);
+ }
+
+ void Register() override
+ {
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_lurk_search_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_lurk_search_AuraScript();
+ }
+};
+
+// 85291 - Lurk Search (triggers Feign Death)
+// 86493 - Lurk Search (triggers Lurk Ressurect)
+class PlayerOrPetOrientationCheck
+{
+public:
+ PlayerOrPetOrientationCheck(Unit* caster) : caster(caster) { }
+
+ bool operator()(WorldObject* object)
+ {
+ return (!object->ToUnit()->IsCharmedOwnedByPlayerOrPlayer() || !object->isInFront(caster, 2.5f));
+ }
+
+private:
+ Unit* caster;
+};
+
+class spell_lurk_search_check : public SpellScriptLoader
+{
+public:
+ spell_lurk_search_check() : SpellScriptLoader("spell_lurk_search_check") { }
+
+ class spell_lurk_search_check_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_lurk_search_check_SpellScript);
+
+ public:
+ spell_lurk_search_check_SpellScript()
+ {
+ countFacingUnits = 0;
+ }
+
+ private:
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_FEIGN_DEATH))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_LURK_RESSURECT))
+ return false;
+ return true;
+ }
+
+ void FilterTargets(std::list& unitList)
+ {
+ unitList.remove_if(PlayerOrPetOrientationCheck(GetCaster()));
+ countFacingUnits = unitList.size();
+ }
+
+ void OnLaunch(SpellEffIndex /*effIndex*/)
+ {
+ Unit* caster = GetCaster();
+
+ switch (GetSpellInfo()->Id)
+ {
+ case SPELL_LURK_CHECK:
+ if (countFacingUnits && !caster->HasAura(SPELL_FEIGN_DEATH))
+ caster->CastSpell(caster, SPELL_FEIGN_DEATH, true);
+ break;
+ case SPELL_FEIGN_DEATH_CHECK:
+ if (!countFacingUnits)
+ caster->CastSpell(caster, SPELL_LURK_RESSURECT, true);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void Register() override
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_lurk_search_check_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ OnEffectLaunch += SpellEffectFn(spell_lurk_search_check_SpellScript::OnLaunch, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+
+ uint32 countFacingUnits;
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_lurk_search_check_SpellScript();
+ }
+};
+
+// 85267 - Feign Death
+class spell_feign_death : public SpellScriptLoader
+{
+public:
+ spell_feign_death() : SpellScriptLoader("spell_feign_death") { }
+
+ class spell_feign_death_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_feign_death_SpellScript);
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ Creature* creature = GetHitUnit()->ToCreature();
+ if (!creature)
+ return;
+
+ creature->RemoveAurasDueToSpell(SPELL_LURK);
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_feign_death_SpellScript::HandleScriptEffect, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_feign_death_SpellScript();
+ }
+};
+
+// 85281 - Lurk Ressurect
+class spell_lurk_ressurect : public SpellScriptLoader
+{
+public:
+ spell_lurk_ressurect() : SpellScriptLoader("spell_lurk_ressurect") { }
+
+ class spell_lurk_ressurect_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_lurk_ressurect_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_LURK))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_LURK_SEARCH))
+ return false;
+ return true;
+ }
+
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Creature* owner = GetOwner()->ToCreature();
+ if (!owner)
+ return;
+
+ owner->RemoveAurasDueToSpell(SPELL_FEIGN_DEATH);
+ owner->RemoveAurasDueToSpell(SPELL_LURK_SEARCH);
+
+ owner->DeleteThreatList();
+ owner->CombatStop(true);
+
+ owner->CastSpell(owner, SPELL_LURK_FIND_VICTIM, true);
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (Creature* owner = GetOwner()->ToCreature())
+ owner->CastSpell(owner, SPELL_LURK, true);
+ }
+
+ void Register() override
+ {
+ OnEffectApply += AuraEffectApplyFn(spell_lurk_ressurect_AuraScript::OnApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ OnEffectRemove += AuraEffectRemoveFn(spell_lurk_ressurect_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_lurk_ressurect_AuraScript();
+ }
+};
+
+// 86456 - Lurk Search
+class spell_lurk_search_victim : public SpellScriptLoader
+{
+public:
+ spell_lurk_search_victim() : SpellScriptLoader("spell_lurk_search_victim") { }
+
+ class spell_lurk_search_victim_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_lurk_search_victim_SpellScript);
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ GetCaster()->AddThreat(GetHitUnit(), 0.0f);
+ GetCaster()->SetInCombatWith(GetHitUnit());
+ GetHitUnit()->SetInCombatWith(GetCaster());
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_lurk_search_victim_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_lurk_search_victim_SpellScript();
+ }
+};
+
+// 84978, 84989, 85395, 85396, 85017 - Slipstream
+// TO-DO: Fix passenger entering vehicle from another vehicle, passenger's vehicle enters vehicle instead... need core fix or we must handle it in this spellscript?
+class spell_slipstream : public SpellScriptLoader
+{
+public:
+ spell_slipstream() : SpellScriptLoader("spell_slipstream") { }
+
+ class spell_slipstream_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_slipstream_SpellScript);
+
+ void SetTarget(WorldObject*& target)
+ {
+ InstanceScript* instance = GetCaster()->GetInstanceScript();
+ if (!instance)
+ return;
+
+ Creature* slipstream = GetCaster()->FindNearestCreature(NPC_SLIPSTREAM, 10.0f); // GetCaster()->GetTransport(); won't work :(
+ if (!slipstream)
+ return;
+
+ switch (GetSpellInfo()->Id)
+ {
+ case SPELL_SLIPSTREAM_FIRST_CONTROL_VEHICLE_AURA:
+ if (slipstream->GetGUID() == instance->GetGuidData(DATA_SLIPSTREAM_1))
+ target = instance->GetCreature(DATA_SLIPSTREAM_2);
+ else if (slipstream->GetGUID() == instance->GetGuidData(DATA_SLIPSTREAM_4))
+ target = instance->GetCreature(DATA_SLIPSTREAM_5);
+ break;
+ case SPELL_SLIPSTREAM_SECOND_CONTROL_VEHICLE_AURA:
+ if (slipstream->GetGUID() == instance->GetGuidData(DATA_SLIPSTREAM_2))
+ target = instance->GetCreature(DATA_SLIPSTREAM_3);
+ else if (slipstream->GetGUID() == instance->GetGuidData(DATA_SLIPSTREAM_5))
+ target = instance->GetCreature(DATA_SLIPSTREAM_6);
+ break;
+ case SPELL_SLIPSTREAM_THIRD_CONTROL_VEHICLE_AURA:
+ target = instance->GetCreature(DATA_SLIPSTREAM_7);
+ break;
+ case SPELL_SLIPSTREAM_FORTH_CONTROL_VEHICLE_AURA:
+ target = instance->GetCreature(DATA_SLIPSTREAM_8);
+ break;
+ case SPELL_SLIPSTREAM_LAST_CONTROL_VEHICLE_AURA: // it won't
+ target = slipstream->FindNearestCreature(NPC_SLIPSTREAM_LANDING_ZONE, 100.0f);
+ break;
+ default:
+ break;
+ }
+ }
+
+ void Register() override
+ {
+ OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_slipstream_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_slipstream_SpellScript();
+ }
+};
+
+
+// 85084 - Howling Gale
+// TO-DO: Fix OnEffectProc.
+class spell_howling_gale : public SpellScriptLoader
+{
+public:
+ spell_howling_gale() : SpellScriptLoader("spell_howling_gale") { }
+
+ class spell_howling_gale_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_howling_gale_AuraScript);
+
+ public:
+ spell_howling_gale_AuraScript()
+ {
+ tickCountdown = 0;
+ proced = false;
+ }
+
+ private:
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ if (!sSpellMgr->GetSpellInfo(SPELL_HOWLING_GALE_VISUAL))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_HOWLING_GALE_KNOCKBACK))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_HOWLING_GALE_VISUAL_2))
+ return false;
+ if (!sSpellMgr->GetSpellInfo(SPELL_HOWLING_GALE_KNOCKBACK_2))
+ return false;
+ return true;
+ }
+
+ void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo*/)
+ {
+ PreventDefaultAction();
+
+ tickCountdown = 20; // 10 seconds
+ proced = true;
+ }
+
+ void HandlePeriodic(AuraEffect const* /*aurEff*/)
+ {
+ if (tickCountdown > 0)
+ tickCountdown -= 1;
+ else
+ {
+ Unit* caster = GetUnitOwner();
+ if (!caster)
+ return;
+
+ // After Howling Gale has been damaged, different spells are cast.
+ caster->CastSpell(caster, !proced ? SPELL_HOWLING_GALE_VISUAL : SPELL_HOWLING_GALE_VISUAL_2);
+ caster->CastSpell(caster, !proced ? SPELL_HOWLING_GALE_KNOCKBACK : SPELL_HOWLING_GALE_KNOCKBACK_2);
+ }
+ }
+
+ void Register() override
+ {
+ OnEffectProc += AuraEffectProcFn(spell_howling_gale_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ OnEffectPeriodic += AuraEffectPeriodicFn(spell_howling_gale_AuraScript::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ }
+
+ uint32 tickCountdown;
+ bool proced;
+ };
+
+ AuraScript* GetAuraScript() const override
+ {
+ return new spell_howling_gale_AuraScript();
+ }
+};
+
+// 87726 - Grounding Field
+class spell_grounding_field : public SpellScriptLoader
+{
+public:
+ spell_grounding_field() : SpellScriptLoader("spell_grounding_field") { }
+
+ class spell_grounding_field_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_grounding_field_SpellScript);
+
+ void GetNearbyGroundFields()
+ {
+ prevent = false;
+
+ std::list groundingFields;
+ GetCaster()->GetCreatureListWithEntryInGrid(groundingFields, NPC_GROUNDING_FIELD, 60.0f);
+
+ if (groundingFields.size() < 3)
+ prevent = true;
+
+ int count = 0;
+ for (Creature* groundingField : groundingFields)
+ {
+ if (GetCaster()->GetGUIDLow() == groundingField->GetGUIDLow())
+ continue;
+
+ GroundFieldPositions[count] = groundingField->GetPosition();
+ count += 1;
+ if (count == 3)
+ break;
+ }
+ }
+
+ void FilterTargets(std::list& targets)
+ {
+ targets.remove_if(TargetInTriangleCheck(true, GroundFieldPositions[0], GroundFieldPositions[1], GroundFieldPositions[2]));
+ }
+
+ void Register() override
+ {
+ BeforeCast += SpellCastFn(spell_grounding_field_SpellScript::GetNearbyGroundFields);
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_grounding_field_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
+ }
+
+ private:
+ bool prevent;
+ Position GroundFieldPositions[3];
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_grounding_field_SpellScript();
+ }
+};
+
+// 87850 - Skyfall
+class spell_skyfall : public SpellScriptLoader
+{
+public:
+ spell_skyfall() : SpellScriptLoader("spell_skyfall") { }
+
+ class spell_skyfall_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_skyfall_SpellScript);
+
+ void HandleDummy(SpellEffIndex /*effIndex*/)
+ {
+ if (Creature* creature = GetHitCreature())
+ creature->CombatStart(GetCaster()->GetVictim());
+ }
+
+ void Register() override
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_skyfall_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const override
+ {
+ return new spell_skyfall_SpellScript();
+ }
+};
+
+// 87854 - Arcane Barrage
+class spell_arcane_barrage : public SpellScriptLoader
+{
+public:
+ spell_arcane_barrage() : SpellScriptLoader("spell_arcane_barrage") { }
+
+ class spell_arcane_barrage_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_arcane_barrage_SpellScript);
+
+ void FilterTargets(std::list& targets)
+ {
+ Trinity::Containers::RandomResizeList(targets, 1);
+ }
+
+ void Register()
+ {
+ OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_arcane_barrage_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_arcane_barrage_SpellScript();
+ }
+};
+
+void AddSC_vortex_pinnacle()
+{
+ new npc_lurking_tempest();
+ new npc_slipstream();
+ new npc_slipstream_landing_zone();
+ new npc_young_storm_dragon();
+ new npc_grounding_field();
+ new npc_skyfall();
+ new npc_skyfall_star();
+ new spell_lurk_search();
+ new spell_lurk_search_check();
+ new spell_feign_death();
+ new spell_lurk_ressurect();
+ new spell_lurk_search_victim();
+ new spell_slipstream();
+// new spell_howling_gale(); // needs proc fix
+ new spell_grounding_field();
+ new spell_skyfall();
+ new spell_arcane_barrage();
+}
diff --git a/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.h b/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.h
new file mode 100644
index 00000000000..a6f34906386
--- /dev/null
+++ b/src/server/scripts/Kalimdor/VortexPinnacle/vortex_pinnacle.h
@@ -0,0 +1,110 @@
+/*
+* Copyright (C) 2008-2015 TrinityCore
+*
+* 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 .
+*/
+
+#ifndef DEF_VORTEX_PINNACLE_H
+#define DEF_VORTEX_PINNACLE_H
+
+#define SCScriptName "instance_vortex_pinnacle"
+#define DataHeader "VP"
+
+#include "G3D/Vector3.h"
+#include "G3D/Triangle.h"
+#include "G3D/Plane.h"
+#include "G3D/CollisionDetection.h"
+
+uint32 const Slipstreams = 13;
+uint32 const PrismGroundingFieldPoints = 3;
+
+enum DataTypes
+{
+ // Encounter States/Boss GUIDs
+ DATA_GRAND_VIZIER_ERTAN,
+ DATA_ALTAIRUS,
+ DATA_ASAAD,
+
+ // Additional Data
+ DATA_SLIPSTREAM,
+ DATA_SLIPSTREAM_1,
+ DATA_SLIPSTREAM_2,
+ DATA_SLIPSTREAM_3,
+ DATA_SLIPSTREAM_4,
+ DATA_SLIPSTREAM_5,
+ DATA_SLIPSTREAM_6,
+ DATA_SLIPSTREAM_7,
+ DATA_SLIPSTREAM_8,
+ DATA_SLIPSTREAM_9,
+ DATA_SLIPSTREAM_10,
+ DATA_SLIPSTREAM_11,
+};
+
+enum Misc
+{
+ NPC_GRAND_VIZIER_ERTAN = 43878,
+ NPC_ALTAIRUS = 43873,
+ NPC_ASAAD = 43875,
+
+ NPC_SLIPSTREAM = 45455,
+ NPC_SLIPSTREAM_LANDING_ZONE = 45504,
+
+ NPC_HOWLING_GALE = 45572,
+
+ // Grounding Field
+ NPC_GROUNDING_FIELD = 47085,
+ SPELL_BEAM_A = 87721,
+ SPELL_BEAM_B = 87722,
+ SPELL_BEAM_C = 87723,
+ ACTION_GROUNDING_FIELD_TOP = 1,
+
+ // Zephyr
+ NPC_ZEPHYR = 45991,
+ EVENT_SUMMON_ZEPHYRS = 1,
+ PATH_ZEPHYR_SOUTH = 4599100,
+ PATH_ZEPHYR_NORTH = 4599101,
+};
+
+class TargetInTriangleCheck
+{
+public:
+ TargetInTriangleCheck(bool negate, Position positionA, Position positionB, Position positionC)
+ : negate(negate), positionA(positionA), positionB(positionB), positionC(positionC) { }
+
+ bool operator()(WorldObject* target) const
+ {
+ return negate != IsInTriangle(target);
+ }
+
+private:
+ bool IsInTriangle(WorldObject* target) const
+ {
+ G3D::Triangle const triangle(PositionToVector3(positionA), PositionToVector3(positionB), PositionToVector3(positionC));
+ G3D::Vector3 const vector(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
+ float b[3];
+ return G3D::CollisionDetection::isPointInsideTriangle(triangle.vertex(0), triangle.vertex(1), triangle.vertex(2), triangle.normal(), vector, b, triangle.primaryAxis());
+ }
+
+ G3D::Vector3 PositionToVector3(Position const& position) const
+ {
+ return G3D::Vector3(position.GetPositionX(), position.GetPositionY(), position.GetPositionZ());
+ }
+
+ bool const negate;
+ Position const positionA;
+ Position const positionB;
+ Position const positionC;
+};
+
+#endif // DEF_VORTEX_PINNACLE_H