diff --git a/Source/Framework/Dynamic/EventMap.cs b/Source/Framework/Dynamic/EventMap.cs
index ec86a4974..6a46af213 100644
--- a/Source/Framework/Dynamic/EventMap.cs
+++ b/Source/Framework/Dynamic/EventMap.cs
@@ -153,7 +153,7 @@ namespace Framework.Dynamic
/// The maximum time until the event occurs as TimeSpan type.
/// The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.
/// The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.
- void RescheduleEvent(uint eventId, TimeSpan minTime, TimeSpan maxTime, uint group = 0, byte phase = 0)
+ public void RescheduleEvent(uint eventId, TimeSpan minTime, TimeSpan maxTime, uint group = 0, byte phase = 0)
{
RescheduleEvent(eventId, RandomHelper.RandTime(minTime, maxTime), group, phase);
}
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/BroodlordLashlayer.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/BroodlordLashlayer.cs
new file mode 100644
index 000000000..4be385de3
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/BroodlordLashlayer.cs
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.AI;
+using Game.Entities;
+using Game.Maps;
+using Game.Scripting;
+using System;
+using System.Collections.Generic;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.BlackwingLair.Broodlord
+{
+ struct SpellIds
+ {
+ public const uint Cleave = 26350;
+ public const uint Blastwave = 23331;
+ public const uint Mortalstrike = 24573;
+ public const uint Knockback = 25778;
+ public const uint SuppressionAura = 22247; // Suppression Device Spell
+ }
+
+ struct TextIds
+ {
+ public const uint SayAggro = 0;
+ public const uint SayLeash = 1;
+ }
+
+ struct EventIds
+ {
+ // Suppression Device Events
+ public const uint SuppressionCast = 1;
+ public const uint SuppressionReset = 2;
+ }
+
+ struct ActionIds
+ {
+ public const int Deactivate = 0;
+ }
+
+ [Script]
+ class boss_broodlord : BossAI
+ {
+ public boss_broodlord(Creature creature) : base(creature, DataTypes.BroodlordLashlayer) { }
+
+ public override void JustEngagedWith(Unit who)
+ {
+ base.JustEngagedWith(who);
+ Talk(TextIds.SayAggro);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(8), task =>
+ {
+ DoCastVictim(SpellIds.Cleave);
+ task.Repeat(TimeSpan.FromSeconds(7));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(12), task =>
+ {
+ DoCastVictim(SpellIds.Blastwave);
+ task.Repeat(TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(16));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(20), task =>
+ {
+ DoCastVictim(SpellIds.Mortalstrike);
+ task.Repeat(TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(35));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(30), task =>
+ {
+ DoCastVictim(SpellIds.Knockback);
+ if (GetThreat(me.GetVictim()) != 0)
+ ModifyThreatByPercent(me.GetVictim(), -50);
+ task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(30));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(1), task =>
+ {
+ if (me.GetDistance(me.GetHomePosition()) > 150.0f)
+ {
+ Talk(TextIds.SayLeash);
+ EnterEvadeMode(EvadeReason.Boundary);
+ }
+ task.Repeat(TimeSpan.FromSeconds(1));
+ });
+ }
+
+ public override void JustDied(Unit killer)
+ {
+ _JustDied();
+
+ List _goList = me.GetGameObjectListWithEntryInGrid(BWLGameObjectIds.SuppressionDevice, 200.0f);
+ foreach (var go in _goList)
+ go.GetAI().DoAction(ActionIds.Deactivate);
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+
+ [Script]
+ class go_suppression_device : GameObjectAI
+ {
+ InstanceScript _instance;
+ bool _active;
+
+ public go_suppression_device(GameObject go) : base(go)
+ {
+ _instance = go.GetInstanceScript();
+ _active = true;
+ }
+
+ public override void InitializeAI()
+ {
+ if (_instance.GetBossState(DataTypes.BroodlordLashlayer) == EncounterState.Done)
+ {
+ Deactivate();
+ return;
+ }
+
+ _events.ScheduleEvent(EventIds.SuppressionCast, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(5));
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ _events.Update(diff);
+
+ _events.ExecuteEvents(eventId =>
+ {
+ switch (eventId)
+ {
+ case EventIds.SuppressionCast:
+ if (me.GetGoState() == GameObjectState.Ready)
+ {
+ me.CastSpell(null, SpellIds.SuppressionAura, true);
+ me.SendCustomAnim(0);
+ }
+ _events.ScheduleEvent(EventIds.SuppressionCast, TimeSpan.FromSeconds(5));
+ break;
+ case EventIds.SuppressionReset:
+ Activate();
+ break;
+ }
+ });
+ }
+
+ public override void OnLootStateChanged(uint state, Unit unit)
+ {
+ switch ((LootState)state)
+ {
+ case LootState.Activated:
+ Deactivate();
+ _events.CancelEvent(EventIds.SuppressionCast);
+ _events.ScheduleEvent(EventIds.SuppressionReset, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(120));
+ break;
+ case LootState.JustDeactivated: // This case prevents the Gameobject despawn by Disarm Trap
+ me.SetLootState(LootState.Ready);
+ break;
+ }
+ }
+
+ public override void DoAction(int action)
+ {
+ if (action == ActionIds.Deactivate)
+ {
+ Deactivate();
+ _events.CancelEvent(EventIds.SuppressionReset);
+ }
+ }
+
+ void Activate()
+ {
+ if (_active)
+ return;
+ _active = true;
+ if (me.GetGoState() == GameObjectState.Active)
+ me.SetGoState(GameObjectState.Ready);
+ me.SetLootState(LootState.Ready);
+ me.RemoveFlag(GameObjectFlags.NotSelectable);
+ _events.ScheduleEvent(EventIds.SuppressionCast, TimeSpan.FromSeconds(0));
+ }
+
+ void Deactivate()
+ {
+ if (!_active)
+ return;
+ _active = false;
+ me.SetGoState(GameObjectState.Active);
+ me.SetFlag(GameObjectFlags.NotSelectable);
+ _events.CancelEvent(EventIds.SuppressionCast);
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Chromaggus.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Chromaggus.cs
new file mode 100644
index 000000000..df7a1ccd9
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Chromaggus.cs
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.AI;
+using Game.Entities;
+using Game.Maps;
+using Game.Scripting;
+using Game.Spells;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.BlackwingLair
+{
+ struct SpellIds
+ {
+ // These spells are actually called elemental shield
+ // What they do is decrease all damage by 75% then they increase
+ // One school of damage by 1100%
+ public const uint FireVulnerability = 22277;
+ public const uint FrostVulnerability = 22278;
+ public const uint ShadowVulnerability = 22279;
+ public const uint NatureVulnerability = 22280;
+ public const uint ArcaneVulnerability = 22281;
+ // Other spells
+ public const uint Incinerate = 23308; //Incinerate 23308; 23309
+ public const uint Timelapse = 23310; //Time lapse 23310; 23311(old threat mod that was removed in 2.01)
+ public const uint Corrosiveacid = 23313; //Corrosive Acid 23313; 23314
+ public const uint Igniteflesh = 23315; //Ignite Flesh 23315; 23316
+ public const uint Frostburn = 23187; //Frost burn 23187; 23189
+ // Brood Affliction 23173 - Scripted Spell that cycles through all targets within 100 yards and has a chance to cast one of the afflictions on them
+ // Since Scripted spells arn't coded I'll just write a function that does the same thing
+ public const uint BroodafBlue = 23153; //Blue affliction 23153
+ public const uint BroodafBlack = 23154; //Black affliction 23154
+ public const uint BroodafRed = 23155; //Red affliction 23155 (23168 on death)
+ public const uint BroodafBronze = 23170; //Bronze Affliction 23170
+ public const uint BroodafGreen = 23169; //Brood Affliction Green 23169
+ public const uint ChromaticMut1 = 23174; //Spell cast on player if they get all 5 debuffs
+ public const uint Frenzy = 28371; //The frenzy spell may be wrong
+ public const uint Enrage = 28747;
+ }
+
+ struct TextIds
+ {
+ public const uint EmoteFrenzy = 0;
+ public const uint EmoteShimmer = 1;
+ }
+
+ [Script]
+ class boss_chromaggus : BossAI
+ {
+ uint Breath1_Spell;
+ uint Breath2_Spell;
+ uint CurrentVurln_Spell;
+ bool Enraged;
+
+ public boss_chromaggus(Creature creature) : base(creature, DataTypes.Chromaggus)
+ {
+ Initialize();
+
+ Breath1_Spell = 0;
+ Breath2_Spell = 0;
+
+ // Select the 2 breaths that we are going to use until despawned
+ // 5 possiblities for the first breath, 4 for the second, 20 total possiblites
+ // This way we don't end up casting 2 of the same breath
+ // Tl Tl would be stupid
+ switch (RandomHelper.URand(0, 19))
+ {
+ // B1 - Incin
+ case 0:
+ Breath1_Spell = SpellIds.Incinerate;
+ Breath2_Spell = SpellIds.Timelapse;
+ break;
+ case 1:
+ Breath1_Spell = SpellIds.Incinerate;
+ Breath2_Spell = SpellIds.Corrosiveacid;
+ break;
+ case 2:
+ Breath1_Spell = SpellIds.Incinerate;
+ Breath2_Spell = SpellIds.Igniteflesh;
+ break;
+ case 3:
+ Breath1_Spell = SpellIds.Incinerate;
+ Breath2_Spell = SpellIds.Frostburn;
+ break;
+
+ // B1 - Tl
+ case 4:
+ Breath1_Spell = SpellIds.Timelapse;
+ Breath2_Spell = SpellIds.Incinerate;
+ break;
+ case 5:
+ Breath1_Spell = SpellIds.Timelapse;
+ Breath2_Spell = SpellIds.Corrosiveacid;
+ break;
+ case 6:
+ Breath1_Spell = SpellIds.Timelapse;
+ Breath2_Spell = SpellIds.Igniteflesh;
+ break;
+ case 7:
+ Breath1_Spell = SpellIds.Timelapse;
+ Breath2_Spell = SpellIds.Frostburn;
+ break;
+
+ //B1 - Acid
+ case 8:
+ Breath1_Spell = SpellIds.Corrosiveacid;
+ Breath2_Spell = SpellIds.Incinerate;
+ break;
+ case 9:
+ Breath1_Spell = SpellIds.Corrosiveacid;
+ Breath2_Spell = SpellIds.Timelapse;
+ break;
+ case 10:
+ Breath1_Spell = SpellIds.Corrosiveacid;
+ Breath2_Spell = SpellIds.Igniteflesh;
+ break;
+ case 11:
+ Breath1_Spell = SpellIds.Corrosiveacid;
+ Breath2_Spell = SpellIds.Frostburn;
+ break;
+
+ //B1 - Ignite
+ case 12:
+ Breath1_Spell = SpellIds.Igniteflesh;
+ Breath2_Spell = SpellIds.Incinerate;
+ break;
+ case 13:
+ Breath1_Spell = SpellIds.Igniteflesh;
+ Breath2_Spell = SpellIds.Corrosiveacid;
+ break;
+ case 14:
+ Breath1_Spell = SpellIds.Igniteflesh;
+ Breath2_Spell = SpellIds.Timelapse;
+ break;
+ case 15:
+ Breath1_Spell = SpellIds.Igniteflesh;
+ Breath2_Spell = SpellIds.Frostburn;
+ break;
+
+ //B1 - Frost
+ case 16:
+ Breath1_Spell = SpellIds.Frostburn;
+ Breath2_Spell = SpellIds.Incinerate;
+ break;
+ case 17:
+ Breath1_Spell = SpellIds.Frostburn;
+ Breath2_Spell = SpellIds.Timelapse;
+ break;
+ case 18:
+ Breath1_Spell = SpellIds.Frostburn;
+ Breath2_Spell = SpellIds.Corrosiveacid;
+ break;
+ case 19:
+ Breath1_Spell = SpellIds.Frostburn;
+ Breath2_Spell = SpellIds.Igniteflesh;
+ break;
+ }
+
+ EnterEvadeMode();
+ }
+
+ void Initialize()
+ {
+ CurrentVurln_Spell = 0; // We use this to store our last vulnerabilty spell so we can remove it later
+ Enraged = false;
+ }
+
+ public override void Reset()
+ {
+ _Reset();
+
+ Initialize();
+ }
+
+ public override void JustEngagedWith(Unit who)
+ {
+ base.JustEngagedWith(who);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(0), task =>
+ {
+ // Remove old vulnerabilty spell
+ if (CurrentVurln_Spell != 0)
+ me.RemoveAurasDueToSpell(CurrentVurln_Spell);
+
+ // Cast new random vulnerabilty on self
+ uint spell = RandomHelper.RAND(SpellIds.FireVulnerability, SpellIds.FrostVulnerability, SpellIds.ShadowVulnerability, SpellIds.NatureVulnerability, SpellIds.ArcaneVulnerability);
+ DoCast(me, spell);
+ CurrentVurln_Spell = spell;
+ Talk(TextIds.EmoteShimmer);
+ task.Repeat(TimeSpan.FromSeconds(45));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(30), task =>
+ {
+ DoCastVictim(Breath1_Spell);
+ task.Repeat(TimeSpan.FromSeconds(60));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(60), task =>
+ {
+ DoCastVictim(Breath2_Spell);
+ task.Repeat(TimeSpan.FromSeconds(60));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(10), task =>
+ {
+ var players = me.GetMap().GetPlayers();
+ foreach (var player in players)
+ {
+ if (player)
+ {
+ DoCast(player, RandomHelper.RAND(SpellIds.BroodafBlue, SpellIds.BroodafBlack, SpellIds.BroodafRed, SpellIds.BroodafBronze, SpellIds.BroodafGreen), new CastSpellExtraArgs(true));
+
+ if (player.HasAura(SpellIds.BroodafBlue) &&
+ player.HasAura(SpellIds.BroodafBlack) &&
+ player.HasAura(SpellIds.BroodafRed) &&
+ player.HasAura(SpellIds.BroodafBronze) &&
+ player.HasAura(SpellIds.BroodafGreen))
+ {
+ DoCast(player, SpellIds.ChromaticMut1);
+ }
+
+ }
+ }
+
+ task.Repeat(TimeSpan.FromSeconds(10));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(15), task =>
+ {
+ DoCast(me, SpellIds.Frenzy);
+ task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(15));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff);
+
+ // Enrage if not already enraged and below 20%
+ if (!Enraged && HealthBelowPct(20))
+ {
+ DoCast(me, SpellIds.Enrage);
+ Enraged = true;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ }
+
+ [Script]
+ class go_chromaggus_lever : GameObjectAI
+ {
+ InstanceScript _instance;
+
+ public go_chromaggus_lever(GameObject go) : base(go)
+ {
+ _instance = go.GetInstanceScript();
+ }
+
+ public override bool OnGossipHello(Player player)
+ {
+ if (_instance.GetBossState(DataTypes.Chromaggus) != EncounterState.Done && _instance.GetBossState(DataTypes.Chromaggus) != EncounterState.InProgress)
+ {
+ _instance.SetBossState(DataTypes.Chromaggus, EncounterState.InProgress);
+
+ Creature creature = _instance.GetCreature(DataTypes.Chromaggus);
+ if (creature)
+ creature.GetAI().JustEngagedWith(player);
+
+ GameObject go = _instance.GetGameObject(DataTypes.GoChromaggusDoor);
+ if (go)
+ _instance.HandleGameObject(ObjectGuid.Empty, true, go);
+ }
+
+ me.SetFlag(GameObjectFlags.NotSelectable | GameObjectFlags.InUse);
+ me.SetGoState(GameObjectState.Active);
+
+ return true;
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Ebonroc.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Ebonroc.cs
new file mode 100644
index 000000000..15d956ce8
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Ebonroc.cs
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.BlackwingLair.Ebonroc
+{
+ struct SpellIds
+ {
+ public const uint Shadowflame = 22539;
+ public const uint Wingbuffet = 23339;
+ public const uint Shadowofebonroc = 23340;
+ }
+
+ [Script]
+ class boss_ebonroc : BossAI
+ {
+ public boss_ebonroc(Creature creature) : base(creature, DataTypes.Ebonroc) { }
+
+ public override void JustEngagedWith(Unit who)
+ {
+ base.JustEngagedWith(who);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(20), task =>
+ {
+ DoCastVictim(SpellIds.Shadowflame);
+ task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(20));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(30), task =>
+ {
+ DoCastVictim(SpellIds.Wingbuffet);
+ task.Repeat(TimeSpan.FromSeconds(30));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(10), task =>
+ {
+ DoCastVictim(SpellIds.Shadowofebonroc);
+ task.Repeat(TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(10));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Firemaw.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Firemaw.cs
new file mode 100644
index 000000000..4817cd92a
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Firemaw.cs
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.BlackwingLair.Firemaw
+{
+ struct SpellIds
+ {
+ public const uint Shadowflame = 22539;
+ public const uint Wingbuffet = 23339;
+ public const uint Flamebuffet = 23341;
+ }
+
+ [Script]
+ class boss_firemaw : BossAI
+ {
+ public boss_firemaw(Creature creature) : base(creature, DataTypes.Firemaw) { }
+
+ public override void JustEngagedWith(Unit who)
+ {
+ base.JustEngagedWith(who);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(20), task =>
+ {
+ DoCastVictim(SpellIds.Shadowflame);
+ task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(20));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(30), task =>
+ {
+ DoCastVictim(SpellIds.Wingbuffet);
+ if (GetThreat(me.GetVictim()) != 0)
+ ModifyThreatByPercent(me.GetVictim(), -75);
+ task.Repeat(TimeSpan.FromSeconds(30));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(5), task =>
+ {
+ DoCastVictim(SpellIds.Flamebuffet);
+ task.Repeat(TimeSpan.FromSeconds(5));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Flamegor.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Flamegor.cs
new file mode 100644
index 000000000..83cd2f571
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Flamegor.cs
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.BlackwingLair.Flamegor
+{
+ struct SpellIds
+ {
+ public const uint Shadowflame = 22539;
+ public const uint Wingbuffet = 23339;
+ public const uint Frenzy = 23342; //This spell periodically triggers fire nova
+ }
+
+ struct TextIds
+ {
+ public const uint EmoteFrenzy = 0;
+ }
+
+ [Script]
+ class boss_flamegor : BossAI
+ {
+ public boss_flamegor(Creature creature) : base(creature, DataTypes.Flamegor) { }
+
+ public override void JustEngagedWith(Unit who)
+ {
+ base.JustEngagedWith(who);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(20), task =>
+ {
+ DoCastVictim(SpellIds.Shadowflame);
+ task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(20));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(30), task =>
+ {
+ DoCastVictim(SpellIds.Wingbuffet);
+ if (GetThreat(me.GetVictim()) != 0)
+ ModifyThreatByPercent(me.GetVictim(), -75);
+ task.Repeat(TimeSpan.FromSeconds(30));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(10), task =>
+ {
+ Talk(TextIds.EmoteFrenzy);
+ DoCast(me, SpellIds.Frenzy);
+ task.Repeat(TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(10));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/InstanceBlackwingLair.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/InstanceBlackwingLair.cs
new file mode 100644
index 000000000..09d4ea756
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/InstanceBlackwingLair.cs
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using System;
+using Game.Maps;
+using System.Collections.Generic;
+using Framework.Constants;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.BlackwingLair
+{
+ //uint const EncounterCount = 8;
+
+
+ struct DataTypes
+ {
+ // Encounter States/Boss GUIDs
+ public const uint RazorgoreTheUntamed = 0;
+ public const uint VaelastrazTheCorrupt = 1;
+ public const uint BroodlordLashlayer = 2;
+ public const uint Firemaw = 3;
+ public const uint Ebonroc = 4;
+ public const uint Flamegor = 5;
+ public const uint Chromaggus = 6;
+ public const uint Nefarian = 7;
+
+ // Additional Data
+ public const uint LordVictorNefarius = 8;
+
+ // Doors
+ public const uint GoChromaggusDoor = 9;
+ }
+
+ struct BWLCreatureIds
+ {
+ public const uint Razorgore = 12435;
+ public const uint BlackwingDragon = 12422;
+ public const uint BlackwingTaskmaster = 12458;
+ public const uint BlackwingLegionaire = 12416;
+ public const uint BlackwingWarlock = 12459;
+ public const uint Vaelastraz = 13020;
+ public const uint Broodlord = 12017;
+ public const uint Firemaw = 11983;
+ public const uint Ebonroc = 14601;
+ public const uint Flamegor = 11981;
+ public const uint Chromaggus = 14020;
+ public const uint VictorNefarius = 10162;
+ public const uint Nefarian = 11583;
+ }
+
+ struct BWLGameObjectIds
+ {
+ public const uint BlackDragonEgg = 177807;
+ public const uint PortcullisRazorgore = 176965;
+ public const uint PortcullisVaelastrasz = 179364;
+ public const uint PortcullisBroodlord = 179365;
+ public const uint PortcullisThreedragons = 179115;
+ public const uint PortcullisChromaggus = 179117; //Door after you kill him, not the one for his room
+ public const uint ChromaggusLever = 179148;
+ public const uint ChromaggusDoor = 179116;
+ public const uint PortcullisNefarian = 176966;
+ public const uint SuppressionDevice = 179784;
+ }
+
+ struct EventIds
+ {
+ public const uint RazorSpawn = 1;
+ public const uint RazorPhaseTwo = 2;
+ public const uint RespawnNefarius = 3;
+ }
+
+ struct BWLMisc
+ {
+ public const uint EncounterCount = 8;
+
+ // Razorgore Egg Event
+ public const int ActionPhaseTwo = 1;
+ public const uint DataEggEvent = 2;
+
+ public static DoorData[] doorData =
+ {
+ new DoorData(BWLGameObjectIds.PortcullisRazorgore, DataTypes.RazorgoreTheUntamed, DoorType.Passage),
+ new DoorData(BWLGameObjectIds.PortcullisVaelastrasz, DataTypes.VaelastrazTheCorrupt, DoorType.Passage),
+ new DoorData(BWLGameObjectIds.PortcullisBroodlord, DataTypes.BroodlordLashlayer, DoorType.Passage),
+ new DoorData(BWLGameObjectIds.PortcullisThreedragons, DataTypes.Firemaw, DoorType.Passage),
+ new DoorData(BWLGameObjectIds.PortcullisThreedragons, DataTypes.Ebonroc, DoorType.Passage),
+ new DoorData(BWLGameObjectIds.PortcullisThreedragons, DataTypes.Flamegor, DoorType.Passage),
+ new DoorData(BWLGameObjectIds.PortcullisChromaggus, DataTypes.Chromaggus, DoorType.Passage),
+ new DoorData(BWLGameObjectIds.PortcullisNefarian, DataTypes.Nefarian, DoorType.Room),
+ };
+
+ public static ObjectData[] creatureData =
+ {
+ new ObjectData(BWLCreatureIds.Razorgore, DataTypes.RazorgoreTheUntamed),
+ new ObjectData(BWLCreatureIds.Vaelastraz, DataTypes.VaelastrazTheCorrupt),
+ new ObjectData(BWLCreatureIds.Broodlord, DataTypes.BroodlordLashlayer),
+ new ObjectData(BWLCreatureIds.Firemaw, DataTypes.Firemaw),
+ new ObjectData(BWLCreatureIds.Ebonroc, DataTypes.Ebonroc),
+ new ObjectData(BWLCreatureIds.Flamegor, DataTypes.Flamegor),
+ new ObjectData(BWLCreatureIds.Chromaggus, DataTypes.Chromaggus),
+ new ObjectData(BWLCreatureIds.Nefarian, DataTypes.Nefarian),
+ new ObjectData(BWLCreatureIds.VictorNefarius, DataTypes.LordVictorNefarius),
+ };
+
+ public static ObjectData[] gameObjectData =
+ {
+ new ObjectData(BWLGameObjectIds.ChromaggusDoor, DataTypes.GoChromaggusDoor),
+ };
+
+ public static Position[] SummonPosition =
+ {
+ new Position(-7661.207520f, -1043.268188f, 407.199554f, 6.280452f),
+ new Position(-7644.145020f, -1065.628052f, 407.204956f, 0.501492f),
+ new Position(-7624.260742f, -1095.196899f, 407.205017f, 0.544694f),
+ new Position(-7608.501953f, -1116.077271f, 407.199921f, 0.816443f),
+ new Position(-7531.841797f, -1063.765381f, 407.199615f, 2.874187f),
+ new Position(-7547.319336f, -1040.971924f, 407.205078f, 3.789175f),
+ new Position(-7568.547852f, -1013.112488f, 407.204926f, 3.773467f),
+ new Position(-7584.175781f, -989.6691289f, 407.199585f, 4.527447f),
+ };
+
+ public static uint[] Entry = { 12422, 12458, 12416, 12420, 12459 };
+ }
+
+ [Script]
+ class instance_blackwing_lair : InstanceMapScript
+ {
+ public instance_blackwing_lair() : base(nameof(instance_blackwing_lair), 469) { }
+
+ class instance_blackwing_lair_InstanceMapScript : InstanceScript
+ {
+ // Razorgore
+ byte EggCount;
+ uint EggEvent;
+ List EggList = new();
+
+ public instance_blackwing_lair_InstanceMapScript(InstanceMap map) : base(map)
+ {
+ SetHeaders("BWL");
+ SetBossNumber(BWLMisc.EncounterCount);
+ LoadDoorData(BWLMisc.doorData);
+ LoadObjectData(BWLMisc.creatureData, BWLMisc.gameObjectData);
+
+ // Razorgore
+ EggCount = 0;
+ EggEvent = 0;
+ }
+
+ public override void OnCreatureCreate(Creature creature)
+ {
+ base.OnCreatureCreate(creature);
+
+ switch (creature.GetEntry())
+ {
+ case BWLCreatureIds.BlackwingDragon:
+ case BWLCreatureIds.BlackwingTaskmaster:
+ case BWLCreatureIds.BlackwingLegionaire:
+ case BWLCreatureIds.BlackwingWarlock:
+ Creature razor = GetCreature(DataTypes.RazorgoreTheUntamed);
+ if (razor != null)
+ {
+ CreatureAI razorAI = razor.GetAI();
+ if (razorAI != null)
+ razorAI.JustSummoned(creature);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ public override uint GetGameObjectEntry(ulong spawnId, uint entry)
+ {
+ if (entry == BWLGameObjectIds.BlackDragonEgg && GetBossState(DataTypes.Firemaw) == EncounterState.Done)
+ return 0;
+ return entry;
+ }
+
+ public override void OnGameObjectCreate(GameObject go)
+ {
+ base.OnGameObjectCreate(go);
+
+ switch (go.GetEntry())
+ {
+ case BWLGameObjectIds.BlackDragonEgg:
+ EggList.Add(go.GetGUID());
+ break;
+ default:
+ break;
+ }
+ }
+
+ public override void OnGameObjectRemove(GameObject go)
+ {
+ base.OnGameObjectRemove(go);
+
+ if (go.GetEntry() == BWLGameObjectIds.BlackDragonEgg)
+ EggList.Remove(go.GetGUID());
+ }
+
+ public override bool CheckRequiredBosses(uint bossId, Player player = null)
+ {
+ if (_SkipCheckRequiredBosses(player))
+ return true;
+
+ switch (bossId)
+ {
+ case DataTypes.BroodlordLashlayer:
+ if (GetBossState(DataTypes.VaelastrazTheCorrupt) != EncounterState.Done)
+ return false;
+ break;
+ case DataTypes.Firemaw:
+ case DataTypes.Ebonroc:
+ case DataTypes.Flamegor:
+ if (GetBossState(DataTypes.BroodlordLashlayer) != EncounterState.Done)
+ return false;
+ break;
+ case DataTypes.Chromaggus:
+ if (GetBossState(DataTypes.Firemaw) != EncounterState.Done
+ || GetBossState(DataTypes.Ebonroc) != EncounterState.Done
+ || GetBossState(DataTypes.Flamegor) != EncounterState.Done)
+ return false;
+ break;
+ default:
+ break;
+ }
+
+ return true;
+ }
+
+ public override bool SetBossState(uint type, EncounterState state)
+ {
+ if (!base.SetBossState(type, state))
+ return false;
+
+ switch (type)
+ {
+ case DataTypes.RazorgoreTheUntamed:
+ if (state == EncounterState.Done)
+ {
+ foreach (var guid in EggList)
+ {
+ GameObject egg = instance.GetGameObject(guid);
+ if (egg)
+ egg.SetLootState(LootState.JustDeactivated);
+ }
+ }
+ SetData(BWLMisc.DataEggEvent, (uint)EncounterState.NotStarted);
+ break;
+ case DataTypes.Nefarian:
+ switch (state)
+ {
+ case EncounterState.NotStarted:
+ Creature nefarian = GetCreature(DataTypes.Nefarian);
+ if (nefarian)
+ nefarian.DespawnOrUnsummon();
+ break;
+ case EncounterState.Fail:
+ _events.ScheduleEvent(EventIds.RespawnNefarius, TimeSpan.FromMinutes(15));
+ SetBossState(DataTypes.Nefarian, EncounterState.NotStarted);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ return true;
+ }
+
+ public override void SetData(uint type, uint data)
+ {
+ if (type == BWLMisc.DataEggEvent)
+ {
+ switch ((EncounterState)data)
+ {
+ case EncounterState.InProgress:
+ _events.ScheduleEvent(EventIds.RazorSpawn, TimeSpan.FromSeconds(45));
+ EggEvent = data;
+ EggCount = 0;
+ break;
+ case EncounterState.NotStarted:
+ _events.CancelEvent(EventIds.RazorSpawn);
+ EggEvent = data;
+ EggCount = 0;
+ break;
+ case EncounterState.Special:
+ if (++EggCount == 15)
+ {
+ Creature razor = GetCreature(DataTypes.RazorgoreTheUntamed);
+ if (razor)
+ {
+ SetData(BWLMisc.DataEggEvent, (uint)EncounterState.Done);
+ razor.RemoveAurasDueToSpell(42013); // MindControl
+ DoRemoveAurasDueToSpellOnPlayers(42013, true, true);
+ }
+ _events.ScheduleEvent(EventIds.RazorPhaseTwo, TimeSpan.FromSeconds(1));
+ _events.CancelEvent(EventIds.RazorSpawn);
+ }
+ if (EggEvent == (uint)EncounterState.NotStarted)
+ SetData(BWLMisc.DataEggEvent, (uint)EncounterState.InProgress);
+ break;
+ }
+ }
+ }
+
+ public override void OnUnitDeath(Unit unit)
+ {
+ //! Hack, needed because of buggy CreatureAI after charm
+ if (unit.GetEntry() == BWLCreatureIds.Razorgore && GetBossState(DataTypes.RazorgoreTheUntamed) != EncounterState.Done)
+ SetBossState(DataTypes.RazorgoreTheUntamed, EncounterState.Done);
+ }
+
+ public override void Update(uint diff)
+ {
+ if (_events.Empty())
+ return;
+
+ _events.Update(diff);
+
+ _events.ExecuteEvents(eventId =>
+ {
+ switch (eventId)
+ {
+ case EventIds.RazorSpawn:
+ for (uint i = RandomHelper.URand(2, 5); i > 0; --i)
+ {
+ Creature summon = instance.SummonCreature(BWLMisc.Entry[RandomHelper.URand(0, 4)], BWLMisc.SummonPosition[RandomHelper.URand(0, 7)]);
+ if (summon)
+ summon.GetAI().DoZoneInCombat();
+ }
+ _events.ScheduleEvent(EventIds.RazorSpawn, TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(17));
+ break;
+ case EventIds.RazorPhaseTwo:
+ _events.CancelEvent(EventIds.RazorSpawn);
+ Creature razor = GetCreature(DataTypes.RazorgoreTheUntamed);
+ if (razor)
+ razor.GetAI().DoAction(BWLMisc.ActionPhaseTwo);
+ break;
+ case EventIds.RespawnNefarius:
+ Creature nefarius = GetCreature(DataTypes.LordVictorNefarius);
+ if (nefarius)
+ {
+ nefarius.SetActive(true);
+ nefarius.SetFarVisible(true);
+ nefarius.Respawn();
+ nefarius.GetMotionMaster().MoveTargetedHome();
+ }
+ break;
+ }
+ });
+ }
+ }
+
+ public override InstanceScript GetInstanceScript(InstanceMap map)
+ {
+ return new instance_blackwing_lair_InstanceMapScript(map);
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Nefarian.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Nefarian.cs
new file mode 100644
index 000000000..9b94024e2
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Nefarian.cs
@@ -0,0 +1,592 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using System;
+using System.Collections.Generic;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.BlackwingLair.VictorNefarius
+{
+ struct SpellIds
+ {
+ // Victor Nefarius
+ // Ubrs Spells
+ public const uint ChromaticChaos = 16337; // Self Cast hits 10339
+ public const uint VaelastraszzSpawn = 16354; // Self Cast Depawn one sec after
+ // Bwl Spells
+ public const uint Shadowbolt = 22677;
+ public const uint ShadowboltVolley = 22665;
+ public const uint ShadowCommand = 22667;
+ public const uint Fear = 22678;
+
+ public const uint NefariansBarrier = 22663;
+
+ // Nefarian
+ public const uint ShadowflameInitial = 22992;
+ public const uint Shadowflame = 22539;
+ public const uint Bellowingroar = 22686;
+ public const uint Veilofshadow = 7068;
+ public const uint Cleave = 20691;
+ public const uint Taillash = 23364;
+
+ public const uint Mage = 23410; // wild magic
+ public const uint Warrior = 23397; // beserk
+ public const uint Druid = 23398; // cat form
+ public const uint Priest = 23401; // corrupted healing
+ public const uint Paladin = 23418; // syphon blessing
+ public const uint Shaman = 23425; // totems
+ public const uint Warlock = 23427; // infernals
+ public const uint Hunter = 23436; // bow broke
+ public const uint Rogue = 23414; // Paralise
+ public const uint DeathKnight = 49576; // Death Grip
+
+ // 19484
+ // 22664
+ // 22674
+ // 22666
+ }
+
+ struct TextIds
+ {
+ // Nefarius
+ // Ubrs
+ public const uint SayChaosSpell = 9;
+ public const uint SaySuccess = 10;
+ public const uint SayFailure = 11;
+ // Bwl
+ public const uint SayGamesbegin1 = 12;
+ public const uint SayGamesbegin2 = 13;
+ // public const uint SayVaelIntro = 14; Not used - when he corrupts Vaelastrasz
+
+ // Nefarian
+ public const uint SayRandom = 0;
+ public const uint SayRaiseSkeletons = 1;
+ public const uint SaySlay = 2;
+ public const uint SayDeath = 3;
+
+ public const uint SayMage = 4;
+ public const uint SayWarrior = 5;
+ public const uint SayDruid = 6;
+ public const uint SayPriest = 7;
+ public const uint SayPaladin = 8;
+ public const uint SayShaman = 9;
+ public const uint SayWarlock = 10;
+ public const uint SayHunter = 11;
+ public const uint SayRogue = 12;
+ public const uint SayDeathKnight = 13;
+
+ public const uint GossipId = 6045;
+ public const uint GossipOptionId = 0;
+ }
+
+ struct CreatureIds
+ {
+ public const uint BronzeDrakanoid = 14263;
+ public const uint BlueDrakanoid = 14261;
+ public const uint RedDrakanoid = 14264;
+ public const uint GreenDrakanoid = 14262;
+ public const uint BlackDrakanoid = 14265;
+ public const uint ChromaticDrakanoid = 14302;
+ public const uint BoneConstruct = 14605;
+ // Ubrs
+ public const uint Gyth = 10339;
+ }
+
+ struct GameObjectIds
+ {
+ public const uint PortcullisActive = 164726;
+ public const uint PortcullisTobossrooms = 175186;
+ }
+
+ struct MiscConst
+ {
+ public const uint NefariusPath2 = 1379671;
+ public const uint NefariusPath3 = 1379672;
+
+ public static Position[] DrakeSpawnLoc = // drakonid
+ {
+ new Position(-7591.151855f, -1204.051880f, 476.800476f, 3.0f),
+ new Position(-7514.598633f, -1150.448853f, 476.796570f, 3.0f)
+ };
+
+ public static Position[] NefarianLoc =
+ {
+ new Position(-7449.763672f, -1387.816040f, 526.783691f, 3.0f), // nefarian spawn
+ new Position(-7535.456543f, -1279.562500f, 476.798706f, 3.0f) // nefarian move
+ };
+
+ public static uint[] Entry = { CreatureIds.BronzeDrakanoid, CreatureIds.BlueDrakanoid, CreatureIds.RedDrakanoid, CreatureIds.GreenDrakanoid, CreatureIds.BlackDrakanoid };
+ }
+
+ struct EventIds
+ {
+ // Victor Nefarius
+ public const uint SpawnAdd = 1;
+ public const uint ShadowBolt = 2;
+ public const uint Fear = 3;
+ public const uint MindControl = 4;
+ // Nefarian
+ public const uint Shadowflame = 5;
+ public const uint Veilofshadow = 6;
+ public const uint Cleave = 7;
+ public const uint Taillash = 8;
+ public const uint Classcall = 9;
+ // Ubrs
+ public const uint Chaos1 = 10;
+ public const uint Chaos2 = 11;
+ public const uint Path2 = 12;
+ public const uint Path3 = 13;
+ public const uint Success1 = 14;
+ public const uint Success2 = 15;
+ public const uint Success3 = 16;
+ }
+
+ [Script]
+ class boss_victor_nefarius : BossAI
+ {
+ uint SpawnedAdds;
+
+ public boss_victor_nefarius(Creature creature) : base(creature, DataTypes.Nefarian)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ SpawnedAdds = 0;
+ }
+
+ public override void Reset()
+ {
+ Initialize();
+
+ if (me.GetMapId() == 469)
+ {
+ if (!me.FindNearestCreature(BWLCreatureIds.Nefarian, 1000.0f, true))
+ _Reset();
+
+ me.SetVisible(true);
+ me.SetNpcFlag(NPCFlags.Gossip);
+ me.SetFaction((uint)FactionTemplates.Friendly);
+ me.SetStandState(UnitStandStateType.SitHighChair);
+ me.RemoveAura(SpellIds.NefariansBarrier);
+ }
+ }
+
+ public override void JustReachedHome()
+ {
+ Reset();
+ }
+
+ void BeginEvent(Player target)
+ {
+ _JustEngagedWith(target);
+
+ Talk(TextIds.SayGamesbegin2);
+
+ me.SetFaction((uint)FactionTemplates.DragonflightBlack);
+ me.RemoveNpcFlag(NPCFlags.Gossip);
+ DoCast(me, SpellIds.NefariansBarrier);
+ me.SetStandState(UnitStandStateType.Stand);
+ me.SetImmuneToPC(false);
+ AttackStart(target);
+ _events.ScheduleEvent(EventIds.ShadowBolt, TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(10));
+ _events.ScheduleEvent(EventIds.Fear, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(20));
+ //_events.ScheduleEvent(EventIds.MindControl, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(35));
+ _events.ScheduleEvent(EventIds.SpawnAdd, TimeSpan.FromSeconds(10));
+ }
+
+ public override void SummonedCreatureDies(Creature summon, Unit killer)
+ {
+ if (summon.GetEntry() != BWLCreatureIds.Nefarian)
+ {
+ summon.UpdateEntry(CreatureIds.BoneConstruct);
+ summon.SetUnitFlag(UnitFlags.Uninteractible);
+ summon.SetReactState(ReactStates.Passive);
+ summon.SetStandState(UnitStandStateType.Dead);
+ }
+ }
+
+ public override void JustSummoned(Creature summon) { }
+
+ public override void SetData(uint type, uint data)
+ {
+ if (type == 1 && data == 1)
+ {
+ me.StopMoving();
+ _events.ScheduleEvent(EventIds.Path2, TimeSpan.FromSeconds(9));
+ }
+
+ if (type == 1 && data == 2)
+ _events.ScheduleEvent(EventIds.Success1, TimeSpan.FromSeconds(5));
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ {
+ _events.Update(diff);
+
+ _events.ExecuteEvents(eventId =>
+ {
+ switch (eventId)
+ {
+ case EventIds.Path2:
+ me.GetMotionMaster().MovePath(MiscConst.NefariusPath2, false);
+ _events.ScheduleEvent(EventIds.Chaos1, TimeSpan.FromSeconds(7));
+ break;
+ case EventIds.Chaos1:
+ Creature gyth = me.FindNearestCreature(CreatureIds.Gyth, 75.0f, true);
+ if (gyth)
+ {
+ me.SetFacingToObject(gyth);
+ Talk(TextIds.SayChaosSpell);
+ }
+ _events.ScheduleEvent(EventIds.Chaos2, TimeSpan.FromSeconds(2));
+ break;
+ case EventIds.Chaos2:
+ DoCast(SpellIds.ChromaticChaos);
+ me.SetFacingTo(1.570796f);
+ break;
+ case EventIds.Success1:
+ Unit player = me.SelectNearestPlayer(60.0f);
+ if (player)
+ {
+ me.SetFacingToObject(player);
+ Talk(TextIds.SaySuccess);
+ GameObject portcullis1 = me.FindNearestGameObject(GameObjectIds.PortcullisActive, 65.0f);
+ if (portcullis1)
+ portcullis1.SetGoState(GameObjectState.Active);
+ GameObject portcullis2 = me.FindNearestGameObject(GameObjectIds.PortcullisTobossrooms, 80.0f);
+ if (portcullis2)
+ portcullis2.SetGoState(GameObjectState.Active);
+ }
+ _events.ScheduleEvent(EventIds.Success2, TimeSpan.FromSeconds(4));
+ break;
+ case EventIds.Success2:
+ DoCast(me, SpellIds.VaelastraszzSpawn);
+ me.DespawnOrUnsummon(TimeSpan.FromSeconds(1));
+ break;
+ case EventIds.Path3:
+ me.GetMotionMaster().MovePath(MiscConst.NefariusPath3, false);
+ break;
+ default:
+ break;
+ }
+ });
+ return;
+ }
+
+ // Only do this if we haven't spawned nefarian yet
+ if (UpdateVictim() && SpawnedAdds <= 42)
+ {
+ _events.Update(diff);
+
+ if (me.HasUnitState(UnitState.Casting))
+ return;
+
+ _events.ExecuteEvents(eventId =>
+ {
+ switch (eventId)
+ {
+ case EventIds.ShadowBolt:
+ switch (RandomHelper.URand(0, 1))
+ {
+ case 0:
+ DoCastVictim(SpellIds.ShadowboltVolley);
+ break;
+ case 1:
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0, 40, true);
+ if (target)
+ DoCast(target, SpellIds.Shadowbolt);
+ break;
+ }
+ ResetThreatList();
+ _events.ScheduleEvent(EventIds.ShadowBolt, TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(10));
+ break;
+ case EventIds.Fear:
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0, 40, true);
+ if (target)
+ DoCast(target, SpellIds.Fear);
+ _events.ScheduleEvent(EventIds.Fear, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(20));
+ break;
+ }
+ case EventIds.MindControl:
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0, 40, true);
+ if (target)
+ DoCast(target, SpellIds.ShadowCommand);
+ _events.ScheduleEvent(EventIds.MindControl, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(35));
+ break;
+ }
+ case EventIds.SpawnAdd:
+ for (byte i = 0; i < 2; ++i)
+ {
+ uint CreatureID;
+ if (RandomHelper.URand(0, 2) == 0)
+ CreatureID = CreatureIds.ChromaticDrakanoid;
+ else
+ CreatureID = MiscConst.Entry[RandomHelper.URand(0, 4)];
+ Creature dragon = me.SummonCreature(CreatureID, MiscConst.DrakeSpawnLoc[i]);
+ if (dragon)
+ {
+ dragon.SetFaction((uint)FactionTemplates.DragonflightBlack);
+ dragon.GetAI().AttackStart(me.GetVictim());
+ }
+
+ if (++SpawnedAdds >= 42)
+ {
+ Creature nefarian = me.SummonCreature(BWLCreatureIds.Nefarian, MiscConst.NefarianLoc[0]);
+ if (nefarian)
+ {
+ nefarian.SetActive(true);
+ nefarian.SetFarVisible(true);
+ nefarian.SetCanFly(true);
+ nefarian.SetDisableGravity(true);
+ nefarian.CastSpell(null, SpellIds.ShadowflameInitial);
+ nefarian.GetMotionMaster().MovePoint(1, MiscConst.NefarianLoc[1]);
+ }
+ _events.CancelEvent(EventIds.MindControl);
+ _events.CancelEvent(EventIds.Fear);
+ _events.CancelEvent(EventIds.ShadowBolt);
+ me.SetVisible(false);
+ return;
+ }
+ }
+ _events.ScheduleEvent(EventIds.SpawnAdd, TimeSpan.FromSeconds(4));
+ break;
+ }
+
+ if (me.HasUnitState(UnitState.Casting))
+ return;
+ });
+ }
+ }
+
+ public override bool OnGossipSelect(Player player, uint menuId, uint gossipListId)
+ {
+ if (menuId == TextIds.GossipId && gossipListId == TextIds.GossipOptionId)
+ {
+ player.CloseGossipMenu();
+ Talk(TextIds.SayGamesbegin1);
+ BeginEvent(player);
+ }
+ return false;
+ }
+ }
+
+ [Script]
+ class boss_nefarian : BossAI
+ {
+ bool canDespawn;
+ uint DespawnTimer;
+ bool Phase3;
+
+ public boss_nefarian(Creature creature) : base(creature, DataTypes.Nefarian)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ Phase3 = false;
+ canDespawn = false;
+ DespawnTimer = 30000;
+ }
+
+ public override void Reset()
+ {
+ Initialize();
+ }
+
+ public override void JustReachedHome()
+ {
+ canDespawn = true;
+ }
+
+ public override void JustEngagedWith(Unit who)
+ {
+ _events.ScheduleEvent(EventIds.Shadowflame, TimeSpan.FromSeconds(12));
+ _events.ScheduleEvent(EventIds.Fear, TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(35));
+ _events.ScheduleEvent(EventIds.Veilofshadow, TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(35));
+ _events.ScheduleEvent(EventIds.Cleave, TimeSpan.FromSeconds(7));
+ //_events.ScheduleEvent(EventIds.Taillash, TimeSpan.FromSeconds(10));
+ _events.ScheduleEvent(EventIds.Classcall, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(35));
+ Talk(TextIds.SayRandom);
+ }
+
+ public override void JustDied(Unit killer)
+ {
+ _JustDied();
+ Talk(TextIds.SayDeath);
+ }
+
+ public override void KilledUnit(Unit victim)
+ {
+ if ((RandomHelper.Rand32() % 5) != 0)
+ return;
+
+ Talk(TextIds.SaySlay, victim);
+ }
+
+ public override void MovementInform(MovementGeneratorType type, uint id)
+ {
+ if (type != MovementGeneratorType.Point)
+ return;
+
+ if (id == 1)
+ {
+ DoZoneInCombat();
+ if (me.GetVictim())
+ AttackStart(me.GetVictim());
+ }
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (canDespawn && DespawnTimer <= diff)
+ {
+ instance.SetBossState(DataTypes.Nefarian, EncounterState.Fail);
+
+ List constructList = me.GetCreatureListWithEntryInGrid(CreatureIds.BoneConstruct, 500.0f);
+ foreach (var creature in constructList)
+ creature.DespawnOrUnsummon();
+
+ }
+ else DespawnTimer -= diff;
+
+ if (!UpdateVictim())
+ return;
+
+ if (canDespawn)
+ canDespawn = false;
+
+ _events.Update(diff);
+
+ if (me.HasUnitState(UnitState.Casting))
+ return;
+
+ _events.ExecuteEvents(eventId =>
+ {
+ switch (eventId)
+ {
+ case EventIds.Shadowflame:
+ DoCastVictim(SpellIds.Shadowflame);
+ _events.ScheduleEvent(EventIds.Shadowflame, TimeSpan.FromSeconds(12));
+ break;
+ case EventIds.Fear:
+ DoCastVictim(SpellIds.Bellowingroar);
+ _events.ScheduleEvent(EventIds.Fear, TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(35));
+ break;
+ case EventIds.Veilofshadow:
+ DoCastVictim(SpellIds.Veilofshadow);
+ _events.ScheduleEvent(EventIds.Veilofshadow, TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(35));
+ break;
+ case EventIds.Cleave:
+ DoCastVictim(SpellIds.Cleave);
+ _events.ScheduleEvent(EventIds.Cleave, TimeSpan.FromSeconds(7));
+ break;
+ case EventIds.Taillash:
+ // Cast Nyi since we need a better check for behind target
+ DoCastVictim(SpellIds.Taillash);
+ _events.ScheduleEvent(EventIds.Taillash, TimeSpan.FromSeconds(10));
+ break;
+ case EventIds.Classcall:
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0, 100.0f, true);
+ if (target)
+ switch (target.GetClass())
+ {
+ case Class.Mage:
+ Talk(TextIds.SayMage);
+ DoCast(me, SpellIds.Mage);
+ break;
+ case Class.Warrior:
+ Talk(TextIds.SayWarrior);
+ DoCast(me, SpellIds.Warrior);
+ break;
+ case Class.Druid:
+ Talk(TextIds.SayDruid);
+ DoCast(target, SpellIds.Druid);
+ break;
+ case Class.Priest:
+ Talk(TextIds.SayPriest);
+ DoCast(me, SpellIds.Priest);
+ break;
+ case Class.Paladin:
+ Talk(TextIds.SayPaladin);
+ DoCast(me, SpellIds.Paladin);
+ break;
+ case Class.Shaman:
+ Talk(TextIds.SayShaman);
+ DoCast(me, SpellIds.Shaman);
+ break;
+ case Class.Warlock:
+ Talk(TextIds.SayWarlock);
+ DoCast(me, SpellIds.Warlock);
+ break;
+ case Class.Hunter:
+ Talk(TextIds.SayHunter);
+ DoCast(me, SpellIds.Hunter);
+ break;
+ case Class.Rogue:
+ Talk(TextIds.SayRogue);
+ DoCast(me, SpellIds.Rogue);
+ break;
+ case Class.Deathknight:
+ Talk(TextIds.SayDeathKnight);
+ DoCast(me, SpellIds.DeathKnight);
+ break;
+ default:
+ break;
+ }
+ _events.ScheduleEvent(EventIds.Classcall, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(35));
+ break;
+ }
+
+ if (me.HasUnitState(UnitState.Casting))
+ return;
+ });
+
+ // Phase3 begins when health below 20 pct
+ if (!Phase3 && HealthBelowPct(20))
+ {
+ List constructList = me.GetCreatureListWithEntryInGrid(CreatureIds.BoneConstruct, 500.0f);
+ foreach (var creature in constructList)
+ {
+ if (creature != null && !creature.IsAlive())
+ {
+ creature.Respawn();
+ DoZoneInCombat(creature);
+ creature.RemoveUnitFlag(UnitFlags.Uninteractible);
+ creature.SetReactState(ReactStates.Aggressive);
+ creature.SetStandState(UnitStandStateType.Stand);
+ }
+ }
+
+ Phase3 = true;
+ Talk(TextIds.SayRaiseSkeletons);
+ }
+
+ DoMeleeAttackIfReady();
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Razorgore.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Razorgore.cs
new file mode 100644
index 000000000..5879885fb
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Razorgore.cs
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.AI;
+using Game.Entities;
+using Game.Maps;
+using Game.Scripting;
+using Game.Spells;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.BlackwingLair.Razorgore
+{
+ struct SpellIds
+ {
+ // @todo orb uses the wrong spell, this needs sniffs
+ public const uint Mindcontrol = 42013;
+ public const uint Channel = 45537;
+ public const uint EggDestroy = 19873;
+
+ public const uint Cleave = 22540;
+ public const uint Warstomp = 24375;
+ public const uint Fireballvolley = 22425;
+ public const uint Conflagration = 23023;
+ }
+
+ struct TextIds
+ {
+ public const uint SayEggsBroken1 = 0;
+ public const uint SayEggsBroken2 = 1;
+ public const uint SayEggsBroken3 = 2;
+ public const uint SayDeath = 3;
+ }
+
+ struct CreatureIds
+ {
+ public const uint EliteDrachkin = 12422;
+ public const uint EliteWarrior = 12458;
+ public const uint Warrior = 12416;
+ public const uint Mage = 12420;
+ public const uint Warlock = 12459;
+ }
+
+ struct GameObjectIds
+ {
+ public const uint Egg = 177807;
+ }
+
+ [Script]
+ class boss_razorgore : BossAI
+ {
+ bool secondPhase;
+
+ public boss_razorgore(Creature creature) : base(creature, DataTypes.RazorgoreTheUntamed)
+ {
+ Initialize();
+ }
+
+ void Initialize()
+ {
+ secondPhase = false;
+ }
+
+ public override void Reset()
+ {
+ _Reset();
+
+ Initialize();
+ instance.SetData(BWLMisc.DataEggEvent, (uint)EncounterState.NotStarted);
+ }
+
+ public override void JustDied(Unit killer)
+ {
+ _JustDied();
+ Talk(TextIds.SayDeath);
+
+ instance.SetData(BWLMisc.DataEggEvent, (uint)EncounterState.NotStarted);
+ }
+
+ void DoChangePhase()
+ {
+ _scheduler.Schedule(TimeSpan.FromSeconds(15), task =>
+ {
+ DoCastVictim(SpellIds.Cleave);
+ task.Repeat(TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(10));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(35), task =>
+ {
+ DoCastVictim(SpellIds.Warstomp);
+ task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(25));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(7), task =>
+ {
+ DoCastVictim(SpellIds.Fireballvolley);
+ task.Repeat(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(15));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(12), task =>
+ {
+ DoCastVictim(SpellIds.Conflagration);
+ task.Repeat(TimeSpan.FromSeconds(30));
+ });
+
+ secondPhase = true;
+ me.RemoveAllAuras();
+ me.SetFullHealth();
+ }
+
+ public override void DoAction(int action)
+ {
+ if (action == BWLMisc.ActionPhaseTwo)
+ DoChangePhase();
+ }
+
+ public override void DamageTaken(Unit who, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null)
+ {
+ // @todo this is wrong - razorgore should still take damage, he should just nuke the whole room and respawn if he dies during P1
+ if (!secondPhase)
+ damage = 0;
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+
+ [Script]
+ class go_orb_of_domination : GameObjectAI
+ {
+ InstanceScript instance;
+
+ public go_orb_of_domination(GameObject go) : base(go)
+ {
+ instance = go.GetInstanceScript();
+ }
+
+ public override bool OnGossipHello(Player player)
+ {
+ if (instance.GetData(BWLMisc.DataEggEvent) != (uint)EncounterState.Done)
+ {
+ Creature razorgore = instance.GetCreature(DataTypes.RazorgoreTheUntamed);
+ if (razorgore)
+ {
+ razorgore.Attack(player, true);
+ player.CastSpell(razorgore, SpellIds.Mindcontrol);
+ }
+ }
+ return true;
+ }
+ }
+
+ [Script] // 19873 - Destroy Egg
+ class spell_egg_event : SpellScript
+ {
+ void HandleOnHit()
+ {
+ InstanceScript instance = GetCaster().GetInstanceScript();
+ if (instance != null)
+ instance.SetData(BWLMisc.DataEggEvent, (uint)EncounterState.Special);
+ }
+
+ public override void Register()
+ {
+ OnHit.Add(new HitHandler(HandleOnHit));
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Vaelastrasz.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Vaelastrasz.cs
new file mode 100644
index 000000000..ce11e3222
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Vaelastrasz.cs
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using Game.Spells;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.BlackwingLair.Vaelastrasz
+{
+ struct SpellIds
+ {
+ public const uint Essenceofthered = 23513;
+ public const uint Flamebreath = 23461;
+ public const uint Firenova = 23462;
+ public const uint Tailswipe = 15847;
+ public const uint Burningadrenaline = 18173; //Cast this one. It's what 3.3.5 Dbm expects.
+ public const uint BurningadrenalineExplosion = 23478;
+ public const uint Cleave = 19983; //Chain cleave is most likely named something different and contains a dummy effect
+ }
+
+ struct TextIds
+ {
+ public const uint SayLine1 = 0;
+ public const uint SayLine2 = 1;
+ public const uint SayLine3 = 2;
+ public const uint SayHalflife = 3;
+ public const uint SayKilltarget = 4;
+
+ public const uint GossipId = 6101;
+ }
+
+ [Script]
+ class boss_vaelastrasz : BossAI
+ {
+ ObjectGuid PlayerGUID;
+ bool HasYelled;
+
+ public boss_vaelastrasz(Creature creature) : base(creature, DataTypes.VaelastrazTheCorrupt)
+ {
+ Initialize();
+ creature.SetNpcFlag(NPCFlags.Gossip);
+ creature.SetFaction((uint)FactionTemplates.Friendly);
+ creature.RemoveUnitFlag(UnitFlags.Uninteractible);
+ }
+
+ void Initialize()
+ {
+ PlayerGUID.Clear();
+ HasYelled = false;
+ }
+
+ public override void Reset()
+ {
+ _Reset();
+
+ me.SetStandState(UnitStandStateType.Dead);
+ Initialize();
+ }
+
+ public override void JustEngagedWith(Unit who)
+ {
+ base.JustEngagedWith(who);
+
+ DoCast(me, SpellIds.Essenceofthered);
+ me.SetHealth(me.CountPctFromMaxHealth(30));
+ // now drop damage requirement to be able to take loot
+ me.ResetPlayerDamageReq();
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(10), task =>
+ {
+ DoCastVictim(SpellIds.Cleave);
+ task.Repeat(TimeSpan.FromSeconds(15));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(15), task =>
+ {
+ DoCastVictim(SpellIds.Flamebreath);
+ task.Repeat(TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(14));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(20), task =>
+ {
+ DoCastVictim(SpellIds.Firenova);
+ task.Repeat(TimeSpan.FromSeconds(15));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(11), task =>
+ {
+ //Only cast if we are behind
+ if (!me.HasInArc(MathF.PI, me.GetVictim()))
+ {
+ DoCast(me.GetVictim(), SpellIds.Tailswipe);
+ }
+ task.Repeat(TimeSpan.FromSeconds(15));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(15), task =>
+ {
+ //selects a random target that isn't the current victim and is a mana user (selects mana users) but not pets
+ //it also ignores targets who have the aura. We don't want to place the debuff on the same target twice.
+ Unit target = SelectTarget(SelectTargetMethod.Random, 1, u => { return u && !u.IsPet() && u.GetPowerType() == PowerType.Mana && !u.HasAura(SpellIds.Burningadrenaline); });
+ if (target != null)
+ me.CastSpell(target, SpellIds.Burningadrenaline, true);
+
+ task.Repeat(TimeSpan.FromSeconds(15));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(45), task =>
+ {
+ //Vael has to cast it himself; contrary to the previous commit's comment. Nothing happens otherwise.
+ me.CastSpell(me.GetVictim(), SpellIds.Burningadrenaline, true);
+ task.Repeat(TimeSpan.FromSeconds(45));
+ });
+ }
+
+ void BeginSpeech(Unit target)
+ {
+ PlayerGUID = target.GetGUID();
+ me.RemoveNpcFlag(NPCFlags.Gossip);
+ _scheduler.Schedule(TimeSpan.FromSeconds(1), task =>
+ {
+ Talk(TextIds.SayLine1);
+ me.SetStandState(UnitStandStateType.Stand);
+ me.HandleEmoteCommand(Emote.OneshotTalk);
+ task.Schedule(TimeSpan.FromSeconds(12), speechTask2 =>
+ {
+ Talk(TextIds.SayLine2);
+ me.HandleEmoteCommand(Emote.OneshotTalk);
+ speechTask2.Schedule(TimeSpan.FromSeconds(12), speechTask3 =>
+ {
+ Talk(TextIds.SayLine3);
+ me.HandleEmoteCommand(Emote.OneshotTalk);
+ speechTask3.Schedule(TimeSpan.FromSeconds(16), speechTask4 =>
+ {
+ me.SetFaction((uint)FactionTemplates.DragonflightBlack);
+ Player player = Global.ObjAccessor.GetPlayer(me, PlayerGUID);
+ if (player)
+ AttackStart(player);
+ });
+ });
+ });
+ });
+ }
+
+ public override void KilledUnit(Unit victim)
+ {
+ if ((RandomHelper.Rand32() % 5) != 0)
+ return;
+
+ Talk(TextIds.SayKilltarget, victim);
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ _scheduler.Update(diff);
+
+ if (!UpdateVictim())
+ return;
+
+ if (me.HasUnitState(UnitState.Casting))
+ return;
+
+ // Yell if hp lower than 15%
+ if (HealthBelowPct(15) && !HasYelled)
+ {
+ Talk(TextIds.SayHalflife);
+ HasYelled = true;
+ }
+
+ DoMeleeAttackIfReady();
+ }
+
+ public override bool OnGossipSelect(Player player, uint menuId, uint gossipListId)
+ {
+ if (menuId == TextIds.GossipId && gossipListId == 0)
+ {
+ player.CloseGossipMenu();
+ BeginSpeech(player);
+ }
+ return false;
+ }
+ }
+
+ //Need to define an aurascript for EventBurningadrenaline's death effect.
+ [Script] // 18173 - Burning Adrenaline
+ class spell_vael_burning_adrenaline : AuraScript
+ {
+ void OnAuraRemoveHandler(AuraEffect aurEff, AuraEffectHandleModes mode)
+ {
+ //The tooltip says the on death the AoE occurs. According to information: http://qaliaresponse.stage.lithium.com/t5/WoW-Mayhem/Surviving-Burning-Adrenaline-For-tanks/td-p/48609
+ //Burning Adrenaline can be survived therefore Blizzard's implementation was an AoE bomb that went off if you were still alive and dealt
+ //damage to the target. You don't have to die for it to go off. It can go off whether you live or die.
+ GetTarget().CastSpell(GetTarget(), SpellIds.BurningadrenalineExplosion, true);
+ }
+
+ public override void Register()
+ {
+ AfterEffectRemove.Add(new EffectApplyHandler(OnAuraRemoveHandler, 2, AuraType.PeriodicTriggerSpell, AuraEffectHandleModes.Real));
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/BaronGeddon.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/BaronGeddon.cs
new file mode 100644
index 000000000..872f43572
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/BaronGeddon.cs
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using Game.Spells;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore.BaronGeddon
+{
+ struct SpellIds
+ {
+ public const uint Inferno = 19695;
+ public const uint InfernoDmg = 19698;
+ public const uint IgniteMana = 19659;
+ public const uint LivingBomb = 20475;
+ public const uint Armageddon = 20478;
+ }
+
+ struct TextIds
+ {
+ public const uint EmoteService = 0;
+ }
+
+ [Script]
+ class boss_baron_geddon : BossAI
+ {
+ public boss_baron_geddon(Creature creature) : base(creature, BossIds.BaronGeddon) { }
+
+ public override void JustEngagedWith(Unit victim)
+ {
+ base.JustEngagedWith(victim);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(45), task =>
+ {
+ DoCast(me, SpellIds.Inferno);
+ task.Repeat(TimeSpan.FromSeconds(45));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(30), task =>
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true, true, -(int)SpellIds.IgniteMana);
+ if (target)
+ DoCast(target, SpellIds.IgniteMana);
+ task.Repeat(TimeSpan.FromSeconds(30));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(35), task =>
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true);
+ if (target)
+ DoCast(target, SpellIds.LivingBomb);
+ task.Repeat(TimeSpan.FromSeconds(35));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff);
+
+ // If we are <2% hp cast Armageddon
+ if (!HealthAbovePct(2))
+ {
+ me.InterruptNonMeleeSpells(true);
+ DoCast(me, SpellIds.Armageddon);
+ Talk(TextIds.EmoteService);
+ return;
+ }
+
+ if (me.HasUnitState(UnitState.Casting))
+ return;
+
+ DoMeleeAttackIfReady();
+ }
+ }
+
+ [Script] // 19695 - Inferno
+ class spell_baron_geddon_inferno : AuraScript
+ {
+ void OnPeriodic(AuraEffect aurEff)
+ {
+ PreventDefaultAction();
+ int[] damageForTick = { 500, 500, 1000, 1000, 2000, 2000, 3000, 5000 };
+ CastSpellExtraArgs args = new CastSpellExtraArgs(TriggerCastFlags.FullMask);
+ args.TriggeringAura = aurEff;
+ args.AddSpellMod(SpellValueMod.BasePoint0, damageForTick[aurEff.GetTickNumber() - 1]);
+ GetTarget().CastSpell((WorldObject)null, SpellIds.InfernoDmg, args);
+ }
+
+ public override void Register()
+ {
+ OnEffectPeriodic.Add(new EffectPeriodicHandler(OnPeriodic, 0, AuraType.PeriodicTriggerSpell));
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Garr.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Garr.cs
new file mode 100644
index 000000000..a0118744b
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Garr.cs
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using Game.Spells;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore.Garr
+{
+ struct SpellIds
+ {
+ // Garr
+ public const uint AntimagicPulse = 19492;
+ public const uint MagmaShackles = 19496;
+ public const uint Enrage = 19516;
+ public const uint SeparationAnxiety = 23492;
+
+ // Adds
+ public const uint Eruption = 19497;
+ public const uint Immolate = 15732;
+ }
+
+ [Script]
+ class boss_garr : BossAI
+ {
+ public boss_garr(Creature creature) : base(creature, BossIds.Garr) { }
+
+ public override void JustEngagedWith(Unit victim)
+ {
+ base.JustEngagedWith(victim);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(25), task =>
+ {
+ DoCast(me, SpellIds.AntimagicPulse);
+ task.Repeat(TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(15));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(15), task =>
+ {
+ DoCast(me, SpellIds.MagmaShackles);
+ task.Repeat(TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(12));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+
+ [Script]
+ class npc_firesworn : ScriptedAI
+ {
+ public npc_firesworn(Creature creature) : base(creature) { }
+
+ void ScheduleTasks()
+ {
+ // Timers for this are probably wrong
+ _scheduler.Schedule(TimeSpan.FromSeconds(4), task =>
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0);
+ if (target)
+ DoCast(target, SpellIds.Immolate);
+
+ task.Repeat(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10));
+ });
+
+ // Separation Anxiety - Periodically check if Garr is nearby
+ // ...and enrage if he is not.
+ _scheduler.Schedule(TimeSpan.FromSeconds(3), task =>
+ {
+ if (!me.FindNearestCreature(MCCreatureIds.Garr, 20.0f))
+ DoCastSelf(SpellIds.SeparationAnxiety);
+ else if (me.HasAura(SpellIds.SeparationAnxiety))
+ me.RemoveAurasDueToSpell(SpellIds.SeparationAnxiety);
+
+ task.Repeat();
+ });
+ }
+
+ public override void Reset()
+ {
+ _scheduler.CancelAll();
+ }
+
+ public override void JustEngagedWith(Unit who)
+ {
+ ScheduleTasks();
+ }
+
+ public override void DamageTaken(Unit attacker, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null)
+ {
+ ulong health10pct = me.CountPctFromMaxHealth(10);
+ ulong health = me.GetHealth();
+ if (health - damage < health10pct)
+ {
+ damage = 0;
+ DoCastVictim(SpellIds.Eruption);
+ me.DespawnOrUnsummon();
+ }
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Gehennas.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Gehennas.cs
new file mode 100644
index 000000000..b6e86ae3b
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Gehennas.cs
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore.Gehennas
+{
+ struct SpellIds
+ {
+ public const uint GehennasCurse = 19716;
+ public const uint RainOfFire = 19717;
+ public const uint ShadowBolt = 19728;
+ }
+
+ [Script]
+ class boss_gehennas : BossAI
+ {
+ public boss_gehennas(Creature creature) : base(creature, BossIds.Gehennas) { }
+
+ public override void JustEngagedWith(Unit victim)
+ {
+ base.JustEngagedWith(victim);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(12), task =>
+ {
+ DoCastVictim(SpellIds.GehennasCurse);
+ task.Repeat(TimeSpan.FromSeconds(22), TimeSpan.FromSeconds(30));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(10), task =>
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0);
+ if (target)
+ DoCast(target, SpellIds.RainOfFire);
+ task.Repeat(TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(12));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(6), task =>
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 1);
+ if (target)
+ DoCast(target, SpellIds.ShadowBolt);
+ task.Repeat(TimeSpan.FromSeconds(7));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Golemagg.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Golemagg.cs
new file mode 100644
index 000000000..f248f94a1
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Golemagg.cs
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.AI;
+using Game.Entities;
+using Game.Maps;
+using Game.Scripting;
+using Game.Spells;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore.Golemagg
+{
+ struct SpellIds
+ {
+ // Golemagg
+ public const uint Magmasplash = 13879;
+ public const uint Pyroblast = 20228;
+ public const uint Earthquake = 19798;
+ public const uint Enrage = 19953;
+ public const uint GolemaggTrust = 20553;
+
+ // Core Rager
+ public const uint Mangle = 19820;
+ }
+
+ struct TextIds
+ {
+ public const uint EmoteLowhp = 0;
+ }
+
+ [Script]
+ class boss_golemagg : BossAI
+ {
+ public boss_golemagg(Creature creature) : base(creature, BossIds.GolemaggTheIncinerator) { }
+
+ public override void Reset()
+ {
+ base.Reset();
+ DoCast(me, SpellIds.Magmasplash, new CastSpellExtraArgs(true));
+ }
+
+ public override void JustEngagedWith(Unit victim)
+ {
+ base.JustEngagedWith(victim);
+ _scheduler.Schedule(TimeSpan.FromSeconds(7), task =>
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0);
+ if (target)
+ DoCast(target, SpellIds.Pyroblast);
+ task.Repeat(TimeSpan.FromSeconds(7));
+ });
+ }
+
+ public override void DamageTaken(Unit attacker, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null)
+ {
+ if (!HealthBelowPct(10) || me.HasAura(SpellIds.Enrage))
+ return;
+
+ DoCast(me, SpellIds.Enrage, new CastSpellExtraArgs(true));
+ _scheduler.Schedule(TimeSpan.FromSeconds(3), task =>
+ {
+ DoCastVictim(SpellIds.Earthquake);
+ task.Repeat(TimeSpan.FromSeconds(3));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+
+ [Script]
+ class npc_core_rager : ScriptedAI
+ {
+ InstanceScript _instance;
+
+ public npc_core_rager(Creature creature) : base(creature)
+ {
+ _instance = creature.GetInstanceScript();
+ }
+
+ public override void Reset()
+ {
+ _scheduler.CancelAll();
+ }
+
+ public override void JustEngagedWith(Unit who)
+ {
+ _scheduler.Schedule(TimeSpan.FromSeconds(7), task => // These times are probably wrong
+ {
+ DoCastVictim(SpellIds.Mangle);
+ task.Repeat(TimeSpan.FromSeconds(10));
+ });
+ }
+
+ public override void DamageTaken(Unit attacker, ref uint damage, DamageEffectType damageType, SpellInfo spellInfo = null)
+ {
+ if (HealthAbovePct(50) || _instance == null)
+ return;
+
+ Creature pGolemagg = ObjectAccessor.GetCreature(me, _instance.GetGuidData(BossIds.GolemaggTheIncinerator));
+ if (pGolemagg)
+ {
+ if (pGolemagg.IsAlive())
+ {
+ me.AddAura(SpellIds.GolemaggTrust, me);
+ Talk(TextIds.EmoteLowhp);
+ me.SetFullHealth();
+ }
+ }
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/InstanceMoltenCore.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/InstanceMoltenCore.cs
new file mode 100644
index 000000000..9b34d5633
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/InstanceMoltenCore.cs
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.Entities;
+using Game.Maps;
+using Game.Scripting;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore
+{
+ struct BossIds
+ {
+ public const uint Lucifron = 0;
+ public const uint Magmadar = 1;
+ public const uint Gehennas = 2;
+ public const uint Garr = 3;
+ public const uint Shazzrah = 4;
+ public const uint BaronGeddon = 5;
+ public const uint SulfuronHarbinger = 6;
+ public const uint GolemaggTheIncinerator = 7;
+ public const uint MajordomoExecutus = 8;
+ public const uint Ragnaros = 9;
+
+ public const uint MaxEncounter = 10;
+ }
+
+ struct ActionIds
+ {
+ public const int StartRagnaros = 0;
+ public const int StartRagnarosAlt = 1;
+ }
+
+ struct MCCreatureIds
+ {
+ public const uint Lucifron = 12118;
+ public const uint Magmadar = 11982;
+ public const uint Gehennas = 12259;
+ public const uint Garr = 12057;
+ public const uint Shazzrah = 12264;
+ public const uint BaronGeddon = 12056;
+ public const uint SulfuronHarbinger = 12098;
+ public const uint GolemaggTheIncinerator = 11988;
+ public const uint MajordomoExecutus = 12018;
+ public const uint Ragnaros = 11502;
+ public const uint FlamewakerHealer = 11663;
+ public const uint FlamewakerElite = 11664;
+ }
+
+ struct MCGameObjectIds
+ {
+ public const uint CacheOfTheFirelord = 179703;
+ }
+
+ struct MCMiscConst
+ {
+ public const uint DataRagnarosAdds = 0;
+
+ public static Position[] SummonPositions =
+ {
+ new Position(737.850f, -1145.35f, -120.288f, 4.71368f),
+ new Position(744.162f, -1151.63f, -119.726f, 4.58204f),
+ new Position(751.247f, -1152.82f, -119.744f, 4.49673f),
+ new Position(759.206f, -1155.09f, -120.051f, 4.30104f),
+ new Position(755.973f, -1152.33f, -120.029f, 4.25588f),
+ new Position(731.712f, -1147.56f, -120.195f, 4.95955f),
+ new Position(726.499f, -1149.80f, -120.156f, 5.24055f),
+ new Position(722.408f, -1152.41f, -120.029f, 5.33087f),
+ new Position(718.994f, -1156.36f, -119.805f, 5.75738f),
+ new Position(838.510f, -829.840f, -232.000f, 2.00000f),
+ };
+
+ public static Position RagnarosTelePos = new Position(829.159f, -815.773f, -228.972f, 5.30500f);
+ public static Position RagnarosSummonPos = new Position(838.510f, -829.840f, -232.000f, 2.00000f);
+ }
+
+ [Script]
+ class instance_molten_core : InstanceMapScript
+ {
+ public instance_molten_core() : base(nameof(instance_molten_core), 409) { }
+
+ class instance_molten_core_InstanceMapScript : InstanceScript
+ {
+ ObjectGuid _golemaggTheIncineratorGUID;
+ ObjectGuid _majordomoExecutusGUID;
+ ObjectGuid _cacheOfTheFirelordGUID;
+ bool _executusSchedule;
+ byte _ragnarosAddDeaths;
+
+ public instance_molten_core_InstanceMapScript(InstanceMap map) : base(map)
+ {
+ SetHeaders("MC");
+ SetBossNumber(BossIds.MaxEncounter);
+ _executusSchedule = false;
+ _ragnarosAddDeaths = 0;
+ }
+
+ public override void OnPlayerEnter(Player player)
+ {
+ if (_executusSchedule)
+ SummonMajordomoExecutus();
+ }
+
+ public override void OnCreatureCreate(Creature creature)
+ {
+ switch (creature.GetEntry())
+ {
+ case MCCreatureIds.GolemaggTheIncinerator:
+ _golemaggTheIncineratorGUID = creature.GetGUID();
+ break;
+ case MCCreatureIds.MajordomoExecutus:
+ _majordomoExecutusGUID = creature.GetGUID();
+ break;
+ default:
+ break;
+ }
+ }
+
+ public override void OnGameObjectCreate(GameObject go)
+ {
+ switch (go.GetEntry())
+ {
+ case MCGameObjectIds.CacheOfTheFirelord:
+ _cacheOfTheFirelordGUID = go.GetGUID();
+ break;
+ default:
+ break;
+ }
+ }
+
+ public override void SetData(uint type, uint data)
+ {
+ if (type == MCMiscConst.DataRagnarosAdds)
+ {
+ if (data == 1)
+ ++_ragnarosAddDeaths;
+ else if (data == 0)
+ _ragnarosAddDeaths = 0;
+ }
+ }
+
+ public override uint GetData(uint type)
+ {
+ switch (type)
+ {
+ case MCMiscConst.DataRagnarosAdds:
+ return _ragnarosAddDeaths;
+ }
+
+ return 0;
+ }
+
+ public override ObjectGuid GetGuidData(uint type)
+ {
+ switch (type)
+ {
+ case BossIds.GolemaggTheIncinerator:
+ return _golemaggTheIncineratorGUID;
+ case BossIds.MajordomoExecutus:
+ return _majordomoExecutusGUID;
+ }
+
+ return ObjectGuid.Empty;
+ }
+
+ public override bool SetBossState(uint bossId, EncounterState state)
+ {
+ if (!base.SetBossState(bossId, state))
+ return false;
+
+ if (state == EncounterState.Done && bossId < BossIds.MajordomoExecutus)
+ if (CheckMajordomoExecutus())
+ SummonMajordomoExecutus();
+
+ if (bossId == BossIds.MajordomoExecutus && state == EncounterState.Done)
+ DoRespawnGameObject(_cacheOfTheFirelordGUID, TimeSpan.FromDays(7));
+
+ return true;
+ }
+
+ void SummonMajordomoExecutus()
+ {
+ _executusSchedule = false;
+ if (!_majordomoExecutusGUID.IsEmpty())
+ return;
+
+ if (GetBossState(BossIds.MajordomoExecutus) != EncounterState.Done)
+ {
+ instance.SummonCreature(MCCreatureIds.MajordomoExecutus, MCMiscConst.SummonPositions[0]);
+ instance.SummonCreature(MCCreatureIds.FlamewakerHealer, MCMiscConst.SummonPositions[1]);
+ instance.SummonCreature(MCCreatureIds.FlamewakerHealer, MCMiscConst.SummonPositions[2]);
+ instance.SummonCreature(MCCreatureIds.FlamewakerHealer, MCMiscConst.SummonPositions[3]);
+ instance.SummonCreature(MCCreatureIds.FlamewakerHealer, MCMiscConst.SummonPositions[4]);
+ instance.SummonCreature(MCCreatureIds.FlamewakerElite, MCMiscConst.SummonPositions[5]);
+ instance.SummonCreature(MCCreatureIds.FlamewakerElite, MCMiscConst.SummonPositions[6]);
+ instance.SummonCreature(MCCreatureIds.FlamewakerElite, MCMiscConst.SummonPositions[7]);
+ instance.SummonCreature(MCCreatureIds.FlamewakerElite, MCMiscConst.SummonPositions[8]);
+ }
+ else
+ {
+ TempSummon summon = instance.SummonCreature(MCCreatureIds.MajordomoExecutus, MCMiscConst.RagnarosTelePos);
+ if (summon)
+ summon.GetAI().DoAction(ActionIds.StartRagnarosAlt);
+ }
+ }
+
+ bool CheckMajordomoExecutus()
+ {
+ if (GetBossState(BossIds.Ragnaros) == EncounterState.Done)
+ return false;
+
+ for (byte i = 0; i < BossIds.MajordomoExecutus; ++i)
+ if (GetBossState(i) != EncounterState.Done)
+ return false;
+
+ return true;
+ }
+
+ void ReadSaveDataMore(string data)
+ {
+ if (CheckMajordomoExecutus())
+ _executusSchedule = true;
+ }
+ }
+
+ public override InstanceScript GetInstanceScript(InstanceMap map)
+ {
+ return new instance_molten_core_InstanceMapScript(map);
+ }
+ }
+}
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Lucifron.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Lucifron.cs
new file mode 100644
index 000000000..c098322b3
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Lucifron.cs
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore.Lucifron
+{
+ struct SpellIds
+ {
+ public const uint ImpendingDoom = 19702;
+ public const uint LucifronCurse = 19703;
+ public const uint ShadowShock = 20603;
+ }
+
+ [Script]
+ class boss_lucifron : BossAI
+ {
+ public boss_lucifron(Creature creature) : base(creature, BossIds.Lucifron) { }
+
+ public override void JustEngagedWith(Unit victim)
+ {
+ base.JustEngagedWith(victim);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(10), task =>
+ {
+ DoCastVictim(SpellIds.ImpendingDoom);
+ task.Repeat(TimeSpan.FromSeconds(20));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(20), task =>
+ {
+ DoCastVictim(SpellIds.LucifronCurse);
+ task.Repeat(TimeSpan.FromSeconds(15));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(6), task =>
+ {
+ DoCastVictim(SpellIds.ShadowShock);
+ task.Repeat(TimeSpan.FromSeconds(6));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Magmadar.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Magmadar.cs
new file mode 100644
index 000000000..9884e767e
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Magmadar.cs
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using Game.Spells;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore.Magmadar
+{
+ struct SpellIds
+ {
+ public const uint Frenzy = 19451;
+ public const uint MagmaSpit = 19449;
+ public const uint Panic = 19408;
+ public const uint LavaBomb = 19428;
+ }
+
+ struct TextIds
+ {
+ public const uint EmoteFrenzy = 0;
+ }
+
+ [Script]
+ class boss_magmadar : BossAI
+ {
+ public boss_magmadar(Creature creature) : base(creature, BossIds.Magmadar) { }
+
+ public override void Reset()
+ {
+ base.Reset();
+ DoCast(me, SpellIds.MagmaSpit, new CastSpellExtraArgs(true));
+ }
+
+ public override void JustEngagedWith(Unit victim)
+ {
+ base.JustEngagedWith(victim);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(30), task =>
+ {
+ Talk(TextIds.EmoteFrenzy);
+ DoCast(me, SpellIds.Frenzy);
+ task.Repeat(TimeSpan.FromSeconds(15));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(20), task =>
+ {
+ DoCastVictim(SpellIds.Panic);
+ task.Repeat(TimeSpan.FromSeconds(35));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(12), task =>
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true, true, -(int)SpellIds.LavaBomb);
+ if (target)
+ DoCast(target, SpellIds.LavaBomb);
+ task.Repeat(TimeSpan.FromSeconds(12));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/MajordomoExecutus.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/MajordomoExecutus.cs
new file mode 100644
index 000000000..bd5b15c6a
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/MajordomoExecutus.cs
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using Game.Spells;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore.Majordomo
+{
+ struct SpellIds
+ {
+ public const uint SummonRagnaros = 19774;
+ public const uint BlastWave = 20229;
+ public const uint Teleport = 20618;
+ public const uint MagicReflection = 20619;
+ public const uint AegisOfRagnaros = 20620;
+ public const uint DamageReflection = 21075;
+ }
+
+ struct TextIds
+ {
+ public const uint SayAggro = 0;
+ public const uint SaySpawn = 1;
+ public const uint SaySlay = 2;
+ public const uint SaySpecial = 3;
+ public const uint SayDefeat = 4;
+
+ public const uint SaySummonMaj = 5;
+ public const uint SayArrival2Maj = 6;
+
+ public const uint OptionIdYouChallengedUs = 0;
+ public const uint MenuOptionYouChallengedUs = 4108;
+ }
+
+ [Script]
+ class boss_majordomo : BossAI
+ {
+ public boss_majordomo(Creature creature) : base(creature, BossIds.MajordomoExecutus) { }
+
+ public override void KilledUnit(Unit victim)
+ {
+ if (RandomHelper.URand(0, 99) < 25)
+ Talk(TextIds.SaySlay);
+ }
+
+ public override void JustEngagedWith(Unit who)
+ {
+ base.JustEngagedWith(who);
+ Talk(TextIds.SayAggro);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(30), task =>
+ {
+ DoCast(me, SpellIds.MagicReflection);
+ task.Repeat(TimeSpan.FromSeconds(30));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(15), task =>
+ {
+ DoCast(me, SpellIds.DamageReflection);
+ task.Repeat(TimeSpan.FromSeconds(30));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(10), task =>
+ {
+ DoCastVictim(SpellIds.BlastWave);
+ task.Repeat(TimeSpan.FromSeconds(10));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(20), task =>
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 1);
+ if (target)
+ DoCast(target, SpellIds.Teleport);
+ task.Repeat(TimeSpan.FromSeconds(20));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ _scheduler.Update(diff);
+
+ if (instance.GetBossState(BossIds.MajordomoExecutus) != EncounterState.Done)
+ {
+ if (!UpdateVictim())
+ return;
+
+ if (!me.FindNearestCreature(MCCreatureIds.FlamewakerHealer, 100.0f) && !me.FindNearestCreature(MCCreatureIds.FlamewakerElite, 100.0f))
+ {
+ instance.UpdateEncounterStateForKilledCreature(me.GetEntry(), me);
+ me.SetFaction((uint)FactionTemplates.Friendly);
+ EnterEvadeMode();
+ Talk(TextIds.SayDefeat);
+ _JustDied();
+ _scheduler.Schedule(TimeSpan.FromSeconds(32), task =>
+ {
+ me.NearTeleportTo(MCMiscConst.RagnarosTelePos.GetPositionX(), MCMiscConst.RagnarosTelePos.GetPositionY(), MCMiscConst.RagnarosTelePos.GetPositionZ(), MCMiscConst.RagnarosTelePos.GetOrientation());
+ me.SetNpcFlag(NPCFlags.Gossip);
+ });
+ return;
+ }
+
+ if (me.HasUnitState(UnitState.Casting))
+ return;
+
+ if (HealthBelowPct(50))
+ DoCast(me, SpellIds.AegisOfRagnaros, new CastSpellExtraArgs(true));
+
+ DoMeleeAttackIfReady();
+ }
+ }
+
+ public override void DoAction(int action)
+ {
+ if (action == ActionIds.StartRagnaros)
+ {
+ me.RemoveNpcFlag(NPCFlags.Gossip);
+ Talk(TextIds.SaySummonMaj);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(8), task =>
+ {
+ instance.instance.SummonCreature(MCCreatureIds.Ragnaros, MCMiscConst.RagnarosSummonPos);
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(24), task =>
+ {
+ Talk(TextIds.SayArrival2Maj);
+ });
+ }
+ else if (action == ActionIds.StartRagnarosAlt)
+ {
+ me.SetFaction((uint)FactionTemplates.Friendly);
+ me.SetNpcFlag(NPCFlags.Gossip);
+ }
+ }
+
+ public override bool OnGossipSelect(Player player, uint menuId, uint gossipListId)
+ {
+ if (menuId == TextIds.MenuOptionYouChallengedUs && gossipListId == TextIds.OptionIdYouChallengedUs)
+ {
+ player.CloseGossipMenu();
+ DoAction(ActionIds.StartRagnaros);
+ }
+ return false;
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Ragnaros.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Ragnaros.cs
new file mode 100644
index 000000000..02260e0fd
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Ragnaros.cs
@@ -0,0 +1,342 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.AI;
+using Game.Entities;
+using Game.Maps;
+using Game.Scripting;
+using System;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore
+{
+ struct SpellIds
+ {
+ public const uint HandOfRagnaros = 19780;
+ public const uint WrathOfRagnaros = 20566;
+ public const uint LavaBurst = 21158;
+ public const uint MagmaBlast = 20565; // Ranged attack
+ public const uint SonsOfFlameDummy = 21108; // Server side effect
+ public const uint Ragsubmerge = 21107; // Stealth aura
+ public const uint Ragemerge = 20568;
+ public const uint MeltWeapon = 21388;
+ public const uint ElementalFire = 20564;
+ public const uint Erruption = 17731;
+ }
+
+ struct TextIds
+ {
+ public const uint SaySummonMaj = 0;
+ public const uint SayArrival1Rag = 1;
+ public const uint SayArrival2Maj = 2;
+ public const uint SayArrival3Rag = 3;
+ public const uint SayArrival5Rag = 4;
+ public const uint SayReinforcements1 = 5;
+ public const uint SayReinforcements2 = 6;
+ public const uint SayHand = 7;
+ public const uint SayWrath = 8;
+ public const uint SayKill = 9;
+ public const uint SayMagmaburst = 10;
+ }
+
+ struct EventIds
+ {
+ public const uint Eruption = 1;
+ public const uint WrathOfRagnaros = 2;
+ public const uint HandOfRagnaros = 3;
+ public const uint LavaBurst = 4;
+ public const uint ElementalFire = 5;
+ public const uint MagmaBlast = 6;
+ public const uint Submerge = 7;
+
+ public const uint Intro1 = 8;
+ public const uint Intro2 = 9;
+ public const uint Intro3 = 10;
+ public const uint Intro4 = 11;
+ public const uint Intro5 = 12;
+ }
+
+ [Script]
+ class boss_ragnaros : BossAI
+ {
+ uint _emergeTimer;
+ byte _introState;
+ bool _hasYelledMagmaBurst;
+ bool _hasSubmergedOnce;
+ bool _isBanished;
+
+ public boss_ragnaros(Creature creature) : base(creature, BossIds.Ragnaros)
+ {
+ Initialize();
+ _introState = 0;
+ me.SetReactState(ReactStates.Passive);
+ me.SetUnitFlag(UnitFlags.NonAttackable);
+ SetCombatMovement(false);
+ }
+
+ void Initialize()
+ {
+ _emergeTimer = 90000;
+ _hasYelledMagmaBurst = false;
+ _hasSubmergedOnce = false;
+ _isBanished = false;
+ }
+
+ public override void Reset()
+ {
+ base.Reset();
+ Initialize();
+ me.SetEmoteState(Emote.OneshotNone);
+ }
+
+ public override void JustEngagedWith(Unit victim)
+ {
+ base.JustEngagedWith(victim);
+ _events.ScheduleEvent(EventIds.Eruption, TimeSpan.FromSeconds(15));
+ _events.ScheduleEvent(EventIds.WrathOfRagnaros, TimeSpan.FromSeconds(30));
+ _events.ScheduleEvent(EventIds.HandOfRagnaros, TimeSpan.FromSeconds(25));
+ _events.ScheduleEvent(EventIds.LavaBurst, TimeSpan.FromSeconds(10));
+ _events.ScheduleEvent(EventIds.ElementalFire, TimeSpan.FromSeconds(3));
+ _events.ScheduleEvent(EventIds.MagmaBlast, TimeSpan.FromSeconds(2));
+ _events.ScheduleEvent(EventIds.Submerge, TimeSpan.FromMinutes(3));
+ }
+
+ public override void KilledUnit(Unit victim)
+ {
+ if (RandomHelper.URand(0, 99) < 25)
+ Talk(TextIds.SayKill);
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (_introState != 2)
+ {
+ if (_introState == 0)
+ {
+ me.HandleEmoteCommand(Emote.OneshotEmerge);
+ _events.ScheduleEvent(EventIds.Intro1, TimeSpan.FromSeconds(4));
+ _events.ScheduleEvent(EventIds.Intro2, TimeSpan.FromSeconds(23));
+ _events.ScheduleEvent(EventIds.Intro3, TimeSpan.FromSeconds(42));
+ _events.ScheduleEvent(EventIds.Intro4, TimeSpan.FromSeconds(43));
+ _events.ScheduleEvent(EventIds.Intro5, TimeSpan.FromSeconds(53));
+ _introState = 1;
+ }
+
+ _events.Update(diff);
+
+ _events.ExecuteEvents(eventId =>
+ {
+ switch (eventId)
+ {
+ case EventIds.Intro1:
+ Talk(TextIds.SayArrival1Rag);
+ break;
+ case EventIds.Intro2:
+ Talk(TextIds.SayArrival3Rag);
+ break;
+ case EventIds.Intro3:
+ me.HandleEmoteCommand(Emote.OneshotAttack1h);
+ break;
+ case EventIds.Intro4:
+ Talk(TextIds.SayArrival5Rag);
+ Creature executus = ObjectAccessor.GetCreature(me, instance.GetGuidData(BossIds.MajordomoExecutus));
+ if (executus)
+ Unit.Kill(me, executus);
+ break;
+ case EventIds.Intro5:
+ me.SetReactState(ReactStates.Aggressive);
+ me.RemoveUnitFlag(UnitFlags.NonAttackable);
+ me.SetImmuneToPC(false);
+ _introState = 2;
+ break;
+ default:
+ break;
+ }
+ });
+ }
+ else
+ {
+ if (_isBanished && ((_emergeTimer <= diff) || (instance.GetData(MCMiscConst.DataRagnarosAdds)) > 8))
+ {
+ //Become unbanished again
+ me.SetReactState(ReactStates.Aggressive);
+ me.SetFaction((uint)FactionTemplates.Monster);
+ me.RemoveUnitFlag(UnitFlags.Uninteractible);
+ me.SetEmoteState(Emote.OneshotNone);
+ me.HandleEmoteCommand(Emote.OneshotEmerge);
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0);
+ if (target)
+ AttackStart(target);
+ instance.SetData(MCMiscConst.DataRagnarosAdds, 0);
+
+ //DoCast(me, SpellRagemerge); //"phase spells" didnt worked correctly so Ive commented them and wrote solution witch doesnt need core support
+ _isBanished = false;
+ }
+ else if (_isBanished)
+ {
+ _emergeTimer -= diff;
+ //Do nothing while banished
+ return;
+ }
+
+ //Return since we have no target
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ _events.ExecuteEvents(eventId =>
+ {
+ switch (eventId)
+ {
+ case EventIds.Eruption:
+ DoCastVictim(SpellIds.Erruption);
+ _events.ScheduleEvent(EventIds.Eruption, TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(45));
+ break;
+ case EventIds.WrathOfRagnaros:
+ DoCastVictim(SpellIds.WrathOfRagnaros);
+ if (RandomHelper.URand(0, 1) != 0)
+ Talk(TextIds.SayWrath);
+ _events.ScheduleEvent(EventIds.WrathOfRagnaros, TimeSpan.FromSeconds(25));
+ break;
+ case EventIds.HandOfRagnaros:
+ DoCast(me, SpellIds.HandOfRagnaros);
+ if (RandomHelper.URand(0, 1) != 0)
+ Talk(TextIds.SayHand);
+ _events.ScheduleEvent(EventIds.HandOfRagnaros, TimeSpan.FromSeconds(20));
+ break;
+ case EventIds.LavaBurst:
+ DoCastVictim(SpellIds.LavaBurst);
+ _events.ScheduleEvent(EventIds.LavaBurst, TimeSpan.FromSeconds(10));
+ break;
+ case EventIds.ElementalFire:
+ DoCastVictim(SpellIds.ElementalFire);
+ _events.ScheduleEvent(EventIds.ElementalFire, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(14));
+ break;
+ case EventIds.MagmaBlast:
+ if (!me.IsWithinMeleeRange(me.GetVictim()))
+ {
+ DoCastVictim(SpellIds.MagmaBlast);
+ if (!_hasYelledMagmaBurst)
+ {
+ //Say our dialog
+ Talk(TextIds.SayMagmaburst);
+ _hasYelledMagmaBurst = true;
+ }
+ }
+ _events.ScheduleEvent(EventIds.MagmaBlast, TimeSpan.FromMilliseconds(2500));
+ break;
+ case EventIds.Submerge:
+ {
+ if (!_isBanished)
+ {
+ //Creature spawning and ragnaros becomming unattackable
+ //is not very well supported in the core //no it really isnt
+ //so added normaly spawning and banish workaround and attack again after 90 secs.
+ me.AttackStop();
+ ResetThreatList();
+ me.SetReactState(ReactStates.Passive);
+ me.InterruptNonMeleeSpells(false);
+ //Root self
+ //DoCast(me, 23973);
+ me.SetFaction((uint)FactionTemplates.Friendly);
+ me.SetUnitFlag(UnitFlags.Uninteractible);
+ me.SetEmoteState(Emote.StateSubmerged);
+ me.HandleEmoteCommand(Emote.OneshotSubmerge);
+ instance.SetData(MCMiscConst.DataRagnarosAdds, 0);
+
+ if (!_hasSubmergedOnce)
+ {
+ Talk(TextIds.SayReinforcements1);
+
+ // summon 8 elementals
+ for (byte i = 0; i < 8; ++i)
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0);
+ if (target != null)
+ {
+ Creature summoned = me.SummonCreature(12143, target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), 0.0f, TempSummonType.TimedOrCorpseDespawn, TimeSpan.FromMinutes(15));
+ if (summoned != null)
+ summoned.GetAI().AttackStart(target);
+ }
+ }
+
+ _hasSubmergedOnce = true;
+ _isBanished = true;
+ //DoCast(me, SpellRagsubmerge);
+ _emergeTimer = 90000;
+
+ }
+ else
+ {
+ Talk(TextIds.SayReinforcements2);
+
+ for (byte i = 0; i < 8; ++i)
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0);
+ if (target != null)
+ {
+ Creature summoned = me.SummonCreature(12143, target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), 0.0f, TempSummonType.TimedOrCorpseDespawn, TimeSpan.FromMinutes(15));
+ if (summoned != null)
+ summoned.GetAI().AttackStart(target);
+ }
+ }
+
+ _isBanished = true;
+ //DoCast(me, SpellRagsubmerge);
+ _emergeTimer = 90000;
+ }
+ }
+ _events.ScheduleEvent(EventIds.Submerge, TimeSpan.FromMinutes(3));
+ break;
+ }
+ default:
+ break;
+ }
+ });
+
+
+ DoMeleeAttackIfReady();
+ }
+ }
+ }
+
+ [Script]
+ class npc_son_of_flame : ScriptedAI //didnt work correctly in Eai for me...
+ {
+ InstanceScript instance;
+
+ public npc_son_of_flame(Creature creature) : base(creature)
+ {
+ instance = me.GetInstanceScript();
+ }
+
+ public override void JustDied(Unit killer)
+ {
+ instance.SetData(MCMiscConst.DataRagnarosAdds, 1);
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ DoMeleeAttackIfReady();
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Shazzrah.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Shazzrah.cs
new file mode 100644
index 000000000..8a11662b3
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Shazzrah.cs
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Framework.Constants;
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using Game.Spells;
+using System;
+using System.Collections.Generic;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore.Shazzrah
+{
+ struct SpellIds
+ {
+ public const uint ArcaneExplosion = 19712;
+ public const uint ShazzrahCurse = 19713;
+ public const uint MagicGrounding = 19714;
+ public const uint Counterspell = 19715;
+ public const uint ShazzrahGateDummy = 23138; // Teleports to and attacks a random target.
+ public const uint ShazzrahGate = 23139;
+ }
+
+ struct EventIds
+ {
+ public const uint ArcaneExplosion = 1;
+ public const uint ArcaneExplosionTriggered = 2;
+ public const uint ShazzrahCurse = 3;
+ public const uint MagicGrounding = 4;
+ public const uint Counterspell = 5;
+ public const uint ShazzrahGate = 6;
+ }
+
+ [Script]
+ class boss_shazzrah : BossAI
+ {
+ public boss_shazzrah(Creature creature) : base(creature, BossIds.Shazzrah) { }
+
+ public override void JustEngagedWith(Unit target)
+ {
+ base.JustEngagedWith(target);
+ _events.ScheduleEvent(EventIds.ArcaneExplosion, TimeSpan.FromSeconds(6));
+ _events.ScheduleEvent(EventIds.ShazzrahCurse, TimeSpan.FromSeconds(10));
+ _events.ScheduleEvent(EventIds.MagicGrounding, TimeSpan.FromSeconds(24));
+ _events.ScheduleEvent(EventIds.Counterspell, TimeSpan.FromSeconds(15));
+ _events.ScheduleEvent(EventIds.ShazzrahGate, TimeSpan.FromSeconds(45));
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _events.Update(diff);
+
+ if (me.HasUnitState(UnitState.Casting))
+ return;
+
+ _events.ExecuteEvents(eventId =>
+ {
+ switch (eventId)
+ {
+ case EventIds.ArcaneExplosion:
+ DoCastVictim(SpellIds.ArcaneExplosion);
+ _events.ScheduleEvent(EventIds.ArcaneExplosion, TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(7));
+ break;
+ // Triggered subsequent to using "Gate of Shazzrah".
+ case EventIds.ArcaneExplosionTriggered:
+ DoCastVictim(SpellIds.ArcaneExplosion);
+ break;
+ case EventIds.ShazzrahCurse:
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true, true, -(int)SpellIds.ShazzrahCurse);
+ if (target)
+ DoCast(target, SpellIds.ShazzrahCurse);
+ _events.ScheduleEvent(EventIds.ShazzrahCurse, TimeSpan.FromSeconds(25), TimeSpan.FromSeconds(30));
+ break;
+ case EventIds.MagicGrounding:
+ DoCast(me, SpellIds.MagicGrounding);
+ _events.ScheduleEvent(EventIds.MagicGrounding, TimeSpan.FromSeconds(35));
+ break;
+ case EventIds.Counterspell:
+ DoCastVictim(SpellIds.Counterspell);
+ _events.ScheduleEvent(EventIds.Counterspell, TimeSpan.FromSeconds(16), TimeSpan.FromSeconds(20));
+ break;
+ case EventIds.ShazzrahGate:
+ ResetThreatList();
+ DoCastAOE(SpellIds.ShazzrahGateDummy);
+ _events.ScheduleEvent(EventIds.ArcaneExplosionTriggered, TimeSpan.FromSeconds(2));
+ _events.RescheduleEvent(EventIds.ArcaneExplosion, TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(6));
+ _events.ScheduleEvent(EventIds.ShazzrahGate, TimeSpan.FromSeconds(45));
+ break;
+ default:
+ break;
+ }
+
+ if (me.HasUnitState(UnitState.Casting))
+ return;
+ });
+
+
+ DoMeleeAttackIfReady();
+ }
+ }
+
+ [Script] // 23138 - Gate of Shazzrah
+ class spell_shazzrah_gate_dummy : SpellScript
+ {
+ public override bool Validate(SpellInfo spellInfo)
+ {
+ return ValidateSpellInfo(SpellIds.ShazzrahGate);
+ }
+
+ void FilterTargets(List targets)
+ {
+ if (targets.Empty())
+ return;
+
+ WorldObject target = targets.SelectRandom();
+ targets.Clear();
+ targets.Add(target);
+ }
+
+ void HandleScript(uint effIndex)
+ {
+ Unit target = GetHitUnit();
+ if (target)
+ {
+ target.CastSpell(GetCaster(), SpellIds.ShazzrahGate, true);
+ Creature creature = GetCaster().ToCreature();
+ if (creature)
+ creature.GetAI().AttackStart(target); // Attack the target which caster will teleport to.
+ }
+ }
+
+ public override void Register()
+ {
+ OnObjectAreaTargetSelect.Add(new ObjectAreaTargetSelectHandler(FilterTargets, 0, Targets.UnitSrcAreaEnemy));
+ OnEffectHitTarget.Add(new EffectHandler(HandleScript, 0, SpellEffectName.Dummy));
+ }
+ }
+}
+
diff --git a/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/SulfuronHarbinger.cs b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/SulfuronHarbinger.cs
new file mode 100644
index 000000000..3f94226da
--- /dev/null
+++ b/Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/SulfuronHarbinger.cs
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2012-2020 CypherCore
+ *
+ * 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 3 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 .
+ */
+
+using Game.AI;
+using Game.Entities;
+using Game.Scripting;
+using System;
+using System.Collections.Generic;
+
+namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore.Sulfuron
+{
+ struct SpellIds
+ {
+ // Sulfuron Harbringer
+ public const uint DarkStrike = 19777;
+ public const uint DemoralizingShout = 19778;
+ public const uint Inspire = 19779;
+ public const uint Knockdown = 19780;
+ public const uint Flamespear = 19781;
+
+ // Adds
+ public const uint Heal = 19775;
+ public const uint Shadowwordpain = 19776;
+ public const uint Immolate = 20294;
+ }
+
+ [Script]
+ class boss_sulfuron : BossAI
+ {
+ public boss_sulfuron(Creature creature) : base(creature, BossIds.SulfuronHarbinger) { }
+
+ public override void JustEngagedWith(Unit victim)
+ {
+ base.JustEngagedWith(victim);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(10), task =>
+ {
+ DoCast(me, SpellIds.DarkStrike);
+ task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(18));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(15), task =>
+ {
+ DoCastVictim(SpellIds.DemoralizingShout);
+ task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(13), task =>
+ {
+ List healers = DoFindFriendlyMissingBuff(45.0f, SpellIds.Inspire);
+ if (!healers.Empty())
+ DoCast(healers.SelectRandom(), SpellIds.Inspire);
+
+ DoCast(me, SpellIds.Inspire);
+ task.Repeat(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(26));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(6), task =>
+ {
+ DoCastVictim(SpellIds.Knockdown);
+ task.Repeat(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(15));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(2), task =>
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true);
+ if (target)
+ DoCast(target, SpellIds.Flamespear);
+ task.Repeat(TimeSpan.FromSeconds(12), TimeSpan.FromSeconds(16));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+
+ [Script]
+ class npc_flamewaker_priest : ScriptedAI
+ {
+ public npc_flamewaker_priest(Creature creature) : base(creature)
+ {
+ }
+
+ public override void Reset()
+ {
+ _scheduler.CancelAll();
+ }
+
+ public override void JustDied(Unit killer)
+ {
+ _scheduler.CancelAll();
+ }
+
+ public override void JustEngagedWith(Unit victim)
+ {
+ base.JustEngagedWith(victim);
+
+ _scheduler.Schedule(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(30), task =>
+ {
+ Unit target = DoSelectLowestHpFriendly(60.0f, 1);
+ if (target)
+ DoCast(target, SpellIds.Heal);
+ task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(2), task =>
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true, true, -(int)SpellIds.Shadowwordpain);
+ if (target)
+ DoCast(target, SpellIds.Shadowwordpain);
+ task.Repeat(TimeSpan.FromSeconds(18), TimeSpan.FromSeconds(26));
+ });
+ _scheduler.Schedule(TimeSpan.FromSeconds(8), task =>
+ {
+ Unit target = SelectTarget(SelectTargetMethod.Random, 0, 0.0f, true, true, -(int)SpellIds.Immolate);
+ if (target)
+ DoCast(target, SpellIds.Immolate);
+ task.Repeat(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(25));
+ });
+ }
+
+ public override void UpdateAI(uint diff)
+ {
+ if (!UpdateVictim())
+ return;
+
+ _scheduler.Update(diff, () => DoMeleeAttackIfReady());
+ }
+ }
+}
+
diff --git a/Source/Scripts/World/NpcSpecial.cs b/Source/Scripts/World/NpcSpecial.cs
index cb0f07a94..d7deea90c 100644
--- a/Source/Scripts/World/NpcSpecial.cs
+++ b/Source/Scripts/World/NpcSpecial.cs
@@ -1288,7 +1288,7 @@ namespace Scripts.World.NpcSpecial
public override void Reset()
{
- _events.Reset();
+ _scheduler.CancelAll();
_scheduler.Schedule(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), fillListTask =>
{
List creatureList = me.GetCreatureListWithEntryInGrid(CreatureIds.BrewfestReveler, 5.0f);