aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/world/3.3.5/2025_12_14_03_world.sql2
-rw-r--r--sql/updates/world/3.3.5/2025_12_15_00_world.sql29
-rw-r--r--sql/updates/world/3.3.5/2025_12_17_00_world.sql63
-rw-r--r--src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp844
4 files changed, 537 insertions, 401 deletions
diff --git a/sql/updates/world/3.3.5/2025_12_14_03_world.sql b/sql/updates/world/3.3.5/2025_12_14_03_world.sql
new file mode 100644
index 00000000000..a2e8b2d5de5
--- /dev/null
+++ b/sql/updates/world/3.3.5/2025_12_14_03_world.sql
@@ -0,0 +1,2 @@
+--
+UPDATE `gameobject` SET `phaseMask`=`phaseMask`|8 WHERE `guid` IN (151102,151103,151104,151105,151106) AND `id` IN (202184,202347,202348,202349,202350);
diff --git a/sql/updates/world/3.3.5/2025_12_15_00_world.sql b/sql/updates/world/3.3.5/2025_12_15_00_world.sql
new file mode 100644
index 00000000000..693c0d5abca
--- /dev/null
+++ b/sql/updates/world/3.3.5/2025_12_15_00_world.sql
@@ -0,0 +1,29 @@
+--
+UPDATE `quest_offer_reward` SET `Emote1`=0, `Emote2`=0, `Emote3`=0, `Emote4`=0, `RewardText`="Wintergarde is saved because of you, $N. To think that one woman could so swiftly turn the tides of battle is hard for most to comprehend; yet here we are - victorious! You have managed to restore the faith of these people and earned the respect of your commanding officers.$B$B<Halford salutes.>$B$BLord Fordragon has returned to Angrathar to prepare our forces for the destruction of the Wrathgate and has requested that you join him! I couldn't recommend a better soldier for the job, $N.", `VerifiedBuild`=12340 WHERE `ID`=12473;
+
+UPDATE `gameobject` SET `position_x`=-8750.37, `position_y`=-2258.32, `position_z`=155.634, `orientation`=0.453786 WHERE `guid`=18679 AND `id`=1731;
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId`=17 AND `SourceEntry`=40969;
+
+UPDATE `creature_template` SET `AIName`='SmartAI' WHERE `entry`=10928;
+DELETE FROM `smart_scripts` WHERE `entryorguid`=10928 AND `source_type`=0;
+INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES('10928','0','0','0','0','0','100','0','2000','4000','4000','7000','0','11','32202','0','0','0','0','0','2','0','0','0','0','0','0','0','0',"Succubus Minion - In Combat - Cast 'Lash of Pain'");
+
+UPDATE `graveyard_zone` SET `GhostZone`=139, `Comment`="Western Plaguelands, Hearthglen - Eastern Plaguelands" WHERE `ID`=1451;
+
+UPDATE `gameobject_template_addon` SET `faction`=474 WHERE `entry`=184085;
+
+UPDATE `creature` SET `spawnMask`=`spawnMask`|1 WHERE `guid` IN (68283,68284) AND `id`=31104;
+
+UPDATE `quest_template_addon` SET `PrevQuestID`=9898 WHERE `ID`=9899;
+
+DELETE FROM `creature` WHERE `guid`=3564 AND `id`=1135;
+DELETE FROM `spawn_group` WHERE `spawnType`=0 AND `spawnId`=3564;
+INSERT INTO `creature` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `modelid`, `equipment_id`, `position_x`, `position_y`, `position_z`, `orientation`, `spawntimesecs`, `wander_distance`, `currentwaypoint`, `curhealth`, `curmana`, `MovementType`, `npcflag`, `unit_flags`, `dynamicflags`, `ScriptName`, `StringId`, `VerifiedBuild`) VALUES('3564','1135','0','0','0','1','1','0','0','-5625.61','-178.399','365.835','4.7822','300','0','0','120','0','0','0','0','0','',NULL,'0');
+INSERT INTO `spawn_group` (`groupId`, `spawnType`, `spawnId`) VALUES('2','0','3564');
+
+UPDATE `creature_template` SET `mechanic_immune_mask`=`mechanic_immune_mask`|4 WHERE `entry` IN (31368, 29306);
+
+UPDATE `npc_vendor` SET `incrtime`=9000 WHERE `entry`=14860 AND `item`=11027;
+
+UPDATE `quest_template_addon` SET `PrevQuestID`=11239 WHERE `ID`=11432;
diff --git a/sql/updates/world/3.3.5/2025_12_17_00_world.sql b/sql/updates/world/3.3.5/2025_12_17_00_world.sql
new file mode 100644
index 00000000000..33e02ad8e1f
--- /dev/null
+++ b/sql/updates/world/3.3.5/2025_12_17_00_world.sql
@@ -0,0 +1,63 @@
+-- Flame Quills
+UPDATE `spell_target_position` SET `PositionX` = 244.1, `PositionY` = 49.9153, `PositionZ` = 20.1795, `VerifiedBuild` = 26365 WHERE `ID` = 34269;
+UPDATE `spell_target_position` SET `PositionX` = 260.572, `PositionY` = 67.3991, `PositionZ` = 20.1799, `VerifiedBuild` = 26365 WHERE `ID` = 34270;
+UPDATE `spell_target_position` SET `PositionX` = 279.967, `PositionY` = 83.4335, `PositionZ` = 20.1794, `VerifiedBuild` = 26365 WHERE `ID` = 34271;
+UPDATE `spell_target_position` SET `PositionX` = 306.56, `PositionY` = 92.0271, `PositionZ` = 20.1798, `VerifiedBuild` = 26365 WHERE `ID` = 34272;
+UPDATE `spell_target_position` SET `PositionX` = 332.415, `PositionY` = 86.6608, `PositionZ` = 20.3436, `VerifiedBuild` = 26365 WHERE `ID` = 34273;
+UPDATE `spell_target_position` SET `PositionX` = 358.834, `PositionY` = 90.569, `PositionZ` = 20.032, `VerifiedBuild` = 26365 WHERE `ID` = 34274;
+UPDATE `spell_target_position` SET `PositionX` = 382.319, `PositionY` = 83.0517, `PositionZ` = 20.1796, `VerifiedBuild` = 26365 WHERE `ID` = 34275;
+UPDATE `spell_target_position` SET `PositionX` = 403.761, `PositionY` = 69.5173, `PositionZ` = 20.1796, `VerifiedBuild` = 26365 WHERE `ID` = 34276;
+UPDATE `spell_target_position` SET `PositionX` = 402.296, `PositionY` = 44.3146, `PositionZ` = 20.1797, `VerifiedBuild` = 26365 WHERE `ID` = 34277;
+UPDATE `spell_target_position` SET `PositionX` = 422.53, `PositionY` = 26.9552, `PositionZ` = 20.1798, `VerifiedBuild` = 26365 WHERE `ID` = 34278;
+UPDATE `spell_target_position` SET `PositionX` = 261.468, `PositionY` = -73.6918, `PositionZ` = 20.1795, `VerifiedBuild` = 26365 WHERE `ID` = 34279;
+UPDATE `spell_target_position` SET `PositionX` = 249.358, `PositionY` = -52.7987, `PositionZ` = 20.1795, `VerifiedBuild` = 26365 WHERE `ID` = 34280;
+UPDATE `spell_target_position` SET `PositionX` = 424.829, `PositionY` = 1.01505, `PositionZ` = 20.18, `VerifiedBuild` = 26365 WHERE `ID` = 34281;
+UPDATE `spell_target_position` SET `PositionX` = 423.478, `PositionY` = -23.9648, `PositionZ` = 20.1799, `VerifiedBuild` = 26365 WHERE `ID` = 34282;
+UPDATE `spell_target_position` SET `PositionX` = 283.424, `PositionY` = -85.9517, `PositionZ` = 20.1798, `VerifiedBuild` = 26365 WHERE `ID` = 34283;
+UPDATE `spell_target_position` SET `PositionX` = 404.622, `PositionY` = -42.1397, `PositionZ` = 20.1798, `VerifiedBuild` = 26365 WHERE `ID` = 34284;
+UPDATE `spell_target_position` SET `PositionX` = 309.55, `PositionY` = -89.3632, `PositionZ` = 20.1796, `VerifiedBuild` = 26365 WHERE `ID` = 34285;
+UPDATE `spell_target_position` SET `PositionX` = 403.462, `PositionY` = -67.8334, `PositionZ` = 20.18, `VerifiedBuild` = 26365 WHERE `ID` = 34286;
+UPDATE `spell_target_position` SET `PositionX` = 335.024, `PositionY` = -83.21, `PositionZ` = 20.388, `VerifiedBuild` = 26365 WHERE `ID` = 34287;
+UPDATE `spell_target_position` SET `PositionX` = 384.251, `PositionY` = -84.3709, `PositionZ` = 20.18, `VerifiedBuild` = 26365 WHERE `ID` = 34288;
+UPDATE `spell_target_position` SET `PositionX` = 359.997, `PositionY` = -92.7042, `PositionZ` = 20.0127, `VerifiedBuild` = 26365 WHERE `ID` = 34289;
+UPDATE `spell_target_position` SET `PositionX` = 241.768, `PositionY` = 24.8276, `PositionY` = 20.3438, `VerifiedBuild` = 26365 WHERE `ID` = 34314;
+UPDATE `spell_target_position` SET `PositionX` = 239.111, `PositionY` = -1.59108, `PositionY` = 27.0491, `VerifiedBuild` = 26365 WHERE `ID` = 34315;
+UPDATE `spell_target_position` SET `PositionX` = 241.073, `PositionY` = -27.0846, `PositionY` = 20.1794, `VerifiedBuild` = 26365 WHERE `ID` = 34316;
+
+-- Ashtongue Ruse
+UPDATE `spell_dbc` SET `ProcChance` = 101, `Effect1` = 6, `EffectImplicitTargetA1` = 1, `EffectApplyAuraName1` = 4, `DmgMultiplier1` = 1 WHERE `Id` = 39555;
+UPDATE `spell_dbc` SET `ProcChance` = 101, `Effect1` = 16, `EffectImplicitTargetA1` = 1, `EffectMiscValue1` = 10946, `DmgMultiplier1` = 1 WHERE `Id` = 39701;
+
+DELETE FROM `spell_script_names` WHERE `ScriptName` = 'spell_alar_ashtongue_ruse_master';
+INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
+(39555, 'spell_alar_ashtongue_ruse_master');
+
+UPDATE `quest_template_addon` SET `SpecialFlags` = 2 WHERE `ID` = 10946;
+
+-- Flame Patch
+UPDATE `spell_dbc` SET `EffectApplyAuraName1` = 0 WHERE `Id` = 29218;
+
+-- Ember Blast (damage component)
+UPDATE `spell_dbc` SET `ProcChance` = 101, `Effect1` = 2, `EffectBasePoints1` = 70000, `EffectImplicitTargetA1` = 38, `DmgMultiplier1` = 1, `DmgMultiplier2` = 1, `DmgMultiplier3` = 1 WHERE `Id` = 41910;
+
+DELETE FROM `conditions` WHERE `SourceTypeOrReferenceId` = 13 AND `SourceEntry` = 41910;
+INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES
+(13,1,41910,0,0,31,0,3,19514,0,0,0,0,"","Group 0: Spell 'Ember Blast' (Effect 0) targets creature 'Al'ar'");
+
+DELETE FROM `spell_custom_attr` WHERE `entry` = 41910;
+INSERT INTO `spell_custom_attr` (`entry`, `attributes`) VALUES
+(41910, 32768); -- SPELL_ATTR0_CU_IGNORE_ARMOR
+
+-- Ember of Al'ar (copied from 39110, matches sniff)
+UPDATE `spell_dbc` SET `ProcChance` = 101, `EquippedItemSubClassMask` = -1, `Effect1` = 28, `EffectDieSides1` = 1, `EffectImplicitTargetA1` = 72, `EffectRadiusIndex1` = 13, `EffectMiscValue1` = 19551, `EffectMiscValueB1` = 64, `DmgMultiplier1` = 1, `DmgMultiplier2` = 1, `DmgMultiplier3` = 1 WHERE `Id` = 41824;
+
+-- Platforms
+UPDATE `creature` SET `StringId` = 'AlarPlatformTrigger1' WHERE `guid` = 144097 AND `id` = 15384;
+UPDATE `creature` SET `StringId` = 'AlarPlatformTrigger2' WHERE `guid` = 144100 AND `id` = 15384;
+UPDATE `creature` SET `StringId` = 'AlarPlatformTrigger3' WHERE `guid` = 144099 AND `id` = 15384;
+UPDATE `creature` SET `StringId` = 'AlarPlatformTrigger4' WHERE `guid` = 144098 AND `id` = 15384;
+UPDATE `creature` SET `StringId` = 'AlarCenterTrigger' WHERE `guid` = 144096 AND `id` = 15384;
+
+-- A'lar
+UPDATE `creature_template` SET `flags_extra` = `flags_extra` |512 WHERE `entry` = 19514;
+UPDATE `creature_template_movement` SET `Ground` = 1 WHERE `CreatureId` = 19514;
diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp
index 27df691b571..13863f16b2d 100644
--- a/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp
+++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_alar.cpp
@@ -15,68 +15,124 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/* ScriptData
-SDName: boss_alar
-SD%Complete: 95
-SDComment:
-SDCategory: Tempest Keep, The Eye
-EndScriptData */
+/*
+ * Everything related to Flame Quills requires sniff verification
+ * When moving to triggers, A'lar shouldn't move to exact trigger's position (positions in sniffs are always different)
+ * Combat timers requires to be revisited
+ * If summoned not on platform, embers should be summoned on the floor, not fall on the floor
+ * SPELL_ASHTONGUE_RUSE_MASTER doesn't appear in sniffs despite it's an aura. Maybe it was a wrong decision to use it
+ */
#include "ScriptMgr.h"
#include "InstanceScript.h"
#include "MotionMaster.h"
-#include "ObjectAccessor.h"
#include "ScriptedCreature.h"
+#include "SpellAuraEffects.h"
#include "SpellInfo.h"
#include "SpellScript.h"
-#include "TemporarySummon.h"
#include "the_eye.h"
-enum Spells
+enum AlarSpells
+{
+ // Phase 1
+ SPELL_SUMMON_PHOENIX_ADDS_1 = 41824,
+ SPELL_FLAME_QUILLS = 34229,
+
+ // Phase 1 & 2
+ SPELL_FLAME_BUFFET = 34121,
+
+ // Transition
+ SPELL_CLEAR_ALL_DEBUFFS = 34098,
+ SPELL_EMBER_BLAST_INVIS = 34341,
+ SPELL_FLIGHT_MODE = 31514,
+ SPELL_REBIRTH = 34342,
+
+ // Phase 2
+ SPELL_SUMMON_FLAME_RING = 29218,
+ SPELL_MELT_ARMOR = 35410,
+ SPELL_CHARGE = 35412,
+ SPELL_BERSERK = 26662,
+
+ // Phase 2: Dive Bomb
+ SPELL_DIVE_BOMB_VISUAL = 35367,
+ SPELL_DIVE_BOMB = 35181,
+ SPELL_REBIRTH_2 = 35369,
+ SPELL_SUMMON_PHOENIX_ADDS_2 = 39110,
+
+ // Ember of Al'ar
+ SPELL_EMBER_BLAST = 34133,
+ SPELL_EMBER_BLAST_DAMAGE = 41910,
+
+ // Flame Patch
+ SPELL_FLAME_PATCH_PERIODIC = 35380,
+
+ // Ruse of the Ashtongue
+ SPELL_ASHTONGUE_RUSE_DUMMY = 39527,
+ SPELL_ASHTONGUE_RUSE_MASTER = 39555,
+ SPELL_ASHTONGUE_RUSE_CREDIT = 39701
+};
+
+enum AlarEvents
{
- SPELL_FLAME_BUFFET = 34121, // Flame Buffet - every 1, 5 secs in phase 1 if there is no victim in melee range and after Dive Bomb in phase 2 with same conditions
- SPELL_FLAME_QUILLS = 34229, // Randomly after changing position in phase after watching tons of movies, set probability 20%
- SPELL_REBIRTH = 34342, // Rebirth - beginning of second phase(after losing all health in phase 1)
- SPELL_REBIRTH_2 = 35369, // Rebirth(another, without healing to full HP) - after Dive Bomb in phase 2
- SPELL_MELT_ARMOR = 35410, // Melt Armor - every 60 sec in phase 2
- SPELL_CHARGE = 35412, // Charge - 30 sec cooldown
- SPELL_DIVE_BOMB_VISUAL = 35367, // Bosskillers says 30 sec cooldown, wowwiki says 30 sec colldown, DBM and BigWigs addons says ~47 sec
- SPELL_DIVE_BOMB = 35181, // after watching tonns of movies, set cooldown to 40+rand()%5.
- SPELL_BERSERK = 45078, // 10 minutes after phase 2 starts(id is wrong, but proper id is unknown)
-
- CREATURE_EMBER_OF_ALAR = 19551, // Al'ar summons one Ember of Al'ar every position change in phase 1 and two after Dive Bomb. Also in phase 2 when Ember of Al'ar dies, boss loses 3% health.
- SPELL_EMBER_BLAST = 34133, // When Ember of Al'ar dies, it casts Ember Blast
-
- CREATURE_FLAME_PATCH_ALAR = 20602, // Flame Patch - every 30 sec in phase 2
- SPELL_FLAME_PATCH = 35380, //
+ // Phase 1
+ EVENT_MOVE_TO_PLATFORM = 1,
+ EVENT_FLAME_QUILLS,
+
+ // Phase 1 & 2
+ EVENT_FLAME_BUFFET,
+
+ // Transition
+ EVENT_TRANSITION_1,
+ EVENT_TRANSITION_2,
+ EVENT_TRANSITION_3,
+ EVENT_TRANSITION_4,
+ EVENT_TRANSITION_5,
+
+ // Phase 2
+ EVENT_FLAME_RING,
+ EVENT_MELT_ARMOR,
+ EVENT_CHARGE_ALAR,
+ EVENT_BERSERK,
+
+ // Phase 2: Dive Bomb
+ EVENT_DIVE_BOMB_1,
+ EVENT_DIVE_BOMB_2,
+ EVENT_DIVE_BOMB_3,
+ EVENT_DIVE_BOMB_4,
+ EVENT_DIVE_BOMB_5,
+ EVENT_DIVE_BOMB_6,
+ EVENT_DIVE_BOMB_7
};
-static float waypoint[6][3] =
+enum AlarPoints
{
- {340.15f, 58.65f, 17.71f},
- {388.09f, 31.54f, 20.18f},
- {388.18f, -32.85f, 20.18f},
- {340.29f, -60.19f, 17.72f},
- {332.0f, 0.01f, 39.0f}, // better not use the same xy coord
- {331.0f, 0.01f, -2.39f}
+ POINT_PLATFORM = 0,
+ POINT_CENTER = 1,
+ POINT_RESSURRECTION = 2,
+ POINT_DIVE_BOMB = 3
};
-enum WaitEventType
+enum AlarActions
{
- WE_NONE = 0,
- WE_DUMMY = 1,
- WE_PLATFORM = 2,
- WE_QUILL = 3,
- WE_DIE = 4,
- WE_REVIVE = 5,
- WE_CHARGE = 6,
- WE_METEOR = 7,
- WE_DIVE = 8,
- WE_LAND = 9,
- WE_SUMMON = 10
+ ACTION_FLAME_QUILLS_END = 0
};
-uint32 const flameQuillsSpells[] =
+enum AlarMisc
+{
+ MODEL_INVISIBLE = 14501
+};
+
+static constexpr std::array<std::string_view, 4> AlarPlatformTrigger =
+{
+ "AlarPlatformTrigger1",
+ "AlarPlatformTrigger2",
+ "AlarPlatformTrigger3",
+ "AlarPlatformTrigger4"
+};
+
+static constexpr std::string_view CenterTriggerStringId = "AlarCenterTrigger";
+
+static constexpr std::array<uint32, 24> FlameQuillsSpells =
{
34269,
34270,
@@ -104,449 +160,404 @@ uint32 const flameQuillsSpells[] =
34316
};
+Position const AlarRessurrectionPosition = { 333.589f, -0.768249f, -2.38949f };
+
+// 19514 - Al'ar
struct boss_alar : public BossAI
{
- boss_alar(Creature* creature) : BossAI(creature, DATA_ALAR)
+ boss_alar(Creature* creature) : BossAI(creature, DATA_ALAR),
+ _isFirstPhase(true), _isInTransition(false), _isFirstPlatform(true), _shouldSpawnEmber(false), _currentPlatform(0) { }
+
+ void JustAppeared() override
{
- Initialize();
- DefaultMoveSpeedRate = creature->GetSpeedRate(MOVE_RUN);
- DiveBomb_Timer = 0;
- MeltArmor_Timer = 0;
- Charge_Timer = 0;
- FlamePatch_Timer = 0;
+ me->SetDisableGravity(true);
}
- void Initialize()
+ void JustEngagedWith(Unit* who) override
{
- Berserk_Timer = 1200000;
- Platforms_Move_Timer = 0;
+ BossAI::JustEngagedWith(who);
- Phase1 = true;
- WaitEvent = WE_NONE;
- WaitTimer = 0;
- AfterMoving = false;
- ForceMove = false;
- ForceTimer = 5000;
+ me->GetMotionMaster()->MoveIdle();
+ me->SetReactState(REACT_PASSIVE);
- cur_wp = 4;
+ events.ScheduleEvent(EVENT_MOVE_TO_PLATFORM, 0s);
}
- WaitEventType WaitEvent;
- uint32 WaitTimer;
-
- bool AfterMoving;
-
- uint32 Platforms_Move_Timer;
- uint32 DiveBomb_Timer;
- uint32 MeltArmor_Timer;
- uint32 Charge_Timer;
- uint32 FlamePatch_Timer;
- uint32 Berserk_Timer;
+ void DamageTaken(Unit* /*doneBy*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
+ {
+ if (damage >= me->GetHealth() && _isFirstPhase)
+ {
+ damage = me->GetHealth() - 1;
- float DefaultMoveSpeedRate;
+ if (_isInTransition)
+ return;
- bool Phase1;
- bool ForceMove;
- uint32 ForceTimer;
+ _isInTransition = true;
- int8 cur_wp;
+ events.Reset();
+ events.ScheduleEvent(EVENT_TRANSITION_1, 0s);
+ }
+ }
- void Reset() override
+ void MovementInform(uint32 type, uint32 id) override
{
- Initialize();
- _Reset();
-
- me->SetDisplayId(me->GetNativeDisplayId());
- me->SetSpeedRate(MOVE_RUN, DefaultMoveSpeedRate);
- //me->SetBoundingRadius(10);
- //me->SetCombatReach(10);
- me->SetDisableGravity(true);
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->setActive(false);
+ if (type == POINT_MOTION_TYPE)
+ {
+ switch (id)
+ {
+ case POINT_PLATFORM:
+ events.ScheduleEvent(EVENT_FLAME_BUFFET, 1s);
+ me->SetControlled(true, UNIT_STATE_ROOT);
+ me->SetDisableGravity(false);
+ me->SetHover(false);
+ me->SetReactState(REACT_AGGRESSIVE);
+ break;
+ case POINT_CENTER:
+ events.ScheduleEvent(EVENT_FLAME_QUILLS, 0s);
+ break;
+ case POINT_DIVE_BOMB:
+ events.ScheduleEvent(EVENT_DIVE_BOMB_2, 2400ms);
+ break;
+ default:
+ break;
+ }
+ }
}
- void JustEngagedWith(Unit* who) override
+ void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
{
- BossAI::JustEngagedWith(who);
- me->SetDisableGravity(true); // after enterevademode will be set walk movement
- me->setActive(true);
+ if (spellInfo->Id == SPELL_DIVE_BOMB_VISUAL)
+ events.ScheduleEvent(EVENT_DIVE_BOMB_3, 0s);
}
- void JustSummoned(Creature* summon) override
+ void OnSpellCast(SpellInfo const* spell) override
{
- if (summon->GetEntry() == CREATURE_EMBER_OF_ALAR)
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- summon->AI()->AttackStart(target);
+ /// !HACK: Creature is immune to fire spells, we set full health manually
+ if (spell->Id == SPELL_REBIRTH)
+ me->SetFullHealth();
}
- void MoveInLineOfSight(Unit* /*who*/) override { }
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_FLAME_QUILLS_END)
+ {
+ DoMoveToPlatform();
+ events.RescheduleEvent(EVENT_MOVE_TO_PLATFORM, 30s, 40s);
+ }
+ }
- void AttackStart(Unit* who) override
+ void DoMoveToPlatform()
{
- if (Phase1)
- AttackStartNoMove(who);
- else
- ScriptedAI::AttackStart(who);
+ if (Creature* trigger = me->FindNearestCreatureWithOptions(250.0f, { .StringId = AlarPlatformTrigger[_currentPlatform] }))
+ me->GetMotionMaster()->MovePoint(POINT_PLATFORM, trigger->GetPositionX(), trigger->GetPositionY(), trigger->GetPositionZ(), false);
}
- void DamageTaken(Unit* /*killer*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
+ void DoMoveToCenter()
{
- if (damage >= me->GetHealth() && Phase1)
- {
- damage = 0;
- if (!WaitEvent)
- {
- WaitEvent = WE_DIE;
- WaitTimer = 0;
- me->SetHealth(0);
- me->InterruptNonMeleeSpells(true);
- me->RemoveAllAuras();
- me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- me->AttackStop();
- me->SetTarget(ObjectGuid::Empty);
- me->SetSpeedRate(MOVE_RUN, 5.0f);
- me->GetMotionMaster()->Clear();
- me->GetMotionMaster()->MovePoint(0, waypoint[5][0], waypoint[5][1], waypoint[5][2]);
- }
- }
+ if (Creature* trigger = me->FindNearestCreatureWithOptions(250.0f, { .StringId = CenterTriggerStringId }))
+ me->GetMotionMaster()->MovePoint(POINT_CENTER, trigger->GetPositionX(), trigger->GetPositionY(), trigger->GetPositionZ());
}
- void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
+ void EnterEvadeMode(EvadeReason /*why*/) override
{
- if (spellInfo->Id == SPELL_DIVE_BOMB_VISUAL)
- {
- me->SetDisplayId(11686);
- //me->SendUpdateObjectToAllExcept(nullptr);
- }
+ summons.DespawnAll();
+ _DespawnAtEvade();
}
- void MovementInform(uint32 type, uint32 /*id*/) override
+ void JustDied(Unit* /*killer*/) override
{
- if (type == POINT_MOTION_TYPE)
- {
- WaitTimer = 1;
- AfterMoving = true;
- ForceMove = false;
- }
+ instance->DoCastSpellOnPlayers(SPELL_ASHTONGUE_RUSE_MASTER);
+
+ _JustDied();
+
+ /// @todo: Guessed. Needed if boss dies during Dive Bomb. What should happen?
+ me->SetDisplayId(me->GetNativeDisplayId());
+ me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
}
void UpdateAI(uint32 diff) override
{
- if (!me->IsEngaged())
+ if (!UpdateVictim())
return;
- if (Berserk_Timer <= diff)
- {
- DoCast(me, SPELL_BERSERK, true);
- Berserk_Timer = 60000;
- }
- else
- Berserk_Timer -= diff;
+ events.Update(diff);
- if (ForceMove)
- {
- if (ForceTimer <= diff)
- {
- me->GetMotionMaster()->MovePoint(0, waypoint[cur_wp][0], waypoint[cur_wp][1], waypoint[cur_wp][2]);
- ForceTimer = 5000;
- }
- else
- ForceTimer -= diff;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
- }
- if (WaitEvent)
+ while (uint32 eventId = events.ExecuteEvent())
{
- if (WaitTimer)
+ switch (eventId)
{
- if (WaitTimer <= diff)
+ // Phase 1
+ case EVENT_MOVE_TO_PLATFORM:
{
- if (AfterMoving)
+ // Verified: A'lar can stay on the same platform (even twice in a row), will summon ember in this case
+ // Verified: After Flame Quills A'lar can move to the old platform
+ // Verified: After Flame Quills A'lar can move to the next platform
+ // Not verified: Can he perform more than one Flame Quills in a row? Currently he can
+
+ // Cancel Flame Buffet so it will be not used during moving
+ events.CancelEvent(EVENT_FLAME_BUFFET);
+
+ // If encounter just started, only move to the first platform
+ if (_isFirstPlatform)
{
- me->GetMotionMaster()->MoveIdle();
- AfterMoving = false;
- }
+ DoMoveToPlatform();
- switch (WaitEvent)
+ _isFirstPlatform = false;
+
+ // We are leaving a small chance to stay on the first platform
+ if (roll_chance_i(80))
+ ++_currentPlatform;
+ }
+ else
{
- case WE_PLATFORM:
- Platforms_Move_Timer = 30000 + rand32() % 5000;
- break;
- case WE_QUILL:
- DoCast(me, SPELL_FLAME_QUILLS, true);
- Platforms_Move_Timer = 1;
- WaitTimer = 10000;
- WaitEvent = WE_DUMMY;
- return;
- case WE_DIE:
- ForceMove = false;
- me->SetStandState(UNIT_STAND_STATE_DEAD);
- WaitTimer = 5000;
- WaitEvent = WE_REVIVE;
- return;
- case WE_REVIVE:
- me->SetStandState(UNIT_STAND_STATE_STAND);
- me->SetFullHealth();
- me->SetSpeedRate(MOVE_RUN, DefaultMoveSpeedRate);
- me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
- DoZoneInCombat();
- DoCast(me, SPELL_REBIRTH, true);
- MeltArmor_Timer = 60000;
- Charge_Timer = 7000;
- DiveBomb_Timer = 40000 + rand32() % 5000;
- FlamePatch_Timer = 30000;
- Phase1 = false;
- break;
- case WE_METEOR:
- DoCast(me, SPELL_DIVE_BOMB_VISUAL, false);
- WaitEvent = WE_DIVE;
- WaitTimer = 4000;
- return;
- case WE_DIVE:
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ me->SetDisableGravity(true);
+ me->SetHover(true);
+ me->SetReactState(REACT_PASSIVE);
+
+ // Else, move either to platform or to center
+ if (roll_chance_i(80))
{
- me->RemoveAurasDueToSpell(SPELL_DIVE_BOMB_VISUAL);
- DoCast(target, SPELL_DIVE_BOMB, true);
- float dist = 3.0f;
- if (me->IsWithinDist3d(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 5.0f))
- dist = 5.0f;
- WaitTimer = 1000 + uint32(floor(dist / 80 * 1000.0f));
- me->UpdatePosition(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0.0f);
- me->StopMoving();
- WaitEvent = WE_LAND;
- return;
+ DoMoveToPlatform();
+
+ if (_currentPlatform == 3)
+ {
+ // If we are on the last platform, we are leaving a small chance to stay on it
+ if (roll_chance_i(80))
+ _currentPlatform = 0;
+ }
+ else
+ {
+ // If we are not on the last platform, we leave a small chance to stay on current
+ if (roll_chance_i(80))
+ ++_currentPlatform;
+ }
+
+ // If we are moving to the next platform or stay on the same, summon ember
+ _shouldSpawnEmber = true;
}
else
{
- EnterEvadeMode();
- return;
+ DoMoveToCenter();
+
+ // If we are moving to the center, do not summon ember
+ _shouldSpawnEmber = false;
}
- case WE_LAND:
- WaitEvent = WE_SUMMON;
- WaitTimer = 2000;
- return;
- case WE_SUMMON:
- for (uint8 i = 0; i < 2; ++i)
- DoSpawnCreature(CREATURE_EMBER_OF_ALAR, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s);
- me->SetBoundingRadius(10);
- me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
- me->SetDisplayId(me->GetNativeDisplayId());
- DoCast(me, SPELL_REBIRTH_2, true);
- break;
- case WE_DUMMY:
- default:
- break;
}
- WaitEvent = WE_NONE;
- WaitTimer = 0;
- }
- else
- WaitTimer -= diff;
- }
- return;
- }
-
- if (Phase1)
- {
- if (!me->IsThreatened())
- {
- EnterEvadeMode();
- return;
- }
+ if (_shouldSpawnEmber)
+ DoCastSelf(SPELL_SUMMON_PHOENIX_ADDS_1);
- if (Platforms_Move_Timer <= diff)
- {
- if (cur_wp == 4)
- {
- cur_wp = 0;
- WaitEvent = WE_PLATFORM;
+ events.Repeat(30s, 40s);
+ break;
}
- else
- {
- if (urand(0, 4)) // next platform
- {
- DoSpawnCreature(CREATURE_EMBER_OF_ALAR, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 5s);
- if (cur_wp == 3)
- cur_wp = 0;
- else
- ++cur_wp;
- WaitEvent = WE_PLATFORM;
- }
- else // flame quill
+ case EVENT_FLAME_QUILLS:
+ DoCastSelf(SPELL_FLAME_QUILLS);
+ break;
+
+ // Phase 1 & 2
+ case EVENT_FLAME_BUFFET:
+ if (!me->IsWithinMeleeRange(me->GetVictim()))
+ DoCastSelf(SPELL_FLAME_BUFFET);
+ events.Repeat(2400ms);
+ break;
+
+ // Transition
+ case EVENT_TRANSITION_1:
+ me->SetControlled(false, UNIT_STATE_ROOT);
+ me->GetMotionMaster()->Clear();
+ me->GetMotionMaster()->MoveIdle();
+ /// @todo: This should not be called. Clear All Debuffs should remove all debuffs. Does it work? Remove this
+ me->RemoveAllAuras();
+ /// @todo: Guessed, this is positive aura, will be not removed by Clear All Debuffs. What should happen if Flame Quills is active here?
+ me->RemoveAurasDueToSpell(SPELL_FLAME_QUILLS);
+ me->SetReactState(REACT_PASSIVE);
+ me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
+ me->SetStandState(UNIT_STAND_STATE_DEAD);
+ DoCastSelf(SPELL_CLEAR_ALL_DEBUFFS);
+ DoCastSelf(SPELL_EMBER_BLAST_INVIS);
+ /// !HACK: Creature is immune to fire spells, we make it invisible without SPELL_EMBER_BLAST_INVIS
+ me->SetVisible(false);
+ events.ScheduleEvent(EVENT_TRANSITION_2, 5s);
+ break;
+ case EVENT_TRANSITION_2:
+ me->SetDisableGravity(true);
+ me->SetHover(true);
+ DoCastSelf(SPELL_FLIGHT_MODE);
+ me->GetMotionMaster()->MovePoint(POINT_RESSURRECTION, AlarRessurrectionPosition);
+ events.ScheduleEvent(EVENT_TRANSITION_3, 10s);
+ break;
+ case EVENT_TRANSITION_3:
+ me->SetDisableGravity(false);
+ me->SetHover(false);
+ /// !HACK: Creature is immune to fire spells, we make it visible manually
+ me->SetVisible(true);
+ me->RemoveAurasDueToSpell(SPELL_EMBER_BLAST_INVIS);
+ events.ScheduleEvent(EVENT_TRANSITION_4, 1s);
+ break;
+ case EVENT_TRANSITION_4:
+ me->SetStandState(UNIT_STAND_STATE_STAND);
+ DoCastSelf(SPELL_REBIRTH);
+ events.ScheduleEvent(EVENT_TRANSITION_5, 3500ms);
+ break;
+ case EVENT_TRANSITION_5:
+ me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
+ me->SetReactState(REACT_AGGRESSIVE);
+ ResetThreatList();
+ DoZoneInCombat();
+
+ _isFirstPhase = false;
+
+ events.ScheduleEvent(EVENT_FLAME_BUFFET, 1s);
+ events.ScheduleEvent(EVENT_FLAME_RING, 20s, 30s);
+ events.ScheduleEvent(EVENT_MELT_ARMOR, 60s);
+ events.ScheduleEvent(EVENT_CHARGE_ALAR, 25s, 40s);
+ events.ScheduleEvent(EVENT_BERSERK, 10min);
+ events.ScheduleEvent(EVENT_DIVE_BOMB_1, 30s, 40s);
+ break;
+
+ // Phase 2
+ case EVENT_FLAME_RING:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_SUMMON_FLAME_RING);
+ events.Repeat(30s, 45s);
+ break;
+ case EVENT_MELT_ARMOR:
+ DoCastVictim(SPELL_MELT_ARMOR);
+ events.Repeat(60s);
+ break;
+ case EVENT_CHARGE_ALAR:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
+ DoCast(target, SPELL_CHARGE);
+ events.Repeat(30s, 35s);
+ break;
+ case EVENT_BERSERK:
+ DoCastSelf(SPELL_BERSERK);
+ break;
+
+ // Phase 2: Dive Bomb
+ case EVENT_DIVE_BOMB_1:
+ me->SetReactState(REACT_PASSIVE);
+
+ events.CancelEvent(EVENT_FLAME_BUFFET);
+ events.RescheduleEvent(EVENT_CHARGE_ALAR, 30s, 35s);
+
+ me->SetDisableGravity(true);
+ me->SetHover(true);
+
+ if (Creature* trigger = me->FindNearestCreatureWithOptions(250.0f, { .StringId = CenterTriggerStringId }))
+ me->GetMotionMaster()->MovePoint(POINT_DIVE_BOMB, trigger->GetPositionX(), trigger->GetPositionY(), trigger->GetPositionZ());
+
+ events.Repeat(40s, 45s);
+ break;
+ case EVENT_DIVE_BOMB_2:
+ DoCastSelf(SPELL_DIVE_BOMB_VISUAL);
+ break;
+ case EVENT_DIVE_BOMB_3:
+ me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
+ me->SetDisplayId(MODEL_INVISIBLE);
+ events.ScheduleEvent(EVENT_DIVE_BOMB_4, 2400ms);
+ break;
+ case EVENT_DIVE_BOMB_4:
+ me->RemoveAurasDueToSpell(SPELL_DIVE_BOMB_VISUAL);
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
{
- cur_wp = 4;
- WaitEvent = WE_QUILL;
+ me->NearTeleportTo(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), target->GetOrientation());
+ DoCast(target, SPELL_DIVE_BOMB);
}
- }
- ForceMove = true;
- ForceTimer = 5000;
- me->GetMotionMaster()->MovePoint(0, waypoint[cur_wp][0], waypoint[cur_wp][1], waypoint[cur_wp][2]);
- WaitTimer = 0;
- return;
- }
- else
- Platforms_Move_Timer -= diff;
- }
- else
- {
- if (Charge_Timer <= diff)
- {
- Unit* target= SelectTarget(SelectTargetMethod::Random, 1, 100, true);
- if (target)
- DoCast(target, SPELL_CHARGE);
- Charge_Timer = 30000;
+ events.ScheduleEvent(EVENT_DIVE_BOMB_5, 1200ms);
+ break;
+ case EVENT_DIVE_BOMB_5:
+ DoCastSelf(SPELL_SUMMON_PHOENIX_ADDS_2);
+ events.ScheduleEvent(EVENT_DIVE_BOMB_6, 2400ms);
+ break;
+ case EVENT_DIVE_BOMB_6:
+ DoCastSelf(SPELL_REBIRTH_2);
+ me->SetDisplayId(me->GetNativeDisplayId());
+ events.ScheduleEvent(EVENT_DIVE_BOMB_7, 2400ms);
+ break;
+ case EVENT_DIVE_BOMB_7:
+ me->SetDisableGravity(false);
+ me->SetHover(false);
+ me->SetReactState(REACT_AGGRESSIVE);
+ me->RemoveUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
+ events.ScheduleEvent(EVENT_FLAME_BUFFET, 1s);
+ break;
+ default:
+ break;
}
- else
- Charge_Timer -= diff;
- if (MeltArmor_Timer <= diff)
- {
- DoCastVictim(SPELL_MELT_ARMOR);
- MeltArmor_Timer = 60000;
- }
- else
- MeltArmor_Timer -= diff;
-
- if (DiveBomb_Timer <= diff)
- {
- me->AttackStop();
- me->GetMotionMaster()->MovePoint(6, waypoint[4][0], waypoint[4][1], waypoint[4][2]);
- me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
- me->SetBoundingRadius(50);
- WaitEvent = WE_METEOR;
- WaitTimer = 0;
- DiveBomb_Timer = 40000 + rand32() % 5000;
+ if (me->HasUnitState(UNIT_STATE_CASTING))
return;
- }
- else
- DiveBomb_Timer -= diff;
-
- if (FlamePatch_Timer <= diff)
- {
- if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0))
- {
- Creature* Summoned = me->SummonCreature(CREATURE_FLAME_PATCH_ALAR, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 2min);
- if (Summoned)
- {
- Summoned->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
- Summoned->SetObjectScale(Summoned->GetObjectScale() * 2.5f);
- Summoned->SetDisplayId(11686);
- Summoned->SetFaction(me->GetFaction());
- Summoned->SetLevel(me->GetLevel());
- Summoned->CastSpell(Summoned, SPELL_FLAME_PATCH, false);
- }
- }
- FlamePatch_Timer = 30000;
- }
- else
- FlamePatch_Timer -= diff;
}
DoMeleeAttackIfReady();
}
- void DoMeleeAttackIfReady()
- {
- if (me->isAttackReady() && !me->IsNonMeleeSpellCast(false))
- {
- if (me->IsWithinMeleeRange(me->GetVictim()))
- {
- me->AttackerStateUpdate(me->GetVictim());
- me->resetAttackTimer();
- }
- else
- {
- if (Unit* target = me->SelectNearestTargetInAttackDistance(5))
- AttackStart(target);
- else
- {
- DoCast(me, SPELL_FLAME_BUFFET, true);
- me->setAttackTimer(BASE_ATTACK, 1500);
- }
- }
- }
- }
+private:
+ bool _isFirstPhase;
+ bool _isInTransition;
+ bool _isFirstPlatform;
+ bool _shouldSpawnEmber;
+ uint8 _currentPlatform;
};
+// 19551 - Ember of Al'ar
struct npc_ember_of_alar : public ScriptedAI
{
- npc_ember_of_alar(Creature* creature) : ScriptedAI(creature)
- {
- Initialize();
- instance = creature->GetInstanceScript();
- creature->SetDisableGravity(true);
- }
+ npc_ember_of_alar(Creature* creature) : ScriptedAI(creature) { }
- void Initialize()
+ void InitializeAI() override
{
- toDie = false;
+ me->SetCorpseDelay(5, true);
+ me->SetReactState(REACT_PASSIVE);
}
- InstanceScript* instance;
- bool toDie;
-
- void Reset() override
+ void JustAppeared() override
{
- Initialize();
+ _scheduler.Schedule(2s, [this](TaskContext /*task*/)
+ {
+ DoZoneInCombat();
+ me->SetReactState(REACT_AGGRESSIVE);
+ });
}
- void JustEngagedWith(Unit* /*who*/) override
+ void JustDied(Unit* /*killer*/) override
{
- DoZoneInCombat();
+ DoCastSelf(SPELL_EMBER_BLAST, true);
+ /// @temporary: Should be triggered from the spell above, doesn't work currently
+ DoCastSelf(SPELL_EMBER_BLAST_DAMAGE, true);
}
- void EnterEvadeMode(EvadeReason /*why*/) override
+ void UpdateAI(uint32 diff) override
{
- me->setDeathState(JUST_DIED);
- }
+ _scheduler.Update(diff);
- void DamageTaken(Unit* killer, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
- {
- if (damage >= me->GetHealth() && killer != me && !toDie)
- {
- damage = 0;
- DoCast(me, SPELL_EMBER_BLAST, true);
- me->SetDisplayId(11686);
- me->SetUnitFlag(UNIT_FLAG_UNINTERACTIBLE);
- if (instance->GetBossState(DATA_ALAR) == IN_PROGRESS)
- {
- if (Unit* Alar = ObjectAccessor::GetUnit(*me, instance->GetGuidData(DATA_ALAR)))
- {
- int32 AlarHealth = int32(Alar->GetHealth()) - int32(Alar->CountPctFromMaxHealth(3));
- if (AlarHealth > 0)
- Alar->SetHealth(AlarHealth);
- else
- Alar->SetHealth(1);
- }
- }
- toDie = true;
- }
+ if (UpdateVictim())
+ DoMeleeAttackIfReady();
}
- void UpdateAI(uint32 /*diff*/) override
- {
- if (!UpdateVictim())
- return;
-
- if (toDie)
- {
- me->KillSelf();
- //me->SetVisibility(VISIBILITY_OFF);
- }
-
- DoMeleeAttackIfReady();
- }
+private:
+ TaskScheduler _scheduler;
};
+// 20602 - Flame Patch (Al'ar)
struct npc_flame_patch_alar : public ScriptedAI
{
npc_flame_patch_alar(Creature* creature) : ScriptedAI(creature) { }
- void Reset() override { }
- void JustEngagedWith(Unit* /*who*/) override { }
- void AttackStart(Unit* /*who*/) override { }
- void MoveInLineOfSight(Unit* /*who*/) override { }
- void UpdateAI(uint32 /*diff*/) override { }
+ void InitializeAI() override
+ {
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ void JustAppeared() override
+ {
+ DoCastSelf(SPELL_FLAME_PATCH_PERIODIC);
+ }
};
// 34229 - Flame Quills
@@ -556,7 +567,7 @@ class spell_alar_flame_quills : public AuraScript
bool Validate(SpellInfo const* /*spellInfo*/) override
{
- return ValidateSpellInfo(flameQuillsSpells);
+ return ValidateSpellInfo(FlameQuillsSpells);
}
bool Load() override
@@ -566,16 +577,46 @@ class spell_alar_flame_quills : public AuraScript
void PeriodicTick(AuraEffect const* aurEff)
{
- PreventDefaultAction();
+ for (uint32 spell : FlameQuillsSpells)
+ GetTarget()->CastSpell(nullptr, spell, aurEff);
+ }
+
+ void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
+ return;
- // cast 24 spells 34269-34289, 34314-34316
- for (uint32 spellId : flameQuillsSpells)
- GetTarget()->CastSpell(nullptr, spellId, aurEff);
+ if (Creature* target = GetTarget()->ToCreature())
+ target->AI()->DoAction(ACTION_FLAME_QUILLS_END);
}
void Register() override
{
OnEffectPeriodic += AuraEffectPeriodicFn(spell_alar_flame_quills::PeriodicTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_alar_flame_quills::AfterRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
+ }
+};
+
+// 39555 - Ashtongue Ruse Master
+class spell_alar_ashtongue_ruse_master : public AuraScript
+{
+ PrepareAuraScript(spell_alar_ashtongue_ruse_master);
+
+ bool Validate(SpellInfo const* /*spellInfo*/) override
+ {
+ return ValidateSpellInfo({ SPELL_ASHTONGUE_RUSE_DUMMY, SPELL_ASHTONGUE_RUSE_CREDIT });
+ }
+
+ void AfterApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ Unit* target = GetTarget();
+ if (target->HasAura(SPELL_ASHTONGUE_RUSE_DUMMY))
+ target->CastSpell(target, SPELL_ASHTONGUE_RUSE_CREDIT, true);
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectApplyFn(spell_alar_ashtongue_ruse_master::AfterApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL);
}
};
@@ -585,4 +626,5 @@ void AddSC_boss_alar()
RegisterTheEyeCreatureAI(npc_ember_of_alar);
RegisterTheEyeCreatureAI(npc_flame_patch_alar);
RegisterSpellScript(spell_alar_flame_quills);
+ RegisterSpellScript(spell_alar_ashtongue_ruse_master);
}