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