Scripts/Antorus: implement Garothi Worldbreaker encounter for normal and heroic difficulty

* added base script support for the encounter for normal and heroic difficulty
* added instance script for Antorus the Burning Throne
* added sniffed template data for involved gameobjects
* added encounter related spawns to Antorus the Burning Throne
* added instance encounter entry for Garothi Worldbreaker
This commit is contained in:
Ovah
2020-04-25 19:04:31 +02:00
committed by GitHub
parent af76dc6b88
commit 030d942efe
6 changed files with 1293 additions and 0 deletions

View File

@@ -0,0 +1,183 @@
-- Spawns
SET @CGUID := 450000;
DELETE FROM `creature` WHERE `guid`= @CGUID+0;
INSERT INTO `creature` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnDifficulties`, `PhaseId`, `PhaseGroup`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `spawndist`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `VerifiedBuild`) VALUES
(@CGUID+0, 122450, 1712, 8638, 9280, "14,15,16,17", 169, 0, 0, 0, -3292.458, 9822.647, -63.49804, 4.729585, 7200, 0, 0, 0, 0, 0, 0, 0, 0, 26365); -- Garothi Worldbreaker
SET @OGUID := 300000;
DELETE FROM `gameobject` WHERE `guid` BETWEEN @OGUID+0 AND @OGUID+2;
INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnDifficulties`, `PhaseId`, `PhaseGroup`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `VerifiedBuild`) VALUES
(@OGUID+0, 278488, 1712, 8638, 8638, '14,15,16,17', 169, 0, -3330.073, 9823.818, -66.76595, 4.92183, 0.02519464, 0.01764011, -0.6292171, 0.7766207, 7200, 255, 1, 30706), -- Rock (Area: -Unknown- - Difficulty: 15)
(@OGUID+1, 253128, 1712, 8638, 8638, '14,15,16,17', 169, 0, -3429.696, 9523.502, 14.88574, 0.254501, 0, 0, 0.1269073, 0.9919146, 7200, 255, 1, 30706), -- Instance Portal (Area: -Unknown- - Difficulty: 15)
(@OGUID+2, 277365, 1712, 8638, 8638, '14,15,16,17', 169, 0, -3324.769, 9814.266, -68.07056, 2.050762, 0, 0, 0.8549118, 0.5187734, 7200, 255, 1, 30706); -- Collision (Area: -Unknown- - Difficulty: 15)
-- Add Missing Gameobject Template Data
DELETE FROM `gameobject_template` WHERE `entry` IN (278488, 277365, 253128);
INSERT INTO `gameobject_template` (`entry`, `type`, `displayId`, `name`, `IconName`, `castBarCaption`, `unk1`, `size`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `Data6`, `Data7`, `Data8`, `Data9`, `Data10`, `Data11`, `Data12`, `Data13`, `Data14`, `Data15`, `Data16`, `Data17`, `Data18`, `Data19`, `Data20`, `Data21`, `Data22`, `Data23`, `Data24`, `Data25`, `Data26`, `Data27`, `Data28`, `Data29`, `Data30`, `Data31`, `Data32`, `Data33`, `RequiredLevel`, `VerifiedBuild`) VALUES
(278488, 0, 46128, 'Rock', '', '', '', 0.5500001, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30706), -- Rock
(277365, 0, 6391, 'Collision', '', '', '', 3.289998, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30706), -- Collision
(253128, 5, 6450, 'Instance Portal', '', '', '', 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30706); -- Instance Portal
-- Gameobject Template Addon
DELETE FROM `gameobject_template_addon` WHERE `entry` IN (278488, 277365, 253128);
INSERT INTO `gameobject_template_addon` (`entry`, `faction`, `flags`) VALUES
(277365, 0, 48), -- Collision
(253128, 0, 32), -- Instance Portal
(278488, 0, 48); -- Rock
-- Instance Script
DELETE FROM `instance_template` WHERE `map`= 1712;
INSERT INTO `instance_template` (`map`, `parent`, `script`, `allowMount`) VALUES
(1712, 0, 'instance_antorus_the_burning_throne', 0);
-- Instance Encounter
DELETE FROM `instance_encounters` WHERE `entry`= 2076;
INSERT INTO `instance_encounters` (`entry`, `creditType`, `creditEntry`, `lastEncounterDungeon`, `comment`) VALUES
(2076, 0, 122450, 0, 'Garothi Worldbreaker');
-- Template Updates
-- Garothi Worldbreaker
UPDATE `creature_template` SET `minlevel`= 113, `maxlevel`= 113, `faction`= 14, `unit_class`= 1, `InhabitType`= 12, `unit_flags2`= 4227072, `VehicleId`= 5430, `mechanic_immune_mask`= 650854271, `ScriptName`= 'boss_garothi_worldbreaker', `flags_extra` = 1 WHERE `entry`= 122450;
-- Annihilator
UPDATE `creature_template` SET `minlevel`= 113, `maxlevel`= 113, `faction`= 14, `unit_class`= 1, `InhabitType`= 12, `unit_flags`= 33554432, `unit_flags2`= 32768, `baseattacktime`= 1500, `VehicleId`= 5430, `mechanic_immune_mask`= 650854271 WHERE `entry`= 122778;
-- Decimator
UPDATE `creature_template` SET `minlevel`= 113, `maxlevel`= 113, `faction`= 14, `unit_class`= 1, `InhabitType`= 12, `unit_flags`= 33554432, `unit_flags2`= 32768, `baseattacktime`= 1500, `VehicleId`= 5430, `mechanic_immune_mask`= 650854271 WHERE `entry`= 122773;
-- Annihilation
UPDATE `creature_template` SET `minlevel`= 113, `maxlevel`= 113, `faction`= 14, `unit_class`= 1, `InhabitType`= 8, `unit_flags`= 33554432, `unit_flags2`= 2048, `flags_extra`= 128 WHERE `entry`= 122818;
-- Garothi Worldbreaker (Surging Fel)
UPDATE `creature_template` SET `minlevel`= 113, `maxlevel`= 113, `faction`= 14, `unit_class`= 1, `InhabitType`= 12, `unit_flags`= 33554432, `unit_flags2`= 34816, `flags_extra`= 128 WHERE `entry`= 124167;
-- Spells
DELETE FROM `spell_script_names` WHERE `ScriptName` IN
('spell_garothi_apocalypse_drive',
'spell_garothi_fel_bombardment_selector',
'spell_garothi_fel_bombardment_warning',
'spell_garothi_fel_bombardment_periodic',
'spell_garothi_searing_barrage_periodic',
'spell_garothi_searing_barrage_dummy',
'spell_garothi_searing_barrage_selector',
'spell_garothi_decimation_selector',
'spell_garothi_decimation_warning',
'spell_garothi_carnage',
'spell_garothi_annihilation_selector',
'spell_garothi_annihilation_triggered',
'spell_garothi_eradication',
'spell_garothi_surging_fel',
'spell_garothi_cannon_chooser');
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(244152, 'spell_garothi_apocalypse_drive'),
(244150, 'spell_garothi_fel_bombardment_selector'),
(246220, 'spell_garothi_fel_bombardment_warning'),
(244536, 'spell_garothi_fel_bombardment_periodic'),
(244398, 'spell_garothi_searing_barrage_dummy'),
(246369, 'spell_garothi_searing_barrage_dummy'),
(246360, 'spell_garothi_searing_barrage_selector'),
(244399, 'spell_garothi_decimation_selector'),
(244410, 'spell_garothi_decimation_warning'),
(244106, 'spell_garothi_carnage'),
(247572, 'spell_garothi_annihilation_selector'),
(244761, 'spell_garothi_annihilation_triggered'),
(244969, 'spell_garothi_eradication'),
(246655, 'spell_garothi_surging_fel'),
(245124, 'spell_garothi_cannon_chooser');
-- Addons
DELETE FROM `creature_template_addon` WHERE `entry` IN (122450, 122778, 122773);
INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `auras`) VALUES
(122450, 0, 0, 0, 0, 0, '246839'), -- 122450 (Garothi Worldbreaker) - Helmet
(122778, 0, 0, 0, 0, 0, '107829'), -- 122778 (Annihilator) - Update Interactions
(122773, 0, 0, 0, 0, 0, '107829'); -- 122773 (Decimator) - Update Interactions
-- Texts
DELETE FROM `creature_text` WHERE `CreatureID` IN (122450, 122773);
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
-- Garothi Worldbreaker
(122450, 0, 0, 'Enemy combatants detected. Threat level nominal.', 14, 0, 100, 0, 0, 86397, 132426, 0, 'Garothi Worldbreaker - Aggro'),
(122450, 1, 0, 'Targets cleared.', 14, 0, 100, 0, 0, 86401, 132427, 0, 'Garothi Worldbreaker - Evade 1'),
(122450, 1, 1, 'Enemy combatants neutralized.', 14, 0, 100, 0, 0, 86974, 135270, 0, 'Garothi Worldbreaker - Evade 2'),
(122450, 1, 2, 'No hostile targets remaining. Continuing patrol.', 14, 0, 100, 0, 0, 86975, 135271, 0, 'Garothi Worldbreaker - Evade 3'),
(122450, 2, 0, '|TInterface\\ICONS\\Ability_BossFelMagnaron_HandEmpowered.blp:20|t %s is powering the |cFFF00000|Hspell:244152|h[Apocalypse Drive]|h|r!', 41, 0, 100, 0, 0, 0, 132631, 0, 'Garothi Worldbreaker - Announce Apocalypse Drive'),
(122450, 3, 0, 'Apocalypse drive engaged.', 14, 0, 100, 0, 0, 86399, 132433, 0, 'Garothi Worldbreaker - Apocalpyse Drive'),
(122450, 4, 0, '|TInterface\\ICONS\\ABILITY_WARRIOR_COLOSSUSSMASH.BLP:20|t The Garothi Worldbreaker rears back for |cFFF00000|Hspell:244969|h[Eradication]|h|r! Run away!', 41, 0, 100, 0, 0, 0, 138536, 0, 'Garothi Worldbreaker - Announce Eradication'),
(122450, 5, 0, 'Systems re-engaged, rerouting power. Weapons primed.', 14, 0, 100, 0, 0, 86400, 132434, 0, 'Garothi Worldbreaker - Finish Apocalypse Drive'),
(122450, 6, 0, 'Targets aquired.', 14, 0, 100, 0, 0, 86971, 135267, 0, 'Garothi Worldbreaker - Decimation 1'),
(122450, 6, 1, 'Targets acquired for decimation.', 14, 0, 100, 0, 0, 86393, 132429, 0, 'Garothi Worldbreaker - Decimation 2'),
(122450, 6, 2, 'Weapon system primed, target locked.', 14, 0, 100, 0, 0, 86395, 132431, 0, 'Garothi Worldbreaker - Decimation 3'),
(122450, 7, 0, 'Leave none alive.', 14, 0, 100, 0, 0, 86396, 132432, 0, 'Garothi Worldbreaker - Annihilation 1'),
(122450, 7, 1, 'Cannon primed for annihilation.', 14, 0, 100, 0, 0, 86394, 132430, 0, 'Garothi Worldbreaker - Annihilation 2'),
(122450, 8, 0, '|TInterface\\ICONS\\ABILITY_HUNTER_SNIPERSHOT.BLP:20|t You are targeted for |cFFF00000|Hspell:244536|h[Fel Bombardment]|h|r!', 42, 0, 100, 0, 0, 0, 132630, 0, 'Garothi Worldbreaker - Announce Fel Bombardment'),
(122450, 9, 0, 'Hostile destroyed.', 14, 0, 100, 0, 0, 86978, 135275, 0, 'Garothi Worldbreaker - Slay 1'),
(122450, 9, 1, 'Threat terminated.', 14, 0, 100, 0, 0, 86977, 135274, 0, 'Garothi Worldbreaker - Slay 2'),
(122450, 9, 2, 'Exterminated.', 14, 0, 100, 0, 0, 86976, 135273, 0, 'Garothi Worldbreaker - Slay 3'),
(122450, 10, 0, 'Critical system failure...', 14, 0, 100, 0, 0, 86398, 132428, 0, 'Garothi Worldbreaker - Death 1'),
(122450, 10, 1, 'Power core... rupturing...', 14, 0, 100, 0, 0, 86972, 135268, 0, 'Garothi Worldbreaker - Death 2'),
(122450, 10, 2, 'Termination imminent...', 14, 0, 100, 0, 0, 86973, 135269, 0, 'Garothi Worldbreaker - Death 3'),
-- Decimator
(122773, 0, 0, '|TInterface\\ICONS\\ABILITY_MAGE_FIRESTARTER.BLP:20|t You are targeted for |cFFF00000|Hspell:244410|h[Decimation]|h|r!', 42, 0, 100, 0, 0, 0, 132901, 0, 'Decimator - Announce Decimation');
-- Conditions
DELETE FROM `conditions` WHERE `SourceEntry` IN (247572, 244761, 245237, 246012) AND `SourceTypeOrReferenceId`= 13;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ScriptName`, `Comment`) VALUES
(13, 1, 247572, 0, 0, 51, 0, 5, 122818, 0, 0, 0, '', 'Annihilation - Target Annihilation'),
(13, 2, 245237, 0, 1, 51, 0, 5, 122773, 0, 0, 0, '', 'Empowered - Target Annihilator'),
(13, 2, 245237, 0, 2, 51, 0, 5, 122778, 0, 0, 0, '', 'Empowered - Target Decimator'),
(13, 1, 246012, 0, 0, 51, 0, 5, 122773, 0, 0, 0, '', 'Restore Health - Target Annihilator'),
(13, 1, 246012, 0, 1, 51, 0, 5, 122778, 0, 0, 0, '', 'Restore Health - Target Decimator');
-- Summon Groups
DELETE FROM `creature_summon_groups` WHERE `summonerId`= 122450 AND `summonerType`= 0;
INSERT INTO `creature_summon_groups` (`summonerId`, `summonerType`, `groupId`, `entry`, `position_x`, `position_y`, `position_z`, `orientation`, `summonType`, `summonTime`) VALUES
-- SUMMON_GROUP_ID_SURGING_FEL = 0
(122450, 0, 0, 124167, -3262, 9810.797, -63.93631, 4.577713, 8, 0),
(122450, 0, 0, 124167, -3277, 9810.8, -63.68398, 4.577713, 8, 0),
(122450, 0, 0, 124167, -3307, 9810.8, -63.85229, 4.577713, 8, 0),
(122450, 0, 0, 124167, -3322, 9810.8, -64.84264, 4.577713, 8, 0),
(122450, 0, 0, 124167, -3292, 9810.797, -64.07504, 4.577713, 8, 0);
-- Vehicle Accessories
DELETE FROM `vehicle_template_accessory` WHERE `entry`= 122450;
INSERT INTO `vehicle_template_accessory` (`entry`, `accessory_entry`, `seat_id`, `minion`, `description`, `summontype`, `summontimer`) VALUES
(122450, 122773, 1, 1, 'Garothi Worldbreaker - Decimator', 6, 200), -- Garothi Worldbreaker - Decimator
(122450, 122778, 0, 1, 'Garothi Worldbreaker - Annihilator', 6, 200); -- Garothi Worldbreaker - Annihilator
-- Spellclicks
DELETE FROM `npc_spellclick_spells` WHERE `npc_entry`= 122450;
INSERT INTO `npc_spellclick_spells` (`npc_entry`, `spell_id`, `cast_flags`, `user_type`) VALUES
(122450, 237873, 1, 1);
-- Model Data
DELETE FROM `creature_model_info` WHERE `DisplayID` IN (76534, 77168, 77029);
INSERT INTO `creature_model_info` (`DisplayID`, `BoundingRadius`, `CombatReach`, `DisplayID_Other_Gender`) VALUES
(76534, 20.02365, 30, 0),
(77168, 3.944656, 75, 0),
(77029, 3.944656, 75, 0);
-- Areatriggers
DELETE FROM `areatrigger_template` WHERE `Id` IN (15496, 0);
INSERT INTO `areatrigger_template` (`Id`, `Type`, `Flags`, `Data0`, `Data1`, `Data2`, `Data3`, `Data4`, `Data5`, `ScriptName`, `VerifiedBuild`) VALUES
(15496, 0, 4, 4, 4, 0, 0, 0, 0, 'at_garothi_annihilation', 26365),
(0, 3, 4, 0, 0, 0, 0, 0, 0, '', 26365);
DELETE FROM `spell_areatrigger` WHERE `SpellMiscId` IN (10662, 10876);
INSERT INTO `spell_areatrigger` (`SpellMiscId`, `AreaTriggerId`) VALUES
(10662, 15496),
(10876, 0);
DELETE FROM `areatrigger_template_polygon_vertices` WHERE `AreaTriggerId`= 0;
INSERT INTO `areatrigger_template_polygon_vertices` (`AreaTriggerId`, `Idx`, `VerticeX`, `VerticeY`, `VerifiedBuild`) VALUES
(0, 0, 0, -15, 26365),
(0, 1, 0, 15, 26365),
(0, 2, 100, -15, 26365),
(0, 3, 100, -15, 26365);
-- Procs
DELETE FROM `spell_proc` WHERE `SpellId`= 244106;
INSERT INTO `spell_proc` (`SpellId`, `SpellFamilyName`, `SpellFamilyMask0`, `SpellFamilyMask1`, `SpellFamilyMask2`, `ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`, `AttributesMask`) VALUES
(244106, 0, 0, 0, 0x00000008, 0, 0, 0, 0, 0);
-- Custom Attributes
DELETE FROM `spell_custom_attr` WHERE `entry` IN (244761, 244410);
INSERT INTO `spell_custom_attr` (`entry`, `attributes`) VALUES
(244761, 0x8),
(244410, 0x1000);

View File

@@ -3590,6 +3590,20 @@ void SpellMgr::LoadSpellInfoCorrections()
});
// ENDOF FIRELANDS SPELLS
//
// ANTORUS THE BURNING THRONE SPELLS
//
// Decimation
ApplySpellFix({ 244449 }, [](SpellInfo* spellInfo)
{
// For some reason there is a instakill effect that serves absolutely no purpose.
// Until we figure out what it's actually used for we disable it.
const_cast<SpellEffectInfo*>(spellInfo->GetEffect(EFFECT_2))->Effect = 0;
});
// ENDOF ANTORUS THE BURNING THRONE SPELLS
// Summon Master Li Fei
ApplySpellFix({ 102445 }, [](SpellInfo* spellInfo)
{

View File

@@ -0,0 +1,75 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DEF_ANTORUS_THE_BURNING_THRONE_H_
#define DEF_ANTORUS_THE_BURNING_THRONE_H_
#include "CreatureAIImpl.h"
#define DataHeader "ABT"
#define ABTScriptName "instance_antorus_the_burning_throne"
uint32 const EncounterCount = 10;
enum AntorusDataTypes
{
// Encounters
DATA_GAROTHI_WORLDBREAKER = 0,
DATA_FELHOUNDS_OF_SAGERAS = 1,
DATA_ANTORAN_HIGH_COMMAND = 2,
DATA_PORTAL_KEEPER_HASABEL = 3,
DATA_EONAR_THE_LIFE_BINDER = 4,
DATA_IMONAR_THE_SOULHUNTER = 5,
DATA_KINGAROTH = 6,
DATA_VARIMATHRAS = 7,
DATA_THE_COVEN_OF_SHIVARRA = 8,
DATA_AGGRAMAR = 9,
DATA_ARGUS_THE_UNMAKER = 10,
// Encounter related data
DATA_DECIMATOR,
DATA_ANNIHILATOR
};
enum AntorusCreatureIds
{
// Bosses
BOSS_GAROTHI_WORLDBREAKER = 122450,
// Encounter related creatures
/*Garothi Worldbreaker*/
NPC_DECIMATOR = 122773,
NPC_ANNIHILATOR = 122778,
NPC_ANNIHILATION = 122818,
NPC_GAROTHI_WORLDBREAKER = 124167
};
enum AntorusGameObjectIds
{
GO_COLLISION = 277365,
GO_ROCK = 278488
};
template <class AI, class T>
inline AI* GetAntorusTheBurningThroneAI(T* obj)
{
return GetInstanceAI<AI>(obj, ABTScriptName);
}
#define RegisterAntorusTheBurningThroneCreatureAI(ai_name) RegisterCreatureAIWithFactory(ai_name, GetAntorusTheBurningThroneAI)
#endif

View File

@@ -0,0 +1,912 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "AreaTriggerAI.h"
#include "CreatureAI.h"
#include "CreatureAIImpl.h"
#include "GridNotifiers.h"
#include "InstanceScript.h"
#include "Map.h"
#include "ObjectAccessor.h"
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "SpellAuras.h"
#include "SpellScript.h"
#include "SpellAuraEffects.h"
#include "antorus_the_burning_throne.h"
enum Texts
{
// Garothi Worldbreaker
SAY_AGGRO = 0,
SAY_DISENGAGE = 1,
SAY_ANNOUNCE_APOCALYPSE_DRIVE = 2,
SAY_APOCALYPSE_DRIVE = 3,
SAY_ANNOUNCE_ERADICATION = 4,
SAY_FINISH_APOCALYPSE_DRIVE = 5,
SAY_DECIMATION = 6,
SAY_ANNIHILATION = 7,
SAY_ANNOUNCE_FEL_BOMBARDMENT = 8,
SAY_SLAY = 9,
SAY_DEATH = 10,
// Decimator
SAY_ANNOUNCE_DECIMATION = 0
};
enum Spells
{
// Garothi Worldbreaker
SPELL_MELEE = 248229,
SPELL_APOCALYPSE_DRIVE = 244152,
SPELL_APOCALYPSE_DRIVE_PERIODIC_DAMAGE = 253300,
SPELL_APOCALYPSE_DRIVE_FINAL_DAMAGE = 240277,
SPELL_ERADICATION = 244969,
SPELL_EMPOWERED = 245237,
SPELL_RESTORE_HEALTH = 246012,
SPELL_ANNIHILATOR_CANNON_EJECT = 245527,
SPELL_DECIMATOR_CANNON_EJECT = 245515,
SPELL_FEL_BOMBARDMENT_SELECTOR = 244150,
SPELL_FEL_BOMBARDMENT_WARNING = 246220,
SPELL_FEL_BOMBARDMENT_DUMMY = 245219,
SPELL_FEL_BOMBARDMENT_PERIODIC = 244536,
SPELL_CANNON_CHOOSER = 245124,
SPELL_SEARING_BARRAGE_ANNIHILATOR = 246368,
SPELL_SEARING_BARRAGE_DECIMATOR = 244395,
SPELL_SEARING_BARRAGE_DUMMY_ANNIHILATOR = 244398,
SPELL_SEARING_BARRAGE_DUMMY_DECIMATOR = 246369,
SPELL_SEARING_BARRAGE_SELECTOR = 246360,
SPELL_SEARING_BARRAGE_DAMAGE_ANNIHILATOR = 244400,
SPELL_SEARING_BARRAGE_DAMAGE_DECIMATOR = 246373,
SPELL_CARNAGE = 244106,
// Decimator
SPELL_DECIMATION_SELECTOR = 244399,
SPELL_DECIMATION_WARNING = 244410,
SPELL_DECIMATION_CAST_VISUAL = 245338,
SPELL_DECIMATION_MISSILE = 244448,
// Annihilator
SPELL_ANNIHILATION_SUMMON = 244790,
SPELL_ANNIHILATION_SELECTOR = 247572,
SPELL_ANNIHILATION_DUMMY = 244294,
SPELL_ANNIHILATION_DAMAGE_UNSPLITTED = 244762,
// Annihilation
SPELL_ANNIHILATION_AREA_TRIGGER = 244795,
SPELL_ANNIHILATION_WARNING = 244799,
// Garothi Worldbreaker (Surging Fel)
SPELL_SURGING_FEL_AREA_TRIGGER = 246655,
SPELL_SURGING_FEL_DAMAGE = 246663
};
enum Events
{
// Garothi Worldbreaker
EVENT_REENGAGE_PLAYERS = 1,
EVENT_FEL_BOMBARDMENT,
EVENT_SEARING_BARRAGE,
EVENT_CANNON_CHOOSER,
EVENT_SURGING_FEL
};
enum Data
{
DATA_LAST_FIRED_CANNON = 0
};
enum AnimKits
{
ANIM_KIT_ID_CANNON_DESTROYED = 13264
};
enum TargetSize : uint8
{
MIN_TARGETS_SIZE = 2,
MAX_TARGETS_SIZE = 6
};
enum Misc
{
SUMMON_GROUP_ID_SURGING_FEL = 0,
ENCOUNTER_ID_GAROTHI_WORLDBREAKER = 2076
};
namespace TargetHandler
{
class VictimCheck
{
public:
VictimCheck(Unit* caster, bool keepTank) : _caster(caster), _keepTank(keepTank) { }
bool operator()(WorldObject* object)
{
Unit* unit = object->ToUnit();
if (!unit)
return true;
if (_caster->GetVictim() && _caster->GetVictim() != unit)
return _keepTank;
return false;
}
private:
Unit* _caster;
bool _keepTank; // true = remove all nontank targets | false = remove current tank
};
void PreferNonTankTargetsAndResizeTargets(std::list<WorldObject*>& targets, Unit* caster)
{
if (targets.empty())
return;
std::list<WorldObject*> targetsCopy = targets;
uint8 size = targetsCopy.size();
// Selecting our prefered target size based on total targets (min 10 player: 2, max 30 player: 6)
uint8 preferedSize = std::min<uint8>(std::max<uint8>(std::ceil(size / 5), MIN_TARGETS_SIZE), MAX_TARGETS_SIZE);
// Now we get rid of the tank as these abilities prefer non-tanks above tanks as long as there are alternatives
targetsCopy.remove_if(TargetHandler::VictimCheck(caster, false));
// We have less available nontank targets than we want, include tanks
if (targetsCopy.size() < preferedSize)
Trinity::Containers::RandomResize(targets, preferedSize);
else
{
// Our target list has enough alternative targets, resize
Trinity::Containers::RandomResize(targetsCopy, preferedSize);
targets = targetsCopy;
}
}
}
static constexpr uint32 const MaxApocalypseDriveCount = 2;
Position const AnnihilationCenterReferencePos = { -3296.72f, 9767.78f, -60.0f };
struct boss_garothi_worldbreaker : public BossAI
{
boss_garothi_worldbreaker(Creature* creature) : BossAI(creature, DATA_GAROTHI_WORLDBREAKER)
{
Initialize();
me->SetReactState(REACT_PASSIVE);
}
void Initialize()
{
SetCombatMovement(false);
switch (GetDifficulty())
{
case DIFFICULTY_MYTHIC_RAID:
case DIFFICULTY_HEROIC_RAID:
_apocalypseDriveHealthLimit[0] = 65;
_apocalypseDriveHealthLimit[1] = 35;
break;
case DIFFICULTY_NORMAL_RAID:
case DIFFICULTY_LFR_NEW:
_apocalypseDriveHealthLimit[0] = 60;
_apocalypseDriveHealthLimit[1] = 20;
break;
default:
break;
}
// Todo: move this section out of the ctor and remove the .clear call when dynamic spawns have been merged.
_apocalypseDriveCount = 0;
_searingBarrageSpellId = 0;
_lastCanonEntry = NPC_DECIMATOR;
_castEradication = false;
_surgingFelDummyGuids.clear();
}
void Reset() override
{
_Reset();
Initialize();
me->SummonCreatureGroup(SUMMON_GROUP_ID_SURGING_FEL);
}
void EnterCombat(Unit* /*who*/) override
{
me->SetReactState(REACT_AGGRESSIVE);
_EnterCombat();
Talk(SAY_AGGRO);
DoCastSelf(SPELL_MELEE);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me);
events.ScheduleEvent(EVENT_FEL_BOMBARDMENT, 9s);
events.ScheduleEvent(EVENT_CANNON_CHOOSER, 8s);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
Talk(SAY_DISENGAGE);
_EnterEvadeMode();
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
events.Reset();
CleanupEncounter();
_DespawnAtEvade();
}
void KilledUnit(Unit* victim) override
{
if (victim->IsPlayer())
Talk(SAY_SLAY);
}
void JustDied(Unit* /*killer*/) override
{
_JustDied();
Talk(SAY_DEATH);
CleanupEncounter();
instance->SendBossKillCredit(ENCOUNTER_ID_GAROTHI_WORLDBREAKER);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
}
void OnSuccessfulSpellCast(SpellInfo const* spell) override
{
switch (spell->Id)
{
case SPELL_APOCALYPSE_DRIVE_FINAL_DAMAGE:
if (_apocalypseDriveCount < MaxApocalypseDriveCount)
events.Reset();
events.ScheduleEvent(EVENT_REENGAGE_PLAYERS, 3s + 500ms);
HideCannons();
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
break;
default:
break;
}
}
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (me->HealthBelowPctDamaged(_apocalypseDriveHealthLimit[_apocalypseDriveCount], damage))
{
me->AttackStop();
me->SetReactState(REACT_PASSIVE);
me->InterruptNonMeleeSpells(true);
me->SetFacingTo(me->GetHomePosition().GetOrientation());
events.Reset();
if (GetDifficulty() == DIFFICULTY_MYTHIC_RAID || GetDifficulty() == DIFFICULTY_HEROIC_RAID)
events.ScheduleEvent(EVENT_SURGING_FEL, 8s);
DoCastSelf(SPELL_APOCALYPSE_DRIVE);
DoCastSelf(SPELL_APOCALYPSE_DRIVE_FINAL_DAMAGE);
Talk(SAY_ANNOUNCE_APOCALYPSE_DRIVE);
Talk(SAY_APOCALYPSE_DRIVE);
me->AddUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
if (Creature* decimator = instance->GetCreature(DATA_DECIMATOR))
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, decimator, 2);
decimator->AddUnitFlag(UNIT_FLAG_IN_COMBAT);
decimator->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
if (Creature* annihilator = instance->GetCreature(DATA_ANNIHILATOR))
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, annihilator, 2);
annihilator->AddUnitFlag(UNIT_FLAG_IN_COMBAT);
annihilator->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
++_apocalypseDriveCount;
}
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
switch (summon->GetEntry())
{
case NPC_ANNIHILATION:
summon->CastSpell(summon, SPELL_ANNIHILATION_WARNING);
summon->CastSpell(summon, SPELL_ANNIHILATION_AREA_TRIGGER);
break;
case NPC_ANNIHILATOR:
case NPC_DECIMATOR:
summon->SetReactState(REACT_PASSIVE);
break;
case NPC_GAROTHI_WORLDBREAKER:
_surgingFelDummyGuids.insert(summon->GetGUID());
break;
default:
break;
}
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
switch (summon->GetEntry())
{
case NPC_DECIMATOR:
case NPC_ANNIHILATOR:
me->InterruptNonMeleeSpells(true);
me->RemoveAurasDueToSpell(SPELL_APOCALYPSE_DRIVE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
if (summon->GetEntry() == NPC_ANNIHILATOR)
_searingBarrageSpellId = SPELL_SEARING_BARRAGE_ANNIHILATOR;
else
_searingBarrageSpellId = SPELL_SEARING_BARRAGE_DECIMATOR;
if (_apocalypseDriveCount < MaxApocalypseDriveCount)
events.Reset();
events.ScheduleEvent(EVENT_SEARING_BARRAGE, 3s + 500ms);
events.ScheduleEvent(EVENT_REENGAGE_PLAYERS, 3s + 500ms);
_castEradication = true;
if (summon->GetEntry() == NPC_DECIMATOR)
DoCastSelf(SPELL_DECIMATOR_CANNON_EJECT);
else
DoCastSelf(SPELL_ANNIHILATOR_CANNON_EJECT);
me->PlayOneShotAnimKitId(ANIM_KIT_ID_CANNON_DESTROYED);
HideCannons();
break;
default:
break;
}
}
uint32 GetData(uint32 type) const override
{
if (type == DATA_LAST_FIRED_CANNON)
return _lastCanonEntry;
return 0;
}
void SetData(uint32 type, uint32 value) override
{
if (type == DATA_LAST_FIRED_CANNON)
_lastCanonEntry = value;
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING) && !me->HasAura(SPELL_APOCALYPSE_DRIVE))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_REENGAGE_PLAYERS:
DoCastSelf(SPELL_EMPOWERED);
DoCastSelf(SPELL_RESTORE_HEALTH);
if (_castEradication)
{
DoCastSelf(SPELL_ERADICATION);
Talk(SAY_ANNOUNCE_ERADICATION);
Talk(SAY_FINISH_APOCALYPSE_DRIVE);
_castEradication = false;
}
me->SetReactState(REACT_AGGRESSIVE);
events.ScheduleEvent(EVENT_FEL_BOMBARDMENT, 20s);
events.ScheduleEvent(EVENT_CANNON_CHOOSER, 18s);
break;
case EVENT_FEL_BOMBARDMENT:
DoCastAOE(SPELL_FEL_BOMBARDMENT_SELECTOR);
events.Repeat(20s);
break;
case EVENT_SEARING_BARRAGE:
DoCastSelf(_searingBarrageSpellId);
break;
case EVENT_CANNON_CHOOSER:
DoCastSelf(SPELL_CANNON_CHOOSER);
events.Repeat(16s);
break;
case EVENT_SURGING_FEL:
{
GuidSet guids = _surgingFelDummyGuids;
guids.erase(_lastSurgingFelDummyGuid);
_lastSurgingFelDummyGuid = Trinity::Containers::SelectRandomContainerElement(guids);
if (Creature* dummy = ObjectAccessor::GetCreature(*me, _lastSurgingFelDummyGuid))
dummy->CastSpell(dummy, SPELL_SURGING_FEL_AREA_TRIGGER);
events.Repeat(8s);
break;
}
default:
break;
}
}
if (me->GetVictim() && me->GetVictim()->IsWithinMeleeRange(me))
DoMeleeAttackIfReady();
else
DoSpellAttackIfReady(SPELL_CARNAGE);
}
private:
uint8 _apocalypseDriveHealthLimit[MaxApocalypseDriveCount];
uint8 _apocalypseDriveCount;
uint32 _searingBarrageSpellId;
uint32 _lastCanonEntry;
bool _castEradication;
ObjectGuid _lastSurgingFelDummyGuid;
GuidSet _surgingFelDummyGuids;
void CleanupEncounter()
{
if (Creature* decimator = instance->GetCreature(DATA_DECIMATOR))
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, decimator);
if (Creature* annihilator = instance->GetCreature(DATA_ANNIHILATOR))
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, annihilator);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_DECIMATION_WARNING);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_FEL_BOMBARDMENT_WARNING);
instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_FEL_BOMBARDMENT_PERIODIC);
summons.DespawnAll();
}
void HideCannons()
{
if (Creature* decimator = instance->GetCreature(DATA_DECIMATOR))
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, decimator);
decimator->AddUnitFlag(UnitFlags(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_UNK_31));
}
if (Creature* annihilator = instance->GetCreature(DATA_ANNIHILATOR))
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, annihilator);
annihilator->AddUnitFlag(UnitFlags(UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_UNK_31));
}
}
};
struct at_garothi_annihilation : AreaTriggerAI
{
at_garothi_annihilation(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger)
{
Initialize();
}
void Initialize()
{
_playerCount = 0;
}
void OnUnitEnter(Unit* unit) override
{
if (!unit->IsPlayer())
return;
_playerCount++;
if (Unit* annihilation = at->GetCaster())
annihilation->RemoveAurasDueToSpell(SPELL_ANNIHILATION_WARNING);
}
void OnUnitExit(Unit* unit) override
{
if (!unit->IsPlayer())
return;
_playerCount--;
if (!_playerCount && !at->IsRemoved())
if (Unit* annihilation = at->GetCaster())
annihilation->CastSpell(annihilation, SPELL_ANNIHILATION_WARNING);
}
private:
uint8 _playerCount;
};
class spell_garothi_apocalypse_drive : public AuraScript
{
PrepareAuraScript(spell_garothi_apocalypse_drive);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_APOCALYPSE_DRIVE_PERIODIC_DAMAGE });
}
void HandlePeriodic(AuraEffect const* aurEff)
{
GetTarget()->CastSpell(GetTarget(), SPELL_APOCALYPSE_DRIVE_PERIODIC_DAMAGE, true, nullptr, aurEff);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_garothi_apocalypse_drive::HandlePeriodic, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY);
}
};
class spell_garothi_fel_bombardment_selector : public SpellScript
{
PrepareSpellScript(spell_garothi_fel_bombardment_selector);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_FEL_BOMBARDMENT_WARNING,
SPELL_FEL_BOMBARDMENT_DUMMY
});
}
void FilterTargets(std::list<WorldObject*>& targets)
{
if (targets.empty())
return;
if (Unit* caster = GetCaster())
targets.remove_if(TargetHandler::VictimCheck(caster, true));
}
void HandleWarningEffect(SpellEffIndex /*effIndex*/)
{
Creature* caster = GetCaster() ? GetCaster()->ToCreature() : nullptr;
if (!caster || !caster->IsAIEnabled)
return;
Unit* target = GetHitUnit();
caster->AI()->Talk(SAY_ANNOUNCE_FEL_BOMBARDMENT, target);
caster->CastSpell(target, SPELL_FEL_BOMBARDMENT_WARNING, true);
caster->CastSpell(target, SPELL_FEL_BOMBARDMENT_DUMMY, true);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_garothi_fel_bombardment_selector::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
OnEffectHitTarget += SpellEffectFn(spell_garothi_fel_bombardment_selector::HandleWarningEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
class spell_garothi_fel_bombardment_warning : public AuraScript
{
PrepareAuraScript(spell_garothi_fel_bombardment_warning);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_FEL_BOMBARDMENT_PERIODIC });
}
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
if (Unit* caster = GetCaster())
caster->CastSpell(GetTarget(), SPELL_FEL_BOMBARDMENT_PERIODIC, true);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_garothi_fel_bombardment_warning::AfterRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
class spell_garothi_fel_bombardment_periodic : public AuraScript
{
PrepareAuraScript(spell_garothi_fel_bombardment_periodic);
bool Validate(SpellInfo const* spellInfo) override
{
return ValidateSpellInfo({ uint32(spellInfo->GetEffect(DIFFICULTY_NONE, EFFECT_0)->BasePoints) });
}
void HandlePeriodic(AuraEffect const* /*aurEff*/)
{
if (Unit* caster = GetCaster())
caster->CastSpell(GetTarget(), uint32(GetSpellInfo()->GetEffect(DIFFICULTY_NONE, EFFECT_0)->BasePoints), true);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_garothi_fel_bombardment_periodic::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
class spell_garothi_searing_barrage_dummy : public SpellScript
{
PrepareSpellScript(spell_garothi_searing_barrage_dummy);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SEARING_BARRAGE_SELECTOR });
}
void HandleHit(SpellEffIndex /*effIndex*/)
{
GetHitUnit()->CastCustomSpell(SPELL_SEARING_BARRAGE_SELECTOR, SPELLVALUE_BASE_POINT0, GetSpellInfo()->Id, GetHitUnit(), true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_garothi_searing_barrage_dummy::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
class spell_garothi_searing_barrage_selector : public SpellScript
{
PrepareSpellScript(spell_garothi_searing_barrage_selector);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo(
{
SPELL_SEARING_BARRAGE_DAMAGE_ANNIHILATOR,
SPELL_SEARING_BARRAGE_DAMAGE_DECIMATOR,
SPELL_SEARING_BARRAGE_DUMMY_ANNIHILATOR,
SPELL_SEARING_BARRAGE_DUMMY_DECIMATOR
});
}
void FilterTargets(std::list<WorldObject*>& targets)
{
TargetHandler::PreferNonTankTargetsAndResizeTargets(targets, GetCaster());
}
void HandleHit(SpellEffIndex /*effIndex*/)
{
uint32 spellId = GetEffectValue() == SPELL_SEARING_BARRAGE_DUMMY_ANNIHILATOR ? SPELL_SEARING_BARRAGE_DAMAGE_ANNIHILATOR : SPELL_SEARING_BARRAGE_DAMAGE_DECIMATOR;
if (Unit* caster = GetCaster())
caster->CastSpell(GetHitUnit(), spellId, true);
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_garothi_searing_barrage_selector::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY);
OnEffectHitTarget += SpellEffectFn(spell_garothi_searing_barrage_selector::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
class spell_garothi_decimation_selector : public SpellScript
{
PrepareSpellScript(spell_garothi_decimation_selector);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DECIMATION_WARNING });
}
void FilterTargets(std::list<WorldObject*>& targets)
{
TargetHandler::PreferNonTankTargetsAndResizeTargets(targets, GetCaster());
}
void HandleHit(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
{
caster->CastSpell(GetHitUnit(), SPELL_DECIMATION_WARNING, true);
if (Creature* decimator = caster->ToCreature())
if (decimator->IsAIEnabled)
decimator->AI()->Talk(SAY_ANNOUNCE_DECIMATION, GetHitUnit());
}
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_garothi_decimation_selector::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
OnEffectHitTarget += SpellEffectFn(spell_garothi_decimation_selector::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
class spell_garothi_decimation_warning : public AuraScript
{
PrepareAuraScript(spell_garothi_decimation_warning);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_DECIMATION_MISSILE });
}
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
{
if (Unit* caster = GetCaster())
{
caster->CastSpell(GetTarget(), SPELL_DECIMATION_MISSILE, true);
if (!caster->HasUnitState(UNIT_STATE_CASTING))
caster->CastSpell(caster, SPELL_DECIMATION_CAST_VISUAL);
}
}
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_garothi_decimation_warning::AfterRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
class spell_garothi_carnage : public AuraScript
{
PrepareAuraScript(spell_garothi_carnage);
void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo& /*eventInfo`*/)
{
// Usually we could just handle this via spell_proc but since we want
// to silence the console message because it's not a spell trigger proc, we need a script here.
PreventDefaultAction();
Remove();
}
void Register() override
{
OnEffectProc += AuraEffectProcFn(spell_garothi_carnage::HandleProc, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
}
};
class spell_garothi_annihilation_selector : public SpellScript
{
PrepareSpellScript(spell_garothi_annihilation_selector);
bool Validate(SpellInfo const* spellInfo) override
{
return ValidateSpellInfo({ uint32(spellInfo->GetEffect(DIFFICULTY_NONE, EFFECT_0)->BasePoints) });
}
void HandleHit(SpellEffIndex effIndex)
{
if (Unit* caster = GetCaster())
caster->CastSpell(GetHitUnit(), uint32(GetSpellInfo()->GetEffect(DIFFICULTY_NONE, effIndex)->BasePoints), true);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_garothi_annihilation_selector::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
class spell_garothi_annihilation_triggered : public SpellScript
{
PrepareSpellScript(spell_garothi_annihilation_triggered);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_ANNIHILATION_DAMAGE_UNSPLITTED });
}
void HandleHit(SpellEffIndex /*effIndex*/)
{
Unit* target = GetHitUnit();
if (target->HasAura(SPELL_ANNIHILATION_WARNING))
target->CastSpell(target, SPELL_ANNIHILATION_DAMAGE_UNSPLITTED, true);
target->RemoveAllAuras();
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_garothi_annihilation_triggered::HandleHit, EFFECT_1, SPELL_EFFECT_DUMMY);
}
};
class spell_garothi_eradication : public SpellScript
{
PrepareSpellScript(spell_garothi_eradication);
void ChangeDamage()
{
if (Unit* caster = GetCaster())
{
uint32 damageReduction = CalculatePct(GetHitDamage(), GetHitUnit()->GetDistance(caster));
SetHitDamage(GetHitDamage() - damageReduction);
}
}
void Register() override
{
OnHit += SpellHitFn(spell_garothi_eradication::ChangeDamage);
}
};
class spell_garothi_surging_fel : public AuraScript
{
PrepareAuraScript(spell_garothi_surging_fel);
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SURGING_FEL_DAMAGE });
}
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE)
GetTarget()->CastSpell(GetTarget(), SPELL_SURGING_FEL_DAMAGE, true);
}
void Register() override
{
AfterEffectRemove += AuraEffectRemoveFn(spell_garothi_surging_fel::AfterRemove, EFFECT_0, SPELL_AURA_AREA_TRIGGER, AURA_EFFECT_HANDLE_REAL);
}
};
class spell_garothi_cannon_chooser : public SpellScript
{
PrepareSpellScript(spell_garothi_cannon_chooser);
void HandleDummyEffect(SpellEffIndex /*effIndex*/)
{
Creature* caster = GetHitCreature();
if (!caster || !caster->IsAIEnabled)
return;
InstanceScript* instance = caster->GetInstanceScript();
if (!instance)
return;
Creature* decimator = instance->GetCreature(DATA_DECIMATOR);
Creature* annihilator = instance->GetCreature(DATA_ANNIHILATOR);
uint32 lastCannonEntry = caster->AI()->GetData(DATA_LAST_FIRED_CANNON);
if ((lastCannonEntry == NPC_ANNIHILATOR && decimator) || (decimator && !annihilator))
{
decimator->CastSpell(decimator, SPELL_DECIMATION_SELECTOR, true);
caster->AI()->Talk(SAY_DECIMATION, decimator);
lastCannonEntry = NPC_DECIMATOR;
}
else if ((lastCannonEntry == NPC_DECIMATOR && annihilator) || (annihilator && !decimator))
{
uint8 count = caster->GetMap()->GetDifficultyID() == DIFFICULTY_MYTHIC_RAID ? MAX_TARGETS_SIZE :
std::max<uint8>(MIN_TARGETS_SIZE, std::ceil(caster->GetMap()->GetPlayersCountExceptGMs() / 5));
for (uint8 i = 0; i < count; i++)
{
float x = AnnihilationCenterReferencePos.GetPositionX() + cos(frand(0.0f, float(M_PI * 2))) * frand(15.0f, 30.0f);
float y = AnnihilationCenterReferencePos.GetPositionY() + sin(frand(0.0f, float(M_PI * 2))) * frand(15.0f, 30.0f);
float z = caster->GetMap()->GetHeight(caster->GetPhaseShift(), x, y, AnnihilationCenterReferencePos.GetPositionZ());
annihilator->CastSpell(x, y, z, SPELL_ANNIHILATION_SUMMON, true);
}
annihilator->CastSpell(annihilator, SPELL_ANNIHILATION_DUMMY);
annihilator->CastSpell(annihilator, SPELL_ANNIHILATION_SELECTOR);
caster->AI()->Talk(SAY_ANNIHILATION);
lastCannonEntry = NPC_ANNIHILATOR;
}
caster->AI()->SetData(DATA_LAST_FIRED_CANNON, lastCannonEntry);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_garothi_cannon_chooser::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
void AddSC_boss_garothi_worldbreaker()
{
RegisterAntorusTheBurningThroneCreatureAI(boss_garothi_worldbreaker);
RegisterAreaTriggerAI(at_garothi_annihilation);
RegisterAuraScript(spell_garothi_apocalypse_drive);
RegisterSpellScript(spell_garothi_fel_bombardment_selector);
RegisterAuraScript(spell_garothi_fel_bombardment_warning);
RegisterAuraScript(spell_garothi_fel_bombardment_periodic);
RegisterSpellScript(spell_garothi_searing_barrage_dummy);
RegisterSpellScript(spell_garothi_searing_barrage_selector);
RegisterSpellScript(spell_garothi_decimation_selector);
RegisterAuraScript(spell_garothi_decimation_warning);
RegisterAuraScript(spell_garothi_carnage);
RegisterSpellScript(spell_garothi_annihilation_selector);
RegisterSpellScript(spell_garothi_annihilation_triggered);
RegisterSpellScript(spell_garothi_eradication);
RegisterAuraScript(spell_garothi_surging_fel);
RegisterSpellScript(spell_garothi_cannon_chooser);
}

View File

@@ -0,0 +1,81 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "antorus_the_burning_throne.h"
#include "Creature.h"
#include "CreatureAI.h"
#include "GameObject.h"
#include "InstanceScript.h"
#include "Map.h"
ObjectData const creatureData[] =
{
{ BOSS_GAROTHI_WORLDBREAKER, DATA_GAROTHI_WORLDBREAKER },
{ NPC_DECIMATOR, DATA_DECIMATOR },
{ NPC_ANNIHILATOR, DATA_ANNIHILATOR },
{ 0, 0 } // END
};
DoorData const doorData[] =
{
{ GO_COLLISION, DATA_GAROTHI_WORLDBREAKER, DOOR_TYPE_PASSAGE },
{ GO_ROCK, DATA_GAROTHI_WORLDBREAKER, DOOR_TYPE_PASSAGE },
{ 0, 0, DOOR_TYPE_ROOM } // END
};
class instance_antorus_the_burning_throne: public InstanceMapScript
{
public:
instance_antorus_the_burning_throne() : InstanceMapScript(ABTScriptName, 757) { }
struct instance_antorus_the_burning_throne_InstanceMapScript: public InstanceScript
{
instance_antorus_the_burning_throne_InstanceMapScript(InstanceMap* map) : InstanceScript(map)
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
LoadObjectData(creatureData, nullptr);
LoadDoorData(doorData);
}
void OnCreatureCreate(Creature* creature) override
{
InstanceScript::OnCreatureCreate(creature);
switch (creature->GetEntry())
{
case NPC_ANNIHILATION:
if (Creature* garothi = GetCreature(DATA_GAROTHI_WORLDBREAKER))
garothi->AI()->JustSummoned(creature);
break;
default:
break;
}
}
};
InstanceScript* GetInstanceScript(InstanceMap* map) const
{
return new instance_antorus_the_burning_throne_InstanceMapScript(map);
}
};
void AddSC_instance_antorus_the_burning_throne()
{
new instance_antorus_the_burning_throne();
}

View File

@@ -0,0 +1,28 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// This is where scripts' loading functions should be declared:
void AddSC_boss_garothi_worldbreaker();
void AddSC_instance_antorus_the_burning_throne();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
void AddArgusScripts()
{
AddSC_boss_garothi_worldbreaker(); // Antorus the Burning Throne
AddSC_instance_antorus_the_burning_throne();
}