// Copyright (c) CypherCore All rights reserved. // Licensed under the Gnu General Public License. See License file in the project root for full license information. using Framework.Constants; using Framework.Dynamic; using Game.AI; using Game.Entities; using Game.Maps; using Game.Scripting; using Game.Spells; using System; using System.Collections.Generic; using System.Linq; namespace Scripts.Spells.Shaman; struct SpellIds { public const uint AftershockEnergize = 210712; public const uint AncestralGuidance = 108281; public const uint AncestralGuidanceHeal = 114911; public const uint ArcticSnowstormAreatrigger = 462767; public const uint ArcticSnowstormSlow = 462765; public const uint AscendanceElemental = 114050; public const uint AscendanceEnhancement = 114051; public const uint AscendanceRestoration = 114052; public const uint ChainLightning = 188443; public const uint ChainLightningEnergize = 195897; public const uint ChainLightningOverload = 45297; public const uint ChainLightningOverloadEnergize = 218558; public const uint ChainedHeal = 70809; public const uint ConvergingStorms = 384363; public const uint CrashLightning = 187874; public const uint CrashLightningCleave = 187878; public const uint CrashLightningDamageBuff = 333964; public const uint DelugeAura = 200075; public const uint DelugeTalent = 200076; public const uint DoomWindsDamage = 469270; public const uint DoomWindsLegendaryCooldown = 335904; public const uint Earthquake = 61882; public const uint EarthquakeKnockingDown = 77505; public const uint EarthquakeTick = 77478; public const uint EarthShieldHeal = 204290; public const uint EarthenRagePassive = 170374; public const uint EarthenRagePeriodic = 170377; public const uint EarthenRageDamage = 170379; public const uint EchoesOfGreatSunderingLegendary = 336217; public const uint EchoesOfGreatSunderingTalent = 384088; public const uint Electrified = 64930; public const uint ElementalBlast = 117014; public const uint ElementalBlastCrit = 118522; public const uint ElementalBlastHaste = 173183; public const uint ElementalBlastMastery = 173184; public const uint ElementalBlastOverload = 120588; public const uint ElementalMastery = 16166; public const uint ElementalWeaponsBuff = 408390; public const uint EnergySurge = 40465; public const uint EnhancedElements = 77223; public const uint FireNovaDamage = 333977; public const uint FireNovaEnabler = 466622; public const uint FlameShock = 188389; public const uint FlametongueAttack = 10444; public const uint FlametongueWeaponEnchant = 334294; public const uint FlametongueWeaponAura = 319778; public const uint ForcefulWindsProc = 262652; public const uint ForcefulWindsTalent = 262647; public const uint FrostShock = 196840; public const uint FrostShockEnergize = 289439; public const uint GatheringStorms = 198299; public const uint GatheringStormsBuff = 198300; public const uint GhostWolf = 2645; public const uint HailstormBuff = 334196; public const uint HailstormTalent = 334195; public const uint HealingRainVisual = 147490; public const uint HealingRain = 73920; public const uint HealingRainHeal = 73921; public const uint IceStrikeOverrideAura = 466469; public const uint IceStrikeProc = 466467; public const uint Icefury = 210714; public const uint IcefuryOverload = 219271; public const uint IgneousPotential = 279830; public const uint ItemLightningShield = 23552; public const uint ItemLightningShieldDamage = 27635; public const uint ItemManaSurge = 23571; public const uint LavaBurst = 51505; public const uint LavaBurstBonusDamage = 71824; public const uint LavaBurstOverload = 77451; public const uint LavaLash = 60103; public const uint LavaSurge = 77762; public const uint LightningBolt = 188196; public const uint LightningBoltEnergize = 214815; public const uint LightningBoltOverload = 45284; public const uint LightningBoltOverloadEnergize = 214816; public const uint LiquidMagmaHit = 192231; public const uint MaelstromController = 343725; public const uint MaelstromWeaponModAura = 187881; public const uint MaelstromWeaponVisibleAura = 344179; public const uint MaelstromWeaponOverlay = 187890; public const uint MaelstromWeaponOverlayHeals = 412692; public const uint MasteryElementalOverload = 168534; public const uint MoltenAssault = 334033; public const uint MoltenThunderProc = 469346; public const uint MoltenThunderTalent = 469344; public const uint NaturesGuardianCooldown = 445698; public const uint OverflowingMaelstromAura = 384669; public const uint OverflowingMaelstromTalent = 384149; public const uint PathOfFlamesSpread = 210621; public const uint PathOfFlamesTalent = 201909; public const uint PowerSurge = 40466; public const uint PrimordialWaveDamage = 375984; public const uint RestorativeMists = 114083; public const uint RestorativeMistsInitial = 294020; public const uint Riptide = 61295; public const uint SpiritWolfTalent = 260878; public const uint SpiritWolfPeriodic = 260882; public const uint SpiritWolfAura = 260881; public const uint StormblastDamage = 390287; public const uint StormblastProc = 470466; public const uint StormblastTalent = 319930; public const uint Stormflurry = 344357; public const uint StormflurryArtifact = 198367; public const uint Stormkeeper = 191634; public const uint Stormstrike = 17364; public const uint StormstrikeDamageMainHand = 32175; public const uint StormstrikeDamageOffHand = 32176; public const uint StormsurgeProc = 201846; public const uint StormweaverPvpTalent = 410673; public const uint StormweaverPvpTalentBuff = 410681; public const uint T29_2PElementalDamageBuff = 394651; public const uint ThorimsInvocation = 384444; public const uint TidalWaves = 53390; public const uint TotemicPowerArmor = 28827; public const uint TotemicPowerAttackPower = 28826; public const uint TotemicPowerMP5 = 28824; public const uint TotemicPowerSpellPower = 28825; public const uint UndulationProc = 216251; public const uint UnlimitedPowerBuff = 272737; public const uint UnrelentingStormsReduction = 470491; public const uint UnrelentingStormsTalent = 470490; public const uint UnrulyWinds = 390288; public const uint VoltaicBlazeDamage = 470057; public const uint VoltaicBlazeOverride = 470058; public const uint WindfuryAttack = 25504; public const uint WindfuryAura = 319773; public const uint WindfuryEnchantment = 334302; public const uint WindfuryVisual1 = 466440; public const uint WindfuryVisual2 = 466442; public const uint WindfuryVisual3 = 466443; public const uint WindRush = 192082; public const uint WindstrikeDamageMainHand = 115357; public const uint WindstrikeDamageOffHand = 115360; public const uint LabelShamanWindfuryTotem = 1038; } class spell_sha_maelstrom_weapon_base { public static bool Validate() { return SpellScriptBase.ValidateSpellInfo (SpellIds.MaelstromWeaponVisibleAura, SpellIds.MaelstromWeaponOverlay, SpellIds.MaelstromWeaponOverlayHeals, SpellIds.OverflowingMaelstromTalent, SpellIds.OverflowingMaelstromAura, SpellIds.StormweaverPvpTalentBuff, SpellIds.IceStrikeProc, SpellIds.HailstormBuff, SpellIds.HailstormTalent) && SpellScriptBase.ValidateSpellEffect((SpellIds.MaelstromWeaponModAura, 1), (SpellIds.StormweaverPvpTalent, 0)); } public static void GenerateMaelstromWeapon(Unit shaman, int stacks) { CastSpellExtraArgs args = new(); args.SetTriggerFlags(TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError); while (--stacks >= 0) { uint totalStacks = shaman.GetAuraCount(SpellIds.MaelstromWeaponVisibleAura); if (totalStacks >= 4) { // cast action bar overlays if (!shaman.HasAura(SpellIds.StormweaverPvpTalent)) shaman.CastSpell(shaman, SpellIds.MaelstromWeaponOverlayHeals, args); shaman.CastSpell(shaman, SpellIds.MaelstromWeaponOverlay, args); } shaman.CastSpell(shaman, SpellIds.MaelstromWeaponModAura, args); shaman.CastSpell(shaman, SpellIds.MaelstromWeaponVisibleAura, args); if (totalStacks >= 5 && shaman.HasAura(SpellIds.OverflowingMaelstromTalent)) shaman.CastSpell(shaman, SpellIds.OverflowingMaelstromAura, args); } } public static void ConsumeMaelstromWeapon(Unit shaman, Aura maelstromWeaponVisibleAura, int stacks, Spell consumingSpell = null) { AuraEffect stormweaver = shaman.GetAuraEffect(SpellIds.StormweaverPvpTalent, 0); if (stormweaver != null) { shaman.RemoveAurasDueToSpell(SpellIds.StormweaverPvpTalentBuff); // remove to ensure new buff has exactly "consumedStacks" stacks Aura maelstromSpellMod = shaman.GetAura(SpellIds.MaelstromWeaponModAura); if (maelstromSpellMod != null) { shaman.CastSpell(shaman, SpellIds.StormweaverPvpTalentBuff, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringSpell = consumingSpell, SpellValueOverrides = { new(SpellValueMod.BasePoint0, maelstromSpellMod.GetEffect(0).GetAmount()), // this is indeed very silly but it is how it behaves on official servers // it ignores how many stacks were actually consumed and calculates benefit from max stacks (Thorim's Invocation can consume less stacks than entire aura) new(SpellValueMod.BasePoint1, MathFunctions.CalculatePct(maelstromSpellMod.GetEffect(1).GetAmount(), stormweaver.GetAmount())), new(SpellValueMod.AuraStack, Math.Min(stacks, maelstromWeaponVisibleAura.GetStackAmount())) } }); } } Aura iceStrike = shaman.GetAura(SpellIds.IceStrikeProc); if (iceStrike != null) { spell_sha_ice_strike_proc script = iceStrike.GetScript(); if (script != null) script.AttemptProc(); } if (shaman.HasAura(SpellIds.HailstormTalent)) shaman.CastSpell(shaman, SpellIds.HailstormBuff, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringSpell = consumingSpell, SpellValueOverrides = { new(SpellValueMod.AuraStack, Math.Min(stacks, maelstromWeaponVisibleAura.GetStackAmount())) } }); if (maelstromWeaponVisibleAura.ModStackAmount(-stacks)) return; // not removed byte newStacks = maelstromWeaponVisibleAura.GetStackAmount(); Aura overflowingMaelstrom = shaman.GetAura(SpellIds.OverflowingMaelstromAura); if (overflowingMaelstrom != null) { if (newStacks > 5) overflowingMaelstrom.SetStackAmount((byte)(newStacks - 5)); else overflowingMaelstrom.Remove(); } Aura maelstromSpellMod1 = shaman.GetAura(SpellIds.MaelstromWeaponModAura); if (maelstromSpellMod1 != null) { if (newStacks > 0) maelstromSpellMod1.SetStackAmount(Math.Min(newStacks, (byte)5)); else maelstromSpellMod1.Remove(); } if (newStacks < 5) { shaman.RemoveAurasDueToSpell(SpellIds.MaelstromWeaponOverlay); shaman.RemoveAurasDueToSpell(SpellIds.MaelstromWeaponOverlayHeals); } } } class WindfuryProcEvent : BasicEvent { Unit _shaman; CastSpellTargetArg _target; int _index; int _endIndex; class WindfuryProcEventInfo { public TimeSpan Delay; public uint VisualSpellId; } static WindfuryProcEventInfo[] Sequence = { new WindfuryProcEventInfo() { Delay = TimeSpan.FromSeconds(500), VisualSpellId = SpellIds.WindfuryVisual1 }, new WindfuryProcEventInfo() { Delay = TimeSpan.FromSeconds(150), VisualSpellId = SpellIds.WindfuryVisual2 }, new WindfuryProcEventInfo() { Delay = TimeSpan.FromSeconds(250), VisualSpellId = SpellIds.WindfuryVisual3 }, }; public WindfuryProcEvent(Unit shaman, Unit target, int attacks) { _shaman = shaman; _target = target; _index = 0; _endIndex = attacks; } public override bool Execute(ulong time, uint diff) { if (_target.Targets == null) return true; _target.Targets.Update(_shaman); if (_target.Targets.GetUnitTarget() == null) return true; CastSpellExtraArgs args = new(); args.TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError; args.TriggeringAura = _shaman.GetAuraEffect(SpellIds.WindfuryAura, 0); // prevent proc from itself _shaman.CastSpell(_shaman, Sequence[_index].VisualSpellId, args); _shaman.CastSpell(_target, SpellIds.WindfuryAttack, args); if (++_index == _endIndex) return true; _shaman.m_Events.AddEvent(this, TimeSpan.FromSeconds(time) + Sequence[_index].Delay); return false; } public static void Trigger(Unit shaman, Unit target) { // Not a separate script because of ordering requirements for Forceful Winds if (shaman.HasAuraEffect(SpellIds.ForcefulWindsTalent, 0)) { Aura forcefulWinds = shaman.GetAura(SpellIds.ForcefulWindsProc); if (forcefulWinds != null) { // gaining a stack should not refresh duration uint maxStack = forcefulWinds.CalcMaxStackAmount(); if (forcefulWinds.GetStackAmount() < maxStack) forcefulWinds.SetStackAmount((byte)(forcefulWinds.GetStackAmount() + 1)); } else { shaman.CastSpell(shaman, SpellIds.ForcefulWindsProc, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError }); } } int attacks = 2; AuraEffect unrulyWinds = shaman.GetAuraEffect(SpellIds.UnrulyWinds, 0); RandomHelper.randChance(unrulyWinds.GetAmount()); if (unrulyWinds != null) ++attacks; shaman.m_Events.AddEventAtOffset(new WindfuryProcEvent(shaman, target, attacks), Sequence.First().Delay); } } [Script] // 273221 - Aftershock class spell_sha_aftershock : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.AftershockEnergize); } bool CheckProc(AuraEffect aurEff, ProcEventInfo eventInfo) { Spell procSpell = eventInfo.GetProcSpell(); if (procSpell != null) { var cost = procSpell.GetPowerTypeCostAmount(PowerType.Maelstrom); if (cost.HasValue) return cost > 0 && RandomHelper.randChance(aurEff.GetAmount()); } return false; } void HandleEffectProc(AuraEffect aurEff, ProcEventInfo eventInfo) { Spell procSpell = eventInfo.GetProcSpell(); eventInfo.GetActor().CastSpell(eventInfo.GetActor(), SpellIds.AftershockEnergize, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringSpell = procSpell, TriggeringAura = aurEff, SpellValueOverrides = { new(SpellValueMod.BasePoint0, procSpell.GetPowerTypeCostAmount(PowerType.Maelstrom).Value) } }); } public override void Register() { DoCheckEffectProc.Add(new(CheckProc, 0, AuraType.Dummy)); OnEffectProc.Add(new(HandleEffectProc, 0, AuraType.Dummy)); } } [Script] // 108281 - Ancestral Guidance class spell_sha_ancestral_guidance : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.AncestralGuidanceHeal); } bool CheckProc(ProcEventInfo eventInfo) { if (eventInfo.GetSpellInfo() != null && eventInfo.GetSpellInfo().Id == SpellIds.AncestralGuidanceHeal) return false; if (eventInfo.GetHealInfo() == null && eventInfo.GetDamageInfo() == null) return false; return true; } void HandleEffectProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); int bp0 = MathFunctions.CalculatePct((int)(eventInfo.GetDamageInfo() != null ? eventInfo.GetDamageInfo().GetDamage() : eventInfo.GetHealInfo().GetHeal()), aurEff.GetAmount()); if (bp0 == 0) return; eventInfo.GetActor().CastSpell(eventInfo.GetActor(), SpellIds.AncestralGuidanceHeal, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringAura = aurEff, SpellValueOverrides = { new(SpellValueMod.BasePoint0, bp0) } }); } public override void Register() { DoCheckProc.Add(new(CheckProc)); OnEffectProc.Add(new(HandleEffectProc, 0, AuraType.PeriodicDummy)); } } [Script] // 114911 - Ancestral Guidance Heal class spell_sha_ancestral_guidance_heal : SpellScript { void ResizeTargets(List targets) { SelectRandomInjuredTargets(targets, 3, true); } public override void Register() { OnObjectAreaTargetSelect.Add(new(ResizeTargets, 0, Targets.UnitCasterAreaRaid)); } } [Script] // 462764 - Arctic Snowstorm class spell_sha_arctic_snowstorm : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ArcticSnowstormAreatrigger); } void HandleEffectProc(AuraEffect aurEff, ProcEventInfo eventInfo) { eventInfo.GetActor().CastSpell(eventInfo.GetActionTarget(), SpellIds.ArcticSnowstormAreatrigger, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError }); } public override void Register() { OnEffectProc.Add(new(HandleEffectProc, 0, AuraType.Dummy)); } } [Script] // 198299 - Gathering Storms class spell_sha_artifact_gathering_storms : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.GatheringStorms, SpellIds.GatheringStormsBuff); } public override bool Load() { return GetCaster().HasAuraEffect(SpellIds.GatheringStorms, 0); } void TriggerBuff(uint effIndex) { AuraEffect gatheringStorms = GetCaster().GetAuraEffect(SpellIds.GatheringStorms, 0); if (gatheringStorms == null) return; GetCaster().CastSpell(GetCaster(), SpellIds.GatheringStormsBuff, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, SpellValueOverrides = { new(SpellValueMod.BasePoint0, (int)(gatheringStorms.GetAmount() * GetUnitTargetCountForEffect(effIndex))) } }); } public override void Register() { OnEffectHit.Add(new(TriggerBuff, 0, SpellEffectName.SchoolDamage)); } } [Script] // 114052 - Ascendance (Restoration) class spell_sha_ascendance_restoration : AuraScript { int _healToDistribute; public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.RestorativeMists); } bool CheckProc(ProcEventInfo procInfo) { return procInfo.GetHealInfo() != null && procInfo.GetHealInfo().GetOriginalHeal() != 0 && procInfo.GetSpellInfo().Id != SpellIds.RestorativeMistsInitial; } void OnProcHeal(AuraEffect aurEff, ProcEventInfo procInfo) { _healToDistribute += MathFunctions.CalculatePct((int)(procInfo.GetHealInfo().GetOriginalHeal()), aurEff.GetAmount()); } void HandleEffectPeriodic(AuraEffect aurEff) { if (_healToDistribute == 0) return; GetTarget().CastSpell(null, SpellIds.RestorativeMists, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringAura = aurEff, SpellValueOverrides = { new(SpellValueMod.BasePoint0, _healToDistribute) } }); _healToDistribute = 0; } public override void Register() { DoCheckProc.Add(new(CheckProc)); OnEffectProc.Add(new(OnProcHeal, 8, AuraType.Dummy)); OnEffectPeriodic.Add(new(HandleEffectPeriodic, 6, AuraType.PeriodicDummy)); } } [Script] // 390370 - Ashen Catalyst class spell_sha_ashen_catalyst : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.LavaLash); } void ReduceLavaLashCooldown(AuraEffect aurEff, ProcEventInfo procInfo) { GetTarget().GetSpellHistory().ModifyCooldown(SpellIds.LavaLash, -aurEff.GetAmount() * TimeSpan.FromSeconds(100)); } public override void Register() { OnEffectProc.Add(new(ReduceLavaLashCooldown, 0, AuraType.ProcTriggerSpell)); } } [Script] // 188443 - Chain Lightning class spell_sha_chain_lightning_crash_lightning : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.CrashLightning, SpellIds.CrashLightningDamageBuff); } public override bool Load() { return GetCaster().HasSpell(SpellIds.CrashLightning); } void HandleCooldownReduction(uint effIndex) { GetCaster().GetSpellHistory().ModifyCooldown(SpellIds.CrashLightning, TimeSpan.FromSeconds(-GetEffectValue()) * GetUnitTargetCountForEffect(0)); } void HandleDamageBuff(uint effIndex) { long targetsHit = GetUnitTargetCountForEffect(effIndex); if (targetsHit > 1) GetCaster().CastSpell(GetCaster(), SpellIds.CrashLightningDamageBuff, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, SpellValueOverrides = { new(SpellValueMod.AuraStack, (int)targetsHit) } }); } public override void Register() { OnEffectLaunch.Add(new(HandleCooldownReduction, 2, SpellEffectName.Dummy)); OnEffectLaunch.Add(new(HandleDamageBuff, 0, SpellEffectName.SchoolDamage)); } } [Script] // 188443 - Chain Lightning class spell_sha_chain_lightning_energize : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ChainLightningEnergize) && ValidateSpellEffect((SpellIds.MaelstromController, 4)); } public override bool Load() { return GetCaster().HasAuraEffect(SpellIds.MaelstromController, 4); } void HandleScript(uint effIndex) { AuraEffect energizeAmount = GetCaster().GetAuraEffect(SpellIds.MaelstromController, 4); if (energizeAmount != null) GetCaster().CastSpell(GetCaster(), SpellIds.ChainLightningEnergize, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringAura = energizeAmount, SpellValueOverrides = { new(SpellValueMod.BasePoint0, (int)(energizeAmount.GetAmount() * GetUnitTargetCountForEffect(0))) } }); } public override void Register() { OnEffectLaunch.Add(new(HandleScript, 0, SpellEffectName.SchoolDamage)); } } [Script] // 45297 - Chain Lightning Overload class spell_sha_chain_lightning_overload : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ChainLightningOverloadEnergize) && ValidateSpellEffect((SpellIds.MaelstromController, 5)); } public override bool Load() { return GetCaster().HasAuraEffect(SpellIds.MaelstromController, 5); } void HandleScript(uint effIndex) { AuraEffect energizeAmount = GetCaster().GetAuraEffect(SpellIds.MaelstromController, 5); if (energizeAmount != null) GetCaster().CastSpell(GetCaster(), SpellIds.ChainLightningOverloadEnergize, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringAura = energizeAmount, SpellValueOverrides = { new(SpellValueMod.BasePoint0, (int)(energizeAmount.GetAmount() * GetUnitTargetCountForEffect(0))) } }); } public override void Register() { OnEffectLaunch.Add(new(HandleScript, 0, SpellEffectName.SchoolDamage)); } } [Script] // 384363 - Converging Storms class spell_sha_converging_storms : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ConvergingStorms, SpellIds.GatheringStormsBuff); } public override bool Load() { return GetCaster().HasAuraEffect(SpellIds.ConvergingStorms, 0); } void TriggerBuff(uint effIndex) { AuraEffect convergingStorms = GetCaster().GetAuraEffect(SpellIds.ConvergingStorms, 0); if (convergingStorms == null) return; GetCaster().CastSpell(GetCaster(), SpellIds.GatheringStormsBuff, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, SpellValueOverrides = { new(SpellValueMod.AuraStack, (int)Math.Min(GetUnitTargetCountForEffect(effIndex), 6)) } }); } public override void Register() { OnEffectHit.Add(new(TriggerBuff, 0, SpellEffectName.SchoolDamage)); } } [Script("spell_sha_stormsurge_proc")] [Script("spell_sha_converging_storms_buff")] // 198300 - Converging Storms class spell_sha_delayed_stormstrike_mod_charge_drop_proc : AuraScript { void DropAura(ProcEventInfo eventInfo) { GetAura().DropChargeDelayed(1); } public override void Register() { AfterProc.Add(new(DropAura)); } } [Script] // 187874 - Crash Lightning class spell_sha_crash_lightning : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.CrashLightningCleave); } void TriggerCleaveBuff(uint effIndex) { if (GetUnitTargetCountForEffect(effIndex) >= 2) GetCaster().CastSpell(GetCaster(), SpellIds.CrashLightningCleave, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.DontReportCastError, TriggeringSpell = GetSpell() }); } public override void Register() { OnEffectHit.Add(new(TriggerCleaveBuff, 0, SpellEffectName.SchoolDamage)); } } [Script] // 200076 - Deluge (attached to 77472 - Healing Wave, 8004 - Healing Surge and 1064 - Chain Heal class spell_sha_deluge : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.Riptide, SpellIds.DelugeAura) && ValidateSpellEffect((SpellIds.DelugeTalent, 0)); } void CalculateHealingBonus(SpellEffectInfo spellEffectInfo, Unit victim, ref int healing, ref int flatMod, ref float pctMod) { AuraEffect deluge = GetCaster().GetAuraEffect(SpellIds.DelugeTalent, 0); if (deluge != null) if (victim.GetAura(SpellIds.Riptide, GetCaster().GetGUID()) != null || victim.GetAura(SpellIds.DelugeAura, GetCaster().GetGUID()) != null) MathFunctions.AddPct(ref pctMod, deluge.GetAmount()); } public override void Register() { CalcHealing.Add(new(CalculateHealingBonus)); } } [Script] // 200075 - Deluge (attached to 73920 - Healing Rain) class spell_sha_deluge_healing_rain : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.DelugeTalent, SpellIds.DelugeAura); } public override bool Load() { return GetUnitOwner().HasAura(SpellIds.DelugeTalent); } void HandleEffectPeriodic(AuraEffect aurEff) { GetCaster().CastSpell(GetHealingRainPosition(GetAura()), SpellIds.DelugeAura, TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError); } Position GetHealingRainPosition(Aura healingRain) { spell_sha_healing_rain_aura script = healingRain.GetScript(); if (script != null) return script.GetPosition(); return healingRain.GetUnitOwner().GetPosition(); } public override void Register() { OnEffectPeriodic.Add(new(HandleEffectPeriodic, 1, AuraType.PeriodicDummy)); } } [Script] // 378270 - Deeply Rooted Elements class spell_sha_deeply_rooted_elements : AuraScript { int _procAttempts; uint _triggeringSpellId; uint _triggeredSpellId; public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.LavaBurst, SpellIds.Stormstrike, SpellIds.Riptide, SpellIds.AscendanceElemental, SpellIds.AscendanceEnhancement, SpellIds.AscendanceRestoration) && ValidateSpellEffect((spellInfo.Id, 0)) && spellInfo.GetEffect(0).IsAura(); } public override bool Load() { return GetUnitOwner().IsPlayer(); } bool CheckProc(AuraEffect aurEff, ProcEventInfo procInfo) { if (procInfo.GetSpellInfo() == null) return false; if (procInfo.GetSpellInfo().Id != _triggeringSpellId) return false; return RandomHelper.randChance(_procAttempts++ - 2); } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { _procAttempts = 0; Unit target = eventInfo.GetActor(); int duration = GetEffect(0).GetAmount(); Aura ascendanceAura = target.GetAura(_triggeredSpellId); if (ascendanceAura != null) duration += ascendanceAura.GetDuration(); target.CastSpell(target, _triggeredSpellId, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreGCD | TriggerCastFlags.IgnoreSpellAndCategoryCD | TriggerCastFlags.IgnoreCastInProgress, TriggeringSpell = eventInfo.GetProcSpell(), TriggeringAura = aurEff, SpellValueOverrides = { new(SpellValueMod.Duration, duration) } }); } public override void Register() { ChrSpecialization specialization = ChrSpecialization.None; Aura aura = GetAura(); if (aura != null) // aura doesn't exist at startup validation { Player owner = aura.GetOwner()?.ToPlayer(); if (owner != null) specialization = owner.GetPrimarySpecialization(); } if (specialization == ChrSpecialization.None || specialization == ChrSpecialization.ShamanElemental) { DoCheckEffectProc.Add(new(CheckProc, 1, AuraType.Dummy)); OnEffectProc.Add(new(HandleProc, 1, AuraType.Dummy)); _triggeringSpellId = SpellIds.LavaBurst; _triggeredSpellId = SpellIds.AscendanceElemental; } if (specialization == ChrSpecialization.None || specialization == ChrSpecialization.ShamanEnhancement) { DoCheckEffectProc.Add(new(CheckProc, 2, AuraType.Dummy)); OnEffectProc.Add(new(HandleProc, 2, AuraType.Dummy)); _triggeringSpellId = SpellIds.Stormstrike; _triggeredSpellId = SpellIds.AscendanceEnhancement; } if (specialization == ChrSpecialization.None || specialization == ChrSpecialization.ShamanRestoration) { DoCheckEffectProc.Add(new(CheckProc, 3, AuraType.Dummy)); OnEffectProc.Add(new(HandleProc, 3, AuraType.Dummy)); _triggeringSpellId = SpellIds.Riptide; _triggeredSpellId = SpellIds.AscendanceRestoration; } } } [Script] // 466772 - Doom Winds class spell_sha_doom_winds : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.DoomWindsDamage); } void PeriodicTick(AuraEffect aurEff) { GetTarget().CastSpell(GetTarget().GetPosition(), SpellIds.DoomWindsDamage, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringAura = aurEff }); } public override void Register() { OnEffectPeriodic.Add(new(PeriodicTick, 2, AuraType.PeriodicDummy)); } } [Script] // 335902 - Doom Winds class spell_sha_doom_winds_legendary : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.DoomWindsLegendaryCooldown); } bool CheckProc(AuraEffect aurEff, ProcEventInfo procInfo) { if (GetTarget().HasAura(SpellIds.DoomWindsLegendaryCooldown)) return false; SpellInfo spellInfo = procInfo.GetSpellInfo(); if (spellInfo == null) return false; return spellInfo.HasLabel(SpellIds.LabelShamanWindfuryTotem); } public override void Register() { DoCheckEffectProc.Add(new(CheckProc, 0, AuraType.ProcTriggerSpell)); } } [Script] // 207778 - Downpour class spell_sha_downpour : SpellScript { int _healedTargets; public override bool Validate(SpellInfo spellInfo) { return ValidateSpellEffect((spellInfo.Id, 1)); } void FilterTargets(List targets) { SelectRandomInjuredTargets(targets, 6, true); } void CountEffectivelyHealedTarget() { // Cooldown increased for each target effectively healed if (GetHitHeal() != 0) ++_healedTargets; } void HandleCooldown() { TimeSpan cooldown = TimeSpan.FromSeconds(GetSpellInfo().RecoveryTime) + TimeSpan.FromSeconds(GetEffectInfo(1).CalcValue() * _healedTargets); GetCaster().GetSpellHistory().StartCooldown(GetSpellInfo(), 0, GetSpell(), false, cooldown); } public override void Register() { OnObjectAreaTargetSelect.Add(new(FilterTargets, 0, Targets.UnitDestAreaAlly)); AfterHit.Add(new(CountEffectivelyHealedTarget)); AfterCast.Add(new(HandleCooldown)); } } [Script] // 204288 - Earth Shield class spell_sha_earth_shield : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.EarthShieldHeal); } bool CheckProc(ProcEventInfo eventInfo) { if (eventInfo.GetDamageInfo() == null || !HasEffect(1) || eventInfo.GetDamageInfo().GetDamage() < GetTarget().CountPctFromMaxHealth(GetEffect(1).GetAmount())) return false; return true; } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); GetTarget().CastSpell(GetTarget(), SpellIds.EarthShieldHeal, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringAura = aurEff, OriginalCaster = GetCasterGUID() }); } public override void Register() { DoCheckProc.Add(new(CheckProc)); OnEffectProc.Add(new(HandleProc, 1, AuraType.Dummy)); } } [Script] // 8042 - Earth Shock class spell_sha_earth_shock : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellEffect((SpellIds.T29_2PElementalDamageBuff, 0)); } void AddScriptedDamageMods() { AuraEffect t29 = GetCaster().GetAuraEffect(SpellIds.T29_2PElementalDamageBuff, 0); if (t29 != null) { SetHitDamage(MathFunctions.CalculatePct(GetHitDamage(), 100 + t29.GetAmount())); t29.GetBase().Remove(); } } public override void Register() { OnHit.Add(new(AddScriptedDamageMods)); } } [Script] // 170374 - Earthen Rage (Passive) class spell_sha_earthen_rage_passive : AuraScript { ObjectGuid _procTargetGuid; public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.EarthenRagePeriodic, SpellIds.EarthenRageDamage); } bool CheckProc(ProcEventInfo procInfo) { return procInfo.GetSpellInfo() != null && procInfo.GetSpellInfo().Id != SpellIds.EarthenRageDamage; } void HandleEffectProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); _procTargetGuid = eventInfo.GetProcTarget().GetGUID(); eventInfo.GetActor().CastSpell(eventInfo.GetActor(), SpellIds.EarthenRagePeriodic, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); } public override void Register() { DoCheckProc.Add(new(CheckProc)); OnEffectProc.Add(new(HandleEffectProc, 0, AuraType.Dummy)); } public ObjectGuid GetProcTarGetGUID() { return _procTargetGuid; } } [Script] // 170377 - Earthen Rage (Proc Aura) class spell_sha_earthen_rage_proc_aura : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.EarthenRagePassive, SpellIds.EarthenRageDamage); } void HandleEffectPeriodic(AuraEffect aurEff) { PreventDefaultAction(); Aura aura = GetCaster().GetAura(SpellIds.EarthenRagePassive); if (aura != null) { spell_sha_earthen_rage_passive script = aura.GetScript(); if (script != null) { Unit procTarget = Global.ObjAccessor.GetUnit(GetCaster(), script.GetProcTarGetGUID()); if (procTarget != null) { GetTarget().CastSpell(procTarget, SpellIds.EarthenRageDamage, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); } } } } public override void Register() { OnEffectPeriodic.Add(new(HandleEffectPeriodic, 0, AuraType.PeriodicDummy)); } } // 61882 - Earthquake [Script] // 8382 - AreaTriggerId class areatrigger_sha_earthquake(AreaTrigger areaTrigger) : AreaTriggerAI(areaTrigger) { TimeSpan _refreshTimer = TimeSpan.Zero; TimeSpan _period = TimeSpan.FromSeconds(1); List _stunnedUnits = new(); float _damageMultiplier = 1.0f; public override void OnCreate(Spell creatingSpell) { Unit caster = at.GetCaster(); if (caster != null) { AuraEffect earthquake = caster.GetAuraEffect(SpellIds.Earthquake, 1); if (earthquake != null) _period = TimeSpan.FromSeconds(earthquake.GetPeriod()); } if (creatingSpell != null) { if (creatingSpell.m_customArg is float damageMultiplier) _damageMultiplier = damageMultiplier; } } public override void OnUpdate(uint diff) { _refreshTimer -= TimeSpan.FromSeconds(diff); while (_refreshTimer <= TimeSpan.Zero) { Unit caster = at.GetCaster(); if (caster != null) caster.CastSpell(at.GetPosition(), SpellIds.EarthquakeTick, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, OriginalCaster = at.GetGUID(), SpellValueOverrides = { new(SpellValueMod.BasePoint0, (int)(caster.SpellBaseDamageBonusDone(SpellSchoolMask.Nature) * 0.213f * _damageMultiplier)) } }); _refreshTimer += _period; } } // Each target can only be stunned once by each earthquake - keep track of who we already stunned public bool AddStunnedTarget(ObjectGuid guid) { if (_stunnedUnits.Contains(guid)) return false; _stunnedUnits.Add(guid); return true; } } [Script] // 61882 - Earthquake class spell_sha_earthquake : SpellScript { static (uint, uint)[] DamageBuffs = { (SpellIds.EchoesOfGreatSunderingLegendary, 1), (SpellIds.EchoesOfGreatSunderingTalent, 0), (SpellIds.T29_2PElementalDamageBuff, 0) }; public override bool Validate(SpellInfo spellInfo) { return ValidateSpellEffect(DamageBuffs); } void SnapshotDamageMultiplier(uint effIndex) { float damageMultiplier = 1.0f; foreach (var (spellId, effect) in DamageBuffs) { AuraEffect buff = GetCaster().GetAuraEffect(spellId, effect); if (buff != null) { MathFunctions.AddPct(ref damageMultiplier, buff.GetAmount()); buff.GetBase().Remove(); } } if (damageMultiplier != 1.0f) GetSpell().m_customArg = damageMultiplier; } public override void Register() { OnEffectLaunch.Add(new(SnapshotDamageMultiplier, 2, SpellEffectName.CreateAreaTrigger)); } } [Script] // 77478 - Earthquake tick class spell_sha_earthquake_tick : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.EarthquakeKnockingDown) && ValidateSpellEffect((spellInfo.Id, 1)); } void HandleOnHit() { Unit target = GetHitUnit(); if (target != null) { if (RandomHelper.randChance(GetEffectInfo(1).CalcValue())) { List areaTriggers = GetCaster().GetAreaTriggers(SpellIds.Earthquake); var itr = areaTriggers.Find(at => at.GetGUID() == GetSpell().GetOriginalCasterGUID()); if (itr != null) { areatrigger_sha_earthquake eq = itr.GetAI(); if (eq != null) if (eq.AddStunnedTarget(target.GetGUID())) GetCaster().CastSpell(target, SpellIds.EarthquakeKnockingDown, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); } } } } public override void Register() { OnHit.Add(new(HandleOnHit)); } } // 117014 - Elemental Blast [Script] // 120588 - Elemental Blast Overload class spell_sha_elemental_blast : SpellScript { static uint[] BuffSpells = [SpellIds.ElementalBlastCrit, SpellIds.ElementalBlastHaste, SpellIds.ElementalBlastMastery]; public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ElementalBlastCrit, SpellIds.ElementalBlastHaste, SpellIds.ElementalBlastMastery) && ValidateSpellEffect((SpellIds.T29_2PElementalDamageBuff, 0)); } void TriggerBuff() { Unit caster = GetCaster(); double total = 0.0; for (var i = 0; i < BuffSpells.Length; ++i) total += !caster.HasAura(BuffSpells[i]) ? 1.0f : 0.0f; uint spellId() { if (total > 0.0) return BuffSpells.SelectRandomElementByWeight(buffSpell => !caster.HasAura(buffSpell) ? 1.0f : 0.0f); // refresh random one if we have them all return BuffSpells.SelectRandom(); } GetCaster().CastSpell(GetCaster(), spellId(), new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); } void AddScriptedDamageMods() { AuraEffect t29 = GetCaster().GetAuraEffect(SpellIds.T29_2PElementalDamageBuff, 0); if (t29 != null) { SetHitDamage(MathFunctions.CalculatePct(GetHitDamage(), 100 + t29.GetAmount())); t29.GetBase().Remove(); } } public override void Register() { AfterCast.Add(new(TriggerBuff)); OnHit.Add(new(AddScriptedDamageMods)); } } [Script] // 384355 - Elemental Weapons class spell_sha_elemental_weapons : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ElementalWeaponsBuff); } public override bool Load() { return GetUnitOwner().IsPlayer(); } void CheckEnchantments() { Player owner = GetUnitOwner().ToPlayer(); int enchatmentCount = 0; if (owner.HasAura(SpellIds.FlametongueWeaponAura)) ++enchatmentCount; if (owner.HasAura(SpellIds.WindfuryAura)) ++enchatmentCount; int valuePerStack = GetEffect(0).GetAmount(); Aura buff = owner.GetAura(SpellIds.ElementalWeaponsBuff); if (buff != null) { if (enchatmentCount != 0) foreach (AuraEffect aurEff in buff.GetAuraEffects()) aurEff.ChangeAmount(valuePerStack * enchatmentCount / 10); else buff.Remove(); } else if (enchatmentCount != 0) owner.CastSpell(owner, SpellIds.ElementalWeaponsBuff, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, SpellValueOverrides = { new( SpellValueMod.BasePoint0, valuePerStack * enchatmentCount / 10 ), new( SpellValueMod.BasePoint1, valuePerStack * enchatmentCount / 10 ) } }); } void RemoveAllBuffs(AuraEffect aurEff, AuraEffectHandleModes mode) { GetUnitOwner().RemoveAurasDueToSpell(SpellIds.ElementalWeaponsBuff); } public override void Register() { OnHeartbeat.Add(new(CheckEnchantments)); AfterEffectRemove.Add(new(RemoveAllBuffs, 0, AuraType.Dummy, AuraEffectHandleModes.Real)); } } class FireNovaTargetCheck : ICheck { public float MaxSearchRange = 40.0f; public Unit Shaman; public bool Invoke(Unit candidate) { return candidate.IsWithinDist3d(Shaman, MaxSearchRange) && candidate.HasAura(SpellIds.FlameShock, Shaman.GetGUID()); } } [Script] // 333974 - Fire Nova class spell_sha_fire_nova : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.FireNovaDamage); } void TriggerDamage(uint effIndex) { Unit shaman = GetCaster(); List targets = new(); FireNovaTargetCheck check = new() { Shaman = shaman }; UnitListSearcher searcher = new(shaman, targets, check); Cell.VisitAllObjects(shaman, searcher, check.MaxSearchRange); CastSpellExtraArgs args = new(); args.SetTriggerFlags(TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError); args.SetTriggeringSpell(GetSpell()); foreach (Unit target in targets) shaman.CastSpell(target, SpellIds.FireNovaDamage, args); } public override void Register() { OnEffectHitTarget.Add(new(TriggerDamage, 0, SpellEffectName.Dummy)); } } [Script] // 466620 - Flame Shock class spell_sha_flame_shock_fire_nova_enabler : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.FlameShock, SpellIds.FireNovaEnabler); } void CheckFlameShocks(AuraEffect aurEff) { Unit shaman = GetTarget(); FireNovaTargetCheck check = new() { Shaman = shaman }; UnitSearcher searcher = new(shaman, check); Cell.VisitAllObjects(shaman, searcher, check.MaxSearchRange); if (searcher.GetResult() != null) shaman.CastSpell(shaman, SpellIds.FireNovaEnabler, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringAura = aurEff }); else shaman.RemoveAurasDueToSpell(SpellIds.FireNovaEnabler); } public override void Register() { OnEffectPeriodic.Add(new(CheckFlameShocks, 0, AuraType.PeriodicDummy)); } } [Script] // 318038 - Flametongue Weapon class spell_sha_flametongue_weapon : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.FlametongueWeaponEnchant); } public override bool Load() { return GetCaster().IsPlayer(); } void HandleEffectHitTarget(uint effIndex) { Player player = GetCaster().ToPlayer(); byte slot = EquipmentSlot.MainHand; if (player.GetPrimarySpecialization() == ChrSpecialization.ShamanEnhancement) slot = EquipmentSlot.OffHand; Item targetItem = player.GetItemByPos(InventorySlots.Bag0, slot); if (targetItem == null || !targetItem.GetTemplate().IsWeapon()) return; player.CastSpell(targetItem, SpellIds.FlametongueWeaponEnchant, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); } public override void Register() { OnEffectHitTarget.Add(new(HandleEffectHitTarget, 0, SpellEffectName.Dummy)); } } [Script] // 319778 - Flametongue - SpellIds.FlametongueWeaponAura class spell_sha_flametongue_weapon_aura : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.FlametongueAttack); } void HandleEffectProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); eventInfo.GetActor().CastSpell(eventInfo.GetActionTarget(), SpellIds.FlametongueAttack, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringAura = aurEff }); } public override void Register() { OnEffectProc.Add(new(HandleEffectProc, 0, AuraType.Dummy)); } } [Script] // 334196 - Hailstorm class spell_sha_hailstorm : AuraScript { void CalcCleaveMod(AuraEffect aurEff, ref SpellModifier spellMod) { if (spellMod == null) { SpellModifierByClassMask mod = new SpellModifierByClassMask(GetAura()); mod.op = SpellModOp.ChainTargets; mod.type = SpellModType.Flat; mod.spellId = GetId(); mod.mask = new FlagArray128(0x80000000, 0x00000000, 0x00000000, 0x00000000); spellMod = mod; } AuraEffect hailstormPassive = GetUnitOwner().GetAuraEffect(SpellIds.HailstormTalent, 0); if (hailstormPassive != null) { int targetCap = hailstormPassive.GetAmount() / aurEff.GetBaseAmount(); ((SpellModifierByClassMask)spellMod).value = Math.Min(targetCap, GetStackAmount()) + 1; } } public override void Register() { DoEffectCalcSpellMod.Add(new(CalcCleaveMod, 1, AuraType.Dummy)); } } [Script] // 73920 - Healing Rain (Aura) class spell_sha_healing_rain_aura : AuraScript { ObjectGuid _visualDummy; Position _dest; public void SetVisualDummy(TempSummon summon) { _visualDummy = summon.GetGUID(); _dest = summon.GetPosition(); } public Position GetPosition() { return _dest; } void HandleEffectPeriodic(AuraEffect aurEff) { GetTarget().CastSpell(_dest, SpellIds.HealingRainHeal, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringAura = aurEff }); } void HandleEffecRemoved(AuraEffect aurEff, AuraEffectHandleModes mode) { Creature summon = ObjectAccessor.GetCreature(GetTarget(), _visualDummy); if (summon != null) summon.DespawnOrUnsummon(); } public override void Register() { OnEffectRemove.Add(new(HandleEffecRemoved, 1, AuraType.PeriodicDummy, AuraEffectHandleModes.Real)); OnEffectPeriodic.Add(new(HandleEffectPeriodic, 1, AuraType.PeriodicDummy)); } } [Script] // 73920 - Healing Rain class spell_sha_healing_rain : SpellScript { const uint NpcHealingRainInvisibleStalker = 73400; void InitializeVisualStalker() { Aura aura = GetHitAura(); if (aura != null) { WorldLocation dest = GetExplTargetDest(); if (dest != null) { TimeSpan duration = TimeSpan.FromSeconds(GetSpellInfo().CalcDuration(GetOriginalCaster())); TempSummon summon = GetCaster().GetMap().SummonCreature(NpcHealingRainInvisibleStalker, dest, null, duration, GetOriginalCaster()); if (summon == null) return; summon.CastSpell(summon, SpellIds.HealingRainVisual, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); spell_sha_healing_rain_aura script = aura.GetScript(); if (script != null) script.SetVisualDummy(summon); } } } public override void Register() { AfterHit.Add(new(InitializeVisualStalker)); } } [Script] // 73921 - Healing Rain class spell_sha_healing_rain_target_limit : SpellScript { void SelectTargets(List targets) { SelectRandomInjuredTargets(targets, 6, true); } public override void Register() { OnObjectAreaTargetSelect.Add(new(SelectTargets, 0, Targets.UnitDestAreaAlly)); } } [Script] // 52042 - Healing Stream Totem class spell_sha_healing_stream_totem_heal : SpellScript { void SelectTargets(List targets) { SelectRandomInjuredTargets(targets, 1, true); } public override void Register() { OnObjectAreaTargetSelect.Add(new(SelectTargets, 0, Targets.UnitDestAreaAlly)); } } [Script] // 201900 - Hot Hand class spell_sha_hot_hand : AuraScript { bool CheckProc(AuraEffect aurEff, ProcEventInfo eventInfo) { return eventInfo.GetActor().HasAura(SpellIds.FlametongueWeaponAura); } public override void Register() { DoCheckEffectProc.Add(new(CheckProc, 0, AuraType.Dummy)); } } [Script] // 342240 - Ice Strike class spell_sha_ice_strike : SpellScript { public override bool Validate(SpellInfo spellInfo) { return spell_sha_maelstrom_weapon_base.Validate(); } void EnergizeMaelstrom(uint effIndex) { spell_sha_maelstrom_weapon_base.GenerateMaelstromWeapon(GetCaster(), GetEffectValue()); } public override void Register() { OnEffectHit.Add(new(EnergizeMaelstrom, 3, SpellEffectName.Dummy)); } } [Script] // 466467 - Ice Strike class spell_sha_ice_strike_proc : AuraScript { int _attemptCount; public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.IceStrikeOverrideAura); } public override void Register() { } public void AttemptProc() { if (!RandomHelper.randChance(++_attemptCount * 7)) return; _attemptCount = 0; Unit shaman = GetUnitOwner(); shaman.CastSpell(shaman, SpellIds.IceStrikeOverrideAura, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.DontReportCastError }); } } [Script] // 210714 - Icefury class spell_sha_icefury : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.FrostShockEnergize); } void HandleEffectProc(AuraEffect aurEff, ProcEventInfo eventInfo) { Unit caster = GetCaster(); if (caster != null) caster.CastSpell(caster, SpellIds.FrostShockEnergize, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress }); } public override void Register() { OnEffectProc.Add(new(HandleEffectProc, 1, AuraType.AddPctModifier)); } } [Script] // 23551 - Lightning Shield T2 Bonus class spell_sha_item_lightning_shield : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ItemLightningShield); } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); GetTarget().CastSpell(eventInfo.GetProcTarget(), SpellIds.ItemLightningShield, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringAura = aurEff }); } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.ProcTriggerSpell)); } } [Script] // 23552 - Lightning Shield T2 Bonus class spell_sha_item_lightning_shield_trigger : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ItemLightningShieldDamage); } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); GetTarget().CastSpell(GetTarget(), SpellIds.ItemLightningShieldDamage, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringAura = aurEff }); } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.ProcTriggerSpell)); } } [Script] // 23572 - Mana Surge class spell_sha_item_mana_surge : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ItemManaSurge); } bool CheckProc(ProcEventInfo eventInfo) { return eventInfo.GetProcSpell() != null; } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); var manaCost = eventInfo.GetProcSpell().GetPowerTypeCostAmount(PowerType.Mana); if (manaCost.HasValue) { int mana = MathFunctions.CalculatePct(manaCost.Value, 35); if (mana > 0) { GetTarget().CastSpell(GetTarget(), SpellIds.ItemManaSurge, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringAura = aurEff, SpellValueOverrides = { new(SpellValueMod.BasePoint0, mana) } }); } } } public override void Register() { DoCheckProc.Add(new(CheckProc)); OnEffectProc.Add(new(HandleProc, 0, AuraType.ProcTriggerSpell)); } } [Script] // 40463 - Shaman Tier 6 Trinket class spell_sha_item_t6_trinket : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.EnergySurge, SpellIds.PowerSurge); } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); SpellInfo spellInfo = eventInfo.GetSpellInfo(); if (spellInfo == null) return; uint spellId; int chance; // Lesser Healing Wave if ((spellInfo.SpellFamilyFlags[0] & 0x00000080) != 0) { spellId = SpellIds.EnergySurge; chance = 10; } // Lightning Bolt else if ((spellInfo.SpellFamilyFlags[0] & 0x00000001) != 0) { spellId = SpellIds.EnergySurge; chance = 15; } // Stormstrike else if ((spellInfo.SpellFamilyFlags[1] & 0x00000010) != 0) { spellId = SpellIds.PowerSurge; chance = 50; } else return; if (RandomHelper.randChance(chance)) eventInfo.GetActor().CastSpell(null, spellId, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } } [Script] // 70811 - Item - Shaman T10 Elemental 2P Bonus class spell_sha_item_t10_elemental_2p_bonus : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ElementalMastery); } void HandleEffectProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); Player target = GetTarget().ToPlayer(); if (target != null) target.GetSpellHistory().ModifyCooldown(SpellIds.ElementalMastery, TimeSpan.FromSeconds(-aurEff.GetAmount())); } public override void Register() { OnEffectProc.Add(new(HandleEffectProc, 0, AuraType.Dummy)); } } [Script] // 189063 - Lightning Vortex (proc 185881 Item - Shaman T18 Elemental 4P Bonus) class spell_sha_item_t18_elemental_4p_bonus : AuraScript { void DiminishHaste(AuraEffect aurEff) { PreventDefaultAction(); AuraEffect hasteBuff = GetEffect(0); if (hasteBuff != null) hasteBuff.ChangeAmount(hasteBuff.GetAmount() - aurEff.GetAmount()); } public override void Register() { OnEffectPeriodic.Add(new(DiminishHaste, 1, AuraType.PeriodicDummy)); } } [Script] // 51505 - Lava burst class spell_sha_lava_burst : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.PathOfFlamesTalent, SpellIds.PathOfFlamesSpread, SpellIds.LavaSurge); } void HandleScript(uint effIndex) { Unit caster = GetCaster(); if (caster != null) if (caster.HasAura(SpellIds.PathOfFlamesTalent)) caster.CastSpell(GetHitUnit(), SpellIds.PathOfFlamesSpread, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringSpell = GetSpell() }); } void EnsureLavaSurgeCanBeImmediatelyConsumed() { Unit caster = GetCaster(); Aura lavaSurge = caster.GetAura(SpellIds.LavaSurge); if (lavaSurge != null) { if (!GetSpell().m_appliedMods.Contains(lavaSurge)) { uint chargeCategoryId = GetSpellInfo().ChargeCategoryId; // Ensure we have at least 1 usable charge after cast to allow next cast immediately if (!caster.GetSpellHistory().HasCharge(chargeCategoryId)) caster.GetSpellHistory().RestoreCharge(chargeCategoryId); } } } public override void Register() { OnEffectHitTarget.Add(new(HandleScript, 0, SpellEffectName.TriggerMissile)); AfterCast.Add(new(EnsureLavaSurgeCanBeImmediatelyConsumed)); } } // 285452 - Lava Burst damage [Script] // 285466 - Lava Burst Overload damage class spell_sha_lava_crit_chance : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.FlameShock); } void CalcCritChance(Unit victim, ref float chance) { Unit caster = GetCaster(); if (caster == null || victim == null) return; if (victim.HasAura(SpellIds.FlameShock, caster.GetGUID())) if (victim.GetTotalAuraModifier(AuraType.ModAttackerSpellAndWeaponCritChance) > -100) chance = 100.0f; } public override void Register() { OnCalcCritChance.Add(new(CalcCritChance)); } } [Script] // 60103 - Lava Lash class spell_sha_lava_lash : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellEffect((spellInfo.Id, 1)) && ValidateSpellInfo(SpellIds.FlametongueWeaponAura); } public override bool Load() { return GetCaster().IsPlayer(); } void AddBonusFlametongueDamage(SpellEffectInfo effectInfo, Unit victim, ref int damage, ref int flatMod, ref float pctMod) { Player caster = GetCaster().ToPlayer(); ObjectGuid offhandItemGuid = caster.GetWeaponForAttack(GetSpellInfo().GetAttackType()).GetGUID(); if (GetCaster().HasAura(SpellIds.FlametongueWeaponAura, ObjectGuid.Empty, offhandItemGuid)) MathFunctions.AddPct(ref pctMod, GetSpell().CalculateDamage(GetEffectInfo(1), victim)); } public override void Register() { CalcDamage.Add(new(AddBonusFlametongueDamage)); } } [Script] // 77756 - Lava Surge class spell_sha_lava_surge : AuraScript { float _normalizedTicks = 0.0f; public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.LavaSurge, SpellIds.IgneousPotential); } bool CheckProcChance(AuraEffect aurEff, ProcEventInfo eventInfo) { Unit caster = GetTarget(); float flameShocks = 0.0f; var shaman = caster.GetGUID(); void work(Unit target) { if (target.HasAuraEffect(SpellIds.FlameShock, 1, shaman)) flameShocks += 1.0f; } UnitWorker worker = new(caster, work); Cell.VisitAllObjects(caster, worker, 100.0f); // Proc uptime is not supposed to scale with the number of applied flame shocks _normalizedTicks += 1.0f / flameShocks; // first 6 ticks after last proc fail to prevent overwriting if (_normalizedTicks < 6.0f) return false; float procChance = aurEff.GetAmount(); AuraEffect igneousPotential = GetTarget().GetAuraEffect(SpellIds.IgneousPotential, 0); if (igneousPotential != null) procChance += igneousPotential.GetAmount(); float missChance = MathF.Max(100 - procChance, 0.0f) / 100.0f; procChance = (1.0f - MathF.Pow(missChance, _normalizedTicks)) * 100.0f; return RandomHelper.randChance(procChance); } void HandleEffectProc(AuraEffect aurEff, ProcEventInfo eventInfo) { _normalizedTicks = 0.0f; PreventDefaultAction(); GetTarget().CastSpell(GetTarget(), SpellIds.LavaSurge, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); } public override void Register() { DoCheckEffectProc.Add(new(CheckProcChance, 0, AuraType.Dummy)); OnEffectProc.Add(new(HandleEffectProc, 0, AuraType.Dummy)); } } [Script] // 77762 - Lava Surge class spell_sha_lava_surge_proc : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.LavaBurst); } public override bool Load() { return GetCaster().IsPlayer(); } void ResetCooldown() { GetCaster().GetSpellHistory().RestoreCharge(Global.SpellMgr.GetSpellInfo(SpellIds.LavaBurst, GetCastDifficulty()).ChargeCategoryId); } public override void Register() { AfterHit.Add(new(ResetCooldown)); } } [Script] // 188196 - Lightning Bolt class spell_sha_lightning_bolt : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.LightningBoltEnergize) && ValidateSpellEffect((SpellIds.MaelstromController, 0)); } void HandleScript(uint effIndex) { AuraEffect energizeAmount = GetCaster().GetAuraEffect(SpellIds.MaelstromController, 0); if (energizeAmount != null) GetCaster().CastSpell(GetCaster(), SpellIds.LightningBoltEnergize, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringAura = energizeAmount, SpellValueOverrides = { new(SpellValueMod.BasePoint0, energizeAmount.GetAmount()) } }); } public override void Register() { OnEffectLaunch.Add(new(HandleScript, 0, SpellEffectName.SchoolDamage)); } } [Script] // 45284 - Lightning Bolt Overload class spell_sha_lightning_bolt_overload : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.LightningBoltOverloadEnergize) && ValidateSpellEffect((SpellIds.MaelstromController, 1)); } void HandleScript(uint effIndex) { AuraEffect energizeAmount = GetCaster().GetAuraEffect(SpellIds.MaelstromController, 1); if (energizeAmount != null) GetCaster().CastSpell(GetCaster(), SpellIds.LightningBoltOverloadEnergize, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringAura = energizeAmount, SpellValueOverrides = { new(SpellValueMod.BasePoint0, energizeAmount.GetAmount()) } }); } public override void Register() { OnEffectLaunch.Add(new(HandleScript, 0, SpellEffectName.SchoolDamage)); } } [Script] // 192223 - Liquid Magma Totem (erupting hit spell) class spell_sha_liquid_magma_totem : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.LiquidMagmaHit); } void HandleEffectHitTarget(uint effIndex) { Unit hitUnit = GetHitUnit(); if (hitUnit != null) GetCaster().CastSpell(hitUnit, SpellIds.LiquidMagmaHit, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); } void HandleTargetSelect(List targets) { // choose one random target from targets if (targets.Count > 1) { WorldObject selected = targets.SelectRandom(); targets.Clear(); targets.Add(selected); } } public override void Register() { OnObjectAreaTargetSelect.Add(new(HandleTargetSelect, 0, Targets.UnitDestAreaEnemy)); OnEffectHitTarget.Add(new(HandleEffectHitTarget, 0, SpellEffectName.Dummy)); } } [Script] // 187880 - Maelstrom Weapon class spell_sha_maelstrom_weapon : AuraScript { public override bool Validate(SpellInfo spellInfo) { return spell_sha_maelstrom_weapon_base.Validate(); } void HandleProc(AuraEffect aurEff, ProcEventInfo procEvent) { spell_sha_maelstrom_weapon_base.GenerateMaelstromWeapon(GetTarget(), 1); } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } } [Script] // 344179 - Maelstrom Weapon class spell_sha_maelstrom_weapon_proc : AuraScript { public override bool Validate(SpellInfo spellInfo) { return spell_sha_maelstrom_weapon_base.Validate(); } bool CheckProc(ProcEventInfo procEvent) { Spell procSpell = procEvent.GetProcSpell(); if (procSpell == null) return false; Aura maelstromSpellMod = GetTarget().GetAura(SpellIds.MaelstromWeaponModAura); if (maelstromSpellMod == null) return false; return procSpell.m_appliedMods.Contains(maelstromSpellMod); } void RemoveMaelstromAuras(ProcEventInfo procEvent) { Unit shaman = GetTarget(); int stacksToConsume = 5; if (shaman.HasAura(SpellIds.OverflowingMaelstromTalent)) stacksToConsume = 10; spell_sha_maelstrom_weapon_base.ConsumeMaelstromWeapon(shaman, GetAura(), stacksToConsume, procEvent.GetProcSpell()); } void ExpireMaelstromAuras(AuraEffect aurEff, AuraEffectHandleModes mode) { Unit shaman = GetTarget(); AuraRemoveMode removeMode = GetTargetApplication().GetRemoveMode(); shaman.RemoveAurasDueToSpell(SpellIds.OverflowingMaelstromAura, ObjectGuid.Empty, 0, removeMode); shaman.RemoveAurasDueToSpell(SpellIds.MaelstromWeaponModAura, ObjectGuid.Empty, 0, removeMode); shaman.RemoveAurasDueToSpell(SpellIds.MaelstromWeaponOverlay, ObjectGuid.Empty, 0, removeMode); shaman.RemoveAurasDueToSpell(SpellIds.MaelstromWeaponOverlayHeals, ObjectGuid.Empty, 0, removeMode); } public override void Register() { DoCheckProc.Add(new(CheckProc)); OnProc.Add(new(RemoveMaelstromAuras)); AfterEffectRemove.Add(new(ExpireMaelstromAuras, 0, AuraType.Dummy, AuraEffectHandleModes.Real)); } } [Script] // 168534 - Mastery: Elemental Overload (passive) class spell_sha_mastery_elemental_overload : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo ( SpellIds.LightningBolt, SpellIds.LightningBoltOverload, SpellIds.ElementalBlast, SpellIds.ElementalBlastOverload, SpellIds.Icefury, SpellIds.IcefuryOverload, SpellIds.LavaBurst, SpellIds.LavaBurstOverload, SpellIds.ChainLightning, SpellIds.ChainLightningOverload, SpellIds.Stormkeeper ); } bool CheckProc(AuraEffect aurEff, ProcEventInfo eventInfo) { SpellInfo spellInfo = eventInfo.GetSpellInfo(); if (spellInfo == null || eventInfo.GetProcSpell() == null) return false; if (GetTriggeredSpellId(spellInfo.Id) == 0) return false; float chance = aurEff.GetAmount(); // Mastery % amount if (spellInfo.Id == SpellIds.ChainLightning) chance /= 3.0f; Aura stormkeeper = eventInfo.GetActor().GetAura(SpellIds.Stormkeeper); if (stormkeeper != null && eventInfo.GetProcSpell().m_appliedMods.Contains(stormkeeper)) chance = 100.0f; return RandomHelper.randChance(chance); } void HandleProc(AuraEffect aurEff, ProcEventInfo procInfo) { PreventDefaultAction(); Unit caster = procInfo.GetActor(); var targets = new CastSpellTargetArg(procInfo.GetProcTarget()); var overloadSpellId = GetTriggeredSpellId(procInfo.GetSpellInfo().Id); var originalCastId = procInfo.GetProcSpell().m_castId; caster.m_Events.AddEventAtOffset(() => { if (targets.Targets == null) return; targets.Targets.Update(caster); CastSpellExtraArgs args = new(); args.OriginalCastId = originalCastId; caster.CastSpell(targets, overloadSpellId, args); }, TimeSpan.FromSeconds(400)); } public override void Register() { DoCheckEffectProc.Add(new(CheckProc, 0, AuraType.Dummy)); OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } static uint GetTriggeredSpellId(uint triggeringSpellId) { switch (triggeringSpellId) { case SpellIds.LightningBolt: return SpellIds.LightningBoltOverload; case SpellIds.ElementalBlast: return SpellIds.ElementalBlastOverload; case SpellIds.Icefury: return SpellIds.IcefuryOverload; case SpellIds.LavaBurst: return SpellIds.LavaBurstOverload; case SpellIds.ChainLightning: return SpellIds.ChainLightningOverload; default: break; } return 0; } } // 45284 - Lightning Bolt Overload // 45297 - Chain Lightning Overload // 114738 - Lava Beam Overload // 120588 - Elemental Blast Overload // 219271 - Icefury Overload [Script] // 285466 - Lava Burst Overload class spell_sha_mastery_elemental_overload_proc : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.MasteryElementalOverload); } void ApplyDamageModifier(uint effIndex) { AuraEffect elementalOverload = GetCaster().GetAuraEffect(SpellIds.MasteryElementalOverload, 1); if (elementalOverload != null) SetHitDamage(MathFunctions.CalculatePct(GetHitDamage(), elementalOverload.GetAmount())); } public override void Register() { OnEffectHitTarget.Add(new(ApplyDamageModifier, 0, SpellEffectName.SchoolDamage)); } } [Script] // 334033 - Molten Assault (60103 - Lava Lash) class spell_sha_molten_assault : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.FlameShock); } public override bool Load() { return GetCaster().HasAura(SpellIds.MoltenAssault); } void TriggerFlameShocks(uint effIndex) { Unit caster = GetCaster(); Unit lavaLashTarget = GetHitUnit(); if (!lavaLashTarget.HasAura(SpellIds.FlameShock, caster.GetGUID())) return; float range = 10.0f; List targets = new(); WorldObjectSpellAreaTargetCheck check = new(range, lavaLashTarget, caster, caster, Global.SpellMgr.GetSpellInfo(SpellIds.FlameShock, Difficulty.None), SpellTargetCheckTypes.Enemy, null, SpellTargetObjectTypes.Unit, WorldObjectSpellAreaTargetSearchReason.Area); WorldObjectListSearcher searcher = new(caster, targets, check, GridMapTypeMask.Creature | GridMapTypeMask.Player); Cell.VisitAllObjects(lavaLashTarget, searcher, range + SharedConst.ExtraCellSearchRadius); var predicate = new UnitAuraCheck(true, SpellIds.FlameShock, GetCaster().GetGUID()).Invoke; targets.PartitionInPlace(predicate); var withoutFlameShockIndex = targets.FindIndex(0, x => !predicate(x)); if (withoutFlameShockIndex != -1) targets.RandomShuffle(withoutFlameShockIndex, targets.Count - withoutFlameShockIndex); CastSpellExtraArgs args = new(); args.SetTriggerFlags(TriggerCastFlags.IgnoreGCD | TriggerCastFlags.IgnoreSpellAndCategoryCD | TriggerCastFlags.IgnorePowerCost | TriggerCastFlags.IgnoreCastInProgress); args.SetTriggeringSpell(GetSpell()); // targets that already have flame shock are first in the list (and need to refresh it) for (var i = 0; i < Math.Min(targets.Count, GetEffectValue() + 1); ++i) caster.CastSpell(targets[i], SpellIds.FlameShock, args); } public override void Register() { OnEffectHitTarget.Add(new(TriggerFlameShocks, 2, SpellEffectName.Dummy)); } } [Script] // 469344 Molten Thunder class spell_sha_molten_thunder : AuraScript { public int ProcCount = 0; public override void Register() { } } [Script] class spell_sha_molten_thunder_sundering : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.MoltenThunderTalent, SpellIds.MoltenThunderProc); } public override bool Load() { return GetCaster().HasAura(SpellIds.MoltenThunderTalent); } void RemoveIncapacitateEffect(List targets) { targets.Clear(); } void RollReset() { Unit shaman = GetCaster(); Aura talent = shaman.GetAura(SpellIds.MoltenThunderTalent); if (talent == null) return; AuraEffect chanceBaseEffect = talent.GetEffect(1); AuraEffect chancePerTargetEffect = talent.GetEffect(2); AuraEffect targetLimitEffect = talent.GetEffect(3); if (chanceBaseEffect == null || chancePerTargetEffect == null || targetLimitEffect == null) return; spell_sha_molten_thunder counterScript = talent.GetScript(); if (counterScript == null) return; int procChance = chanceBaseEffect.GetAmount(); procChance += (int)Math.Min(targetLimitEffect.GetAmount(), GetUnitTargetCountForEffect(0)) * chancePerTargetEffect.GetAmount(); procChance >>= counterScript.ProcCount; // Each consecutive reset reduces these chances by half if (RandomHelper.randChance(procChance)) { shaman.CastSpell(shaman, SpellIds.MoltenThunderProc, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringSpell = GetSpell() }); shaman.GetSpellHistory().ResetCooldown(GetSpellInfo().Id, true); ++counterScript.ProcCount; } else counterScript.ProcCount = 0; } public override void Register() { OnObjectAreaTargetSelect.Add(new(RemoveIncapacitateEffect, 3, Targets.UnitRectCasterEnemy)); AfterCast.Add(new(RollReset)); } } [Script] // 30884 - Nature's Guardian class spell_sha_natures_guardian : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.NaturesGuardianCooldown); } bool CheckProc(AuraEffect aurEff, ProcEventInfo eventInfo) { return eventInfo.GetActionTarget().HealthBelowPct(aurEff.GetAmount()) && !eventInfo.GetActionTarget().HasAura(SpellIds.NaturesGuardianCooldown); } void StartCooldown(AuraEffect aurEff, ProcEventInfo eventInfo) { Unit shaman = eventInfo.GetActionTarget(); shaman.CastSpell(shaman, SpellIds.NaturesGuardianCooldown, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringAura = aurEff }); } public override void Register() { DoCheckEffectProc.Add(new(CheckProc, 0, AuraType.Dummy)); OnEffectProc.Add(new(StartCooldown, 0, AuraType.Dummy)); } } [Script] // 210621 - Path of Flames Spread class spell_sha_path_of_flames_spread : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.FlameShock); } void FilterTargets(List targets) { targets.Remove(GetExplTargetUnit()); targets.RandomResize(new UnitAuraCheck(false, SpellIds.FlameShock, GetCaster().GetGUID()).Invoke, 1); } void HandleScript(uint effIndex) { Unit mainTarget = GetExplTargetUnit(); if (mainTarget != null) { Aura flameShock = mainTarget.GetAura(SpellIds.FlameShock, GetCaster().GetGUID()); if (flameShock != null) { Aura newAura = GetCaster().AddAura(SpellIds.FlameShock, GetHitUnit()); if (newAura != null) { newAura.SetDuration(flameShock.GetDuration()); newAura.SetMaxDuration(flameShock.GetDuration()); } } } } public override void Register() { OnObjectAreaTargetSelect.Add(new(FilterTargets, 1, Targets.UnitDestAreaEnemy)); OnEffectHitTarget.Add(new(HandleScript, 1, SpellEffectName.Dummy)); } } [Script] // 375982 - Primordial Wave class spell_sha_primordial_wave : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.FlameShock, SpellIds.PrimordialWaveDamage); } void TriggerDamage(uint effIndex) { Unit shaman = GetCaster(); List targets = new(); FireNovaTargetCheck check = new() { MaxSearchRange = GetSpell().GetMinMaxRange(false).maxRange, Shaman = shaman }; UnitListSearcher searcher = new(shaman, targets, check); Cell.VisitAllObjects(shaman, searcher, check.MaxSearchRange); CastSpellExtraArgs args = new(); args.SetTriggerFlags(TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError); args.SetTriggeringSpell(GetSpell()); foreach (Unit target in targets) shaman.CastSpell(target, SpellIds.PrimordialWaveDamage, args); } void PreventLavaSurge(uint effIndex) { PreventHitDefaultEffect(effIndex); } void EnergizeMaelstrom(uint effIndex) { spell_sha_maelstrom_weapon_base.GenerateMaelstromWeapon(GetCaster(), GetEffectValue()); } public override void Register() { ChrSpecialization specialization = ChrSpecialization.None; Spell spell = GetSpell(); if (spell != null) // spell doesn't exist at startup validation { Player caster = spell.GetCaster()?.ToPlayer(); if (caster != null) specialization = caster.GetPrimarySpecialization(); } OnEffectHitTarget.Add(new(TriggerDamage, 0, SpellEffectName.Dummy)); if (specialization != ChrSpecialization.ShamanElemental) OnEffectLaunch.Add(new(PreventLavaSurge, 5, SpellEffectName.TriggerSpell)); if (specialization == ChrSpecialization.None || specialization == ChrSpecialization.ShamanEnhancement) OnEffectHitTarget.Add(new(EnergizeMaelstrom, 4, SpellEffectName.Dummy)); } } // 114083 - Restorative Mists [Script] // 294020 - Restorative Mists class spell_sha_restorative_mists : SpellScript { void HandleHeal(uint effIndex) { SetHitHeal((int)(GetHitHeal() / GetUnitTargetCountForEffect(effIndex))); } public override void Register() { OnEffectHitTarget.Add(new(HandleHeal, 0, SpellEffectName.Heal)); } } // 2645 - Ghost Wolf // 260878 - Spirit Wolf class spell_sha_spirit_wolf : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.GhostWolf, SpellIds.SpiritWolfTalent, SpellIds.SpiritWolfPeriodic, SpellIds.SpiritWolfAura); } void OnApply(AuraEffect aurEff, AuraEffectHandleModes mode) { Unit target = GetTarget(); if (target.HasAura(SpellIds.SpiritWolfTalent) && target.HasAura(SpellIds.GhostWolf)) target.CastSpell(target, SpellIds.SpiritWolfPeriodic, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringAura = aurEff }); } void OnRemove(AuraEffect aurEff, AuraEffectHandleModes mode) { GetTarget().RemoveAurasDueToSpell(SpellIds.SpiritWolfPeriodic); GetTarget().RemoveAurasDueToSpell(SpellIds.SpiritWolfAura); } public override void Register() { AfterEffectApply.Add(new(OnApply, 0, AuraType.Any, AuraEffectHandleModes.Real)); AfterEffectRemove.Add(new(OnRemove, 0, AuraType.Any, AuraEffectHandleModes.Real)); } } [Script] // 319930 - Stormblast class spell_sha_stormblast : AuraScript { public ObjectGuid AllowedOriginalCastId; public override void Register() { } } [Script] // 470466 - Stormblast (Stormstrike and Winstrike damaging spells) class spell_sha_stormblast_damage : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellEffect((SpellIds.StormblastTalent, 0), (SpellIds.EnhancedElements, 0)); } public override bool Load() { Aura stormblast = GetCaster().GetAura(SpellIds.StormblastTalent); if (stormblast != null) { spell_sha_stormblast script = stormblast.GetScript(); if (script != null) return script.AllowedOriginalCastId == GetSpell().m_originalCastId; } return false; } void TriggerDamage() { AuraEffect stormblast = GetCaster().GetAuraEffect(SpellIds.StormblastTalent, 0); if (stormblast != null) { int damage = MathFunctions.CalculatePct(GetHitDamage(), stormblast.GetAmount()); // Not part of SpellFamilyFlags for mastery effect but known to be affected by it AuraEffect mastery = GetCaster().GetAuraEffect(SpellIds.EnhancedElements, 0); if (mastery != null) MathFunctions.AddPct(ref damage, mastery.GetAmount()); GetCaster().CastSpell(GetHitUnit(), SpellIds.StormblastDamage, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, SpellValueOverrides = { new(SpellValueMod.BasePoint0, damage) } }); } } public override void Register() { AfterHit.Add(new(TriggerDamage)); } } [Script] // 470466 - Stormblast (17364 - Stormstrike, 115356 - Windstrike) class spell_sha_stormblast_proc : SpellScript { public override bool Load() { Unit caster = GetCaster(); return caster.HasAura(SpellIds.StormblastTalent) && caster.HasAura(SpellIds.StormblastProc); } // Store allowed CastId in passive aura because damaging spells are delayed (and delayed further if Stormflurry is triggered) void SaveCastId() { Unit caster = GetCaster(); Aura stormblast = caster.GetAura(SpellIds.StormblastTalent); if (stormblast != null) { spell_sha_stormblast script = stormblast.GetScript(); if (script != null) script.AllowedOriginalCastId = GetSpell().m_castId; } caster.RemoveAuraFromStack(SpellIds.StormblastProc); } public override void Register() { OnCast.Add(new(SaveCastId)); } } class StormflurryEvent : BasicEvent { Unit _caster; CastSpellTargetArg _target; ObjectGuid _originalCastId; int _damagePercent; uint _mainHandDamageSpellId; uint _offHandDamageSpellId; int _procChance; public StormflurryEvent(Unit caster, Unit target, ObjectGuid originalCastId, int damagePercent, uint mainHandDamageSpellId, uint offHandDamageSpellId, int procChance) { _caster = caster; _target = target; _originalCastId = originalCastId; _damagePercent = damagePercent; _mainHandDamageSpellId = mainHandDamageSpellId; _offHandDamageSpellId = offHandDamageSpellId; _procChance = procChance; } public override bool Execute(ulong time, uint diff) { if (_target.Targets == null) return true; _target.Targets.Update(_caster); CastSpellExtraArgs args = new(); args.TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError; args.OriginalCastId = _originalCastId; args.CustomArg = new Data() { DamagePercent = _damagePercent }; _caster.CastSpell(_target, _mainHandDamageSpellId, args); _caster.CastSpell(_target, _offHandDamageSpellId, args); if (!RandomHelper.randChance(_procChance)) return true; _caster.m_Events.AddEvent(this, TimeSpan.FromSeconds(time) + TimeSpan.FromSeconds(200)); return false; } public class Data { public int DamagePercent; } } // 198367 Stormflurry // 344357 Stormflurry [Script("spell_sha_artifact_stormflurry_stormstrike", SpellIds.StormflurryArtifact, SpellIds.StormstrikeDamageMainHand, SpellIds.StormstrikeDamageOffHand)] [Script("spell_sha_artifact_stormflurry_windstrike", SpellIds.StormflurryArtifact, SpellIds.WindstrikeDamageMainHand, SpellIds.WindstrikeDamageOffHand)] [Script("spell_sha_stormflurry_stormstrike", SpellIds.Stormflurry, SpellIds.StormstrikeDamageMainHand, SpellIds.StormstrikeDamageOffHand)] [Script("spell_sha_stormflurry_windstrike", SpellIds.Stormflurry, SpellIds.WindstrikeDamageMainHand, SpellIds.WindstrikeDamageOffHand)] class spell_sha_stormflurry : SpellScript { uint _stormflurrySpellId; uint _mainHandDamageSpellId; uint _offHandDamageSpellId; public spell_sha_stormflurry(uint stormflurrySpellId, uint mainHandDamageSpellId, uint offHandDamageSpellId) { _stormflurrySpellId = stormflurrySpellId; _mainHandDamageSpellId = mainHandDamageSpellId; _offHandDamageSpellId = offHandDamageSpellId; } public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(_stormflurrySpellId, _mainHandDamageSpellId, _offHandDamageSpellId) && ValidateSpellEffect((spellInfo.Id, 1)) && spellInfo.GetEffect(0).IsEffect(SpellEffectName.TriggerSpell) && spellInfo.GetEffect(1).IsEffect(SpellEffectName.TriggerSpell); } public override bool Load() { return GetCaster().HasAura(_stormflurrySpellId); } void HandleProc(uint effIndex) { Unit caster = GetCaster(); Aura stormflurry = caster.GetAura(_stormflurrySpellId); if (stormflurry == null) return; AuraEffect chanceEffect = stormflurry.GetEffect(0); AuraEffect damageEffect = stormflurry.GetEffect(1); if (chanceEffect == null || damageEffect == null) return; int procChance = chanceEffect.GetAmount(); if (!RandomHelper.randChance(procChance)) return; caster.m_Events.AddEventAtOffset(new StormflurryEvent(caster, GetHitUnit(), GetSpell().m_castId, damageEffect.GetAmount(), _mainHandDamageSpellId, _offHandDamageSpellId, procChance), TimeSpan.FromSeconds(200)); } public override void Register() { OnEffectHitTarget.Add(new(HandleProc, 1, SpellEffectName.TriggerSpell)); } } // 32175 - Stormstrike [Script] // 32176 - Stormstrike Off-Hand class spell_sha_stormflurry_damage : SpellScript { public override bool Load() { return GetSpell().m_customArg.GetType() == typeof(StormflurryEvent.Data); } void ApplyModifier(SpellEffectInfo effectInfo, Unit victim, ref int damage, ref int flatMod, ref float pctMod) { MathFunctions.ApplyPct(ref pctMod, ((StormflurryEvent.Data)GetSpell().m_customArg).DamagePercent); } public override void Register() { CalcDamage.Add(new(ApplyModifier)); } } [Script] // 201845 - Stormsurge class spell_sha_stormsurge : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.StormsurgeProc); } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { eventInfo.GetActor().CastSpell(eventInfo.GetActor(), SpellIds.StormsurgeProc, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, TriggeringAura = aurEff }); } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } } [Script] // 187881 - Maelstrom Weapon class spell_sha_stormweaver : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.StormweaverPvpTalent); } public override bool Load() { return GetCaster().HasAura(SpellIds.StormweaverPvpTalent); } void PreventAffectingHealingSpells(ref WorldObject target) { target = null; } public override void Register() { OnObjectTargetSelect.Add(new(PreventAffectingHealingSpells, 2, Targets.UnitCaster)); OnObjectTargetSelect.Add(new(PreventAffectingHealingSpells, 4, Targets.UnitCaster)); } } [Script] // 384359 - Swirling Maelstrom class spell_sha_swirling_maelstrom : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellEffect((spellInfo.Id, 1)) && spell_sha_maelstrom_weapon_base.Validate(); } bool CheckHailstormProc(ProcEventInfo eventInfo) { if (eventInfo.GetSpellInfo().IsAffected(SpellFamilyNames.Shaman, new FlagArray128(0x80000000, 0x0, 0x0, 0x0))) // Frost Shock { Aura hailstorm = eventInfo.GetActor().GetAura(SpellIds.HailstormBuff); if (hailstorm == null || hailstorm.GetStackAmount() < GetEffect(1).GetAmount()) return false; if (!eventInfo.GetProcSpell().m_appliedMods.Contains(hailstorm)) return false; } return true; } void EnergizeMaelstrom(AuraEffect aurEff, ProcEventInfo eventInfo) { spell_sha_maelstrom_weapon_base.GenerateMaelstromWeapon(GetTarget(), aurEff.GetAmount()); } public override void Register() { DoCheckProc.Add(new(CheckHailstormProc)); OnEffectProc.Add(new(EnergizeMaelstrom, 0, AuraType.Dummy)); } } [Script] // 384444 - Thorim's Invocation class spell_sha_thorims_invocation : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.LightningBolt, SpellIds.ChainLightning); } public override void Register() { } public uint SpellIdToTrigger = SpellIds.LightningBolt; } // 188196 - Lightning Bolt // 188443 - Chain Lightning [Script] // 452201 - Tempest class spell_sha_thorims_invocation_primer : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ThorimsInvocation, SpellIds.LightningBolt, SpellIds.ChainLightning) && ValidateSpellEffect((spellInfo.Id, 0)) && spellInfo.GetEffect(0).IsEffect(SpellEffectName.SchoolDamage); } void UpdateThorimsInvocationSpell() { Aura thorimsInvocation = GetCaster().GetAura(SpellIds.ThorimsInvocation); if (thorimsInvocation != null) { spell_sha_thorims_invocation spellIdHolder = thorimsInvocation.GetScript(); if (spellIdHolder != null) spellIdHolder.SpellIdToTrigger = GetUnitTargetCountForEffect(0) > 1 ? SpellIds.ChainLightning : SpellIds.LightningBolt; } } public override void Register() { AfterCast.Add(new(UpdateThorimsInvocationSpell)); } } [Script] // 115357 - Windstrike (Mh) class spell_sha_thorims_invocation_trigger : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellEffect((SpellIds.ThorimsInvocation, 0)); } public override bool Load() { return GetCaster().HasAura(SpellIds.ThorimsInvocation); } void TriggerLightningSpell(uint effIndex) { Unit caster = GetCaster(); AuraEffect thorimsInvocation = caster.GetAuraEffect(SpellIds.ThorimsInvocation, 0); if (thorimsInvocation == null) return; spell_sha_thorims_invocation spellIdHolder = thorimsInvocation.GetBase().GetScript(); if (spellIdHolder == null) return; var (spellInfo, triggerFlags) = caster.GetCastSpellInfo(Global.SpellMgr.GetSpellInfo(spellIdHolder.SpellIdToTrigger, GetCastDifficulty())); // Remove Overflowing Maelstrom spellmod early to make next cast behave as if it consumed only 5 or less maelstrom stacks // this works because consuming "up to 5 stacks" will always cause Maelstrom Weapon stacks to drop to 5 or lower // which means Overflowing Maelstrom needs removing anyway caster.RemoveAurasDueToSpell(SpellIds.OverflowingMaelstromAura); caster.CastSpell(GetHitUnit(), spellInfo.Id, new CastSpellExtraArgs() { TriggerFlags = triggerFlags | TriggerCastFlags.IgnoreGCD | TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.IgnoreCastTime | TriggerCastFlags.DontReportCastError, TriggeringSpell = GetSpell() }); // Manually remove stacks - Maelstrom Weapon aura cannot proc from procs and free Lightning Bolt/Chain Lightning procs from Arc Discharge (455096) shoulnd't consume it Aura maelstromWeaponVisibleAura = caster.GetAura(SpellIds.MaelstromWeaponVisibleAura); if (maelstromWeaponVisibleAura != null) spell_sha_maelstrom_weapon_base.ConsumeMaelstromWeapon(caster, maelstromWeaponVisibleAura, thorimsInvocation.GetAmount()); } public override void Register() { OnEffectHitTarget.Add(new(TriggerLightningSpell, 0, SpellEffectName.SchoolDamage)); } } [Script] // 51564 - Tidal Waves class spell_sha_tidal_waves : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.TidalWaves); } void HandleEffectProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); GetTarget().CastSpell(GetTarget(), SpellIds.TidalWaves, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringAura = aurEff, SpellValueOverrides = { new( SpellValueMod.BasePoint0, -aurEff.GetAmount() ), new(SpellValueMod.BasePoint1, aurEff.GetAmount() ) } }); } public override void Register() { OnEffectProc.Add(new(HandleEffectProc, 0, AuraType.Dummy)); } } [Script] // 28823 - Totemic Power class spell_sha_t3_6p_bonus : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.TotemicPowerArmor, SpellIds.TotemicPowerAttackPower, SpellIds.TotemicPowerSpellPower, SpellIds.TotemicPowerMP5); } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); uint spellId; Unit caster = eventInfo.GetActor(); Unit target = eventInfo.GetProcTarget(); switch (target.GetClass()) { case Class.Paladin: case Class.Priest: case Class.Shaman: case Class.Druid: spellId = SpellIds.TotemicPowerMP5; break; case Class.Mage: case Class.Warlock: spellId = SpellIds.TotemicPowerSpellPower; break; case Class.Hunter: case Class.Rogue: spellId = SpellIds.TotemicPowerAttackPower; break; case Class.Warrior: spellId = SpellIds.TotemicPowerArmor; break; default: return; } caster.CastSpell(target, spellId, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringAura = aurEff }); } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } } [Script] // 28820 - Lightning Shield class spell_sha_t3_8p_bonus : AuraScript { void PeriodicTick(AuraEffect aurEff) { PreventDefaultAction(); // Need remove self if Lightning Shield not active if (GetTarget().GetAuraEffect(AuraType.ProcTriggerSpell, SpellFamilyNames.Shaman, new FlagArray128(0x400), GetCaster().GetGUID()) == null) Remove(); } public override void Register() { OnEffectPeriodic.Add(new(PeriodicTick, 1, AuraType.PeriodicTriggerSpell)); } } [Script] // 64928 - Item - Shaman T8 Elemental 4P Bonus class spell_sha_t8_elemental_4p_bonus : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.Electrified); } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); DamageInfo damageInfo = eventInfo.GetDamageInfo(); if (damageInfo == null || damageInfo.GetDamage() == 0) return; SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.Electrified, GetCastDifficulty()); int amount = MathFunctions.CalculatePct((int)(damageInfo.GetDamage()), aurEff.GetAmount()); Cypher.Assert(spellInfo.GetMaxTicks() > 0); amount /= (int)spellInfo.GetMaxTicks(); Unit caster = eventInfo.GetActor(); Unit target = eventInfo.GetProcTarget(); caster.CastSpell(target, SpellIds.Electrified, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringAura = aurEff, SpellValueOverrides = { new(SpellValueMod.BasePoint0, amount) } }); } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } } [Script] // 67228 - Item - Shaman T9 Elemental 4P Bonus (Lava Burst) class spell_sha_t9_elemental_4p_bonus : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.LavaBurstBonusDamage); } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); DamageInfo damageInfo = eventInfo.GetDamageInfo(); if (damageInfo == null || damageInfo.GetDamage() == 0) return; SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.LavaBurstBonusDamage, GetCastDifficulty()); int amount = MathFunctions.CalculatePct((int)(damageInfo.GetDamage()), aurEff.GetAmount()); Cypher.Assert(spellInfo.GetMaxTicks() > 0); amount /= (int)spellInfo.GetMaxTicks(); Unit caster = eventInfo.GetActor(); Unit target = eventInfo.GetProcTarget(); caster.CastSpell(target, SpellIds.LavaBurstBonusDamage, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringAura = aurEff, SpellValueOverrides = { new(SpellValueMod.BasePoint0, amount) } }); } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } } [Script] // 70817 - Item - Shaman T10 Elemental 4P Bonus class spell_sha_t10_elemental_4p_bonus : AuraScript { void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); Unit caster = eventInfo.GetActor(); Unit target = eventInfo.GetProcTarget(); // try to find spell Flame Shock on the target AuraEffect flameShock = target.GetAuraEffect(AuraType.PeriodicDamage, SpellFamilyNames.Shaman, new FlagArray128(0x10000000), caster.GetGUID()); if (flameShock == null) return; Aura flameShockAura = flameShock.GetBase(); int maxDuration = flameShockAura.GetMaxDuration(); int newDuration = flameShockAura.GetDuration() + aurEff.GetAmount() * Time.InMilliseconds; flameShockAura.SetDuration(newDuration); // is it blizzlike to change max duration for Fs? if (newDuration > maxDuration) flameShockAura.SetMaxDuration(newDuration); } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } } [Script] // 70808 - Item - Shaman T10 Restoration 4P Bonus class spell_sha_t10_restoration_4p_bonus : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.ChainedHeal); } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); HealInfo healInfo = eventInfo.GetHealInfo(); if (healInfo == null || healInfo.GetHeal() == 0) return; SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(SpellIds.ChainedHeal, GetCastDifficulty()); int amount = MathFunctions.CalculatePct((int)(healInfo.GetHeal()), aurEff.GetAmount()); Cypher.Assert(spellInfo.GetMaxTicks() > 0); amount /= (int)spellInfo.GetMaxTicks(); Unit caster = eventInfo.GetActor(); Unit target = eventInfo.GetProcTarget(); caster.CastSpell(target, SpellIds.ChainedHeal, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringAura = aurEff, SpellValueOverrides = { new(SpellValueMod.BasePoint0, amount) } }); } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } } [Script] // 260895 - Unlimited Power class spell_sha_unlimited_power : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.UnlimitedPowerBuff); } void HandleProc(AuraEffect aurEff, ProcEventInfo procInfo) { Unit caster = procInfo.GetActor(); Aura aura = caster.GetAura(SpellIds.UnlimitedPowerBuff); if (aura != null) aura.SetStackAmount((byte)(aura.GetStackAmount() + 1)); else caster.CastSpell(caster, SpellIds.UnlimitedPowerBuff, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringSpell = procInfo.GetProcSpell() }); } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } } [Script] // 200071 - Undulation class spell_sha_undulation_passive : AuraScript { byte _castCounter = 1; // first proc happens after two casts, then one every 3 casts public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.UndulationProc); } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { if (++_castCounter == 3) { GetTarget().CastSpell(GetTarget(), SpellIds.UndulationProc, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); _castCounter = 0; } } public override void Register() { OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } } [Script] // 470490 - Unrelenting Storms class spell_sha_unrelenting_storms : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.UnrelentingStormsReduction) && ValidateSpellEffect((SpellIds.UnrelentingStormsTalent, 1)); } public override bool Load() { return GetCaster().HasAura(SpellIds.UnrelentingStormsTalent); } void Trigger(uint effIndex) { Unit shaman = GetCaster(); Aura unrelentingStorms = shaman.GetAura(SpellIds.UnrelentingStormsTalent); if (unrelentingStorms == null) return; long targetLimit = 0; AuraEffect limitEffect = unrelentingStorms.GetEffect(0); if (limitEffect != null) targetLimit = limitEffect.GetAmount(); if (GetUnitTargetCountForEffect(effIndex) > targetLimit) return; TimeSpan cooldown = TimeSpan.FromSeconds(0); AuraEffect reductionPctEffect = unrelentingStorms.GetEffect(1); if (reductionPctEffect != null) { SpellHistory.GetCooldownDurations(GetSpellInfo(), 0, ref cooldown); shaman.CastSpell(shaman, SpellIds.UnrelentingStormsReduction, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError, SpellValueOverrides = { new(SpellValueMod.BasePoint0, -(int)(MathFunctions.CalculatePct((int)cooldown.TotalMilliseconds, reductionPctEffect.GetAmount()))) } }); } if (shaman.HasAura(SpellIds.WindfuryAura)) WindfuryProcEvent.Trigger(shaman, GetHitUnit()); } public override void Register() { OnEffectHitTarget.Add(new(Trigger, 0, SpellEffectName.SchoolDamage)); } } [Script] // 470057 - Voltaic Blaze class spell_sha_voltaic_blaze : SpellScript { public override bool Validate(SpellInfo spellInfo) { return spell_sha_maelstrom_weapon_base.Validate(); } void ApplyFlameShock(uint effIndex) { Unit caster = GetCaster(); var targets = new CastSpellTargetArg(GetHitUnit()); caster.m_Events.AddEventAtOffset(() => { if (targets.Targets == null) return; targets.Targets.Update(caster); caster.CastSpell(targets, SpellIds.FlameShock, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); }, TimeSpan.FromSeconds(500)); } void EnergizeMaelstrom(uint effIndex) { spell_sha_maelstrom_weapon_base.GenerateMaelstromWeapon(GetCaster(), GetEffectValue()); } public override void Register() { OnEffectHitTarget.Add(new(ApplyFlameShock, 0, SpellEffectName.SchoolDamage)); OnEffectHitTarget.Add(new(EnergizeMaelstrom, 1, SpellEffectName.Dummy)); } } [Script] // 470058 - Voltaic Blaze class spell_sha_voltaic_blaze_aura : AuraScript { bool CheckProc(ProcEventInfo eventInfo) { // 470057 - Voltaic Blaze does not have any unique SpellFamilyFlags, check by id return eventInfo.GetSpellInfo().Id == SpellIds.VoltaicBlazeDamage; } public override void Register() { DoCheckProc.Add(new(CheckProc)); } } [Script] // 470053 - Voltaic Blaze class spell_sha_voltaic_blaze_talent : AuraScript { bool CheckProc(AuraEffect aurEff, ProcEventInfo eventInfo) { return RandomHelper.randChance(aurEff.GetAmount()); } void HandleProc(AuraEffect aurEff, ProcEventInfo eventInfo) { eventInfo.GetActor().CastSpell(eventInfo.GetActor(), SpellIds.VoltaicBlazeOverride); } public override void Register() { DoCheckEffectProc.Add(new(CheckProc, 0, AuraType.Dummy)); OnEffectProc.Add(new(HandleProc, 0, AuraType.Dummy)); } } [Script] // 33757 - Windfury Weapon class spell_sha_windfury_weapon : SpellScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.WindfuryEnchantment); } public override bool Load() { return GetCaster().IsPlayer(); } void HandleEffect(uint effIndex) { PreventHitDefaultEffect(effIndex); Item mainHand = GetCaster().ToPlayer().GetWeaponForAttack(WeaponAttackType.BaseAttack, false); if (mainHand != null) { GetCaster().CastSpell(mainHand, SpellIds.WindfuryEnchantment, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask, TriggeringSpell = GetSpell() }); } } public override void Register() { OnEffectHitTarget.Add(new(HandleEffect, 0, SpellEffectName.Dummy)); } } [Script] // 319773 - Windfury Weapon (proc) class spell_sha_windfury_weapon_proc : AuraScript { public override bool Validate(SpellInfo spellInfo) { return ValidateSpellInfo(SpellIds.WindfuryAttack, SpellIds.WindfuryVisual1, SpellIds.WindfuryVisual2, SpellIds.WindfuryVisual3, SpellIds.UnrulyWinds, SpellIds.ForcefulWindsTalent, SpellIds.ForcefulWindsProc); } void HandleEffectProc(AuraEffect aurEff, ProcEventInfo eventInfo) { PreventDefaultAction(); WindfuryProcEvent.Trigger(eventInfo.GetActor(), eventInfo.GetActionTarget()); } public override void Register() { OnEffectProc.Add(new(HandleEffectProc, 0, AuraType.Dummy)); } } // 462767 - Arctic Snowstorm [Script] // 36797 - AreatriggerId class areatrigger_sha_arctic_snowstorm(AreaTrigger areaTrigger) : AreaTriggerAI(areaTrigger) { public override void OnUnitEnter(Unit unit) { Unit caster = at.GetCaster(); if (caster != null) { if (unit.GetAura(SpellIds.FrostShock, caster.GetGUID()) != null) return; if (caster.IsValidAttackTarget(unit)) caster.CastSpell(unit, SpellIds.ArcticSnowstormSlow, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.IgnoreCastInProgress | TriggerCastFlags.DontReportCastError }); } } public override void OnUnitExit(Unit unit, AreaTriggerExitReason reason) { unit.RemoveAurasDueToSpell(SpellIds.ArcticSnowstormSlow, at.GetCasterGUID()); } } // 192078 - Wind Rush Totem (Spell) [Script] // 12676 - AreaTriggerId class areatrigger_sha_wind_rush_totem(AreaTrigger areaTrigger) : AreaTriggerAI(areaTrigger) { static int RefreshTime = 4500; int _refreshTimer = RefreshTime; public override void OnUpdate(uint diff) { _refreshTimer -= (int)diff; if (_refreshTimer <= 0) { Unit caster = at.GetCaster(); if (caster != null) { foreach (ObjectGuid guid in at.GetInsideUnits()) { Unit unit = Global.ObjAccessor.GetUnit(caster, guid); if (unit != null) CastSpeedBuff(caster, unit); } } _refreshTimer += RefreshTime; } } public override void OnUnitEnter(Unit unit) { Unit caster = at.GetCaster(); if (caster != null) CastSpeedBuff(caster, unit); } void CastSpeedBuff(Unit caster, Unit unit) { if (!caster.IsValidAssistTarget(unit)) return; caster.CastSpell(unit, SpellIds.WindRush, new CastSpellExtraArgs() { TriggerFlags = TriggerCastFlags.FullMask }); } }