diff --git a/sql/updates/WIP/theralion_and_valiona.sql b/sql/updates/WIP/theralion_and_valiona.sql new file mode 100644 index 00000000000..08eb8510208 --- /dev/null +++ b/sql/updates/WIP/theralion_and_valiona.sql @@ -0,0 +1,122 @@ +-- Template Updates +-- Theralion +UPDATE `creature_template` SET `ScriptName`= 'boss_theralion', `flags_extra`= 512 WHERE `entry`= 45993; +UPDATE `creature_template` SET `DamageModifier`= 80, `flags_extra`= 512 WHERE `entry` IN (45993); +-- Valiona +UPDATE `creature_template` SET `ScriptName`= 'boss_valiona', `flags_extra`= 512 WHERE `entry`= 45992; +UPDATE `creature_template` SET `DamageModifier`= 80, `flags_extra`= 512 WHERE `entry` IN (45992); +-- Valiona (Fire Dummy) +UPDATE `creature_template` SET `flags_extra`= 128 WHERE `entry`= 46147; +-- Theralion Flight Target Stalker +UPDATE `creature_template` SET `InhabitType`= 4, `flags_extra`= 128 WHERE `entry`= 46364; +-- Convective Flames +UPDATE `creature_template` SET `unit_flags`= 33554432, `flags_extra`= 128, `InhabitType`= 13 WHERE `entry`= 46588; +-- Dazzling Destruction Stalker +UPDATE `creature_template` SET `unit_flags`= 33554432, `flags_extra`= 128, `InhabitType`= 13 WHERE `entry`= 46374; +-- Fabolous Flames +UPDATE `creature_template` SET `unit_flags`= 33554432, `flags_extra`= 128, `InhabitType`= 13 WHERE `entry`= 46448; + +-- Template Addon +DELETE FROM `creature_template_addon` WHERE `entry` IN (46374, 46448); +INSERT INTO `creature_template_addon` (`entry`, `auras`) VALUES +(46374, '86383'), +(46448, '86506'); + +-- Areatriggers +DELETE FROM `areatrigger_scripts` WHERE `entry`= 6442; +INSERT INTO `areatrigger_scripts` (`entry`, `ScriptName`) VALUES +(6442, 'at_theralion_and_valiona_intro'); + +-- Correct Phasing for Theralion and Valiona +UPDATE `creature` SET `PhaseId`= 0, `PhaseGroup`= 525 WHERE `id` IN (45992, 45993); + +-- Creature Texts +DELETE FROM `creature_text` WHERE `CreatureID` IN (43324, 45992, 45993); +-- Cho'Gall +INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `comment`) VALUES +(43324, 0, 0, 'Valiona, Theralion, put them in their place.', 14, 0, 100, 0, 0, 22063, 47518, 'Cho''gall - Theralion and Valiona Intro'), +(43324, 1, 0, '(Come closer, closer. Let us see your faces. All will be humbled before his power.)', 14, 0, 100, 0, 0, 22064, 47538, 'Cho''gall - Theralion and Valiona Death'), +-- Valiona +(45992, 0, 0, 'Do as the master commands, Theralion! Kill them!', 14, 0, 100, 0, 0, 21894, 47523, 'Valiona - Intro 1'), +(45992, 1, 0, 'You are worthless, Theralion!', 14, 0, 100, 0, 0, 21895, 47524, 'Valiona - Intro 2'), +(45992, 2, 0, '|TInterface\\Icons\\spell_fire_twilightnova.blp:20|t%s casts |cFFFF0000|Hspell:86788|h[Blackout]|h|r!', 41, 0, 100, 0, 0, 0, 47624, 'Valiona'), +(45992, 3, 0, '|TInterface\\Icons\\spell_fire_twilightfire.blp:20|t%s takes a |cFFFF0000|Hspell:86059|h[Deep Breath]|h|r!', 41, 0, 100, 0, 0, 21898, 46712, 'Valiona to Breath Flight Target Stalker'), +(45992, 4, 0, 'Theralion, I will engulf the hallway. Cover their escape!', 14, 0, 100, 0, 0, 21898, 47961, 'Valiona to Breath Flight Target Stalker'), +(45992, 5, 0, 'At least... Theralion dies with me...', 14, 0, 100, 0, 0, 21897, 47960, 'Valiona to Player'), +-- Theralion +(45993, 0, 0, 'The master was clearly speaking to you, Valiona. I am far too busy to attack ANYONE.', 14, 0, 100, 0, 0, 20300, 47521, 'Theralion - Intro 1'), +(45993, 1, 0, 'How dare you call me worthless! You will see why I am mother''s favored child!', 14, 0, 100, 0, 0, 20301, 47522, 'Theralion - Intro 2'), +(45993, 2, 0, 'You are not the boss of me, Valiona! I will engulf as I please!', 14, 0, 100, 0, 0, 20304, 47911, 'Theralion to Theralion Flight Target Stalker'), +(45993, 3, 0, '|TInterface\\Icons\\spell_fire_twilightpyroblast.blp:20|t%s begins to cast |cFF00EEFF|Hspell:86408|h[Dazzling Destruction]|h|r!', 41, 0, 100, 0, 0, 0, 46714, 'Theralion to Theralion Flight Target Stalker'), +(45993, 4, 0, '|TInterface\\Icons\\spell_holy_consumemagic.blp:20|t%s begins to cast |cFF00EEFF|Hspell:86622|h[Engulfing Magic]|h|r!', 41, 0, 100, 0, 0, 0, 46713, 'Theralion'), +(45993, 5, 0, 'WRITHE IN AGONY!', 14, 0, 100, 0, 0, 20306, 47913, 'Theralion to Valiona'); + +-- Spells +DELETE FROM `spell_script_names` WHERE `ScriptName` IN +('spell_valiona_blackout_dummy', +'spell_valiona_blackout', +'spell_valiona_devouring_flames_targeting', +'spell_valiona_devouring_flames', +'spell_valiona_twilight_meteorite_targeting', +'spell_theralion_dazzling_destruction_targeting', +'spell_theralion_dazzling_destruction_dummy', +'spell_theralion_dazzling_destruction', +'spell_theralion_dazzling_destruction_twilight_realm', +'spell_theralion_twilight_shift', +'spell_theralion_fabulous_flames_targeting', +'spell_theralion_engulfing_magic_targeting', +'spell_theralion_engulfing_magic'); + +INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES +(86673, 'spell_valiona_blackout_dummy'), +(86788, 'spell_valiona_blackout'), +(92876, 'spell_valiona_blackout'), +(92877, 'spell_valiona_blackout'), +(92878, 'spell_valiona_blackout'), +(86832, 'spell_valiona_devouring_flames_targeting'), +(86844, 'spell_valiona_devouring_flames'), +(92872, 'spell_valiona_devouring_flames'), +(92873, 'spell_valiona_devouring_flames'), +(92874, 'spell_valiona_devouring_flames'), +(88518, 'spell_valiona_twilight_meteorite_targeting'), +(86380, 'spell_theralion_dazzling_destruction_targeting'), +(92923, 'spell_theralion_dazzling_destruction_targeting'), +(92924, 'spell_theralion_dazzling_destruction_targeting'), +(92925, 'spell_theralion_dazzling_destruction_targeting'), +(86408, 'spell_theralion_dazzling_destruction_dummy'), +(86406, 'spell_theralion_dazzling_destruction'), +(92926, 'spell_theralion_dazzling_destruction'), +(92927, 'spell_theralion_dazzling_destruction'), +(92928, 'spell_theralion_dazzling_destruction'), +(93063, 'spell_theralion_dazzling_destruction_twilight_realm'), +(88436, 'spell_theralion_twilight_shift'), +(92892, 'spell_theralion_twilight_shift'), +(92893, 'spell_theralion_twilight_shift'), +(92894, 'spell_theralion_twilight_shift'), +(86495, 'spell_theralion_fabulous_flames_targeting'), +(86607, 'spell_theralion_engulfing_magic_targeting'), +(92912, 'spell_theralion_engulfing_magic_targeting'), +(92913, 'spell_theralion_engulfing_magic_targeting'), +(92914, 'spell_theralion_engulfing_magic_targeting'), +(86622, 'spell_theralion_engulfing_magic'), +(95639, 'spell_theralion_engulfing_magic'), +(95640, 'spell_theralion_engulfing_magic'), +(95641, 'spell_theralion_engulfing_magic'); + +-- Conditions +DELETE FROM `conditions` WHERE `SourceEntry` IN (90346, 90345, 86840, 86379, 86408, 86406, 92926, 92927, 92928) AND `SourceTypeOrReferenceId`= 13; +INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ScriptName`, `Comment`) VALUES +(13, 1, 90346, 0, 0, 31, 0, 3, 45992, 0, 0, 0, '', 'Share Health - Target Valiona'), +(13, 1, 90345, 0, 0, 31, 0, 3, 45993, 0, 0, 0, '', 'Share Health - Target Theralion'), +(13, 1, 86840, 0, 0, 31, 0, 3, 46588, 0, 0, 0, '', 'Devouring Flames - Target Convective Flames'), +(13, 1, 86379, 0, 0, 31, 0, 3, 46364, 0, 0, 0, '', 'Dazzling Destruction - Target Theralion Flight Target Stalker'), +(13, 1, 86408, 0, 0, 31, 0, 3, 46374, 0, 0, 0, '', 'Dazzling Destruction - Target Dazzling Destruction Stalker'), +(13, 2, 86406, 0, 0, 31, 0, 3, 46374, 0, 0, 0, '', 'Dazzling Destruction - Target Dazzling Destruction Stalker'), +(13, 2, 92926, 0, 0, 31, 0, 3, 46374, 0, 0, 0, '', 'Dazzling Destruction - Target Dazzling Destruction Stalker'), +(13, 2, 92927, 0, 0, 31, 0, 3, 46374, 0, 0, 0, '', 'Dazzling Destruction - Target Dazzling Destruction Stalker'), +(13, 2, 92928, 0, 0, 31, 0, 3, 46374, 0, 0, 0, '', 'Dazzling Destruction - Target Dazzling Destruction Stalker'); + +-- Spell Procs +DELETE FROM `spell_proc` WHERE `SpellId`= -86622; +INSERT INTO `spell_proc` (`SpellId`, `ProcFlags`, `SpellTypeMask`, `SpellPhaseMask`, `HitMask`, `AttributesMask`) VALUES +(-86622, 0x00055554, 1 | 2, 2, 0, 32); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 26fcfe587fd..622b679a079 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1671,10 +1671,6 @@ void WorldObject::UpdateAllowedPositionZ(float x, float y, float &z) const if (z < ground_z) z = ground_z; } - - // Creatures that are simulating flight effects or actual flight should use HoverHeight - if ((ToUnit() && (ToUnit()->IsFlying() || ToUnit()->IsHovering() || ToUnit()->IsLevitating())) && !ToUnit()->IsUnderWater()) - z += GetFloatValue(UNIT_FIELD_HOVERHEIGHT); break; } case TYPEID_PLAYER: diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 56002dca9c7..99bb288450f 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -4185,6 +4185,34 @@ void SpellMgr::LoadSpellInfoCorrections() // ENDOF THE VORTEX PINNACLE SPELLS + // + // BASTION OF TWILIGHT SPELLS + // + // Theralion and Valiona + // Blackout + ApplySpellFix({ + 86825, + 92879, + 92880, + 92881 + }, [](SpellInfo* spellInfo) + { + spellInfo->AttributesCu |= SPELL_ATTR0_CU_SHARE_DAMAGE; + }); + + // Twilight Meteorite + ApplySpellFix({ + 86013, + 92859, + 92860, + 92861 + }, [](SpellInfo* spellInfo) + { + spellInfo->AttributesCu |= SPELL_ATTR0_CU_SHARE_DAMAGE; + }); + + // ENDOF BASTION OF TWILIGHT + // // DEADMINES SPELLS // diff --git a/src/server/scripts/EasternKingdoms/BastionOfTwilight/bastion_of_twilight.cpp b/src/server/scripts/EasternKingdoms/BastionOfTwilight/bastion_of_twilight.cpp new file mode 100644 index 00000000000..c7cc6b5a6a6 --- /dev/null +++ b/src/server/scripts/EasternKingdoms/BastionOfTwilight/bastion_of_twilight.cpp @@ -0,0 +1,44 @@ +/* +* Copyright (C) 2008-2018 TrinityCore +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see . +*/ + +#include "ObjectMgr.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "GameObject.h" +#include "GameObjectAI.h" +#include "Player.h" +#include "bastion_of_twilight.h" + +class at_theralion_and_valiona_intro : public AreaTriggerScript +{ + public: + at_theralion_and_valiona_intro() : AreaTriggerScript("at_theralion_and_valiona_intro") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) + { + if (InstanceScript* instance = player->GetInstanceScript()) + instance->SetData(DATA_AT_THERALION_AND_VALIONA_INTRO, IN_PROGRESS); + return true; + } +}; + +void AddSC_bastion_of_twilight() +{ + new at_theralion_and_valiona_intro(); +} \ No newline at end of file diff --git a/src/server/scripts/EasternKingdoms/BastionOfTwilight/bastion_of_twilight.h b/src/server/scripts/EasternKingdoms/BastionOfTwilight/bastion_of_twilight.h index d00fb061bc6..64c8e6f91c7 100644 --- a/src/server/scripts/EasternKingdoms/BastionOfTwilight/bastion_of_twilight.h +++ b/src/server/scripts/EasternKingdoms/BastionOfTwilight/bastion_of_twilight.h @@ -27,31 +27,37 @@ uint32 const EncounterCountHeroic = 5; enum BoTDataTypes { // Encounter Types - DATA_HALFUS_WYRMBREAKER = 0, - DATA_THERALION_AND_VALIONA = 1, - DATA_ASCENDANT_COUNCIL = 2, - DATA_CHOGALL = 3, - DATA_SINESTRA = 4, + DATA_HALFUS_WYRMBREAKER = 0, + DATA_THERALION_AND_VALIONA = 1, + DATA_ASCENDANT_COUNCIL = 2, + DATA_CHOGALL = 3, + DATA_SINESTRA = 4, // Creature Types - DATA_PROTO_BEHEMOTH = 5, - DATA_THERALION = 6, - DATA_VALIONA = 7, - DATA_IGNACIOUS = 8, - DATA_FELUDIUS = 9, - DATA_TERRASTRA = 10, - DATA_ARION = 11, - DATA_ELEMENTIUM_MONSTROSITY = 12, + DATA_PROTO_BEHEMOTH = 5, + DATA_THERALION = 6, + DATA_VALIONA = 7, + DATA_IGNACIOUS = 8, + DATA_FELUDIUS = 9, + DATA_TERRASTRA = 10, + DATA_ARION = 11, + DATA_ELEMENTIUM_MONSTROSITY = 12, // GameObject Types - DATA_WHELP_CAGE = 13, + DATA_WHELP_CAGE = 13, + + // Areatriggers + DATA_AT_HALFUS_INTRO = 14, + DATA_AT_THERALION_AND_VALIONA_INTRO = 15, // Encounter Related /*Halfus Wyrmbreaker*/ DATA_UNRESPONSIVE_DRAGON_FIRST, DATA_UNRESPONSIVE_DRAGON_SECOND, DATA_CAST_DRAGON_BUFFS, - DATA_OPEN_ORPHANED_EMERALD_WHELP_CAGE + DATA_OPEN_ORPHANED_EMERALD_WHELP_CAGE, + + /*Theralion and Valiona*/ }; enum BoTDataStates @@ -60,36 +66,48 @@ enum BoTDataStates DRAGON_BUFFS_PROTO_BEHEMOTH, }; +enum BoTAreatriggerIndex +{ + AT_INDEX_HALFUS_WYRMBREAKER_INTRO = 1, + AT_INDEX_THERALION_AND_VALIONA_INTRO = 2 +}; + enum BoTCreatures { // Bosses - BOSS_HALFUS_WYRMBREAKER = 44600, - BOSS_THERALION = 45993, - BOSS_VALIONA = 45992, - BOSS_IGNACIOUS = 43686, - BOSS_FELUDIUS = 43687, - BOSS_TERRASTRA = 43689, - BOSS_ARION = 43688, - BOSS_ELEMENTIUM_MONSTROSITY = 43735, - BOSS_CHOGALL = 43324, - BOSS_SINESTRA = 45213, + BOSS_HALFUS_WYRMBREAKER = 44600, + BOSS_THERALION = 45993, + BOSS_VALIONA = 45992, + BOSS_IGNACIOUS = 43686, + BOSS_FELUDIUS = 43687, + BOSS_TERRASTRA = 43689, + BOSS_ARION = 43688, + BOSS_ELEMENTIUM_MONSTROSITY = 43735, + BOSS_CHOGALL = 43324, + BOSS_SINESTRA = 45213, // Encounter related /*Halfus Wyrmbreaker*/ - NPC_PROTO_BEHEMOTH = 44687, - NPC_NETHER_SCION = 44645, - NPC_NETHER_SCION_ENCOUNTER = 44828, - NPC_SLATE_DRAGON = 44652, - NPC_SLATE_DRAGON_ENCOUNTER = 44829, - NPC_STORM_RIDER = 44650, - NPC_STORM_RIDER_ENCOUNTER = 44826, - NPC_TIME_WARDEN = 44797, - NPC_TIME_WARDEN_ENCOUNTER = 44653, - NPC_ORPHANED_EMERALD_WELP = 44641, - NPC_SPIKE = 44765, + NPC_PROTO_BEHEMOTH = 44687, + NPC_NETHER_SCION = 44645, + NPC_NETHER_SCION_ENCOUNTER = 44828, + NPC_SLATE_DRAGON = 44652, + NPC_SLATE_DRAGON_ENCOUNTER = 44829, + NPC_STORM_RIDER = 44650, + NPC_STORM_RIDER_ENCOUNTER = 44826, + NPC_TIME_WARDEN = 44797, + NPC_TIME_WARDEN_ENCOUNTER = 44653, + NPC_ORPHANED_EMERALD_WELP = 44641, + NPC_SPIKE = 44765, + + /*Theralion and Valiona*/ + NPC_THERALION_FLIGHT_TARGET_STALKER = 46364, + NPC_CONVECTIVE_FLAMES = 46588, + NPC_DAZZLING_DESTRUCTION_STALKER = 46374, + NPC_FABULOUS_FLAMES = 46448, // Generic Creatures - NPC_INVISIBLE_STALKER = 42098 + NPC_INVISIBLE_STALKER = 42098 }; enum BoTGameObjects @@ -106,13 +124,23 @@ enum BoTGameObjects enum BoTActions { - ACTION_ENABLE_MALEVOLENT_STRIKES = 1, - ACTION_ENABLE_FRENZIED_ASSAULT = 2, - ACTION_ENABLE_SHADOW_NOVA = 3, - ACTION_ENABLE_FIREBALL_BARRAGE = 1, - ACTION_ENABLE_SCORCHING_BREATH = 2, - ACTION_CAST_DRAGONS_VENGEANCE = 3, - ACTION_MOVE_OUT_OF_CAGE = 4 + // Halfus Wyrmbreaker + ACTION_ENABLE_MALEVOLENT_STRIKES = 1, + ACTION_ENABLE_FRENZIED_ASSAULT = 2, + ACTION_ENABLE_SHADOW_NOVA = 3, + ACTION_ENABLE_FIREBALL_BARRAGE = 1, + ACTION_ENABLE_SCORCHING_BREATH = 2, + ACTION_CAST_DRAGONS_VENGEANCE = 3, + ACTION_MOVE_OUT_OF_CAGE = 4, + + // Theralion and Valiona + ACTION_START_ARGUMENT_INTRO = 1, + + // Cho'Gall (Non-Boss version) + ACTION_TALK_INTRO_HALFUS_WYRMBREAKER = 1, + + // Cho'Gall (Boss) + ACTION_TALK_INTRO_THERALION_AND_VALIONA = 1 }; enum BoTEvents diff --git a/src/server/scripts/EasternKingdoms/BastionOfTwilight/boss_theralion_and_valiona.cpp b/src/server/scripts/EasternKingdoms/BastionOfTwilight/boss_theralion_and_valiona.cpp new file mode 100644 index 00000000000..3ff24b4ac98 --- /dev/null +++ b/src/server/scripts/EasternKingdoms/BastionOfTwilight/boss_theralion_and_valiona.cpp @@ -0,0 +1,1188 @@ +/* +* Copyright (C) 2008-2018 TrinityCore +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +* more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see . +*/ + +#include "ObjectMgr.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "GameObject.h" +#include "GameObjectAI.h" +#include "Player.h" +#include "PhasingHandler.h" +#include "bastion_of_twilight.h" + +enum Texts +{ + // Theralion and Valiona + SAY_ARGUE_WITH_SIBLING_1 = 0, + SAY_ARGUE_WITH_SIBLING_2 = 1, + + // Theralion + SAY_DAZZLING_DESTRUCTION = 2, + SAY_ANNOUNCE_DAZZLING_DESTRUCTION = 3, + SAY_ANNOUNCE_ENGULFING_MAGIC = 4, + + // Valiona + SAY_ANNOUNCE_BLACKOUT = 2, +}; + +enum Spells +{ + // Theralion + SPELL_SHARE_HEALTH_1 = 90346, + SPELL_TWILIGHT_BLAST = 86369, + SPELL_DAZZLING_DESTRUCTION_SCRIPT = 86379, // probably a Blizzard script thing. Unneeded for our handling + SPELL_DAZZLING_DESTRUCTION_TARGETIG = 86380, + SPELL_DAZZLING_DESTRUCTION_DUMMY = 86408, + SPELL_DAZZLING_DESTRUCTION_TWILIGHT_REALM = 93063, + SPELL_TWILIGHT_PROTECTION_BUFF = 86415, + SPELL_FABULOUS_FLAMES_TARGETING = 86495, + SPELL_ENGULFING_MAGIC_TARGETING = 86607, + SPELL_ENGULFING_MAGIC_TRIGGERED = 86631, + + // Valiona + SPELL_SHARE_HEALTH_2 = 90345, + SPELL_BLACKOUT_DUMMY = 86673, + SPELL_BLACKOUT_DAMAGE = 86825, + SPELL_DEVOURING_FLAMES_TARGETING = 86832, + SPELL_DEVOURING_FLAMES = 86840, + SPELL_TWILIGHT_METEORITE_TARGETING = 88518, + SPELL_DUMMY_NUKE = 80776, // used to select Theralion's current victim. We do it different and better + SPELL_TWILIGHT_ZONE = 86214, + + // Dazzling Destruction Stalker + SPELL_DAZZLING_DESTRUCTION_STALKER_VISUAL = 86383 +}; + +enum Events +{ + // Theralion and Valiona + EVENT_TALK_ARGUMENT_1 = 1, + EVENT_TALK_ARGUMENT_2, + EVENT_LIFTOFF, + EVENT_FLY_TO_DESTINATION, + EVENT_LAND, + EVENT_ATTACK_PLAYERS, + + // Theralion + EVENT_TWILIGHT_BLAST, + EVENT_DAZZLING_DESTRUCTION, + EVENT_FABULOUS_FLAMES, + EVENT_ENGULFING_MAGIC, + + // Valiona + EVENT_BLACKOUT, + EVENT_DEVOURING_FLAMES, + EVENT_TWILIGHT_METEORITE, + + EVENT_DEEP_BREATH, + EVENT_FACE_TO_DIRECTION, + EVENT_FLY_TO_STARTING_POINT, + EVENT_FLY_TO_OTHER_SIDE, +}; + +enum Phases +{ + PHASE_INTRO = 0, + PHASE_COMBAT = 1 +}; + +enum AnimKits +{ + ANIM_KIT_LIFTOFF = 1009 +}; + +enum MovementPoints +{ + POINT_TAKEOFF_DESTINATION = 1, + POINT_LAND = 2, + POINT_DEEP_BREATH_1 = 3, + POINT_DEEP_BREATH_2 = 4 +}; + +enum PhaseIds +{ + PHASE_ID_TWILIGHT_SHIFT = 290 +}; + +enum DeepBreathSides +{ + SIDE_VALIONA = 0, + SIDE_THERALION = 1 +}; + +Position const TheralionLandingPos = { -740.804f, -683.642f, 831.8898f }; + +Position const DeepBreathStartingPositions[] = +{ + { -741.4598f, -592.8389f, 859.1005f }, // Valiona's side + { -740.4072f, -776.5493f, 858.7795f } // Theralion's side +}; + +class boss_theralion : public CreatureScript +{ + public: + boss_theralion() : CreatureScript("boss_theralion") { } + + struct boss_theralionAI : public BossAI + { + boss_theralionAI(Creature* creature) : BossAI(creature, DATA_THERALION_AND_VALIONA) + { + Initialize(); + } + + void Initialize() + { + _dazzlingDestructionCount = 0; + } + + void Reset() override + { + _Reset(); + Initialize(); + events.SetPhase(PHASE_INTRO); + DoCastAOE(SPELL_SHARE_HEALTH_1, true); + } + + void JustEngagedWith(Unit* who) override + { + _JustEngagedWith(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + events.SetPhase(PHASE_COMBAT); + + if (Creature* valiona = instance->GetCreature(DATA_VALIONA)) + valiona->AI()->AttackStart(who); + + events.ScheduleEvent(EVENT_LIFTOFF, Milliseconds(1)); + events.ScheduleEvent(EVENT_DAZZLING_DESTRUCTION, Minutes(1) + Seconds(22)); + } + + void KilledUnit(Unit* victim) override + { + //if (victim->GetTypeId() == TYPEID_PLAYER) + // Talk(SAY_SLAY); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + me->SendSetPlayHoverAnim(false); + me->SetDisableGravity(false); + me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + summons.DespawnAll(); + _DespawnAtEvade(); + } + + void SpellHit(Unit* caster, SpellInfo const* spell) override + { + if (!caster) + return; + + switch (spell->Id) + { + case SPELL_SHARE_HEALTH_2: + if (!caster->HasAura(SPELL_SHARE_HEALTH_1)) + DoCastAOE(SPELL_SHARE_HEALTH_1, true); + break; + default: + break; + } + } + + void DoAction(int32 action) + { + switch (action) + { + case ACTION_START_ARGUMENT_INTRO: + events.ScheduleEvent(EVENT_TALK_ARGUMENT_1, Seconds(8) + Milliseconds(800)); + break; + default: + break; + } + } + + void JustSummoned(Creature* summon) + { + summons.Summon(summon); + + switch (summon->GetEntry()) + { + case NPC_DAZZLING_DESTRUCTION_STALKER: + DoCast(summon, SPELL_DAZZLING_DESTRUCTION_DUMMY); + PhasingHandler::InheritPhaseShift(summon, me); + break; + case NPC_FABULOUS_FLAMES: + PhasingHandler::InheritPhaseShift(summon, me); + break; + default: + break; + } + } + + uint32 GetData(uint32 type) const override + { + return 0; + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) + return; + + switch (id) + { + case POINT_TAKEOFF_DESTINATION: + events.ScheduleEvent(EVENT_TWILIGHT_BLAST, Milliseconds(400)); + break; + case POINT_LAND: + me->SetDisableGravity(false); + me->SendSetPlayHoverAnim(false); + me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + events.ScheduleEvent(EVENT_ATTACK_PLAYERS, Seconds(2)); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_TALK_ARGUMENT_1: + Talk(SAY_ARGUE_WITH_SIBLING_1); + events.ScheduleEvent(EVENT_TALK_ARGUMENT_2, Seconds(11)); + break; + case EVENT_TALK_ARGUMENT_2: + Talk(SAY_ARGUE_WITH_SIBLING_2); + break; + case EVENT_LIFTOFF: + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + me->PlayOneShotAnimKitId(ANIM_KIT_LIFTOFF); + me->SetDisableGravity(true); + me->SendSetPlayHoverAnim(true); + me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + events.ScheduleEvent(EVENT_FLY_TO_DESTINATION, Seconds(1)); + events.CancelEvent(EVENT_FABULOUS_FLAMES); + events.CancelEvent(EVENT_ENGULFING_MAGIC); + break; + case EVENT_FLY_TO_DESTINATION: + if (Creature* stalker = me->FindNearestCreature(NPC_THERALION_FLIGHT_TARGET_STALKER, 100.0f, true)) + me->GetMotionMaster()->MovePoint(POINT_TAKEOFF_DESTINATION, stalker->GetPosition(), false); + break; + case EVENT_TWILIGHT_BLAST: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true, 0)) + DoCast(target, SPELL_TWILIGHT_BLAST); + events.Repeat(Seconds(2) + Milliseconds(400)); + break; + case EVENT_DAZZLING_DESTRUCTION: + if (_dazzlingDestructionCount == 0) + { + DoCastAOE(SPELL_DAZZLING_DESTRUCTION_SCRIPT, true); + Talk(SAY_DAZZLING_DESTRUCTION); + Talk(SAY_ANNOUNCE_DAZZLING_DESTRUCTION); + events.CancelEvent(EVENT_TWILIGHT_BLAST); + } + + if (_dazzlingDestructionCount < 3) + { + DoCastAOE(SPELL_DAZZLING_DESTRUCTION_TARGETIG, true); + _dazzlingDestructionCount++; + } + + if (_dazzlingDestructionCount < 3) + events.Repeat(Seconds(4) + Milliseconds(700)); + else + events.ScheduleEvent(EVENT_LAND, Seconds(4)); + break; + case EVENT_LAND: + me->GetMotionMaster()->MoveLand(POINT_LAND, TheralionLandingPos); + break; + case EVENT_ATTACK_PLAYERS: + me->SetReactState(REACT_AGGRESSIVE); + if (Unit* target = me->GetVictim()) + me->AI()->AttackStart(target); + + events.ScheduleEvent(EVENT_FABULOUS_FLAMES, Seconds(3) + Milliseconds(600)); + events.ScheduleEvent(EVENT_ENGULFING_MAGIC, Seconds(12)); + break; + case EVENT_FABULOUS_FLAMES: + DoCastAOE(SPELL_FABULOUS_FLAMES_TARGETING); + events.Repeat(Seconds(15) + Milliseconds(700)); + break; + case EVENT_ENGULFING_MAGIC: + DoCastAOE(SPELL_ENGULFING_MAGIC_TARGETING); + Talk(SAY_ANNOUNCE_ENGULFING_MAGIC); + events.Repeat(Seconds(40)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + uint8 _dazzlingDestructionCount; + }; + + CreatureAI* GetAI(Creature *creature) const override + { + return GetBastionOfTwilightAI(creature); + } +}; + +class boss_valiona : public CreatureScript +{ + public: + boss_valiona() : CreatureScript("boss_valiona") { } + + struct boss_valionaAI : public BossAI + { + boss_valionaAI(Creature* creature) : BossAI(creature, DATA_THERALION_AND_VALIONA) + { + Initialize(); + } + + void Initialize() + { + _deepBreathCount = 0; + _currentRoomSide = SIDE_VALIONA; + + FillDeepBreathPaths(); + } + + void FillDeepBreathPaths() + { + _deepBreathWaypoints.clear(); + + // Pattern is: Valiona's side to Theralion's side + // Just invert the logic to get the opposite result + // Note: for some reason Blizzard has spawned flight + // target stalkers but the positions in sniffs are different + _deepBreathWaypoints = + { + { + // Entrance Lane + { -759.2115f, -604.4235f, 851.0311f }, + { -756.6174f, -767.658f, 850.3376f } + }, + { + // Exit Lane + { -758.427f, -602.9468f, 851.3987f }, + { -757.4211f, -766.2177f, 849.9313f } + }, + { + // Center Lane + { -759.2116f, -604.4235f, 851.0311f }, + { -756.634f, -767.6933f, 850.3306f } + } + }; + Trinity::Containers::RandomShuffle(_deepBreathWaypoints); + } + + void Reset() override + { + _Reset(); + Initialize(); + events.SetPhase(PHASE_INTRO); + DoCastAOE(SPELL_SHARE_HEALTH_2, true); + } + + void JustEngagedWith(Unit* who) override + { + _JustEngagedWith(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me); + events.SetPhase(PHASE_COMBAT); + events.ScheduleEvent(EVENT_BLACKOUT, Seconds(10) + Milliseconds(500)); + events.ScheduleEvent(EVENT_DEVOURING_FLAMES, Seconds(25)); + events.ScheduleEvent(EVENT_LIFTOFF, Minutes(1) + Seconds(37)); + + if (Creature* theralion = instance->GetCreature(DATA_THERALION)) + theralion->AI()->AttackStart(who); + } + + void KilledUnit(Unit* victim) override + { + //if (victim->GetTypeId() == TYPEID_PLAYER) + // Talk(SAY_SLAY); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + } + + void EnterEvadeMode(EvadeReason /*why*/) override + { + _EnterEvadeMode(); + instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me); + me->SendSetPlayHoverAnim(false); + me->SetDisableGravity(false); + me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + summons.DespawnAll(); + _DespawnAtEvade(); + } + + void SpellHit(Unit* caster, SpellInfo const* spell) override + { + if (!caster) + return; + + switch (spell->Id) + { + case SPELL_SHARE_HEALTH_1: + if (!caster->HasAura(SPELL_SHARE_HEALTH_2)) + DoCastAOE(SPELL_SHARE_HEALTH_2, true); + break; + default: + break; + } + } + + void DoAction(int32 action) + { + switch (action) + { + case ACTION_START_ARGUMENT_INTRO: + events.ScheduleEvent(EVENT_TALK_ARGUMENT_1, Seconds(4)); + break; + default: + break; + } + } + + void JustSummoned(Creature* summon) + { + summons.Summon(summon); + + switch (summon->GetEntry()) + { + case NPC_CONVECTIVE_FLAMES: + me->StopMoving(); + me->SetFacingToObject(summon); + DoCast(summon, SPELL_DEVOURING_FLAMES); + break; + default: + break; + } + } + + uint32 GetData(uint32 type) const override + { + return 0; + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) + return; + + switch (id) + { + case POINT_TAKEOFF_DESTINATION: + events.ScheduleEvent(EVENT_TWILIGHT_METEORITE, Seconds(2)); + events.ScheduleEvent(EVENT_DEEP_BREATH, Minutes(1) + Seconds(21)); + break; + case POINT_LAND: + me->SetDisableGravity(false); + me->SendSetPlayHoverAnim(false); + me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + events.ScheduleEvent(EVENT_ATTACK_PLAYERS, Seconds(2)); + break; + case POINT_DEEP_BREATH_1: + events.ScheduleEvent(EVENT_FACE_TO_DIRECTION, Seconds(1)); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO)) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_TALK_ARGUMENT_1: + Talk(SAY_ARGUE_WITH_SIBLING_1); + events.ScheduleEvent(EVENT_TALK_ARGUMENT_2, Seconds(11)); + break; + case EVENT_TALK_ARGUMENT_2: + Talk(SAY_ARGUE_WITH_SIBLING_2); + break; + case EVENT_BLACKOUT: + DoCastAOE(SPELL_BLACKOUT_DUMMY, true); + Talk(SAY_ANNOUNCE_BLACKOUT); + events.Repeat(Seconds(46)); + break; + case EVENT_DEVOURING_FLAMES: + DoCastAOE(SPELL_DEVOURING_FLAMES_TARGETING, true); + events.Repeat(Seconds(41)); + break; + case EVENT_LIFTOFF: + me->AttackStop(); + me->SetReactState(REACT_PASSIVE); + events.CancelEvent(EVENT_BLACKOUT); + events.CancelEvent(EVENT_DEVOURING_FLAMES); + me->PlayOneShotAnimKitId(ANIM_KIT_LIFTOFF); + me->SetDisableGravity(true); + me->SendSetPlayHoverAnim(true); + me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + events.ScheduleEvent(EVENT_FLY_TO_DESTINATION, Seconds(1)); + events.ScheduleEvent(EVENT_DEEP_BREATH, Minutes(1) + Seconds(25) + Milliseconds(100)); + break; + case EVENT_FLY_TO_DESTINATION: + { + Position pos = me->GetPosition(); + pos.m_positionZ += 25.0f; + me->GetMotionMaster()->MovePoint(POINT_TAKEOFF_DESTINATION, pos, false); + break; + } + case EVENT_TWILIGHT_METEORITE: + DoCastAOE(SPELL_TWILIGHT_METEORITE_TARGETING, true); + events.Repeat(Seconds(1) + Milliseconds(200)); + break; + case EVENT_DEEP_BREATH: + if (_deepBreathCount == 0) + events.CancelEvent(EVENT_TWILIGHT_METEORITE); + + if (_currentRoomSide == SIDE_VALIONA) + { + _currentRoomSide = SIDE_THERALION; + me->GetMotionMaster()->MovePoint(POINT_DEEP_BREATH_1, DeepBreathStartingPositions[_currentRoomSide], false); + } + else + { + _currentRoomSide = SIDE_VALIONA; + me->GetMotionMaster()->MovePoint(POINT_DEEP_BREATH_1, DeepBreathStartingPositions[_currentRoomSide], false); + } + _deepBreathCount++; + break; + case EVENT_FACE_TO_DIRECTION: + if (_currentRoomSide == SIDE_THERALION) + { + _currentDeepBreathWaypoint = *_deepBreathWaypoints.begin()->end(); + me->SetFacingTo(me->GetAngle(*_deepBreathWaypoints.begin()->begin())); + } + else if (_currentRoomSide == SIDE_VALIONA) + { + _currentDeepBreathWaypoint = *_deepBreathWaypoints.begin()->begin(); + me->SetFacingTo(me->GetAngle(*_deepBreathWaypoints.begin()->end())); + } + + _deepBreathWaypoints.erase(_deepBreathWaypoints.begin()); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + uint8 _deepBreathCount; + uint8 _currentRoomSide; + Position _currentDeepBreathWaypoint; + std::vector> _deepBreathWaypoints; + }; + + CreatureAI* GetAI(Creature *creature) const override + { + return GetBastionOfTwilightAI(creature); + } +}; + +class spell_theralion_dazzling_destruction_targeting : public SpellScriptLoader +{ + public: + spell_theralion_dazzling_destruction_targeting() : SpellScriptLoader("spell_theralion_dazzling_destruction_targeting") { } + + class spell_theralion_dazzling_destruction_targeting_SpellScript : public SpellScript + { + PrepareSpellScript(spell_theralion_dazzling_destruction_targeting_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_theralion_dazzling_destruction_targeting_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_theralion_dazzling_destruction_targeting_SpellScript(); + } +}; + +class ValidDazzlingDestructionStalkerCheck +{ + public: + ValidDazzlingDestructionStalkerCheck() { } + + bool operator()(WorldObject* object) + { + return (!object->ToUnit()->HasAura(SPELL_DAZZLING_DESTRUCTION_STALKER_VISUAL)); + } +}; + +class spell_theralion_dazzling_destruction_dummy : public SpellScriptLoader +{ + public: + spell_theralion_dazzling_destruction_dummy() : SpellScriptLoader("spell_theralion_dazzling_destruction_dummy") { } + + class spell_theralion_dazzling_destruction_dummy_SpellScript : public SpellScript + { + PrepareSpellScript(spell_theralion_dazzling_destruction_dummy_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + targets.remove_if(ValidDazzlingDestructionStalkerCheck()); + } + + void HandleHit(SpellEffIndex effIndex) + { + if (Unit* caster = GetCaster()) + caster->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[effIndex].BasePoints, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_theralion_dazzling_destruction_dummy_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_theralion_dazzling_destruction_dummy_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_theralion_dazzling_destruction_dummy_SpellScript(); + } +}; + +class IsInTwilightPhaseCheck +{ +public: + IsInTwilightPhaseCheck() { } + + bool operator()(WorldObject* object) + { + return (object->GetPhaseShift().HasPhase(PHASE_ID_TWILIGHT_SHIFT)); + } +}; + +class spell_theralion_dazzling_destruction : public SpellScriptLoader +{ + public: + spell_theralion_dazzling_destruction() : SpellScriptLoader("spell_theralion_dazzling_destruction") { } + + class spell_theralion_dazzling_destruction_SpellScript : public SpellScript + { + PrepareSpellScript(spell_theralion_dazzling_destruction_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_DAZZLING_DESTRUCTION_TWILIGHT_REALM }); + } + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + targets.remove_if(IsInTwilightPhaseCheck()); + } + + void HandleScriptEffect(SpellEffIndex effIndex) + { + GetHitUnit()->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[effIndex].BasePoints, true); + } + + void HandleScriptEffectTrigger(SpellEffIndex effIndex) + { + if (Unit* target = GetHitUnit()) + { + if (GetExplTargetDest() && GetExplTargetDest()->GetPosition() == target->GetPosition()) + { + target->RemoveAllAuras(); + target->CastSpell(target, GetSpellInfo()->Effects[effIndex].BasePoints, true); + target->CastSpell(target, SPELL_DAZZLING_DESTRUCTION_TWILIGHT_REALM, true); + } + } + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_theralion_dazzling_destruction_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_theralion_dazzling_destruction_SpellScript::FilterTargets, EFFECT_2, TARGET_UNIT_DEST_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_theralion_dazzling_destruction_SpellScript::HandleScriptEffectTrigger, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + OnEffectHitTarget += SpellEffectFn(spell_theralion_dazzling_destruction_SpellScript::HandleScriptEffect, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_theralion_dazzling_destruction_SpellScript(); + } +}; + +class TwilightProtectionCheck +{ + public: + TwilightProtectionCheck() { } + + bool operator()(WorldObject* object) + { + return (object->ToUnit()->HasAura(SPELL_TWILIGHT_PROTECTION_BUFF) + || !object->GetPhaseShift().HasPhase(PHASE_ID_TWILIGHT_SHIFT)); + } +}; + +class spell_theralion_dazzling_destruction_twilight_realm: public SpellScriptLoader +{ + public: + spell_theralion_dazzling_destruction_twilight_realm() : SpellScriptLoader("spell_theralion_dazzling_destruction_twilight_realm") { } + + class spell_theralion_dazzling_destruction_twilight_realm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_theralion_dazzling_destruction_twilight_realm_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + targets.remove_if(TwilightProtectionCheck()); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_theralion_dazzling_destruction_twilight_realm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_theralion_dazzling_destruction_twilight_realm_SpellScript(); + } +}; + +class spell_theralion_twilight_shift: public SpellScriptLoader +{ + public: + spell_theralion_twilight_shift() : SpellScriptLoader("spell_theralion_twilight_shift") { } + + class spell_theralion_twilight_shift_SpellScript : public SpellScript + { + PrepareSpellScript(spell_theralion_twilight_shift_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + targets.remove_if(IsInTwilightPhaseCheck()); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_theralion_twilight_shift_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_theralion_twilight_shift_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENEMY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_theralion_twilight_shift_SpellScript::FilterTargets, EFFECT_2, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_theralion_twilight_shift_SpellScript(); + } +}; + +class spell_theralion_fabulous_flames_targeting : public SpellScriptLoader +{ + public: + spell_theralion_fabulous_flames_targeting() : SpellScriptLoader("spell_theralion_fabulous_flames_targeting") { } + + class spell_theralion_fabulous_flames_targeting_SpellScript : public SpellScript + { + PrepareSpellScript(spell_theralion_fabulous_flames_targeting_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void HandleHit(SpellEffIndex effIndex) + { + if (Unit* caster = GetCaster()) + caster->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[effIndex].BasePoints, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_theralion_fabulous_flames_targeting_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_theralion_fabulous_flames_targeting_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_theralion_fabulous_flames_targeting_SpellScript(); + } +}; + +class SpellcasterClassCheck +{ + public: + SpellcasterClassCheck() { } + + bool operator()(WorldObject* object) + { + if (Unit* target = object->ToUnit()) + return (target->getClass() == CLASS_HUNTER + || target->getClass() == CLASS_WARRIOR + || target->getClass() == CLASS_DEATH_KNIGHT); + + return false; + } +}; + +class spell_theralion_engulfing_magic_targeting : public SpellScriptLoader +{ + public: + spell_theralion_engulfing_magic_targeting() : SpellScriptLoader("spell_theralion_engulfing_magic_targeting") { } + + class spell_theralion_engulfing_magic_targeting_SpellScript : public SpellScript + { + PrepareSpellScript(spell_theralion_engulfing_magic_targeting_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + // according to sniffs if no spellcaster class is found, the current victim is the target instead + if (targets.size() > 1) + targets.remove_if(SpellcasterClassCheck()); + + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_theralion_engulfing_magic_targeting_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_theralion_engulfing_magic_targeting_SpellScript(); + } +}; + +class spell_theralion_engulfing_magic : public SpellScriptLoader +{ + public: + spell_theralion_engulfing_magic() : SpellScriptLoader("spell_theralion_engulfing_magic") { } + + class spell_theralion_engulfing_magic_AuraScript : public AuraScript + { + PrepareAuraScript(spell_theralion_engulfing_magic_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_ENGULFING_MAGIC_TRIGGERED }); + } + + void HandleProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) + { + PreventDefaultAction(); + int32 bp = 0; + if (HealInfo* healInfo = eventInfo.GetHealInfo()) + bp += healInfo->GetHeal(); + + if (DamageInfo* dmgInfo = eventInfo.GetDamageInfo()) + bp += dmgInfo->GetDamage(); + + if (bp) + GetCaster()->CastCustomSpell(GetCaster(), SPELL_ENGULFING_MAGIC_TRIGGERED, &bp, nullptr, nullptr, true, nullptr, aurEff); + } + + void Register() override + { + OnEffectProc += AuraEffectProcFn(spell_theralion_engulfing_magic_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_MOD_DAMAGE_PERCENT_DONE); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_theralion_engulfing_magic_AuraScript(); + } +}; + +class spell_valiona_blackout_dummy : public SpellScriptLoader +{ + public: + spell_valiona_blackout_dummy() : SpellScriptLoader("spell_valiona_blackout_dummy") { } + + class spell_valiona_blackout_dummy_SpellScript : public SpellScript + { + PrepareSpellScript(spell_valiona_blackout_dummy_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void HandleHit(SpellEffIndex effIndex) + { + if (Unit* caster = GetCaster()) + caster->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[effIndex].BasePoints, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_valiona_blackout_dummy_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_valiona_blackout_dummy_SpellScript::HandleHit, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_valiona_blackout_dummy_SpellScript(); + } +}; + +class spell_valiona_blackout: public SpellScriptLoader +{ + public: + spell_valiona_blackout() : SpellScriptLoader("spell_valiona_blackout") { } + + class spell_valiona_blackout_AuraScript : public AuraScript + { + PrepareAuraScript(spell_valiona_blackout_AuraScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + return ValidateSpellInfo({ SPELL_BLACKOUT_DAMAGE }); + } + + void OnAuraRemoveHandler(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_ENEMY_SPELL + || GetTargetApplication()->GetRemoveMode() == AURA_REMOVE_BY_EXPIRE) + if (Unit* target = GetTarget()) + target->CastSpell(target, SPELL_BLACKOUT_DAMAGE, true); + } + + void Register() override + { + AfterEffectRemove += AuraEffectRemoveFn(spell_valiona_blackout_AuraScript::OnAuraRemoveHandler, EFFECT_0, SPELL_AURA_SCHOOL_HEAL_ABSORB, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_valiona_blackout_AuraScript(); + } +}; + +class spell_valiona_devouring_flames_targeting : public SpellScriptLoader +{ + public: + spell_valiona_devouring_flames_targeting() : SpellScriptLoader("spell_valiona_devouring_flames_targeting") { } + + class spell_valiona_devouring_flames_targeting_SpellScript : public SpellScript + { + PrepareSpellScript(spell_valiona_devouring_flames_targeting_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_valiona_devouring_flames_targeting_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_valiona_devouring_flames_targeting_SpellScript(); + } +}; + +class spell_valiona_devouring_flames : public SpellScriptLoader +{ + public: + spell_valiona_devouring_flames() : SpellScriptLoader("spell_valiona_devouring_flames") { } + + class spell_valiona_devouring_flames_SpellScript : public SpellScript + { + PrepareSpellScript(spell_valiona_devouring_flames_SpellScript); + + void ChangeDamage() + { + if (Unit* caster = GetCaster()) + { + uint32 damageReduction = CalculatePct(GetHitDamage(), GetHitUnit()->GetDistance(caster)); + SetHitDamage(GetHitDamage() - damageReduction); + } + } + + void Register() override + { + OnHit += SpellHitFn(spell_valiona_devouring_flames_SpellScript::ChangeDamage); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_valiona_devouring_flames_SpellScript(); + } +}; + +class TheralionVictimCheck +{ + public: + TheralionVictimCheck(Unit* _theralion) : theralion(_theralion) { } + + bool operator()(WorldObject* object) + { + return (theralion->GetVictim() && theralion->GetVictim() == object->ToUnit()); + } + private: + Unit* theralion; + +}; + +class spell_valiona_twilight_meteorite_targeting : public SpellScriptLoader +{ + public: + spell_valiona_twilight_meteorite_targeting() : SpellScriptLoader("spell_valiona_twilight_meteorite_targeting") { } + + class spell_valiona_twilight_meteorite_targeting_SpellScript : public SpellScript + { + PrepareSpellScript(spell_valiona_twilight_meteorite_targeting_SpellScript); + + void FilterTargets(std::list& targets) + { + if (targets.empty()) + return; + + if (Unit* caster = GetCaster()) + if (InstanceScript* instance = caster->GetInstanceScript()) + if (Creature* theralion = instance->GetCreature(DATA_THERALION)) + targets.remove_if(TheralionVictimCheck(theralion)); + + if (targets.empty()) + return; + + Trinity::Containers::RandomResize(targets, 1); + } + + void HandleEffect(SpellEffIndex effIndex) + { + if (Unit* caster = GetCaster()) + caster->CastSpell(GetHitUnit(), GetSpellInfo()->Effects[effIndex].BasePoints); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_valiona_twilight_meteorite_targeting_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_valiona_twilight_meteorite_targeting_SpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_valiona_twilight_meteorite_targeting_SpellScript(); + } +}; + +void AddSC_boss_theralion_and_valiona() +{ + new boss_theralion(); + new boss_valiona(); + + new spell_theralion_dazzling_destruction_targeting(); + new spell_theralion_dazzling_destruction_dummy(); + new spell_theralion_dazzling_destruction(); + new spell_theralion_dazzling_destruction_twilight_realm(); + new spell_theralion_twilight_shift(); + new spell_theralion_fabulous_flames_targeting(); + new spell_theralion_engulfing_magic_targeting(); + new spell_theralion_engulfing_magic(); + + new spell_valiona_blackout_dummy(); + new spell_valiona_blackout(); + new spell_valiona_devouring_flames_targeting(); + new spell_valiona_devouring_flames(); + new spell_valiona_twilight_meteorite_targeting(); +} diff --git a/src/server/scripts/EasternKingdoms/BastionOfTwilight/instance_bastion_of_twilight.cpp b/src/server/scripts/EasternKingdoms/BastionOfTwilight/instance_bastion_of_twilight.cpp index 1e212d8583f..306f0b6d7e6 100644 --- a/src/server/scripts/EasternKingdoms/BastionOfTwilight/instance_bastion_of_twilight.cpp +++ b/src/server/scripts/EasternKingdoms/BastionOfTwilight/instance_bastion_of_twilight.cpp @@ -69,6 +69,8 @@ uint32 HalfusDragonEntries[] = NPC_ORPHANED_EMERALD_WELP }; +Position const BreathFlightTargetStalkerSortPos = { -740.677f, -592.328f, 859.455f }; + class instance_bastion_of_twilight : public InstanceMapScript { public: @@ -126,6 +128,15 @@ class instance_bastion_of_twilight : public InstanceMapScript if (creature->GetPositionZ() < 850.0f) _dancingFlamesInvisibleStalkerGUIDs.insert(creature->GetGUID()); break; + case NPC_CONVECTIVE_FLAMES: + if (Creature* valiona = GetCreature(DATA_VALIONA)) + valiona->AI()->JustSummoned(creature); + break; + case NPC_DAZZLING_DESTRUCTION_STALKER: + case NPC_FABULOUS_FLAMES: + if (Creature* theralion = GetCreature(DATA_THERALION)) + theralion->AI()->JustSummoned(creature); + break; default: break; } @@ -286,6 +297,29 @@ class instance_bastion_of_twilight : public InstanceMapScript if (orphanedEmeraldWhelp->GetEntry() == NPC_ORPHANED_EMERALD_WELP) orphanedEmeraldWhelp->AI()->DoAction(ACTION_MOVE_OUT_OF_CAGE); break; + case DATA_AT_HALFUS_INTRO: + if (_lastAreatriggerIndex < AT_INDEX_HALFUS_WYRMBREAKER_INTRO) + { + _lastAreatriggerIndex = AT_INDEX_HALFUS_WYRMBREAKER_INTRO; + SaveToDB(); + } + break; + case DATA_AT_THERALION_AND_VALIONA_INTRO: + if (_lastAreatriggerIndex < AT_INDEX_THERALION_AND_VALIONA_INTRO) + { + if (Creature* chogall = GetCreature(DATA_CHOGALL)) + chogall->AI()->DoAction(ACTION_TALK_INTRO_THERALION_AND_VALIONA); + + if (Creature* theralion = GetCreature(DATA_THERALION)) + theralion->AI()->DoAction(ACTION_START_ARGUMENT_INTRO); + + if (Creature* valiona = GetCreature(DATA_VALIONA)) + valiona->AI()->DoAction(ACTION_START_ARGUMENT_INTRO); + + _lastAreatriggerIndex = AT_INDEX_THERALION_AND_VALIONA_INTRO; + SaveToDB(); + } + break; default: break; } diff --git a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp index 1b90ffc9bd5..91ced24f25f 100644 --- a/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp +++ b/src/server/scripts/EasternKingdoms/eastern_kingdoms_script_loader.cpp @@ -25,7 +25,9 @@ void AddSC_boss_alizabal(); //Baradin Hold void AddSC_boss_occuthar(); void AddSC_boss_pit_lord_argaloth(); void AddSC_instance_baradin_hold(); -void AddSC_boss_halfus_wyrmbreaker(); //Bastion of Twilight +void AddSC_bastion_of_twilight(); //Bastion of Twilight +void AddSC_boss_halfus_wyrmbreaker(); +void AddSC_boss_theralion_and_valiona(); void AddSC_instance_bastion_of_twilight(); void AddSC_boss_romogg_bonecrusher(); //Blackrock Caverns void AddSC_boss_corla(); @@ -235,7 +237,9 @@ void AddEasternKingdomsScripts() AddSC_boss_occuthar(); AddSC_boss_pit_lord_argaloth(); AddSC_instance_baradin_hold(); - AddSC_boss_halfus_wyrmbreaker(); //Bastion of Twilight + AddSC_bastion_of_twilight(); //Bastion of Twilight + AddSC_boss_halfus_wyrmbreaker(); + AddSC_boss_theralion_and_valiona(); AddSC_instance_bastion_of_twilight(); AddSC_boss_romogg_bonecrusher(); //Blackrock Caverns AddSC_boss_corla();