diff options
author | Krudor <erikstrandberg93@hotmail.com> | 2017-08-22 18:28:07 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2017-08-22 18:28:07 +0200 |
commit | 28ec50b0534c721e613d68b7b1daa73d573fbc17 (patch) | |
tree | 8bfdfc604ce6d0201fbfe8b2d2464717ba378b53 | |
parent | cc6ca733d8064e12c7b11590250a99f696bbf9c5 (diff) |
Scripts/Firelands: Baleroc
Closes #17527
-rw-r--r-- | sql/updates/world/master/2017_08_22_00_world.sql | 174 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 22 | ||||
-rw-r--r-- | src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp | 874 | ||||
-rw-r--r-- | src/server/scripts/Kalimdor/Firelands/firelands.cpp | 318 | ||||
-rw-r--r-- | src/server/scripts/Kalimdor/Firelands/firelands.h | 66 | ||||
-rw-r--r-- | src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp | 53 | ||||
-rw-r--r-- | src/server/scripts/Kalimdor/kalimdor_script_loader.cpp | 4 |
7 files changed, 1509 insertions, 2 deletions
diff --git a/sql/updates/world/master/2017_08_22_00_world.sql b/sql/updates/world/master/2017_08_22_00_world.sql new file mode 100644 index 00000000000..de6b6edcd46 --- /dev/null +++ b/sql/updates/world/master/2017_08_22_00_world.sql @@ -0,0 +1,174 @@ +-- Baleroc +DELETE FROM `creature` WHERE `guid` IN (339184, 339185); -- Remove sniff spawn of Riplimb and Rageface in Baleroc encounter area +UPDATE `creature` SET `equipment_id`=1, `position_x`=95.15452, `position_y`=-63.20313, `position_z`=54.9362, `orientation`=3.16296, `spawntimesecs`=604800 WHERE `guid`=338782; + +DELETE FROM `creature_equip_template` WHERE `CreatureID`=53494 AND ID IN (2, 3); +INSERT INTO `creature_equip_template` (`CreatureID`, `ID`, `ItemID1`, `ItemID2`, `ItemID3`, `VerifiedBuild`) VALUES +(53494, 2, 71138, 0, 0, 0), +(53494, 3, 71082, 0, 0, 0); + +DELETE FROM `creature_formations` WHERE `leaderGUID` IN (339198,339284); +INSERT INTO `creature_formations` (`leaderGUID`, `memberGUID`, `dist`, `angle`, `groupAI`, `point_1`, `point_2`) VALUES +(339198, 339198, 0, 0, 2, 0, 0), +(339198, 317657, 0, 0, 2, 0, 0), +(339284, 339284, 0, 0, 2, 0, 0), +(339284, 339285, 0, 0, 2, 0, 0); + +-- Baleroc (10-man Normal) +DELETE FROM `creature_loot_template` WHERE `Entry`=53494; +INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(53494, 69815, 0, 100, 1, 1, 1, 18, 23, 'Baleroc 10N - Seething Cinder'), +(53494, 71141, 0, 80, 1, 1, 1, 1, 1, 'Baleroc 10N - Eternal Ember'), +(53494, 1, 34385, 100, 0, 1, 1, 2, 2, 'Baleroc 10N - Gear'); +-- Baleroc (25-man Normal) +DELETE FROM `creature_loot_template` WHERE `Entry`=53587; +INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(53587, 69815, 0, 100, 1, 1, 1, 48, 55, 'Baleroc 25N - Seeting Cinder'), +(53587, 71141, 0, 100, 1, 1, 1, 1, 3, 'Baleroc 25N - Eternal Ember'), +(53587, 1, 34385, 100, 0, 1, 1, 5, 5, 'Baleroc 25N - Gear'); +-- Baleroc (10-man Heroic) +DELETE FROM `creature_loot_template` WHERE `Entry`=53588; +INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(53588, 69815, 0, 100, 1, 1, 1, 23, 26, 'Baleroc 10H - Seething Cinder'), +(53588, 71141, 0, 80, 1, 1, 1, 1, 1, 'Baleroc 10H - Eternal Ember'), +(53588, 1, 34386, 100, 0, 1, 1, 2, 2, 'Baleroc 10H - Gear'), +(53588, 2, 34387, 100, 0, 1, 1, 1, 1, 'Baleroc 10H - Token'); +-- Baleroc (25-man Heroic) +DELETE FROM `creature_loot_template` WHERE `Entry`=53589; +INSERT INTO `creature_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(53589, 69815, 0, 100, 1, 1, 1, 55, 66, 'Baleroc 25H - Seething Cinder'), +(53589, 71141, 0, 100, 1, 1, 1, 1, 3, 'Baleroc 25H - Eternal Ember'), +(53589, 1, 34386, 100, 0, 1, 1, 5, 5, 'Baleroc 25H - Gear'), +(53589, 2, 34387, 100, 0, 1, 1, 3, 3, 'Baleroc 25H - Tokens'); + +UPDATE `creature_template` SET `difficulty_entry_1`=54162, `HealthScalingExpansion`=3, `speed_walk`=0.714286, `mechanic_immune_mask`=617561727, `flags_extra`=1073741824, `ScriptName`='npc_firelands_flame_archon' WHERE `entry`=54161; +UPDATE `creature_template` SET `minlevel`=87, `maxlevel`=87, `faction`=16, `speed_walk`=0.714286, `speed_run`=1.42857, `unit_flags`=32832, `unit_flags2`=`unit_flags2`|2097152, `mechanic_immune_mask`=617561727, `flags_extra`=1073741824 WHERE `entry`=54162; +UPDATE `creature_template` SET `difficulty_entry_1`=54196, `speed_walk`=0.277777, `speed_run`=1.71429, `mechanic_immune_mask`=617561687, `ScriptName`='npc_firelands_molten_flamefather' WHERE `entry`=54143; +UPDATE `creature_template` SET `minlevel`=87, `maxlevel`=87, `HealthScalingExpansion`=3, `faction`=16, `speed_walk`=0.277777, `speed_run`=1.71429, `unit_flags`=32832, `unit_flags2`=`unit_flags2`|4194304, `mechanic_immune_mask`=617561687 WHERE `entry`=54196; +UPDATE `creature_template` SET `speed_walk`=0.277777, `speed_run`=1.71429, `unit_flags`=64, `unit_flags2`=32768, `mechanic_immune_mask`=617561727, `flags_extra`=1073741824, `AIName`='PassiveAI' WHERE `entry`=54145; +UPDATE `creature_template` SET `difficulty_entry_1`=54204, `unit_flags2`=`unit_flags2`|2097152, `ScriptName`='npc_firelands_magmakin' WHERE `entry`=54144; +UPDATE `creature_template` SET `minlevel`=87, `maxlevel`=87, `HealthScalingExpansion`=3, `faction`=16, `speed_walk`=0.555556, `speed_run`=1.71429, `unit_flags2`=2099200 WHERE `entry`=54204; +UPDATE `creature_template` SET `minlevel`=88, `maxlevel`=88, `HealthScalingExpansion`=3, `faction`=14, `speed_walk`=1.14286, `speed_run`=2, `unit_flags`=32768, `unit_flags2`=2099200, `type_flags2`=128, `mechanic_immune_mask`=617561975, `flags_extra`=1073741825 WHERE `entry` IN (53587, 53588, 53589); +UPDATE `creature_template` SET `difficulty_entry_1`=53587, `difficulty_entry_2`=53588, `difficulty_entry_3`=53589, `speed_walk`=1.14286, `mechanic_immune_mask`=617561975, `flags_extra`=`flags_extra`|1073741824, `ScriptName`='boss_baleroc' WHERE `entry`=53494; +UPDATE `creature_template` SET `lootid`=53587 WHERE `entry`=53587; +UPDATE `creature_template` SET `lootid`=53588 WHERE `entry`=53588; +UPDATE `creature_template` SET `lootid`=53589 WHERE `entry`=53589; +UPDATE `creature_template` SET `speed_walk`=0.357142, `speed_run`=1.14286, `unit_flags`=33554432, `flags_extra`=128, `ScriptName`='npc_shard_of_torment' WHERE `entry`=53495; + +DELETE FROM `creature_text` WHERE `entry`=53494; +INSERT INTO `creature_text` (`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES +(53494, 0, 0, 'You are forbidden from my master''s domain, mortals.', 14, 0, 100, 0, 0, 24441, 52180, 3, 'Baleroc - Enter Combat'), +(53494, 1, 0, 'Fool mortals. Hurl yourselves into your own demise!', 14, 0, 100, 0, 0, 24446, 52185, 3, 'Baleroc - Shards of Torment'), +(53494, 2, 0, 'Burn beneath my molten fury!', 14, 0, 100, 0, 0, 24459, 52181, 3, 'Baleroc - Inferno Blade'), +(53494, 3, 0, 'By the Firelord''s command, you, too, shall perish!', 14, 0, 100, 0, 0, 24447, 52182, 3, 'Baleroc - Decimation Blade'), +(53494, 4, 0, 'You have been judged.', 14, 0, 100, 0, 0, 24449, 52177, 3, 'Baleroc - Kill Player (1)'), +(53494, 4, 1, 'Behold your weakness.', 14, 0, 100, 0, 0, 24451, 52178, 3, 'Baleroc - Kill Player (2)'), +(53494, 4, 2, 'None shall pass!', 14, 0, 100, 0, 0, 24452, 52179, 3, 'Baleroc - Kill Player (3)'), +(53494, 5, 0, 'Mortal filth... the master''s keep is forbidden....', 14, 0, 100, 0, 0, 24444, 52650, 3, 'Baleroc - Death'), +(53494, 6, 0, 'Your flesh is forfeit to the fires of this realm.', 14, 0, 100, 0, 0, 24450, 52183, 3, 'Baleroc - Berserk'), +(53494, 7, 0, '%s goes into a berserker rage!', 41, 0, 100, 0, 0, 0, 4428, 3, 'Baleroc - Berserk (Emote)'), +(53494, 8, 0, '|TInterface\\Icons\\spell_shadow_curse.blp:20|t%s readies his |cFF7A0080|Hspell:99352|h[Decimation Blade]|h|r!', 41, 0, 100, 0, 0, 0, 52889, 3, 'Baleroc - Decimation Blade (Emote)'), +(53494, 9, 0, '|TInterface\\Icons\\inv_sword_09.blp:20|t%s readies his |cFFFF0000|Hspell:99350|h[Inferno Blade]|h|r!', 41, 0, 100, 0, 0, 0, 52890, 3, 'Baleroc - Inferno Blade (Emote)'); + +DELETE FROM `criteria_data` WHERE `criteria_id`=17577; +INSERT INTO `criteria_data` (`criteria_id`, `type`, `value1`, `value2`, `ScriptName`) VALUES (17577, 11, 0, 0, 'achievement_share_the_pain'); + +DELETE FROM `linked_respawn` WHERE `guid` IN (317642,317652,317657,339198,339284,339285); -- guid is unique, not linkedGuid +INSERT INTO `linked_respawn` (`guid`, `linkedGuid`, `linkType`) VALUES +(317642, 338782, 0), +(317652, 338782, 0), +(317657, 338782, 0), +(339198, 338782, 0), +(339284, 338782, 0), +(339285, 338782, 0); + +-- Normal shared items +DELETE FROM `reference_loot_template` WHERE `Entry`=34380; +INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(34380, 71782, 0, 16, 0, 1, 1, 1, 1, 'Normal - Shatterskull Bonecrusher'), +(34380, 71775, 0, 16, 0, 1, 1, 1, 1, 'Normal - Smoldering Censer of Purity'), +(34380, 71776, 0, 16, 0, 1, 1, 1, 1, 'Normal - Eye of Purification'), +(34380, 71780, 0, 13, 0, 1, 1, 1, 1, 'Normal - Zoid''s Firelit Greatsword'), +(34380, 71779, 0, 11, 0, 1, 1, 1, 1, 'Normal - Avool''s Incendiary Shanker'), +(34380, 71787, 0, 11, 0, 1, 1, 1, 1, 'Normal - Entrail Disgorger'), +(34380, 71785, 0, 17, 0, 1, 1, 1, 1, 'Normal - Firethorn Mindslicer'); +-- Heroic shared items +DELETE FROM `reference_loot_template` WHERE `Entry`=34381; +INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(34381, 71783, 0, 15, 0, 1, 1, 1, 1, 'Heroic - Shatterskull Bonecrusher'), +(34381, 71774, 0, 15, 0, 1, 1, 1, 1, 'Heroic - Smoldering Censer of Purity'), +(34381, 71777, 0, 15, 0, 1, 1, 1, 1, 'Heroic - Eye of Purification'), +(34381, 71781, 0, 12, 0, 1, 1, 1, 1, 'Heroic - Zoid''s Firelit Greatsword'), +(34381, 71778, 0, 11, 0, 1, 1, 1, 1, 'Heroic - Avool''s Incendiary Shanker'), +(34381, 71786, 0, 11, 0, 1, 1, 1, 1, 'Heroic - Entrail Disgorger'), +(34381, 71784, 0, 16, 0, 1, 1, 1, 1, 'Heroic - Firethorn Mindslicer'), +(34381, 71617, 0, 5, 0, 1, 1, 1, 1, 'Heroic - Crystallized Firestone'); +-- Baleroc normal +DELETE FROM `reference_loot_template` WHERE `Entry`=34385; +INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(34385, 68982, 0, 12, 0, 1, 1, 1, 1, 'Normal - Necromantic Focus'), +(34385, 71343, 0, 10, 0, 1, 1, 1, 1, 'Normal - Mantle of Closed Doors'), +(34385, 70917, 0, 8, 0, 1, 1, 1, 1, 'Normal - Flickering Handguards'), +(34385, 71323, 0, 8, 0, 1, 1, 1, 1, 'Normal - Molten Scream'), +(34385, 71315, 0, 7, 0, 1, 1, 1, 1, 'Normal - Decimation Treads'), +(34385, 71345, 0, 7, 0, 1, 1, 1, 1, 'Normal - Shoulderpads of the Forgotten Gate'), +(34385, 71314, 0, 7, 0, 1, 1, 1, 1, 'Normal - Breastplate of the Incendiary Soul'), +(34385, 71312, 0, 7, 0, 1, 1, 1, 1, 'Normal - Gatecrasher'), +(34385, 71342, 0, 6, 0, 1, 1, 1, 1, 'Normal - Casque of Flame'), +(34385, 71340, 0, 6, 0, 1, 1, 1, 1, 'Normal - Gatekeeper''s Embrace'), +(34385, 71341, 0, 6, 0, 1, 1, 1, 1, 'Normal - Glowing Wing Bracers'), +(34385, 70915, 0, 6, 0, 1, 1, 1, 1, 'Normal - Shard of Torment'), +(34385, 70916, 0, 5, 0, 1, 1, 1, 1, 'Normal - Helm of Blazing Glory'), +(34385, 1, 34380, 5, 0, 1, 0, 1, 1, 'Normal - Shared loot table'); +-- Baleroc heroic +DELETE FROM `reference_loot_template` WHERE `Entry`=34386; +INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(34386, 69139, 0, 12, 0, 1, 1, 1, 1, 'Heroic - Necromantic Focus'), +(34386, 71461, 0, 10, 0, 1, 1, 1, 1, 'Heroic - Mantle of Closed Doors'), +(34386, 71458, 0, 8, 0, 1, 1, 1, 1, 'Heroic - Flickering Handguards'), +(34386, 71462, 0, 8, 0, 1, 1, 1, 1, 'Heroic - Molten Scream'), +(34386, 71457, 0, 7, 0, 1, 1, 1, 1, 'Heroic - Decimation Treads'), +(34386, 71456, 0, 7, 0, 1, 1, 1, 1, 'Heroic - Shoulderpads of the Forgotten Gate'), +(34386, 71455, 0, 7, 0, 1, 1, 1, 1, 'Heroic - Breastplate of the Incendiary Soul'), +(34386, 71454, 0, 7, 0, 1, 1, 1, 1, 'Heroic - Gatecrasher'), +(34386, 71465, 0, 6, 0, 1, 1, 1, 1, 'Heroic - Casque of Flame'), +(34386, 71464, 0, 6, 0, 1, 1, 1, 1, 'Heroic - Gatekeeper''s Embrace'), +(34386, 71463, 0, 6, 0, 1, 1, 1, 1, 'Heroic - Glowing Wing Bracers'), +(34386, 71460, 0, 6, 0, 1, 1, 1, 1, 'Heroic - Shard of Torment'), +(34386, 71459, 0, 5, 0, 1, 1, 1, 1, 'Heroic - Helm of Blazing Glory'), +(34386, 1, 34381, 5, 0, 1, 0, 1, 1, 'Heroic - Shared loot table'); +-- Baleroc heroic tokens +DELETE FROM `reference_loot_template` WHERE `Entry`=34387; +INSERT INTO `reference_loot_template` (`Entry`, `Item`, `Reference`, `Chance`, `QuestRequired`, `LootMode`, `GroupId`, `MinCount`, `MaxCount`, `Comment`) VALUES +(34387, 71669, 0, 40, 0, 1, 1, 1, 1, 'Heroic - Gauntlets of the Fiery Vanquisher'), +(34387, 71676, 0, 30, 0, 1, 1, 1, 1, 'Heroic - Gauntlets of the Fiery Conqueror'), +(34387, 71683, 0, 30, 0, 1, 1, 1, 1, 'Heroic - Gauntlets of the Fiery Protector'); + +DELETE FROM `spell_script_names` WHERE `spell_id` IN (100799,99342,99350,99352,99353,99515,99516,99517,99259,99253,99256,99257,99489,99263,99262); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(100799, 'spell_firelands_fiery_torment'), +(99342, 'spell_baleroc_blades_of_baleroc'), +(99350, 'spell_baleroc_inferno_blade'), +(99352, 'spell_baleroc_decimation_blade'), +(99353, 'spell_baleroc_decimating_strike'), +(99515, 'spell_baleroc_countdown_aoe_dummy'), +(99516, 'spell_baleroc_countdown'), +(99517, 'spell_baleroc_countdown_proximity_check'), +(99259, 'spell_baleroc_shards_of_torment_target_search'), +(99253, 'spell_baleroc_torment_target_search'), +(99256, 'spell_baleroc_torment'), +(99257, 'spell_baleroc_tormented'), +(99489, 'spell_baleroc_tormented_spread'), +(99263, 'spell_baleroc_vital_flame'), +(99262, 'spell_baleroc_vital_spark'); + +-- Firelands Spells +DELETE FROM `spell_script_names` WHERE `spell_id` IN (101089,101092,101093); +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(101089, 'spell_firelands_smouldering'), +(101092, 'spell_firelands_smouldering'), +(101093, 'spell_firelands_smouldering_aura'); + +DELETE FROM `spell_proc` WHERE `SpellId`=99262; +INSERT INTO `spell_proc` (`SpellId`,`SpellTypeMask`,`SpellPhaseMask`) VALUES +(99262,2,2); diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 28534345dad..0a2ae57ffd1 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3676,6 +3676,28 @@ void SpellMgr::LoadSpellInfoCorrections() }); // ENDOF ISLE OF CONQUEST SPELLS + // + // FIRELANDS SPELLS + // + // Torment Searcher + ApplySpellFix({ 99253 }, [](SpellInfo* spellInfo) + { + const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_0))->MaxRadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_15_YARDS); + }); + + // Torment Damage + ApplySpellFix({ 99256 }, [](SpellInfo* spellInfo) + { + spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1; + }); + + // Blaze of Glory + ApplySpellFix({ 99252 }, [](SpellInfo* spellInfo) + { + spellInfo->AuraInterruptFlags |= AURA_INTERRUPT_FLAG_CHANGE_MAP; + }); + // ENDOF FIRELANDS SPELLS + // Summon Master Li Fei ApplySpellFix({ 102445 }, [](SpellInfo* spellInfo) { diff --git a/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp b/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp new file mode 100644 index 00000000000..4f012d7f2d1 --- /dev/null +++ b/src/server/scripts/Kalimdor/Firelands/boss_baleroc.cpp @@ -0,0 +1,874 @@ +/* + * Copyright (C) 2008-2017 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ScriptMgr.h" +#include "Containers.h" +#include "firelands.h" +#include "GridNotifiers.h" +#include "PassiveAI.h" +#include "Spell.h" +#include "SpellAuras.h" +#include "SpellAuraEffects.h" +#include "SpellMgr.h" + +enum Spells +{ + // Baleroc + //SPELL_LEASH = 101514, // Server-side, used to keep him in his encounter area? TrinityCore does not need a spell to handle this + SPELL_BLADES_OF_BALEROC = 99342, + SPELL_INFERNO_BLADE = 99350, + SPELL_INFERNO_STRIKE = 99351, + SPELL_DECIMATION_BLADE = 99352, + SPELL_DECIMATION_BLADE_2 = 99405, + SPELL_DECIMATING_STRIKE = 99353, + SPELL_BLAZE_OF_GLORY = 99252, + SPELL_INCENDIARY_SOUL = 99369, + SPELL_SHARDS_OF_TORMENT = 99259, + SPELL_SHARDS_OF_TORMENT_SUMMON = 99260, + SPELL_TORMENT_PRE_VISUAL = 99258, + SPELL_TORMENT_ACTIVE = 99254, + SPELL_TORMENT_PERIODIC = 99255, + SPELL_WAVE_OF_TORMENT = 99261, + SPELL_TORMENTED = 99257, + SPELL_TORMENT = 99256, + SPELL_COUNTDOWN = 99515, + SPELL_COUNTDOWN_AURA = 99516, + SPELL_COUNTDOWN_3 = 99517, + SPELL_COUNTDOWN_AOE_EXPLOSION = 99518, + SPELL_COUNTDOWN_VISUAL_LINK = 99519, + SPELL_VITAL_SPARK = 99262, + SPELL_VITAL_FLAME = 99263, + SPELL_BERSERK = 26662, +}; + +enum Emotes +{ + SAY_AGGRO = 0, + SAY_SHARDS_OF_TORMENT = 1, + SAY_INFERNO_BLADE = 2, + SAY_DECIMATION_BLADE = 3, + SAY_KILL = 4, + SAY_DEATH = 5, + SAY_ENRAGE = 6, + EMOTE_ENRAGE = 7, + EMOTE_DECIMATION_BLADE = 8, + EMOTE_INFERNO_BLADE = 9, +}; + +enum Guids +{ + GUID_TORMENTED = 1, +}; + +enum Actions +{ + ACTION_EQUIP_DEFAULT = 1, + ACTION_EQUIP_INFERNO_BLADE = 2, + ACTION_EQUIP_DECIMATION_BLADE = 3, +}; + + +enum Misc +{ + EQUIP_DEFAULT = 1, + EQUIP_INFERNO_BLADE = 2, + EQUIP_DECIMATION_BLADE = 3, +}; + +enum Phases +{ + PHASE_NONE = 0, + PHASE_ONE = 1 +}; + +// http://www.wowhead.com/npc=53494/baleroc +struct boss_baleroc : public firelands_bossAI +{ + boss_baleroc(Creature* creature) : firelands_bossAI(creature, DATA_BALEROC), _canYellKilledPlayer(true) + { + scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } + + void Reset() override + { + firelands_bossAI::Reset(); + _canYellKilledPlayer = true; + EquipWeapon(EQUIP_DEFAULT); + } + + void EnterCombat(Unit* target) override + { + firelands_bossAI::EnterCombat(target); + + Talk(SAY_AGGRO); + PreparePhase(PHASE_ONE); + + _sharedThePain.clear(); + } + + void PreparePhase(Phases phase) + { + //events.SetPhase(phase); + + switch (phase) + { + case PHASE_ONE: + scheduler.Schedule(Milliseconds(8500), [this](TaskContext context) + { + me->AddAura(SPELL_INCENDIARY_SOUL, me); // No cast + DoCastVictim(SPELL_BLAZE_OF_GLORY); + context.Repeat(Milliseconds(11500)); + }); + scheduler.Schedule(Seconds(5), [this](TaskContext context) + { + DoCastAOE(SPELL_SHARDS_OF_TORMENT); + context.Repeat(Seconds(34)); + }); + if (me->GetMap()->IsHeroic()) + { + scheduler.Schedule(Seconds(26), [this](TaskContext context) + { + DoCastAOE(SPELL_COUNTDOWN); + context.Repeat(Seconds(48)); + }); + } + scheduler.Schedule(Milliseconds(30500), [this](TaskContext context) + { + DoCastSelf(SPELL_BLADES_OF_BALEROC); + context.Repeat(Seconds(47)); + }); + scheduler.Schedule(Minutes(6), [this](TaskContext) + { + Talk(SAY_ENRAGE); + Talk(EMOTE_ENRAGE); + DoCastSelf(SPELL_BERSERK); + }); + break; + default: + break; + } + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_EQUIP_DEFAULT: + case ACTION_EQUIP_INFERNO_BLADE: + case ACTION_EQUIP_DECIMATION_BLADE: + EquipWeapon(action); + break; + default: + break; + } + } + + void KilledUnit(Unit* who) override + { + if (who->GetTypeId() == TYPEID_PLAYER && _canYellKilledPlayer) + { + _canYellKilledPlayer = false; + Talk(SAY_KILL); + + separateScheduler.Schedule(Seconds(8), [this](TaskContext) + { + _canYellKilledPlayer = true; + }); + } + } + + void JustDied(Unit* killer) override + { + Talk(SAY_DEATH); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BLAZE_OF_GLORY); + firelands_bossAI::JustDied(killer); + } + + void EnterEvadeMode(EvadeReason reason) override + { + summons.DespawnAll(); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_BLAZE_OF_GLORY); + firelands_bossAI::EnterEvadeMode(reason); + } + + void UpdateAI(uint32 diff) override + { + scheduler.Update(diff); + separateScheduler.Update(diff); + firelands_bossAI::UpdateAI(diff); + } + + void SetGUID(ObjectGuid guid, int32 type = 0) override + { + switch (type) + { + case GUID_TORMENTED: + ++_sharedThePain[guid]; + break; + default: + break; + } + } + + uint32 GetData(uint32 type) const override + { + switch (type) + { + case GUID_TORMENTED: + for (auto const& entry : _sharedThePain) + if (entry.second > 3) + return 1; + break; + default: + break; + } + + return 0; + } + +private: + void EquipWeapon(uint8 equipment) const + { + switch (equipment) + { + case EQUIP_DEFAULT: + me->LoadEquipment(equipment); + me->SetCanDualWield(true); + break; + case EQUIP_INFERNO_BLADE: + case EQUIP_DECIMATION_BLADE: + me->LoadEquipment(equipment); + me->SetCanDualWield(false); + break; + default: + break; + } + } + // Our default TaskScheduler has a UNIT_STATE_CASTING validator that would get in the way of certain tasks, run them on a separate track. + TaskScheduler separateScheduler; + bool _canYellKilledPlayer; + std::unordered_map<ObjectGuid, uint32> _sharedThePain; +}; + +// http://www.wowhead.com/npc=53495/shard-of-torment +struct npc_shard_of_torment : public NullCreatureAI +{ + npc_shard_of_torment(Creature* creature) : NullCreatureAI(creature) { } + + void IsSummonedBy(Unit* /*summoner*/) override + { + DoCastAOE(SPELL_TORMENT_PRE_VISUAL); + scheduler.Schedule(Milliseconds(4400), [this](TaskContext) + { + me->RemoveAurasDueToSpell(SPELL_TORMENT_PRE_VISUAL); + DoCastAOE(SPELL_TORMENT_ACTIVE); + scheduler.Schedule(Milliseconds(1100), [this](TaskContext context) + { + DoCastAOE(SPELL_WAVE_OF_TORMENT); + context.Repeat(Seconds(1)); + }); + }); + } + + void SpellHitTarget(Unit* /*target*/, const SpellInfo* spell) override + { + if (spell->Id != SPELL_TORMENT) + return; + + scheduler.CancelAll(); + scheduler.Schedule(Milliseconds(1100), [this](TaskContext context) + { + DoCastAOE(SPELL_WAVE_OF_TORMENT); + context.Repeat(Seconds(1)); + }); + } + + void UpdateAI(uint32 diff) override + { + scheduler.Update(diff); + } + +private: + TaskScheduler scheduler; +}; + +// http://www.wowhead.com/spell=99342/blades-of-baloroc +class spell_baleroc_blades_of_baleroc : public SpellScript +{ + PrepareSpellScript(spell_baleroc_blades_of_baleroc); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_INFERNO_BLADE, SPELL_DECIMATION_BLADE }); + } + + void ChooseBlade(SpellEffIndex /*effIndex*/) + { + Creature* caster = GetCaster()->ToCreature(); + if (!caster || !caster->IsAIEnabled) + return; + + switch (urand(1, 2)) + { + case 1: + caster->AI()->DoCast(SPELL_INFERNO_BLADE); + caster->AI()->Talk(SAY_INFERNO_BLADE); + caster->AI()->Talk(EMOTE_INFERNO_BLADE); + break; + case 2: + caster->AI()->DoCast(SPELL_DECIMATION_BLADE); + caster->AI()->Talk(SAY_DECIMATION_BLADE); + caster->AI()->Talk(EMOTE_DECIMATION_BLADE); + break; + default: + break; + } + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_baleroc_blades_of_baleroc::ChooseBlade, EFFECT_0, SPELL_EFFECT_DUMMY); + } +}; + +// http://www.wowhead.com/spell=99350/inferno-blade +class spell_baleroc_inferno_blade : public AuraScript +{ + PrepareAuraScript(spell_baleroc_inferno_blade); + + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTarget()->IsAIEnabled) + GetTarget()->GetAI()->DoAction(ACTION_EQUIP_INFERNO_BLADE); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTarget()->IsAIEnabled) + GetTarget()->GetAI()->DoAction(ACTION_EQUIP_DEFAULT); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_baleroc_inferno_blade::OnApply, EFFECT_0, SPELL_AURA_OVERRIDE_AUTOATTACK_WITH_MELEE_SPELL, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_baleroc_inferno_blade::OnRemove, EFFECT_0, SPELL_AURA_OVERRIDE_AUTOATTACK_WITH_MELEE_SPELL, AURA_EFFECT_HANDLE_REAL); + } +}; + +// http://www.wowhead.com/spell=99352/decimation-blade +class spell_baleroc_decimation_blade : public AuraScript +{ + PrepareAuraScript(spell_baleroc_decimation_blade); + + bool Load() override + { + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTarget()->IsAIEnabled) + GetTarget()->GetAI()->DoAction(ACTION_EQUIP_DECIMATION_BLADE); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTarget()->IsAIEnabled) + GetTarget()->GetAI()->DoAction(ACTION_EQUIP_DEFAULT); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_baleroc_decimation_blade::OnApply, EFFECT_1, SPELL_AURA_OVERRIDE_AUTOATTACK_WITH_MELEE_SPELL, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_baleroc_decimation_blade::OnRemove, EFFECT_1, SPELL_AURA_OVERRIDE_AUTOATTACK_WITH_MELEE_SPELL, AURA_EFFECT_HANDLE_REAL); + } +}; + +// http://www.wowhead.com/spell=99353/decimating-strike +class spell_baleroc_decimating_strike : public SpellScript +{ + PrepareSpellScript(spell_baleroc_decimating_strike); + + bool Validate(SpellInfo const* spellInfo) override + { + if (!spellInfo->GetEffect(EFFECT_0)) + return false; + SpellEffectInfo const* spellEffectInfo = spellInfo->GetEffect(EFFECT_2); + return spellEffectInfo && ValidateSpellInfo({ uint32(spellEffectInfo->BasePoints) }); + } + + void ChangeDamage() + { + int32 healthPctDmg = GetHitUnit()->CountPctFromMaxHealth(GetSpellInfo()->GetEffect(EFFECT_0)->BasePoints); + int32 flatDmg = GetSpellInfo()->GetEffect(EFFECT_2)->BasePoints; + + SetHitDamage(healthPctDmg < flatDmg ? flatDmg : healthPctDmg); + } + + void Register() override + { + OnHit += SpellHitFn(spell_baleroc_decimating_strike::ChangeDamage); + } +}; + +// http://www.wowhead.com/spell=99515/countdown +class spell_baleroc_countdown_aoe_dummy : public SpellScript +{ + PrepareSpellScript(spell_baleroc_countdown_aoe_dummy); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_COUNTDOWN_VISUAL_LINK, SPELL_COUNTDOWN_AURA }); + } + + void CastSpellLink() + { + Unit* firstTarget = ObjectAccessor::GetUnit(*GetCaster(), _targets.front()); + Unit* secondTarget = ObjectAccessor::GetUnit(*GetCaster(), _targets.back()); + if (!firstTarget || !secondTarget) + return; + + firstTarget->CastSpell(secondTarget, SPELL_COUNTDOWN_VISUAL_LINK, true); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_COUNTDOWN_AURA); + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + Creature* caster = GetCaster()->ToCreature(); + if (!caster) + return; + + if (WorldObject* tank = caster->AI()->SelectTarget(SELECT_TARGET_TOPAGGRO)) + targets.remove(tank); + + if (targets.size() < 2) + { + FinishCast(SPELL_FAILED_NO_VALID_TARGETS); + return; + } + + Trinity::Containers::RandomResize(targets, 2); + + _targets.push_back(targets.front()->GetGUID()); + _targets.push_back(targets.back()->GetGUID()); + } + + void Register() override + { + AfterCast += SpellCastFn(spell_baleroc_countdown_aoe_dummy::CastSpellLink); + OnEffectHitTarget += SpellEffectFn(spell_baleroc_countdown_aoe_dummy::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_baleroc_countdown_aoe_dummy::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + + GuidList _targets; +}; + +// http://www.wowhead.com/spell=99516/countdown +class spell_baleroc_countdown : public AuraScript +{ + PrepareAuraScript(spell_baleroc_countdown); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_COUNTDOWN_VISUAL_LINK, SPELL_COUNTDOWN_AOE_EXPLOSION }); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + GetTarget()->RemoveAurasDueToSpell(SPELL_COUNTDOWN_VISUAL_LINK); + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + GetTarget()->CastSpell(static_cast<Unit*>(nullptr), SPELL_COUNTDOWN_AOE_EXPLOSION, true); + } + + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_baleroc_countdown::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL); + } +}; + +// http://www.wowhead.com/spell=99517/countdown +class spell_baleroc_countdown_proximity_check : public SpellScript +{ + PrepareSpellScript(spell_baleroc_countdown_proximity_check); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_COUNTDOWN_AURA }); + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetCaster()->RemoveAurasDueToSpell(SPELL_COUNTDOWN_AURA); + GetHitUnit()->RemoveAurasDueToSpell(SPELL_COUNTDOWN_AURA); + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove(GetCaster()); + targets.remove_if(Trinity::UnitAuraCheck(false, SPELL_COUNTDOWN_AURA)); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_baleroc_countdown_proximity_check::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_baleroc_countdown_proximity_check::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ALLY); + } +}; + +// http://www.wowhead.com/spell=99259/shards-of-torment +class spell_baleroc_shards_of_torment_target_search : public SpellScript +{ + PrepareSpellScript(spell_baleroc_shards_of_torment_target_search); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_SHARDS_OF_TORMENT_SUMMON }); + } + + bool Load() override + { + _hasTarget = false; + return GetCaster()->GetTypeId() == TYPEID_UNIT; + } + + void OnSpellCast() + { + if (_hasTarget) + ENSURE_AI(boss_baleroc, GetCaster()->GetAI())->Talk(SAY_SHARDS_OF_TORMENT); + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetCaster()->CastSpell(GetHitUnit(), SPELL_SHARDS_OF_TORMENT_SUMMON, true); + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + // Shards of torment seems to target tanks if no other targets are available as of Warlords of Draenor + if (targets.size() <= 1) + { + _hasTarget = !targets.empty(); + return; + } + + Creature* caster = GetCaster()->ToCreature(); + if (!caster || !caster->IsAIEnabled) + return; + + if (WorldObject* tank = caster->AI()->SelectTarget(SELECT_TARGET_TOPAGGRO)) + targets.remove(tank); + + std::list<WorldObject*> melee, ranged; + for (WorldObject* target : targets) + { + if (caster->IsWithinMeleeRange(target->ToUnit())) + melee.push_back(target); + else + ranged.push_back(target); + } + + targets.clear(); + + if (caster->GetMap()->Is25ManRaid()) + if (WorldObject* target = GetRandomContainerElement(ranged, melee)) + targets.push_back(target); + + if (WorldObject* target = GetRandomContainerElement(melee, ranged)) + targets.push_back(target); + + _hasTarget = !targets.empty(); + } + + WorldObject* GetRandomContainerElement(std::list<WorldObject*>& priority1, std::list<WorldObject*>& priority2) const + { + WorldObject* target = nullptr; + target = GetRandomContainerElement(&priority1); + if (target) + priority1.remove(target); + else + { + target = GetRandomContainerElement(&priority2); + priority2.remove(target); + } + + return target; + } + + static WorldObject* GetRandomContainerElement(std::list<WorldObject*> const* list) + { + if (!list->empty()) + return Trinity::Containers::SelectRandomContainerElement(*list); + + return nullptr; + } + + void Register() override + { + OnCast += SpellCastFn(spell_baleroc_shards_of_torment_target_search::OnSpellCast); + OnEffectHitTarget += SpellEffectFn(spell_baleroc_shards_of_torment_target_search::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_baleroc_shards_of_torment_target_search::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + + bool _hasTarget; +}; + +// http://www.wowhead.com/spell=99253/torment +class spell_baleroc_torment_target_search : public SpellScript +{ + PrepareSpellScript(spell_baleroc_torment_target_search); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_TORMENT_PERIODIC }); + } + + void OnHit(SpellEffIndex /*effIndex*/) + { + Spell* spell = GetCaster()->GetCurrentSpell(CURRENT_CHANNELED_SPELL); + if (spell && spell->m_targets.GetUnitTargetGUID() == _target) + return; + + if (GetHitUnit()->GetGUID() == _target) + GetCaster()->CastSpell(GetHitUnit(), SPELL_TORMENT_PERIODIC); + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(PlayerCheck()); + if (targets.empty()) + return; + + targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster())); + _target = targets.front()->GetGUID(); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_baleroc_torment_target_search::OnHit, EFFECT_0, SPELL_EFFECT_DUMMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_baleroc_torment_target_search::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + + ObjectGuid _target; +}; + +// http://www.wowhead.com/spell=99256/torment +class spell_baleroc_torment : public SpellScript +{ + PrepareSpellScript(spell_baleroc_torment); + + void ModifyDamage() + { + SetHitDamage(GetHitDamage() * GetHitUnit()->GetAuraCount(GetSpellInfo()->Id)); + } + + void Register() override + { + OnHit += SpellHitFn(spell_baleroc_torment::ModifyDamage); + } +}; + +class spell_baleroc_torment_AuraScript : public AuraScript +{ + PrepareAuraScript(spell_baleroc_torment_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_VITAL_FLAME, SPELL_VITAL_SPARK, SPELL_TORMENTED }); + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + Unit* healer = eventInfo.GetProcTarget(); + if (healer->HasAura(SPELL_VITAL_FLAME)) + return; + + bool Is25ManHeroic = healer->GetMap()->IsHeroic() && healer->GetMap()->Is25ManRaid(); + uint32 stacks = healer->GetAuraCount(SPELL_VITAL_SPARK) + std::min(uint8(ceil(GetStackAmount() / (Is25ManHeroic ? 5 : 3))), uint8(255)); + + healer->SetAuraStack(SPELL_VITAL_SPARK, healer, stacks); + healer->GetAura(SPELL_VITAL_SPARK)->RefreshDuration(); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH) + GetTarget()->CastSpell(GetTarget(), SPELL_TORMENTED, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_baleroc_torment_AuraScript::HandleProc, EFFECT_1, SPELL_AURA_DUMMY); + OnEffectRemove += AuraEffectRemoveFn(spell_baleroc_torment_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } +}; + +// http://www.wowhead.com/spell=99257/tormented +class spell_baleroc_tormented : public AuraScript +{ + PrepareAuraScript(spell_baleroc_tormented); + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (InstanceScript* instance = GetTarget()->GetInstanceScript()) + if (Creature* baleroc = ObjectAccessor::GetCreature(*GetTarget(), instance->GetGuidData(DATA_BALEROC))) + baleroc->AI()->SetGUID(GetTarget()->GetGUID(), GUID_TORMENTED); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_baleroc_tormented::OnApply, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL_OR_REAPPLY_MASK); + } +}; + +// http://www.wowhead.com/spell=99489/tormented +class spell_baleroc_tormented_spread : public SpellScript +{ + PrepareSpellScript(spell_baleroc_tormented_spread); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_TORMENTED }); + } + + void HandleScript(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_TORMENTED, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_baleroc_tormented_spread::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } +}; + +// http://www.wowhead.com/spell=99262/vital-spark +class spell_baleroc_vital_spark : public AuraScript +{ + PrepareAuraScript(spell_baleroc_vital_spark); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_BLAZE_OF_GLORY, SPELL_VITAL_FLAME }); + } + + void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + if (Unit* target = eventInfo.GetProcTarget()) + if (target->HasAura(SPELL_BLAZE_OF_GLORY)) + GetCaster()->CastSpell(GetCaster(), SPELL_VITAL_FLAME, true); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_baleroc_vital_spark::HandleProc, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY); + } +}; + +// http://www.wowhead.com/spell=99263/vital-flame +class spell_baleroc_vital_flame : public AuraScript +{ + PrepareAuraScript(spell_baleroc_vital_flame); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_VITAL_SPARK }); + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (!GetCaster()->HasAura(SPELL_VITAL_SPARK)) + { + stacks = 0; + return; + } + + stacks = GetCaster()->GetAuraCount(SPELL_VITAL_SPARK); + int32 healingPct = sSpellMgr->AssertSpellInfo(SPELL_VITAL_SPARK)->GetEffect(EFFECT_0)->BasePoints * stacks; + + if (GetAura()->GetEffect(EFFECT_0)->GetAmount() < healingPct) + GetAura()->GetEffect(EFFECT_0)->SetAmount(healingPct); + + GetCaster()->RemoveAura(SPELL_VITAL_SPARK); + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + GetCaster()->SetAuraStack(SPELL_VITAL_SPARK, GetCaster(), stacks); + } + + void Register() override + { + OnEffectApply += AuraEffectApplyFn(spell_baleroc_vital_flame::OnApply, EFFECT_0, SPELL_AURA_359, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_baleroc_vital_flame::OnRemove, EFFECT_0, SPELL_AURA_359, AURA_EFFECT_HANDLE_REAL); + } + + uint32 stacks; +}; + +// http://www.wowhead.com/achievement=5830/share-the-pain //17577 +class achievement_share_the_pain : public AchievementCriteriaScript +{ + public: + achievement_share_the_pain() : AchievementCriteriaScript("achievement_share_the_pain") { } + + bool OnCheck(Player* /*source*/, Unit* target) override + { + if (!target) + return false; + + return target->GetAI()->GetData(GUID_TORMENTED) == 0; + } +}; + +void AddSC_boss_baleroc() +{ + RegisterFirelandsAI(boss_baleroc); + RegisterFirelandsAI(npc_shard_of_torment); + RegisterSpellScript(spell_baleroc_blades_of_baleroc); + RegisterAuraScript(spell_baleroc_inferno_blade); + RegisterAuraScript(spell_baleroc_decimation_blade); + RegisterSpellScript(spell_baleroc_decimating_strike); + RegisterSpellScript(spell_baleroc_countdown_aoe_dummy); + RegisterAuraScript(spell_baleroc_countdown); + RegisterSpellScript(spell_baleroc_countdown_proximity_check); + RegisterSpellScript(spell_baleroc_shards_of_torment_target_search); + RegisterSpellScript(spell_baleroc_torment_target_search); + RegisterSpellAndAuraScriptPair(spell_baleroc_torment, spell_baleroc_torment_AuraScript); + RegisterAuraScript(spell_baleroc_tormented); + RegisterSpellScript(spell_baleroc_tormented_spread); + RegisterAuraScript(spell_baleroc_vital_spark); + RegisterAuraScript(spell_baleroc_vital_flame); + new achievement_share_the_pain(); +}; diff --git a/src/server/scripts/Kalimdor/Firelands/firelands.cpp b/src/server/scripts/Kalimdor/Firelands/firelands.cpp index 092ff5c3b2a..9ed7ce1ebe0 100644 --- a/src/server/scripts/Kalimdor/Firelands/firelands.cpp +++ b/src/server/scripts/Kalimdor/Firelands/firelands.cpp @@ -15,12 +15,326 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "firelands.h" +#include "ScriptMgr.h" #include "Creature.h" -#include "CreatureAI.h" +#include "firelands.h" +#include "GridNotifiers.h" +#include "Vehicle.h" + +enum Spells +{ + // Baleroc Trash + SPELL_FLAME_TORRENT = 100795, + SPELL_FIERY_TORMENT = 100797, + SPELL_FIERY_TORMENT_DAMAGE = 100802, + SPELL_EARTHQUAKE = 100724, + SPELL_MAGMA_CONDUIT = 100728, + SPELL_ERUPTION = 100755, + SPELL_SUMMON_MAGMAKIN = 100746, + + // Legendary questline + SPELL_SMOULDERING_QUEST_CHECK_A = 101089, // Alliance - Unverified + SPELL_SMOULDERING_QUEST_CHECK_H = 101092 // Horde - Unverified +}; bool DelayedAttackStartEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) { _owner->AI()->DoZoneInCombat(_owner, 200.0f); return true; } + +bool DelayedSpellCastEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) +{ + _owner->CastSpell(_target, _spellId, _triggered); + return true; +} + +void firelands_bossAI::EnterCombat(Unit* target) +{ + BossAI::EnterCombat(target); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); +} + +void firelands_bossAI::JustDied(Unit* killer) +{ + BossAI::JustDied(killer); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + me->m_Events.AddEvent(new DelayedSpellCastEvent(me, static_cast<Unit*>(nullptr), SPELL_SMOULDERING_1, false), me->m_Events.CalculateTime(2 * IN_MILLISECONDS)); + me->m_Events.AddEvent(new DelayedSpellCastEvent(me, static_cast<Unit*>(nullptr), SPELL_SMOULDERING_2, false), me->m_Events.CalculateTime(2 * IN_MILLISECONDS)); +} + +void firelands_bossAI::EnterEvadeMode(EvadeReason why) +{ + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + + // Copy paste ScriptedAI::EnterEvadeMode functionality to exclude Reset function call + if (!_EnterEvadeMode(why)) + return; + + if (!me->GetVehicle()) // otherwise me will be in evade mode forever + { + if (Unit* owner = me->GetCharmerOrOwner()) + { + me->GetMotionMaster()->Clear(false); + me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE); + } + else + { + // Required to prevent attacking creatures that are evading and cause them to reenter combat + // Does not apply to MoveFollow + me->AddUnitState(UNIT_STATE_EVADE); + me->GetMotionMaster()->MoveTargetedHome(); + } + } + + // Copy paste reason + //Reset(); + + if (me->IsVehicle()) // use the same sequence of addtoworld, aireset may remove all summons! + me->GetVehicleKit()->Reset(true); + + _DespawnAtEvade(); +} + +// http://www.wowhead.com/npc=54161/flame-archon +struct npc_firelands_flame_archon : public ScriptedAI +{ + npc_firelands_flame_archon(Creature* creature) : ScriptedAI(creature) + { + scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } + + void EnterCombat(Unit* /*attacker*/) override + { + scheduler.Schedule(Seconds(10), Seconds(12), [this](TaskContext context) + { + DoCastAOE(SPELL_FLAME_TORRENT); + context.Repeat(Seconds(15), Seconds(17)); + }); + scheduler.Schedule(Seconds(25), [this](TaskContext context) + { + DoCastAOE(SPELL_FIERY_TORMENT); + context.Repeat(Seconds(45)); + }); + } + + void JustDied(Unit* killer) override + { + scheduler.CancelAll(); + ScriptedAI::JustDied(killer); + } + + void EnterEvadeMode(EvadeReason why) override + { + scheduler.CancelAll(); + ScriptedAI::EnterEvadeMode(why); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + scheduler.Update(diff); + + DoMeleeAttackIfReady(); + } + +private: + TaskScheduler scheduler; +}; + +// http://www.wowhead.com/npc=54143/molten-flamefather +struct npc_firelands_molten_flamefather : public ScriptedAI +{ + npc_firelands_molten_flamefather(Creature* creature) : ScriptedAI(creature) + { + scheduler.SetValidator([this] + { + return !me->HasUnitState(UNIT_STATE_CASTING); + }); + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() != NPC_MAGMA_CONDUIT) + return; + + summon->CastSpell(summon, SPELL_SUMMON_MAGMAKIN); + } + + void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override + { + if (summon->GetEntry() != NPC_MAGMA_CONDUIT) + return; + + summon->DespawnOrUnsummon(); + } + + void EnterCombat(Unit* /*attacker*/) override + { + scheduler.Schedule(Seconds(5), [this](TaskContext context) + { + DoCastAOE(SPELL_MAGMA_CONDUIT); + if (Is25ManRaid()) + DoCastAOE(SPELL_MAGMA_CONDUIT); + context.Repeat(Seconds(25)); + }); + scheduler.Schedule(Milliseconds(12800), [this](TaskContext context) + { + DoCastAOE(SPELL_EARTHQUAKE); + context.Repeat(Milliseconds(32500)); + }); + } + + void JustDied(Unit* killer) override + { + scheduler.CancelAll(); + ScriptedAI::JustDied(killer); + } + + void EnterEvadeMode(EvadeReason why) override + { + scheduler.CancelAll(); + ScriptedAI::EnterEvadeMode(why); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + scheduler.Update(diff); + + DoMeleeAttackIfReady(); + } + +private: + TaskScheduler scheduler; +}; + +// http://www.wowhead.com/npc=54144/magmakin +struct npc_firelands_magmakin : public ScriptedAI +{ + npc_firelands_magmakin(Creature* creature) : ScriptedAI(creature) { } + + void IsSummonedBy(Unit* /*summoner*/) override + { + //Not actually sniffed behavior + Unit* target = me->SelectNearestTarget(50.0f, true); + if (!target) + return; + + me->AddThreat(target, 50000000.0f); + me->TauntApply(target); + } + + void UpdateAI(uint32 /*diff*/) override + { + if (!UpdateVictim()) + return; + + DoSpellAttackIfReady(SPELL_ERUPTION); + } +}; + +// http://www.wowhead.com/spell=100799/fiery-torment +class spell_firelands_fiery_torment : public SpellScript +{ + PrepareSpellScript(spell_firelands_fiery_torment); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_FIERY_TORMENT_DAMAGE }); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_FIERY_TORMENT_DAMAGE, true); + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + if (targets.empty()) + return; + + targets.sort(Trinity::ObjectDistanceOrderPred(GetCaster(), true)); + targets.resize(1); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_firelands_fiery_torment::HandleScript, EFFECT_0, SPELL_EFFECT_DUMMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_firelands_fiery_torment::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } +}; + +// http://www.wowhead.com/spell=101089/smouldering +// http://www.wowhead.com/spell=101092/smouldering +class spell_firelands_smouldering : public SpellScript +{ + PrepareSpellScript(spell_firelands_smouldering); + + void CheckQuestStatus(std::list<WorldObject*>& targets) + { + uint32 questId = 0; + switch (GetSpellInfo()->Id) + { + case SPELL_SMOULDERING_QUEST_CHECK_A: + questId = QUEST_HEART_OF_FLAME_A; + break; + case SPELL_SMOULDERING_QUEST_CHECK_H: + questId = QUEST_HEART_OF_FLAME_H; + break; + default: + break; + } + + bool raidHasQuest = targets.end() != std::find_if(targets.begin(), targets.end(), [questId](WorldObject* worldObject) + { + if (Player* player = worldObject->ToPlayer()) + if (player->GetQuestStatus(questId) == QUEST_STATUS_INCOMPLETE) + return true; + + return false; + }); + + targets.clear(); + if (raidHasQuest) + targets.push_back(GetCaster()); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_firelands_smouldering::CheckQuestStatus, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + } +}; + +// http://www.wowhead.com/spell=101093/smouldering +class spell_firelands_smouldering_aura : public SpellScript +{ + PrepareSpellScript(spell_firelands_smouldering_aura); + + void SetTarget(WorldObject*& target) + { + target = GetCaster(); + } + + void Register() override + { + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_firelands_smouldering_aura::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY); + } +}; + +void AddSC_firelands() +{ + RegisterFirelandsAI(npc_firelands_flame_archon); + RegisterFirelandsAI(npc_firelands_molten_flamefather); + RegisterFirelandsAI(npc_firelands_magmakin); + RegisterSpellScript(spell_firelands_fiery_torment); + RegisterSpellScript(spell_firelands_smouldering); + RegisterSpellScript(spell_firelands_smouldering_aura); +} diff --git a/src/server/scripts/Kalimdor/Firelands/firelands.h b/src/server/scripts/Kalimdor/Firelands/firelands.h index 59fa43baeec..e2dc5aedec4 100644 --- a/src/server/scripts/Kalimdor/Firelands/firelands.h +++ b/src/server/scripts/Kalimdor/Firelands/firelands.h @@ -20,6 +20,7 @@ #include "CreatureAIImpl.h" #include "EventProcessor.h" +#include "ScriptedCreature.h" class Creature; @@ -41,12 +42,43 @@ enum FLDataTypes enum FLCreatureIds { + // Bosses + NPC_SHANNOX = 53691, + NPC_LORD_RHYOLITH = 52558, + NPC_BETH_TILAC = 52498, + NPC_ALYSRAZOR = 52530, + NPC_BALEROC = 53494, + NPC_MAJORDOMO_STAGHELM = 52571, + NPC_RAGNAROS = 52409, + + // Alysrazor NPC_BLAZING_MONSTROSITY_LEFT = 53786, NPC_BLAZING_MONSTROSITY_RIGHT = 53791, NPC_EGG_PILE = 53795, NPC_HARBINGER_OF_FLAME = 53793, NPC_MOLTEN_EGG_TRASH = 53914, NPC_SMOULDERING_HATCHLING = 53794, + + // Baleroc + NPC_MAGMA_CONDUIT = 54145, + NPC_MAGMAKIN = 54144 +}; + +enum GameobjectIds +{ + GO_BALEROC_FIREWALL = 209066 +}; + +enum FirelandsSpells +{ + SPELL_SMOULDERING_1 = 101089, + SPELL_SMOULDERING_2 = 101092, +}; + +enum FirelandsQuests +{ + QUEST_HEART_OF_FLAME_A = 29307, + QUEST_HEART_OF_FLAME_H = 29308 }; class DelayedAttackStartEvent : public BasicEvent @@ -60,10 +92,44 @@ class DelayedAttackStartEvent : public BasicEvent Creature* _owner; }; +class DelayedSpellCastEvent : public BasicEvent +{ + public: + DelayedSpellCastEvent(Creature* owner, Unit* target, uint32 spellId, bool triggered) : _owner(owner), _target(target), _spellId(spellId), _triggered(triggered) { } + + bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override; + + private: + Creature* _owner; + Unit* _target; + uint32 _spellId; + bool _triggered; +}; + +class PlayerCheck +{ + public: + bool operator()(WorldObject* object) const + { + return object->GetTypeId() != TYPEID_PLAYER; + } +}; + +struct firelands_bossAI : public BossAI +{ + firelands_bossAI(Creature* creature, uint32 bossId) : BossAI(creature, bossId) { } + + void EnterCombat(Unit* target) override; + void JustDied(Unit* killer) override; + void EnterEvadeMode(EvadeReason why) override; +}; + template<typename AI> inline AI* GetFirelandsAI(Creature* creature) { return GetInstanceAI<AI>(creature, FirelandsScriptName); } +#define RegisterFirelandsAI(AI) RegisterCreatureAIWithFactory(AI, GetFirelandsAI) + #endif // FIRELANDS_H_ diff --git a/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp b/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp index da1fe55d2a5..c2bc3aa1263 100644 --- a/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp +++ b/src/server/scripts/Kalimdor/Firelands/instance_firelands.cpp @@ -18,6 +18,7 @@ #include "ScriptMgr.h" #include "Creature.h" #include "firelands.h" +#include "GameObject.h" #include "InstanceScript.h" #include "Map.h" @@ -42,8 +43,60 @@ class instance_firelands : public InstanceMapScript // Cannot directly start attacking here as the creature is not yet on map creature->m_Events.AddEvent(new DelayedAttackStartEvent(creature), creature->m_Events.CalculateTime(500)); break; + case NPC_BALEROC: + BalerocGUID = creature->GetGUID(); + break; + default: + break; + } + } + + void OnGameObjectCreate(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_BALEROC_FIREWALL: + BalerocDoorGUID = go->GetGUID(); + if (GetBossState(DATA_SHANNOX) == DONE || GetBossState(DATA_BALEROC) == DONE) + go->SetGoState(GO_STATE_ACTIVE); + break; + default: + break; } } + + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; + + if ((type == DATA_SHANNOX && state == DONE) || (type == DATA_BALEROC && state != IN_PROGRESS)) + { + if (GameObject* door = instance->GetGameObject(BalerocDoorGUID)) + door->SetGoState(GO_STATE_ACTIVE); + } + else if (type == DATA_BALEROC && state == IN_PROGRESS) + if (GameObject* door = instance->GetGameObject(BalerocDoorGUID)) + door->SetGoState(GO_STATE_READY); + + return true; + } + + ObjectGuid GetGuidData(uint32 type) const override + { + switch (type) + { + case DATA_BALEROC: + return BalerocGUID; + default: + break; + } + return ObjectGuid::Empty; + } + + protected: + ObjectGuid BalerocDoorGUID; + ObjectGuid BalerocGUID; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp index cdca725290d..2fdd22e9be0 100644 --- a/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp +++ b/src/server/scripts/Kalimdor/kalimdor_script_loader.cpp @@ -91,7 +91,9 @@ void AddSC_boss_temple_guardian_anhuur(); void AddSC_boss_earthrager_ptah(); void AddSC_boss_anraphet(); void AddSC_instance_firelands(); +void AddSC_firelands(); void AddSC_boss_alysrazor(); +void AddSC_boss_baleroc(); void AddSC_ashenvale(); void AddSC_azshara(); @@ -220,5 +222,7 @@ void AddKalimdorScripts() AddSC_boss_anraphet(); AddSC_instance_firelands(); + AddSC_firelands(); AddSC_boss_alysrazor(); + AddSC_boss_baleroc(); } |