From f42b21a6de32b9076eb3d3d73de60f719d17de07 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Fri, 8 Jul 2022 11:43:58 -0400 Subject: [PATCH] Start adding missing scripts Part4 --- Source/Framework/Dynamic/EventMap.cs | 2 +- .../BlackwingLair/BroodlordLashlayer.cs | 209 +++++++ .../BlackwingLair/Chromaggus.cs | 297 +++++++++ .../BlackwingLair/Ebonroc.cs | 67 ++ .../BlackwingLair/Firemaw.cs | 69 ++ .../BlackwingLair/Flamegor.cs | 75 +++ .../BlackwingLair/InstanceBlackwingLair.cs | 376 +++++++++++ .../BlackwingLair/Nefarian.cs | 592 ++++++++++++++++++ .../BlackwingLair/Razorgore.cs | 185 ++++++ .../BlackwingLair/Vaelastrasz.cs | 214 +++++++ .../MoltenCore/BaronGeddon.cs | 113 ++++ .../BlackrockMountain/MoltenCore/Garr.cs | 131 ++++ .../BlackrockMountain/MoltenCore/Gehennas.cs | 71 +++ .../BlackrockMountain/MoltenCore/Golemagg.cs | 141 +++++ .../MoltenCore/InstanceMoltenCore.cs | 245 ++++++++ .../BlackrockMountain/MoltenCore/Lucifron.cs | 67 ++ .../BlackrockMountain/MoltenCore/Magmadar.cs | 83 +++ .../MoltenCore/MajordomoExecutus.cs | 160 +++++ .../BlackrockMountain/MoltenCore/Ragnaros.cs | 342 ++++++++++ .../BlackrockMountain/MoltenCore/Shazzrah.cs | 156 +++++ .../MoltenCore/SulfuronHarbinger.cs | 145 +++++ Source/Scripts/World/NpcSpecial.cs | 2 +- 22 files changed, 3740 insertions(+), 2 deletions(-) create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/BroodlordLashlayer.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Chromaggus.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Ebonroc.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Firemaw.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Flamegor.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/InstanceBlackwingLair.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Nefarian.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Razorgore.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/BlackwingLair/Vaelastrasz.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/BaronGeddon.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Garr.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Gehennas.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Golemagg.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/InstanceMoltenCore.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Lucifron.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Magmadar.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/MajordomoExecutus.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Ragnaros.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/Shazzrah.cs create mode 100644 Source/Scripts/EasternKingdoms/BlackrockMountain/MoltenCore/SulfuronHarbinger.cs 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);