TrinityCore
Loading...
Searching...
No Matches
spell_shaman.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Scripts for spells with SPELLFAMILY_SHAMAN and SPELLFAMILY_GENERIC spells used by shaman players.
20 * Ordered alphabetically using scriptname.
21 * Scriptnames of files in this file should be prefixed with "spell_sha_".
22 */
23
24#include "ScriptMgr.h"
25#include "AreaTriggerAI.h"
26#include "CellImpl.h"
27#include "Containers.h"
28#include "GridNotifiersImpl.h"
29#include "Item.h"
30#include "ObjectAccessor.h"
31#include "Player.h"
32#include "SpellAuraEffects.h"
33#include "SpellHistory.h"
34#include "SpellMgr.h"
35#include "SpellScript.h"
36#include "TemporarySummon.h"
37
39{
176
181
186
188{
189 static bool Validate();
190 static void GenerateMaelstromWeapon(Unit* shaman, int32 stacks);
191 static void ConsumeMaelstromWeapon(Unit* shaman, Aura* maelstromWeaponVisibleAura, int32 stacks, Spell const* consumingSpell = nullptr);
192};
193
195{
196public:
202
203 static constexpr std::array<WindfuryProcEventInfo, 3> Sequence =
204 { {
205 {.Delay = 500ms, .VisualSpellId = SPELL_SHAMAN_WINDFURY_VISUAL_1 },
206 {.Delay = 150ms, .VisualSpellId = SPELL_SHAMAN_WINDFURY_VISUAL_2 },
207 {.Delay = 250ms, .VisualSpellId = SPELL_SHAMAN_WINDFURY_VISUAL_3 },
208 } };
209
210 WindfuryProcEvent(Unit* shaman, Unit* target, std::ptrdiff_t attacks) : _shaman(shaman), _target(target), _itr(Sequence.begin()), _end(_itr + attacks) { }
211
212 bool Execute(uint64 time, uint32 /*diff*/) override;
213
214 static void Trigger(Unit* shaman, Unit* target);
215
216private:
219 using EventInfoIterator = decltype(Sequence)::const_iterator;
222};
223
224// 273221 - Aftershock
226{
227 bool Validate(SpellInfo const* /*spellEntry*/) override
228 {
230 }
231
232 static bool CheckProc(AuraScript const&, AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
233 {
234 if (Spell const* procSpell = eventInfo.GetProcSpell())
235 if (Optional<int32> cost = procSpell->GetPowerTypeCostAmount(POWER_MAELSTROM))
236 return cost > 0 && roll_chance(aurEff->GetAmount());
237
238 return false;
239 }
240
241 static void HandleEffectProc(AuraScript const&, AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
242 {
243 Spell const* procSpell = eventInfo.GetProcSpell();
245 .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
246 .TriggeringSpell = procSpell,
247 .TriggeringAura = aurEff,
248 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, static_cast<SpellEffectValue>(*procSpell->GetPowerTypeCostAmount(POWER_MAELSTROM)) } }
249 });
250 }
251
257};
258
259// 108281 - Ancestral Guidance
261{
262 bool Validate(SpellInfo const* /*spellInfo*/) override
263 {
265 }
266
267 static bool CheckProc(AuraScript const&, ProcEventInfo const& eventInfo)
268 {
269 if (eventInfo.GetSpellInfo() && eventInfo.GetSpellInfo()->Id == SPELL_SHAMAN_ANCESTRAL_GUIDANCE_HEAL)
270 return false;
271
272 if (!eventInfo.GetHealInfo() && !eventInfo.GetDamageInfo())
273 return false;
274
275 return true;
276 }
277
278 void HandleEffectProc(AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
279 {
281 SpellEffectValue bp0 = CalculatePct(eventInfo.GetDamageInfo() ? eventInfo.GetDamageInfo()->GetDamage() : eventInfo.GetHealInfo()->GetHeal(), aurEff->GetAmount());
282 if (!bp0)
283 return;
284
287 .TriggeringAura = aurEff,
288 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, bp0 } }
289 });
290 }
291
297};
298
299// 114911 - Ancestral Guidance Heal
312
313// 462764 - Arctic Snowstorm
315{
316 bool Validate(SpellInfo const* /*spellEntry*/) override
317 {
319 }
320
321 static void HandleEffectProc(AuraScript const&, AuraEffect const* /*aurEff*/, ProcEventInfo const& eventInfo)
322 {
324 CastSpellExtraArgsInit{ .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR });
325 }
326
331};
332
333// 198299 - Gathering Storms
335{
336 bool Validate(SpellInfo const* /*spellInfo*/) override
337 {
339 }
340
341 bool Load() override
342 {
344 }
345
346 void TriggerBuff(SpellEffIndex effIndex) const
347 {
349 if (!gatheringStorms)
350 return;
351
354 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, gatheringStorms->GetAmount() * GetUnitTargetCountForEffect(effIndex) } }
355 });
356 }
357
362};
363
364// 114052 - Ascendance (Restoration)
366{
367 bool Validate(SpellInfo const* /*spellInfo*/) override
368 {
370 }
371
372 static bool CheckProc(AuraScript const&, ProcEventInfo const& procInfo)
373 {
374 return procInfo.GetHealInfo() && procInfo.GetHealInfo()->GetOriginalHeal() && procInfo.GetSpellInfo()->Id != SPELL_SHAMAN_RESTORATIVE_MISTS_INITIAL;
375 }
376
377 void OnProcHeal(AuraEffect const* aurEff, ProcEventInfo const& procInfo)
378 {
380 }
381
383 {
385 return;
386
389 .TriggeringAura = aurEff,
390 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, _healToDistribute } }
391 });
393 }
394
401
402private:
404};
405
406// 390370 - Ashen Catalyst
408{
409 bool Validate(SpellInfo const* /*spellInfo*/) override
410 {
412 }
413
414 void ReduceLavaLashCooldown(AuraEffect const* aurEff, ProcEventInfo const& /*procInfo*/) const
415 {
417 }
418
423};
424
425// 188443 - Chain Lightning
459
460// 188443 - Chain Lightning
462{
463 bool Validate(SpellInfo const* /*spellInfo*/) override
464 {
467 }
468
469 bool Load() override
470 {
472 }
473
474 void HandleScript(SpellEffIndex /*effIndex*/) const
475 {
476 if (AuraEffect const* energizeAmount = GetCaster()->GetAuraEffect(SPELL_SHAMAN_MAELSTROM_CONTROLLER, EFFECT_4))
479 .TriggeringAura = energizeAmount,
480 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, energizeAmount->GetAmount() * GetUnitTargetCountForEffect(EFFECT_0) } }
481 });
482 }
483
488};
489
490// 45297 - Chain Lightning Overload
519
520// 384363 - Converging Storms
522{
523 bool Validate(SpellInfo const* /*spellInfo*/) override
524 {
526 }
527
528 bool Load() override
529 {
531 }
532
533 void TriggerBuff(SpellEffIndex effIndex) const
534 {
536 if (!convergingStorms)
537 return;
538
541 .SpellValueOverrides = { { SPELLVALUE_AURA_STACK, std::min<int32>(GetUnitTargetCountForEffect(effIndex), 6) } }
542 });
543 }
544
549};
550
551// 198300 - Converging Storms
564
565// 187874 - Crash Lightning
587
588// 200076 - Deluge (attached to 77472 - Healing Wave, 8004 - Healing Surge and 1064 - Chain Heal
590{
591 bool Validate(SpellInfo const* /*spellInfo*/) override
592 {
595 }
596
597 void CalculateHealingBonus(SpellEffectInfo const& /*spellEffectInfo*/, Unit const* victim, int32& /*healing*/, int32& /*flatMod*/, float& pctMod) const
598 {
599 if (AuraEffect const* deluge = GetCaster()->GetAuraEffect(SPELL_SHAMAN_DELUGE_TALENT, EFFECT_0))
600 if (victim->GetAura(SPELL_SHAMAN_RIPTIDE, GetCaster()->GetGUID()) || victim->GetAura(SPELL_SHAMAN_DELUGE_AURA, GetCaster()->GetGUID()))
601 AddPct(pctMod, deluge->GetAmount());
602 }
603
608};
609
610namespace HealingRain
611{
612Position GetHealingRainPosition(Aura const* healingRain);
613}
614
615// 200075 - Deluge (attached to 73920 - Healing Rain)
638
639// 378270 - Deeply Rooted Elements
641{
649
650 bool Load() override
651 {
652 return GetUnitOwner()->IsPlayer();
653 }
654
655 bool CheckProc(AuraEffect const* /*aurEff*/, ProcEventInfo const& procInfo)
656 {
657 if (!procInfo.GetSpellInfo())
658 return false;
659
660 if (procInfo.GetSpellInfo()->Id != _triggeringSpellId)
661 return false;
662
663 return roll_chance(_procAttempts++ - 2);
664 }
665
666 void HandleProc(AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
667 {
668 _procAttempts = 0;
669
670 Unit* target = eventInfo.GetActor();
671
672 int32 duration = GetEffect(EFFECT_0)->GetAmountAsInt();
673 if (Aura const* ascendanceAura = target->GetAura(_triggeredSpellId))
674 duration += ascendanceAura->GetDuration();
675
678 .TriggeringSpell = eventInfo.GetProcSpell(),
679 .TriggeringAura = aurEff,
680 .SpellValueOverrides = { { SPELLVALUE_DURATION, duration } }
681 });
682 }
683
684 void Register() override
685 {
687 if (Aura const* aura = GetAura()) // aura doesn't exist at startup validation
688 if (Player const* owner = Object::ToPlayer(aura->GetOwner()))
689 specialization = owner->GetPrimarySpecialization();
690
691 if (specialization == ChrSpecialization::None || specialization == ChrSpecialization::ShamanElemental)
692 {
697 }
698
699 if (specialization == ChrSpecialization::None || specialization == ChrSpecialization::ShamanEnhancement)
700 {
705 }
706
707 if (specialization == ChrSpecialization::None || specialization == ChrSpecialization::ShamanRestoration)
708 {
713 }
714 }
715
719};
720
721// 466772 - Doom Winds
723{
724 bool Validate(SpellInfo const* /*spellInfo*/) override
725 {
727 }
728
729 void PeriodicTick(AuraEffect const* aurEff) const
730 {
733 .TriggeringAura = aurEff
734 });
735 }
736
741};
742
743// 335902 - Doom Winds
745{
746 bool Validate(SpellInfo const* /*spellInfo*/) override
747 {
749 }
750
751 bool CheckProc(AuraEffect const* /*aurEff*/, ProcEventInfo const& procInfo) const
752 {
754 return false;
755
756 SpellInfo const* spellInfo = procInfo.GetSpellInfo();
757 if (!spellInfo)
758 return false;
759
761 }
762
767};
768
769// 207778 - Downpour
771{
772 bool Validate(SpellInfo const* spellInfo) override
773 {
774 return ValidateSpellEffect({ { spellInfo->Id, EFFECT_1 } });
775 }
776
777 static void FilterTargets(SpellScript const&, std::list<WorldObject*>& targets)
778 {
779 Trinity::SelectRandomInjuredTargets(targets, 6, true);
780 }
781
783 {
784 // Cooldown increased for each target effectively healed
785 if (GetHitHeal())
787 }
788
789 void HandleCooldown() const
790 {
791 SpellHistory::Duration cooldown = Milliseconds(GetSpellInfo()->RecoveryTime) + Seconds(GetEffectInfo(EFFECT_1).CalcValueAsInt() * _healedTargets);
792 GetCaster()->GetSpellHistory()->StartCooldown(GetSpellInfo(), 0, GetSpell(), false, cooldown);
793 }
794
801
803};
804
805// 204288 - Earth Shield
807{
808 bool Validate(SpellInfo const* /*spellInfo*/) override
809 {
811 }
812
813 bool CheckProc(ProcEventInfo const& eventInfo) const
814 {
815 if (!eventInfo.GetDamageInfo() || !HasEffect(EFFECT_1) || eventInfo.GetDamageInfo()->GetDamage() < GetTarget()->CountPctFromMaxHealth(GetEffect(EFFECT_1)->GetAmount()))
816 return false;
817 return true;
818 }
819
820 void HandleProc(AuraEffect const* aurEff, ProcEventInfo const& /*eventInfo*/)
821 {
823
826 .TriggeringAura = aurEff,
827 .OriginalCaster = GetCasterGUID()
828 });
829 }
830
836};
837
838// 8042 - Earth Shock
840{
841 bool Validate(SpellInfo const* /*spellInfo*/) override
842 {
844 }
845
847 {
849 {
850 SetHitDamage(CalculatePct(GetHitDamage(), 100 + t29->GetAmount()));
851 t29->GetBase()->Remove();
852 }
853 }
854
859};
860
861// 170374 - Earthen Rage (Passive)
863{
864 bool Validate(SpellInfo const* /*spellInfo*/) override
865 {
867 }
868
869 static bool CheckProc(AuraScript const&, ProcEventInfo const& procInfo)
870 {
871 return procInfo.GetSpellInfo() && procInfo.GetSpellInfo()->Id != SPELL_SHAMAN_EARTHEN_RAGE_DAMAGE;
872 }
873
874 void HandleEffectProc(AuraEffect const* /*aurEff*/, ProcEventInfo const& eventInfo)
875 {
877 _procTargetGuid = eventInfo.GetProcTarget()->GetGUID();
879 .TriggerFlags = TRIGGERED_FULL_MASK
880 });
881 }
882
888
890
891public:
893 {
894 return _procTargetGuid;
895 }
896};
897
898// 170377 - Earthen Rage (Proc Aura)
922
923// 61882 - Earthquake
924// 8382 - AreaTriggerId
926{
928
929 void OnCreate(Spell const* creatingSpell) override
930 {
931 if (Unit* caster = at->GetCaster())
932 if (AuraEffect const* earthquake = caster->GetAuraEffect(SPELL_SHAMAN_EARTHQUAKE, EFFECT_1))
933 _period = Milliseconds(earthquake->GetPeriod());
934
935 if (creatingSpell)
936 if (float const* damageMultiplier = std::any_cast<float>(&creatingSpell->m_customArg))
937 _damageMultiplier = *damageMultiplier;
938 }
939
940 void OnUpdate(uint32 diff) override
941 {
943 while (_refreshTimer <= 0s)
944 {
945 if (Unit* caster = at->GetCaster())
947 .TriggerFlags = TRIGGERED_FULL_MASK,
948 .OriginalCaster = at->GetGUID(),
949 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, caster->SpellBaseDamageBonusDone(SPELL_SCHOOL_MASK_NATURE) * 0.213 * _damageMultiplier } }
950 });
951
953 }
954 }
955
956 // Each target can only be stunned once by each earthquake - keep track of who we already stunned
957 bool AddStunnedTarget(ObjectGuid const& guid)
958 {
959 return _stunnedUnits.insert(guid).second;
960 }
961
962private:
963 Milliseconds _refreshTimer = 0s;
964 Milliseconds _period = 1s;
966 float _damageMultiplier = 1.0f;
967};
968
969// 61882 - Earthquake
971{
972 static constexpr std::array<std::pair<uint32, SpellEffIndex>, 3> DamageBuffs =
973 { {
977 } };
978
979 bool Validate(SpellInfo const* /*spellInfo*/) override
980 {
982 }
983
985 {
986 float damageMultiplier = 1.0f;
987 for (auto const& [spellId, effect] : DamageBuffs)
988 {
989 if (AuraEffect* buff = GetCaster()->GetAuraEffect(spellId, effect))
990 {
991 AddPct(damageMultiplier, buff->GetAmount());
992 buff->GetBase()->Remove();
993 }
994 }
995
996 if (damageMultiplier != 1.0f)
997 GetSpell()->m_customArg = damageMultiplier;
998 }
999
1004};
1005
1006// 77478 - Earthquake tick
1008{
1009 bool Validate(SpellInfo const* spellInfo) override
1010 {
1012 && ValidateSpellEffect({ { spellInfo->Id, EFFECT_1 } });
1013 }
1014
1015 void HandleOnHit() const
1016 {
1017 if (Unit* target = GetHitUnit())
1018 {
1019 if (roll_chance(GetEffectInfo(EFFECT_1).CalcValue()))
1020 {
1021 std::vector<AreaTrigger*> areaTriggers = GetCaster()->GetAreaTriggers(SPELL_SHAMAN_EARTHQUAKE);
1022 auto itr = std::ranges::find(areaTriggers, GetSpell()->GetOriginalCasterGUID(), [](AreaTrigger const* at) { return at->GetGUID(); });
1023 if (itr != areaTriggers.end())
1025 if (eq->AddStunnedTarget(target->GetGUID()))
1027 }
1028 }
1029 }
1030
1031 void Register() override
1032 {
1034 }
1035};
1036
1037// 117014 - Elemental Blast
1038// 120588 - Elemental Blast Overload
1040{
1042
1054
1055 void TriggerBuff() const
1056 {
1057 Unit* caster = GetCaster();
1058 std::array<double, BuffSpells.size()> weights;
1059 double total = 0.0;
1060 for (std::size_t i = 0; i < BuffSpells.size(); ++i)
1061 total += weights[i] = !caster->HasAura(BuffSpells[i]) ? 1.0 : 0.0;
1062
1063 uint32 spellId = [&]
1064 {
1065 if (total > 0.0)
1067
1068 // refresh random one if we have them all
1070 }();
1071
1073 }
1074
1076 {
1078 {
1079 SetHitDamage(CalculatePct(GetHitDamage(), 100 + t29->GetAmount()));
1080 t29->GetBase()->Remove();
1081 }
1082 }
1083
1089};
1090
1091// 384355 - Elemental Weapons
1093{
1094 bool Validate(SpellInfo const* /*spellInfo*/) override
1095 {
1097 }
1098
1099 bool Load() override
1100 {
1101 return GetUnitOwner()->IsPlayer();
1102 }
1103
1105 {
1106 Player* owner = GetUnitOwner()->ToPlayer();
1107 int32 enchatmentCount = 0;
1109 ++enchatmentCount;
1111 ++enchatmentCount;
1112
1113 SpellEffectValue valuePerStack = GetEffect(EFFECT_0)->GetAmount();
1114
1116 {
1117 if (enchatmentCount)
1118 for (AuraEffect* aurEff : buff->GetAuraEffects())
1119 aurEff->ChangeAmount(valuePerStack * enchatmentCount / 10);
1120 else
1121 buff->Remove();
1122 }
1123 else if (enchatmentCount)
1126 .SpellValueOverrides = {
1127 { SPELLVALUE_BASE_POINT0, valuePerStack * enchatmentCount / 10 },
1128 { SPELLVALUE_BASE_POINT1, valuePerStack * enchatmentCount / 10 }
1129 }
1130 });
1131 }
1132
1137
1143};
1144
1145// 196884 - Feral Lunge
1147{
1148 bool Validate(SpellInfo const* /*spellInfo*/) override
1149 {
1151 }
1152
1153 bool Load() override
1154 {
1156 }
1157
1166
1167 void Register() override
1168 {
1169 }
1170};
1171
1172// 215802 - Feral Lunge Damage
1174{
1175 bool Validate(SpellInfo const* /*spellInfo*/) override
1176 {
1178 }
1179
1180 void HandleHit(SpellEffIndex /*effIndex*/) const
1181 {
1183 }
1184
1189};
1190
1192{
1193 float MaxSearchRange = 40.0f;
1194 Unit const* Shaman;
1195
1196 bool operator()(Unit const* candidate) const
1197 {
1198 return candidate->IsWithinDist3d(Shaman, MaxSearchRange) && candidate->HasAura(SPELL_SHAMAN_FLAME_SHOCK, Shaman->GetGUID());
1199 }
1200};
1201
1202// 333974 - Fire Nova
1204{
1205 bool Validate(SpellInfo const* /*spellInfo*/) override
1206 {
1208 }
1209
1210 void TriggerDamage(SpellEffIndex /*effIndex*/) const
1211 {
1212 Unit* shaman = GetCaster();
1213 std::vector<Unit*> targets;
1214 FireNovaTargetCheck check{ .Shaman = shaman };
1215 Trinity::UnitListSearcher searcher(shaman, targets, check);
1216 Cell::VisitAllObjects(shaman, searcher, check.MaxSearchRange);
1217
1218 CastSpellExtraArgs args;
1221
1222 for (Unit* target : targets)
1223 shaman->CastSpell(target, SPELL_SHAMAN_FIRE_NOVA_DAMAGE, args);
1224 }
1225
1230};
1231
1232// 466620 - Flame Shock
1234{
1235 bool Validate(SpellInfo const* /*spellInfo*/) override
1236 {
1238 }
1239
1240 void CheckFlameShocks(AuraEffect const* aurEff) const
1241 {
1242 Unit* shaman = GetTarget();
1243 Unit* target = nullptr;
1244 FireNovaTargetCheck check{ .Shaman = shaman };
1245 Trinity::UnitSearcher searcher(shaman, target, check);
1246 Cell::VisitAllObjects(shaman, searcher, check.MaxSearchRange);
1247 if (target)
1250 .TriggeringAura = aurEff
1251 });
1252 else
1254 }
1255
1260};
1261
1262// 318038 - Flametongue Weapon
1264{
1265 bool Validate(SpellInfo const* /*spellInfo*/) override
1266 {
1268 }
1269
1270 bool Load() override
1271 {
1272 return GetCaster()->GetTypeId() == TYPEID_PLAYER;
1273 }
1274
1275 void HandleEffectHitTarget(SpellEffIndex /*effIndex*/) const
1276 {
1277 Player* player = GetCaster()->ToPlayer();
1281
1282 Item* targetItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
1283 if (!targetItem || !targetItem->GetTemplate()->IsWeapon())
1284 return;
1285
1287 }
1288
1293};
1294
1295// 319778 - Flametongue - SPELL_SHAMAN_FLAMETONGUE_WEAPON_AURA
1297{
1298 bool Validate(SpellInfo const* /*spellInfo*/) override
1299 {
1301 }
1302
1303 void HandleEffectProc(AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
1304 {
1306
1308 .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
1309 .TriggeringAura = aurEff
1310 });
1311 }
1312
1317};
1318
1319// 334196 - Hailstorm
1321{
1322 void CalcCleaveMod(AuraEffect const* aurEff, SpellModifier*& spellMod) const
1323 {
1324 if (!spellMod)
1325 spellMod = new SpellFlatModifierByClassMask(SpellModOp::ChainTargets, GetId(), GetAura(), { 0x80000000, 0x00000000, 0x00000000, 0x00000000 });
1326
1327 if (AuraEffect const* hailstormPassive = GetUnitOwner()->GetAuraEffect(SPELL_SHAMAN_HAILSTORM_TALENT, EFFECT_0))
1328 {
1329 int32 targetCap = hailstormPassive->GetAmount() / aurEff->GetBaseAmount();
1330 static_cast<SpellFlatModifierByClassMask*>(spellMod)->value = std::min<int32>(targetCap, GetStackAmount()) + 1;
1331 }
1332 }
1333
1338};
1339
1340// 73920 - Healing Rain (Aura)
1342{
1343public:
1344 void SetVisualDummy(TempSummon const* summon)
1345 {
1346 _visualDummy = summon->GetGUID();
1347 _dest = summon->GetPosition();
1348 }
1349
1350 Position GetPosition() const { return _dest; }
1351
1352private:
1353 void HandleEffectPeriodic(AuraEffect const* aurEff) const
1354 {
1357 .TriggeringAura = aurEff
1358 });
1359 }
1360
1361 void HandleEffecRemoved(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) const
1362 {
1364 summon->DespawnOrUnsummon();
1365 }
1366
1372
1375};
1376
1378{
1379 if (spell_sha_healing_rain_aura const* script = healingRain->GetScript<spell_sha_healing_rain_aura>())
1380 return script->GetPosition();
1381
1382 return healingRain->GetUnitOwner()->GetPosition();
1383}
1384
1385// 73920 - Healing Rain
1387{
1389 {
1390 if (Aura* aura = GetHitAura())
1391 {
1392 if (WorldLocation const* dest = GetExplTargetDest())
1393 {
1394 Milliseconds duration = Milliseconds(GetSpellInfo()->CalcDuration(GetOriginalCaster()));
1396 if (!summon)
1397 return;
1398
1400
1401 if (spell_sha_healing_rain_aura* script = aura->GetScript<spell_sha_healing_rain_aura>())
1402 script->SetVisualDummy(summon);
1403 }
1404 }
1405 }
1406
1411};
1412
1413// 73921 - Healing Rain
1415{
1416 static void SelectTargets(SpellScript const&, std::list<WorldObject*>& targets)
1417 {
1418 Trinity::SelectRandomInjuredTargets(targets, 6, true);
1419 }
1420
1425};
1426
1427// 52042 - Healing Stream Totem
1429{
1430 static void SelectTargets(SpellScript const&, std::list<WorldObject*>& targets)
1431 {
1432 Trinity::SelectRandomInjuredTargets(targets, 1, true);
1433 }
1434
1439};
1440
1441// 201900 - Hot Hand
1443{
1444 static bool CheckProc(AuraScript const&, AuraEffect const* /*aurEff*/, ProcEventInfo const& eventInfo)
1445 {
1447 }
1448
1453};
1454
1455// 342240 - Ice Strike
1473
1474// 466467 - Ice Strike
1476{
1477 bool Validate(SpellInfo const* /*spellInfo*/) override
1478 {
1480 }
1481
1482 void Register() override { }
1483
1484public:
1486 {
1487 if (!roll_chance(++_attemptCount * 7))
1488 return;
1489
1490 _attemptCount = 0;
1491 Unit* shaman = GetUnitOwner();
1494 });
1495 }
1496
1497private:
1499};
1500
1501// 210714 - Icefury
1503{
1504 bool Validate(SpellInfo const* /*spellInfo*/) override
1505 {
1507 }
1508
1509 void HandleEffectProc(AuraEffect const* /*aurEff*/, ProcEventInfo const& /*eventInfo*/) const
1510 {
1511 if (Unit* caster = GetCaster())
1513 }
1514
1519};
1520
1521// 23551 - Lightning Shield T2 Bonus
1523{
1524 bool Validate(SpellInfo const* /*spellInfo*/) override
1525 {
1527 }
1528
1529 void HandleProc(AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
1530 {
1533 .TriggerFlags = TRIGGERED_FULL_MASK,
1534 .TriggeringAura = aurEff
1535 });
1536 }
1537
1542};
1543
1544// 23552 - Lightning Shield T2 Bonus
1546{
1547 bool Validate(SpellInfo const* /*spellInfo*/) override
1548 {
1550 }
1551
1552 void HandleProc(AuraEffect const* aurEff, ProcEventInfo const& /*eventInfo*/)
1553 {
1557 .TriggeringAura = aurEff
1558 });
1559 }
1560
1565};
1566
1567// 23572 - Mana Surge
1569{
1570 bool Validate(SpellInfo const* /*spellInfo*/) override
1571 {
1573 }
1574
1575 static bool CheckProc(AuraScript const&, ProcEventInfo const& eventInfo)
1576 {
1577 return eventInfo.GetProcSpell() != nullptr;
1578 }
1579
1580 void HandleProc(AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
1581 {
1583
1585 {
1586 SpellEffectValue mana = CalculatePct(*manaCost, 35);
1587 if (mana > 0)
1588 {
1591 .TriggeringAura = aurEff,
1592 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, mana } }
1593 });
1594 }
1595 }
1596 }
1597
1603};
1604
1605// 40463 - Shaman Tier 6 Trinket
1607{
1608 bool Validate(SpellInfo const* /*spellInfo*/) override
1609 {
1610 return ValidateSpellInfo(
1611 {
1614 });
1615 }
1616
1617 void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo const& eventInfo)
1618 {
1620 SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
1621 if (!spellInfo)
1622 return;
1623
1624 uint32 spellId;
1625 int32 chance;
1626
1627 // Lesser Healing Wave
1628 if (spellInfo->SpellFamilyFlags[0] & 0x00000080)
1629 {
1630 spellId = SPELL_SHAMAN_ENERGY_SURGE;
1631 chance = 10;
1632 }
1633 // Lightning Bolt
1634 else if (spellInfo->SpellFamilyFlags[0] & 0x00000001)
1635 {
1636 spellId = SPELL_SHAMAN_ENERGY_SURGE;
1637 chance = 15;
1638 }
1639 // Stormstrike
1640 else if (spellInfo->SpellFamilyFlags[1] & 0x00000010)
1641 {
1642 spellId = SPELL_SHAMAN_POWER_SURGE;
1643 chance = 50;
1644 }
1645 else
1646 return;
1647
1648 if (roll_chance(chance))
1649 eventInfo.GetActor()->CastSpell(nullptr, spellId, CastSpellExtraArgsInit{ .TriggerFlags = TRIGGERED_FULL_MASK });
1650 }
1651
1656};
1657
1658// 70811 - Item - Shaman T10 Elemental 2P Bonus
1660{
1661 bool Validate(SpellInfo const* /*spellInfo*/) override
1662 {
1664 }
1665
1666 void HandleEffectProc(AuraEffect const* aurEff, ProcEventInfo const& /*eventInfo*/)
1667 {
1669 if (Player* target = GetTarget()->ToPlayer())
1670 target->GetSpellHistory()->ModifyCooldown(SPELL_SHAMAN_ELEMENTAL_MASTERY, Milliseconds(-aurEff->GetAmountAsInt()));
1671 }
1672
1677};
1678
1679// 189063 - Lightning Vortex (proc 185881 Item - Shaman T18 Elemental 4P Bonus)
1681{
1682 void DiminishHaste(AuraEffect const* aurEff)
1683 {
1685 if (AuraEffect* hasteBuff = GetEffect(EFFECT_0))
1686 hasteBuff->ChangeAmount(hasteBuff->GetAmount() - aurEff->GetAmount());
1687 }
1688
1693};
1694
1695// 51505 - Lava burst
1697{
1702
1703 void HandleScript(SpellEffIndex /*effIndex*/) const
1704 {
1705 if (Unit* caster = GetCaster())
1706 if (caster->HasAura(SPELL_SHAMAN_PATH_OF_FLAMES_TALENT))
1709 .TriggeringSpell = GetSpell()
1710 });
1711 }
1712
1714 {
1715 Unit* caster = GetCaster();
1716
1717 if (Aura* lavaSurge = caster->GetAura(SPELL_SHAMAN_LAVA_SURGE))
1718 {
1719 if (!GetSpell()->m_appliedMods.contains(lavaSurge))
1720 {
1721 uint32 chargeCategoryId = GetSpellInfo()->ChargeCategoryId;
1722
1723 // Ensure we have at least 1 usable charge after cast to allow next cast immediately
1724 if (!caster->GetSpellHistory()->HasCharge(chargeCategoryId))
1725 caster->GetSpellHistory()->RestoreCharge(chargeCategoryId);
1726 }
1727 }
1728 }
1729
1735};
1736
1737// 285452 - Lava Burst damage
1738// 285466 - Lava Burst Overload damage
1740{
1741 bool Validate(SpellInfo const* /*spellInfo*/) override
1742 {
1744 }
1745
1746 void CalcCritChance(Unit const* victim, float& chance) const
1747 {
1748 Unit* caster = GetCaster();
1749
1750 if (!caster || !victim)
1751 return;
1752
1753 if (victim->HasAura(SPELL_SHAMAN_FLAME_SHOCK, caster->GetGUID()))
1755 chance = 100.f;
1756 }
1757
1762};
1763
1764// 60103 - Lava Lash
1766{
1767 bool Validate(SpellInfo const* spellInfo) override
1768 {
1769 return ValidateSpellEffect({ { spellInfo->Id, EFFECT_1 } })
1771 }
1772
1773 bool Load() override
1774 {
1775 return GetCaster()->IsPlayer();
1776 }
1777
1778 void AddBonusFlametongueDamage(SpellEffectInfo const& /*effectInfo*/, Unit const* victim, int32& /*damage*/, int32& /*flatMod*/, float& pctMod) const
1779 {
1780 Player* caster = GetCaster()->ToPlayer();
1781 ObjectGuid offhandItemGuid = Object::GetGUID(caster->GetWeaponForAttack(GetSpellInfo()->GetAttackType()));
1783 AddPct(pctMod, GetSpell()->CalculateDamage(GetEffectInfo(EFFECT_1), victim));
1784 }
1785
1790};
1791
1792// 77756 - Lava Surge
1794{
1795 bool Validate(SpellInfo const* /*spellInfo*/) override
1796 {
1798 }
1799
1800 bool CheckProcChance(AuraEffect const* aurEff, ProcEventInfo const& /*eventInfo*/)
1801 {
1802 Unit* caster = GetTarget();
1803 float flameShocks = 0.0f;
1804 auto work = [&, shaman = caster->GetGUID()](Unit const* target)
1805 {
1806 if (target->HasAuraEffect(SPELL_SHAMAN_FLAME_SHOCK, EFFECT_1, shaman))
1807 flameShocks += 1.0f;
1808 };
1809 Trinity::UnitWorker worker(caster, work);
1810 Cell::VisitAllObjects(caster, worker, 100.0f);
1811
1812 // Proc uptime is not supposed to scale with the number of applied flame shocks
1813 _normalizedTicks += 1.0 / flameShocks;
1814
1815 // first 6 ticks after last proc fail to prevent overwriting
1816 if (_normalizedTicks < 6.0)
1817 return false;
1818
1819 SpellEffectValue procChance = aurEff->GetAmount();
1820 if (AuraEffect const* igneousPotential = GetTarget()->GetAuraEffect(SPELL_SHAMAN_IGNEOUS_POTENTIAL, EFFECT_0))
1821 procChance += igneousPotential->GetAmount();
1822
1823 SpellEffectValue missChance = std::max(100 - procChance, 0.0) / 100.0;
1824
1825 procChance = (1.0 - std::pow(missChance, _normalizedTicks)) * 100.0;
1826
1827 return roll_chance(procChance);
1828 }
1829
1837
1843
1845};
1846
1847// 77762 - Lava Surge
1849{
1850 bool Validate(SpellInfo const* /*spellInfo*/) override
1851 {
1853 }
1854
1855 bool Load() override
1856 {
1857 return GetCaster()->GetTypeId() == TYPEID_PLAYER;
1858 }
1859
1860 void ResetCooldown() const
1861 {
1862 GetCaster()->GetSpellHistory()->RestoreCharge(sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_LAVA_BURST, GetCastDifficulty())->ChargeCategoryId);
1863 }
1864
1869};
1870
1871// 188196 - Lightning Bolt
1873{
1874 bool Validate(SpellInfo const* /*spellInfo*/) override
1875 {
1878 }
1879
1880 void HandleScript(SpellEffIndex /*effIndex*/) const
1881 {
1882 if (AuraEffect const* energizeAmount = GetCaster()->GetAuraEffect(SPELL_SHAMAN_MAELSTROM_CONTROLLER, EFFECT_0))
1885 .TriggeringAura = energizeAmount,
1886 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, energizeAmount->GetAmount() } }
1887 });
1888 }
1889
1894};
1895
1896// 45284 - Lightning Bolt Overload
1898{
1904
1905 void HandleScript(SpellEffIndex /*effIndex*/) const
1906 {
1907 if (AuraEffect const* energizeAmount = GetCaster()->GetAuraEffect(SPELL_SHAMAN_MAELSTROM_CONTROLLER, EFFECT_1))
1910 .TriggeringAura = energizeAmount,
1911 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, energizeAmount->GetAmount() } }
1912 });
1913 }
1914
1919};
1920
1921// 192223 - Liquid Magma Totem (erupting hit spell)
1923{
1924 bool Validate(SpellInfo const* /*spellInfo*/) override
1925 {
1927 }
1928
1934
1935 static void HandleTargetSelect(SpellScript const&, std::list<WorldObject*>& targets)
1936 {
1937 // choose one random target from targets
1938 if (targets.size() > 1)
1939 {
1941 targets.clear();
1942 targets.push_back(selected);
1943 }
1944 }
1945
1951};
1952
1972
1974{
1975 CastSpellExtraArgs args;
1977 while (--stacks >= 0)
1978 {
1980 if (totalStacks >= 4)
1981 {
1982 // cast action bar overlays
1985
1986 shaman->CastSpell(shaman, SPELL_SHAMAN_MAELSTROM_WEAPON_OVERLAY, args);
1987 }
1988
1991 if (totalStacks >= 5 && shaman->HasAura(SPELL_SHAMAN_OVERFLOWING_MAELSTROM_TALENT))
1993 }
1994}
1995
1996void spell_sha_maelstrom_weapon_base::ConsumeMaelstromWeapon(Unit* shaman, Aura* maelstromWeaponVisibleAura, int32 stacks, Spell const* consumingSpell)
1997{
1998 if (AuraEffect const* stormweaver = shaman->GetAuraEffect(SPELL_SHAMAN_STORMWEAVER_PVP_TALENT, EFFECT_0))
1999 {
2000 shaman->RemoveAurasDueToSpell(SPELL_SHAMAN_STORMWEAVER_PVP_TALENT_BUFF); // remove to ensure new buff has exactly "consumedStacks" stacks
2001 if (Aura const* maelstromSpellMod = shaman->GetAura(SPELL_SHAMAN_MAELSTROM_WEAPON_MOD_AURA))
2004 .TriggeringSpell = consumingSpell,
2005 .SpellValueOverrides = {
2006 { SPELLVALUE_BASE_POINT0, maelstromSpellMod->GetEffect(EFFECT_0)->GetAmount() },
2007 // this is indeed very silly but it is how it behaves on official servers
2008 // it ignores how many stacks were actually consumed and calculates benefit from max stacks (Thorim's Invocation can consume less stacks than entire aura)
2009 { SPELLVALUE_BASE_POINT1, CalculatePct(maelstromSpellMod->GetEffect(EFFECT_1)->GetAmount(), stormweaver->GetAmount()) },
2010 { SPELLVALUE_AURA_STACK, std::min<int32>(stacks, maelstromWeaponVisibleAura->GetStackAmount()) }
2011 }
2012 });
2013 }
2014
2015 if (Aura const* iceStrike = shaman->GetAura(SPELL_SHAMAN_ICE_STRIKE_PROC))
2016 if (spell_sha_ice_strike_proc* script = iceStrike->GetScript<spell_sha_ice_strike_proc>())
2017 script->AttemptProc();
2018
2022 .TriggeringSpell = consumingSpell,
2023 .SpellValueOverrides = { { SPELLVALUE_AURA_STACK, std::min<int32>(stacks, maelstromWeaponVisibleAura->GetStackAmount()) } }
2024 });
2025
2026 if (maelstromWeaponVisibleAura->ModStackAmount(-stacks))
2027 return;
2028
2029 // not removed
2030 uint8 newStacks = maelstromWeaponVisibleAura->GetStackAmount();
2031
2032 if (Aura* overflowingMaelstrom = shaman->GetAura(SPELL_SHAMAN_OVERFLOWING_MAELSTROM_AURA))
2033 {
2034 if (newStacks > 5)
2035 overflowingMaelstrom->SetStackAmount(newStacks - 5);
2036 else
2037 overflowingMaelstrom->Remove();
2038 }
2039
2040 if (Aura* maelstromSpellMod = shaman->GetAura(SPELL_SHAMAN_MAELSTROM_WEAPON_MOD_AURA))
2041 {
2042 if (newStacks > 0)
2043 maelstromSpellMod->SetStackAmount(std::min<uint8>(newStacks, 5));
2044 else
2045 maelstromSpellMod->Remove();
2046 }
2047
2048 if (newStacks < 5)
2049 {
2050 shaman->RemoveAurasDueToSpell(SPELL_SHAMAN_MAELSTROM_WEAPON_OVERLAY);
2051 shaman->RemoveAurasDueToSpell(SPELL_SHAMAN_MAELSTROM_WEAPON_OVERLAY_HEALS);
2052 }
2053}
2054
2055// 187880 - Maelstrom Weapon
2057{
2058 bool Validate(SpellInfo const* /*spellInfo*/) override
2059 {
2061 }
2062
2063 void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo const& /*procEvent*/) const
2064 {
2066 }
2067
2072};
2073
2074// 344179 - Maelstrom Weapon
2076{
2077 bool Validate(SpellInfo const* /*spellInfo*/) override
2078 {
2080 }
2081
2082 bool CheckProc(ProcEventInfo const& procEvent) const
2083 {
2084 Spell const* procSpell = procEvent.GetProcSpell();
2085 if (!procSpell)
2086 return false;
2087
2089 if (!maelstromSpellMod)
2090 return false;
2091
2092 return procSpell->m_appliedMods.contains(maelstromSpellMod);
2093 }
2094
2095 void RemoveMaelstromAuras(ProcEventInfo const& procEvent) const
2096 {
2097 Unit* shaman = GetTarget();
2098 int32 stacksToConsume = 5;
2100 stacksToConsume = 10;
2101
2102 spell_sha_maelstrom_weapon_base::ConsumeMaelstromWeapon(shaman, GetAura(), stacksToConsume, procEvent.GetProcSpell());
2103 }
2104
2114
2121};
2122
2123// 168534 - Mastery: Elemental Overload (passive)
2125{
2143
2144 static bool CheckProc(AuraScript const&, AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
2145 {
2146 SpellInfo const* spellInfo = eventInfo.GetSpellInfo();
2147 if (!spellInfo || !eventInfo.GetProcSpell())
2148 return false;
2149
2150 if (!GetTriggeredSpellId(spellInfo->Id))
2151 return false;
2152
2153 SpellEffectValue chance = aurEff->GetAmount(); // Mastery % amount
2154
2155 if (spellInfo->Id == SPELL_SHAMAN_CHAIN_LIGHTNING)
2156 chance /= 3.0;
2157
2158 if (Aura* stormkeeper = eventInfo.GetActor()->GetAura(SPELL_SHAMAN_STORMKEEPER))
2159 if (eventInfo.GetProcSpell()->m_appliedMods.contains(stormkeeper))
2160 chance = 100.0;
2161
2162 return roll_chance(chance);
2163 }
2164
2165 void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo const& procInfo)
2166 {
2168
2169 Unit* caster = procInfo.GetActor();
2170
2171 caster->m_Events.AddEventAtOffset([caster,
2172 targets = CastSpellTargetArg(procInfo.GetProcTarget()),
2173 overloadSpellId = GetTriggeredSpellId(procInfo.GetSpellInfo()->Id),
2174 originalCastId = procInfo.GetProcSpell()->m_castId]() mutable
2175 {
2176 if (!targets.Targets)
2177 return;
2178
2179 targets.Targets->Update(caster);
2180
2181 CastSpellExtraArgs args;
2182 args.OriginalCastId = originalCastId;
2183 caster->CastSpell(targets, overloadSpellId, args);
2184 }, 400ms);
2185 }
2186
2192
2193 static uint32 GetTriggeredSpellId(uint32 triggeringSpellId)
2194 {
2195 switch (triggeringSpellId)
2196 {
2202 default:
2203 break;
2204 }
2205 return 0;
2206 }
2207};
2208
2209// 45284 - Lightning Bolt Overload
2210// 45297 - Chain Lightning Overload
2211// 114738 - Lava Beam Overload
2212// 120588 - Elemental Blast Overload
2213// 219271 - Icefury Overload
2214// 285466 - Lava Burst Overload
2216{
2217 bool Validate(SpellInfo const* /*spellInfo*/) override
2218 {
2220 }
2221
2223 {
2224 if (AuraEffect const* elementalOverload = GetCaster()->GetAuraEffect(SPELL_SHAMAN_MASTERY_ELEMENTAL_OVERLOAD, EFFECT_1))
2225 SetHitDamage(CalculatePct(GetHitDamage(), elementalOverload->GetAmount()));
2226 }
2227
2232};
2233
2234// 334033 - Molten Assault (60103 - Lava Lash)
2236{
2237 bool Validate(SpellInfo const* /*spellInfo*/) override
2238 {
2240 }
2241
2242 bool Load() override
2243 {
2245 }
2246
2247 void TriggerFlameShocks(SpellEffIndex /*effIndex*/) const
2248 {
2249 Unit* caster = GetCaster();
2250 Unit const* lavaLashTarget = GetHitUnit();
2251 if (!lavaLashTarget->HasAura(SPELL_SHAMAN_FLAME_SHOCK, caster->GetGUID()))
2252 return;
2253
2254 float range = 10.0f;
2255 std::vector<WorldObject*> targets;
2256 Trinity::WorldObjectSpellAreaTargetCheck check({ .Max = range }, lavaLashTarget, caster, caster, sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_FLAME_SHOCK, DIFFICULTY_NONE),
2259 Cell::VisitAllObjects(lavaLashTarget, searcher, range + EXTRA_CELL_SEARCH_RADIUS);
2260
2261 auto withoutFlameShockItr = std::partition(targets.begin(), targets.end(), Trinity::UnitAuraCheck(true, SPELL_SHAMAN_FLAME_SHOCK, GetCaster()->GetGUID()));
2262 std::size_t flameShocksMissing = GetEffectValueAsInt() + 1 - std::ranges::distance(targets.begin(), withoutFlameShockItr);
2263
2264 if (flameShocksMissing)
2265 Trinity::Containers::RandomShuffle(withoutFlameShockItr, targets.end());
2266
2267 CastSpellExtraArgs args;
2270
2271 // targets that already have flame shock are first in the list (and need to refresh it)
2272 for (std::size_t i = 0; i < std::min<std::size_t>(targets.size(), GetEffectValueAsInt() + 1); ++i)
2273 caster->CastSpell(targets[i], SPELL_SHAMAN_FLAME_SHOCK, args);
2274 }
2275
2280};
2281
2282// 469344 Molten Thunder
2284{
2285 void Register() override { }
2286
2287public:
2289};
2290
2292{
2293 bool Validate(SpellInfo const* /*spellInfo*/) override
2294 {
2296 }
2297
2298 bool Load() override
2299 {
2301 }
2302
2303 static void RemoveIncapacitateEffect(SpellScript const&, std::list<WorldObject*>& targets)
2304 {
2305 targets.clear();
2306 }
2307
2308 void RollReset() const
2309 {
2310 Unit* shaman = GetCaster();
2311 Aura const* talent = shaman->GetAura(SPELL_SHAMAN_MOLTEN_THUNDER_TALENT);
2312 if (!talent)
2313 return;
2314
2315 AuraEffect const* chanceBaseEffect = talent->GetEffect(EFFECT_1);
2316 AuraEffect const* chancePerTargetEffect = talent->GetEffect(EFFECT_2);
2317 AuraEffect const* targetLimitEffect = talent->GetEffect(EFFECT_3);
2318 if (!chanceBaseEffect || !chancePerTargetEffect || !targetLimitEffect)
2319 return;
2320
2322 if (!counterScript)
2323 return;
2324
2325 SpellEffectValue procChance = chanceBaseEffect->GetAmount();
2326 procChance += std::min<SpellEffectValue>(targetLimitEffect->GetAmount(), GetUnitTargetCountForEffect(EFFECT_0)) * chancePerTargetEffect->GetAmount();
2327 procChance *= std::pow(0.5, counterScript->ProcCount); // Each consecutive reset reduces these chances by half
2328 if (roll_chance(procChance))
2329 {
2332 .TriggeringSpell = GetSpell()
2333 });
2334 shaman->GetSpellHistory()->ResetCooldown(GetSpellInfo()->Id, true);
2335 ++counterScript->ProcCount;
2336 }
2337 else
2338 counterScript->ProcCount = 0;
2339 }
2340
2346};
2347
2348// 30884 - Nature's Guardian
2350{
2351 bool Validate(SpellInfo const* /*spellInfo*/) override
2352 {
2354 }
2355
2356 static bool CheckProc(AuraScript const&, AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
2357 {
2358 return eventInfo.GetActionTarget()->HealthBelowPct(aurEff->GetAmount())
2360 }
2361
2362 static void StartCooldown(AuraScript const&, AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
2363 {
2364 Unit* shaman = eventInfo.GetActionTarget();
2367 .TriggeringAura = aurEff
2368 });
2369 }
2370
2376};
2377
2378// 210621 - Path of Flames Spread
2380{
2381 bool Validate(SpellInfo const* /*spellInfo*/) override
2382 {
2384 }
2385
2386 void FilterTargets(std::list<WorldObject*>& targets) const
2387 {
2388 targets.remove(GetExplTargetUnit());
2390 }
2391
2392 void HandleScript(SpellEffIndex /*effIndex*/) const
2393 {
2394 if (Unit* mainTarget = GetExplTargetUnit())
2395 {
2396 if (Aura* flameShock = mainTarget->GetAura(SPELL_SHAMAN_FLAME_SHOCK, GetCaster()->GetGUID()))
2397 {
2398 if (Aura* newAura = GetCaster()->AddAura(SPELL_SHAMAN_FLAME_SHOCK, GetHitUnit()))
2399 {
2400 newAura->SetDuration(flameShock->GetDuration());
2401 newAura->SetMaxDuration(flameShock->GetDuration());
2402 }
2403 }
2404 }
2405 }
2406
2412};
2413
2414// 375982 - Primordial Wave
2416{
2417 bool Validate(SpellInfo const* /*spellInfo*/) override
2418 {
2420 }
2421
2422 void TriggerDamage(SpellEffIndex /*effIndex*/) const
2423 {
2424 Unit* shaman = GetCaster();
2425 std::vector<Unit*> targets;
2426 FireNovaTargetCheck check{ .MaxSearchRange = GetSpell()->GetMinMaxRange(false).Max, .Shaman = shaman };
2427 Trinity::UnitListSearcher searcher(shaman, targets, check);
2428 Cell::VisitAllObjects(shaman, searcher, check.MaxSearchRange);
2429
2430 CastSpellExtraArgs args;
2433
2434 for (Unit* target : targets)
2435 shaman->CastSpell(target, SPELL_SHAMAN_PRIMORDIAL_WAVE_DAMAGE, args);
2436 }
2437
2439 {
2440 PreventHitDefaultEffect(effIndex);
2441 }
2442
2447
2448 void Register() override
2449 {
2451 if (Spell const* spell = GetSpell()) // spell doesn't exist at startup validation
2452 if (Player const* caster = Object::ToPlayer(spell->GetCaster()))
2453 specialization = caster->GetPrimarySpecialization();
2454
2456
2457 if (specialization != ChrSpecialization::ShamanElemental)
2459
2460 if (specialization == ChrSpecialization::None || specialization == ChrSpecialization::ShamanEnhancement)
2462 }
2463};
2464
2465// 114083 - Restorative Mists
2466// 294020 - Restorative Mists
2479
2480// 2645 - Ghost Wolf
2481// 260878 - Spirit Wolf
2511
2512// 319930 - Stormblast
2514{
2515 void Register() override { }
2516
2517public:
2519};
2520
2521// 470466 - Stormblast (Stormstrike and Winstrike damaging spells)
2523{
2524 bool Validate(SpellInfo const* /*spellInfo*/) override
2525 {
2526 return ValidateSpellEffect({
2529 });
2530 }
2531
2532 bool Load() override
2533 {
2534 if (Aura const* stormblast = GetCaster()->GetAura(SPELL_SHAMAN_STORMBLAST_TALENT))
2535 if (spell_sha_stormblast const* script = stormblast->GetScript<spell_sha_stormblast>())
2536 return script->AllowedOriginalCastId == GetSpell()->m_originalCastId;
2537
2538 return false;
2539 }
2540
2541 void TriggerDamage() const
2542 {
2543 if (AuraEffect const* stormblast = GetCaster()->GetAuraEffect(SPELL_SHAMAN_STORMBLAST_TALENT, EFFECT_0))
2544 {
2545 SpellEffectValue damage = CalculatePct(GetHitDamage(), stormblast->GetAmount());
2546
2547 // Not part of SpellFamilyFlags for mastery effect but known to be affected by it
2548 if (AuraEffect const* mastery = GetCaster()->GetAuraEffect(SPELL_SHAMAN_ENHANCED_ELEMENTS, EFFECT_0))
2549 AddPct(damage, mastery->GetAmount());
2550
2553 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, damage } }
2554 });
2555 }
2556 }
2557
2562};
2563
2564// 470466 - Stormblast (17364 - Stormstrike, 115356 - Windstrike)
2566{
2567 bool Load() override
2568 {
2569 Unit const* caster = GetCaster();
2572 }
2573
2574 // Store allowed CastId in passive aura because damaging spells are delayed (and delayed further if Stormflurry is triggered)
2575 void SaveCastId() const
2576 {
2577 Unit* caster = GetCaster();
2578 if (Aura* stormblast = caster->GetAura(SPELL_SHAMAN_STORMBLAST_TALENT))
2579 if (spell_sha_stormblast* script = stormblast->GetScript<spell_sha_stormblast>())
2580 script->AllowedOriginalCastId = GetSpell()->m_castId;
2581
2583 }
2584
2585 void Register() override
2586 {
2588 }
2589};
2590
2592{
2593public:
2594 struct Data
2595 {
2597 };
2598
2599 explicit StormflurryEvent(Unit* caster, Unit* target, ObjectGuid const& originalCastId, SpellEffectValue damagePercent,
2600 uint32 mainHandDamageSpellId, uint32 offHandDamageSpellId, SpellEffectValue procChance)
2601 : _caster(caster), _target(target), _originalCastId(originalCastId), _damagePercent(damagePercent),
2602 _mainHandDamageSpellId(mainHandDamageSpellId), _offHandDamageSpellId(offHandDamageSpellId), _procChance(procChance)
2603 {
2604 }
2605
2606 bool Execute(uint64 time, uint32 /*diff*/) override
2607 {
2608 if (!_target.Targets)
2609 return true;
2610
2611 _target.Targets->Update(_caster);
2612
2613 CastSpellExtraArgs args;
2616 args.CustomArg.emplace<Data>().DamagePercent = _damagePercent;
2617
2620
2622 return true;
2623
2624 _caster->m_Events.AddEvent(this, Milliseconds(time) + 200ms);
2625 return false;
2626 }
2627
2628private:
2636};
2637
2638// 198367 Stormflurry
2639// 344357 Stormflurry
2641{
2642public:
2643 explicit spell_sha_stormflurry(uint32 stormflurrySpellId, uint32 mainHandDamageSpellId, uint32 offHandDamageSpellId)
2644 : _stormflurrySpellId(stormflurrySpellId), _mainHandDamageSpellId(mainHandDamageSpellId), _offHandDamageSpellId(offHandDamageSpellId) { }
2645
2646 bool Validate(SpellInfo const* spellInfo) override
2647 {
2649 && ValidateSpellEffect({ { spellInfo->Id, EFFECT_1 } })
2652 }
2653
2654 bool Load() override
2655 {
2657 }
2658
2659 void HandleProc(SpellEffIndex /*effIndex*/) const
2660 {
2661 Unit* caster = GetCaster();
2662 Aura const* stormflurry = caster->GetAura(_stormflurrySpellId);
2663 if (!stormflurry)
2664 return;
2665
2666 AuraEffect const* chanceEffect = stormflurry->GetEffect(EFFECT_0);
2667 AuraEffect const* damageEffect = stormflurry->GetEffect(EFFECT_1);
2668 if (!chanceEffect || !damageEffect)
2669 return;
2670
2671 SpellEffectValue procChance = chanceEffect->GetAmount();
2672 if (!roll_chance(procChance))
2673 return;
2674
2675 caster->m_Events.AddEventAtOffset(new StormflurryEvent(caster, GetHitUnit(), GetSpell()->m_castId, damageEffect->GetAmount(),
2676 _mainHandDamageSpellId, _offHandDamageSpellId, procChance), 200ms);
2677 }
2678
2683
2684private:
2688};
2689
2690// 32175 - Stormstrike
2691// 32176 - Stormstrike Off-Hand
2693{
2694 bool Load() override
2695 {
2696 return GetSpell()->m_customArg.type() == typeid(StormflurryEvent::Data);
2697 }
2698
2699 void ApplyModifier(SpellEffectInfo const& /*effectInfo*/, Unit* /*victim*/, int32& /*damage*/, int32& /*flatMod*/, float& pctMod) const
2700 {
2701 ApplyPct(pctMod, std::any_cast<StormflurryEvent::Data>(&GetSpell()->m_customArg)->DamagePercent);
2702 }
2703
2708};
2709
2710// 201845 - Stormsurge
2712{
2713 bool Validate(SpellInfo const* /*spellInfo*/) override
2714 {
2716 }
2717
2718 static void HandleProc(AuraScript const&, AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
2719 {
2721 .TriggerFlags = TRIGGERED_IGNORE_CAST_IN_PROGRESS | TRIGGERED_DONT_REPORT_CAST_ERROR,
2722 .TriggeringAura = aurEff
2723 });
2724 }
2725
2730};
2731
2732// 187881 - Maelstrom Weapon
2756
2757// 384359 - Swirling Maelstrom
2759{
2760 bool Validate(SpellInfo const* spellInfo) override
2761 {
2762 return ValidateSpellEffect({ { spellInfo->Id, EFFECT_1 } })
2764 }
2765
2766 bool CheckHailstormProc(ProcEventInfo const& eventInfo) const
2767 {
2768 if (eventInfo.GetSpellInfo()->IsAffected(SPELLFAMILY_SHAMAN, { 0x80000000, 0x0, 0x0, 0x0 })) // Frost Shock
2769 {
2770 Aura* hailstorm = eventInfo.GetActor()->GetAura(SPELL_SHAMAN_HAILSTORM_BUFF);
2771 if (!hailstorm || hailstorm->GetStackAmount() < GetEffect(EFFECT_1)->GetAmount())
2772 return false;
2773
2774 if (!eventInfo.GetProcSpell()->m_appliedMods.contains(hailstorm))
2775 return false;
2776 }
2777
2778 return true;
2779 }
2780
2781 void EnergizeMaelstrom(AuraEffect const* aurEff, ProcEventInfo const& /*eventInfo*/) const
2782 {
2784 }
2785
2791};
2792
2793// 384444 - Thorim's Invocation
2795{
2796 bool Validate(SpellInfo const* /*spellInfo*/) override
2797 {
2799 }
2800
2801 void Register() override
2802 {
2803 }
2804
2805public:
2807};
2808
2809// 188196 - Lightning Bolt
2810// 188443 - Chain Lightning
2811// 452201 - Tempest
2813{
2820
2822 {
2823 if (Aura const* thorimsInvocation = GetCaster()->GetAura(SPELL_SHAMAN_THORIMS_INVOCATION))
2824 if (spell_sha_thorims_invocation* spellIdHolder = thorimsInvocation->GetScript<spell_sha_thorims_invocation>())
2826 }
2827
2832};
2833
2834// 115357 - Windstrike (MH)
2836{
2837 bool Validate(SpellInfo const* /*spellInfo*/) override
2838 {
2840 }
2841
2842 bool Load() override
2843 {
2845 }
2846
2847 void TriggerLightningSpell(SpellEffIndex /*effIndex*/) const
2848 {
2849 Unit* caster = GetCaster();
2850
2851 AuraEffect const* thorimsInvocation = caster->GetAuraEffect(SPELL_SHAMAN_THORIMS_INVOCATION, EFFECT_0);
2852 if (!thorimsInvocation)
2853 return;
2854
2855 spell_sha_thorims_invocation const* spellIdHolder = thorimsInvocation->GetBase()->GetScript<spell_sha_thorims_invocation>();
2856 if (!spellIdHolder)
2857 return;
2858
2859 auto [spellInfo, triggerFlags] = caster->GetCastSpellInfo(sSpellMgr->GetSpellInfo(spellIdHolder->SpellIdToTrigger, GetCastDifficulty()));
2860
2861 // Remove Overflowing Maelstrom spellmod early to make next cast behave as if it consumed only 5 or less maelstrom stacks
2862 // this works because consuming "up to 5 stacks" will always cause Maelstrom Weapon stacks to drop to 5 or lower
2863 // which means Overflowing Maelstrom needs removing anyway
2865
2866 caster->CastSpell(GetHitUnit(), spellInfo->Id, CastSpellExtraArgsInit{
2868 .TriggeringSpell = GetSpell()
2869 });
2870
2871 // 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
2872 if (Aura* maelstromWeaponVisibleAura = caster->GetAura(SPELL_SHAMAN_MAELSTROM_WEAPON_VISIBLE_AURA))
2873 spell_sha_maelstrom_weapon_base::ConsumeMaelstromWeapon(caster, maelstromWeaponVisibleAura, thorimsInvocation->GetAmountAsInt());
2874 }
2875
2880};
2881
2882// 51564 - Tidal Waves
2884{
2885 bool Validate(SpellInfo const* /*spellInfo*/) override
2886 {
2888 }
2889
2890 void HandleEffectProc(AuraEffect const* aurEff, ProcEventInfo const& /*eventInfo*/)
2891 {
2893
2896 .TriggeringAura = aurEff,
2897 .SpellValueOverrides =
2898 {
2899 { SPELLVALUE_BASE_POINT0, -aurEff->GetAmount() },
2900 { SPELLVALUE_BASE_POINT1, aurEff->GetAmount() }
2901 }
2902 });
2903 }
2904
2909};
2910
2911// 28823 - Totemic Power
2913{
2924
2925 void HandleProc(AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
2926 {
2928
2929 uint32 spellId;
2930 Unit* caster = eventInfo.GetActor();
2931 Unit* target = eventInfo.GetProcTarget();
2932
2933 switch (target->GetClass())
2934 {
2935 case CLASS_PALADIN:
2936 case CLASS_PRIEST:
2937 case CLASS_SHAMAN:
2938 case CLASS_DRUID:
2940 break;
2941 case CLASS_MAGE:
2942 case CLASS_WARLOCK:
2944 break;
2945 case CLASS_HUNTER:
2946 case CLASS_ROGUE:
2948 break;
2949 case CLASS_WARRIOR:
2951 break;
2952 default:
2953 return;
2954 }
2955
2956 caster->CastSpell(target, spellId, CastSpellExtraArgsInit{
2958 .TriggeringAura = aurEff
2959 });
2960 }
2961
2966};
2967
2968// 28820 - Lightning Shield
2970{
2971 void PeriodicTick(AuraEffect const* /*aurEff*/)
2972 {
2974
2975 // Need remove self if Lightning Shield not active
2976 if (!GetTarget()->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_SHAMAN, flag128(0x400), GetCaster()->GetGUID()))
2977 Remove();
2978 }
2979
2984};
2985
2986// 64928 - Item - Shaman T8 Elemental 4P Bonus
2988{
2989 bool Validate(SpellInfo const* /*spellInfo*/) override
2990 {
2992 && sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_ELECTRIFIED, DIFFICULTY_NONE)->GetEffect(EFFECT_0).GetPeriodicTickCount() > 0;
2993 }
2994
2995 void HandleProc(AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
2996 {
2998
2999 DamageInfo* damageInfo = eventInfo.GetDamageInfo();
3000 if (!damageInfo || !damageInfo->GetDamage())
3001 return;
3002
3003 SpellEffectInfo const& dotEffect = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_ELECTRIFIED, GetCastDifficulty())->GetEffect(EFFECT_0);
3004 SpellEffectValue amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
3005
3006 amount /= dotEffect.GetPeriodicTickCount();
3007
3008 Unit* caster = eventInfo.GetActor();
3009 Unit* target = eventInfo.GetProcTarget();
3010
3013 .TriggeringAura = aurEff,
3014 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, amount } }
3015 });
3016 }
3017
3022};
3023
3024// 67228 - Item - Shaman T9 Elemental 4P Bonus (Lava Burst)
3026{
3027 bool Validate(SpellInfo const* /*spellInfo*/) override
3028 {
3030 && sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE, DIFFICULTY_NONE)->GetEffect(EFFECT_0).GetPeriodicTickCount() > 0;
3031 }
3032
3033 void HandleProc(AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
3034 {
3036
3037 DamageInfo* damageInfo = eventInfo.GetDamageInfo();
3038 if (!damageInfo || !damageInfo->GetDamage())
3039 return;
3040
3041 SpellEffectInfo const& dotEffect = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE, GetCastDifficulty())->GetEffect(EFFECT_0);
3042 SpellEffectValue amount = CalculatePct(static_cast<int32>(damageInfo->GetDamage()), aurEff->GetAmount());
3043
3044 amount /= dotEffect.GetPeriodicTickCount();
3045
3046 Unit* caster = eventInfo.GetActor();
3047 Unit* target = eventInfo.GetProcTarget();
3048
3051 .TriggeringAura = aurEff,
3052 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, amount } }
3053 });
3054 }
3055
3060};
3061
3062// 70817 - Item - Shaman T10 Elemental 4P Bonus
3064{
3065 void HandleProc(AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
3066 {
3068
3069 Unit* caster = eventInfo.GetActor();
3070 Unit* target = eventInfo.GetProcTarget();
3071
3072 // try to find spell Flame Shock on the target
3073 AuraEffect* flameShock = target->GetAuraEffect(SPELL_AURA_PERIODIC_DAMAGE, SPELLFAMILY_SHAMAN, flag128(0x10000000), caster->GetGUID());
3074 if (!flameShock)
3075 return;
3076
3077 Aura* flameShockAura = flameShock->GetBase();
3078
3079 int32 maxDuration = flameShockAura->GetMaxDuration();
3080 int32 newDuration = flameShockAura->GetDuration() + aurEff->GetAmountAsInt() * IN_MILLISECONDS;
3081
3082 flameShockAura->SetDuration(newDuration);
3083 // is it blizzlike to change max duration for FS?
3084 if (newDuration > maxDuration)
3085 flameShockAura->SetMaxDuration(newDuration);
3086 }
3087
3092};
3093
3094// 70808 - Item - Shaman T10 Restoration 4P Bonus
3096{
3097 bool Validate(SpellInfo const* /*spellInfo*/) override
3098 {
3100 && sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_CHAINED_HEAL, DIFFICULTY_NONE)->GetEffect(EFFECT_0).GetPeriodicTickCount() > 0;
3101 }
3102
3103 void HandleProc(AuraEffect const* aurEff, ProcEventInfo const& eventInfo)
3104 {
3106
3107 HealInfo* healInfo = eventInfo.GetHealInfo();
3108 if (!healInfo || !healInfo->GetHeal())
3109 return;
3110
3111 SpellEffectInfo const& dotEffect = sSpellMgr->AssertSpellInfo(SPELL_SHAMAN_CHAINED_HEAL, GetCastDifficulty())->GetEffect(EFFECT_0);
3112 SpellEffectValue amount = CalculatePct(static_cast<int32>(healInfo->GetHeal()), aurEff->GetAmount());
3113
3114 amount /= dotEffect.GetPeriodicTickCount();
3115
3116 Unit* caster = eventInfo.GetActor();
3117 Unit* target = eventInfo.GetProcTarget();
3118
3121 .TriggeringAura = aurEff,
3122 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, amount } }
3123 });
3124 }
3125
3130};
3131
3132// 260895 - Unlimited Power
3134{
3135 bool Validate(SpellInfo const* /*spellInfo*/) override
3136 {
3138 }
3139
3140 static void HandleProc(AuraScript const&, AuraEffect const* /*aurEff*/, ProcEventInfo const& procInfo)
3141 {
3142 Unit* caster = procInfo.GetActor();
3143 if (Aura* aura = caster->GetAura(SPELL_SHAMAN_UNLIMITED_POWER_BUFF))
3144 aura->SetStackAmount(aura->GetStackAmount() + 1);
3145 else
3148 .TriggeringSpell = procInfo.GetProcSpell()
3149 });
3150 }
3151
3156};
3157
3158// 200071 - Undulation
3160{
3161 bool Validate(SpellInfo const* /*spellInfo*/) override
3162 {
3164 }
3165
3166 void HandleProc(AuraEffect const* /*aurEff*/, ProcEventInfo const& /*eventInfo*/)
3167 {
3168 if (++_castCounter == 3)
3169 {
3171 _castCounter = 0;
3172 }
3173 }
3174
3179
3180 uint8 _castCounter = 1; // first proc happens after two casts, then one every 3 casts
3181};
3182
3183// 470490 - Unrelenting Storms
3185{
3191
3192 bool Load() override
3193 {
3195 }
3196
3197 void Trigger(SpellEffIndex effIndex) const
3198 {
3199 Unit* shaman = GetCaster();
3200 Aura const* unrelentingStorms = shaman->GetAura(SPELL_SHAMAN_UNRELENTING_STORMS_TALENT);
3201 if (!unrelentingStorms)
3202 return;
3203
3204 int64 targetLimit = 0;
3205 if (AuraEffect const* limitEffect = unrelentingStorms->GetEffect(EFFECT_0))
3206 targetLimit = limitEffect->GetAmountAsInt();
3207
3208 if (GetUnitTargetCountForEffect(effIndex) > targetLimit)
3209 return;
3210
3211 SpellHistory::Duration cooldown = 0ms;
3212 if (AuraEffect const* reductionPctEffect = unrelentingStorms->GetEffect(EFFECT_1))
3213 {
3214 SpellHistory::GetCooldownDurations(GetSpellInfo(), 0, &cooldown, nullptr, nullptr);
3215
3218 .SpellValueOverrides = { { SPELLVALUE_BASE_POINT0, SpellEffectValue(-CalculatePct(cooldown.count(), reductionPctEffect->GetAmount())) } }
3219 });
3220 }
3221
3224 }
3225
3230};
3231
3232// 470057 - Voltaic Blaze
3234{
3235 bool Validate(SpellInfo const* /*spellInfo*/) override
3236 {
3238 }
3239
3240 void ApplyFlameShock(SpellEffIndex /*effIndex*/) const
3241 {
3242 Unit* caster = GetCaster();
3243 caster->m_Events.AddEventAtOffset([caster, targets = CastSpellTargetArg(GetHitUnit())]() mutable
3244 {
3245 if (!targets.Targets)
3246 return;
3247
3248 targets.Targets->Update(caster);
3249
3251 }, 500ms);
3252 }
3253
3258
3264};
3265
3266// 470058 - Voltaic Blaze
3268{
3269 static bool CheckProc(AuraScript const&, ProcEventInfo const& eventInfo)
3270 {
3271 // 470057 - Voltaic Blaze does not have any unique SpellFamilyFlags, check by id
3272 return eventInfo.GetSpellInfo()->Id == SPELL_SHAMAN_VOLTAIC_BLAZE_DAMAGE;
3273 }
3274
3279};
3280
3281// 470053 - Voltaic Blaze
3283{
3284 static bool CheckProc(AuraScript const&, AuraEffect const* aurEff, ProcEventInfo const& /*eventInfo*/)
3285 {
3286 return roll_chance(aurEff->GetAmount());
3287 }
3288
3289 static void HandleProc(AuraScript const&, AuraEffect const* /*aurEff*/, ProcEventInfo const& eventInfo)
3290 {
3292 }
3293
3299};
3300
3301// 33757 - Windfury Weapon
3303{
3304 bool Validate(SpellInfo const* /*spellInfo*/) override
3305 {
3307 }
3308
3309 bool Load() override
3310 {
3311 return GetCaster()->IsPlayer();
3312 }
3313
3315 {
3316 PreventHitDefaultEffect(effIndex);
3317
3318 if (Item* mainHand = GetCaster()->ToPlayer()->GetWeaponForAttack(BASE_ATTACK, false))
3321 .TriggeringSpell = GetSpell()
3322 });
3323 }
3324
3329};
3330
3332{
3333 if (!_target.Targets)
3334 return true;
3335
3336 _target.Targets->Update(_shaman);
3337 if (!_target.Targets->GetUnitTarget())
3338 return true;
3339
3340 CastSpellExtraArgs args;
3342 args.TriggeringAura = _shaman->GetAuraEffect(SPELL_SHAMAN_WINDFURY_AURA, EFFECT_0); // prevent proc from itself
3343
3344 _shaman->CastSpell(_shaman, _itr->VisualSpellId, args);
3346
3347 if (++_itr == _end)
3348 return true;
3349
3350 _shaman->m_Events.AddEvent(this, Milliseconds(time) + _itr->Delay);
3351 return false;
3352}
3353
3355{
3356 // Not a separate script because of ordering requirements for Forceful Winds
3358 {
3359 if (Aura* forcefulWinds = shaman->GetAura(SPELL_SHAMAN_FORCEFUL_WINDS_PROC))
3360 {
3361 // gaining a stack should not refresh duration
3362 uint32 maxStack = forcefulWinds->CalcMaxStackAmount();
3363 if (forcefulWinds->GetStackAmount() < maxStack)
3364 forcefulWinds->SetStackAmount(forcefulWinds->GetStackAmount() + 1);
3365 }
3366 else
3369 });
3370 }
3371
3372 std::ptrdiff_t attacks = 2;
3373 if (AuraEffect const* unrulyWinds = shaman->GetAuraEffect(SPELL_SHAMAN_UNRULY_WINDS, EFFECT_0); roll_chance(unrulyWinds->GetAmount()))
3374 ++attacks;
3375
3376 shaman->m_Events.AddEventAtOffset(new WindfuryProcEvent(shaman, target, attacks), Sequence.front().Delay);
3377}
3378
3379// 319773 - Windfury Weapon (proc)
3407
3408// 462767 - Arctic Snowstorm
3409// 36797 - AreatriggerId
3411{
3413
3414 void OnUnitEnter(Unit* unit) override
3415 {
3416 if (Unit* caster = at->GetCaster())
3417 {
3418 if (unit->GetAura(SPELL_SHAMAN_FROST_SHOCK, caster->GetGUID()))
3419 return;
3420
3421 if (caster->IsValidAttackTarget(unit))
3423 }
3424 }
3425
3430};
3431
3432// 192078 - Wind Rush Totem (Spell)
3433// 12676 - AreaTriggerId
3435{
3436 static constexpr uint32 REFRESH_TIME = 4500;
3437
3439
3440 void OnUpdate(uint32 diff) override
3441 {
3442 _refreshTimer -= diff;
3443 if (_refreshTimer <= 0)
3444 {
3445 if (Unit* caster = at->GetCaster())
3446 for (ObjectGuid const& guid : at->GetInsideUnits())
3447 if (Unit* unit = ObjectAccessor::GetUnit(*caster, guid))
3448 CastSpeedBuff(caster, unit);
3449
3451 }
3452 }
3453
3454 void OnUnitEnter(Unit* unit) override
3455 {
3456 if (Unit* caster = at->GetCaster())
3457 CastSpeedBuff(caster, unit);
3458 }
3459
3460 static void CastSpeedBuff(Unit* caster, Unit* unit)
3461 {
3462 if (!caster->IsValidAssistTarget(unit))
3463 return;
3464
3466 }
3467
3468private:
3470};
3471
3473{
3545 RegisterSpellScriptWithArgs(spell_sha_stormflurry, "spell_sha_artifact_stormflurry_stormstrike",
3547 RegisterSpellScriptWithArgs(spell_sha_stormflurry, "spell_sha_artifact_stormflurry_windstrike",
3549 RegisterSpellScriptWithArgs(spell_sha_stormflurry, "spell_sha_stormflurry_stormstrike",
3551 RegisterSpellScriptWithArgs(spell_sha_stormflurry, "spell_sha_stormflurry_windstrike",
3578}
AreaTriggerExitReason
Definition AreaTrigger.h:69
@ IN_MILLISECONDS
Definition Common.h:38
ChrSpecialization
Definition DBCEnums.h:398
@ DIFFICULTY_NONE
Definition DBCEnums.h:933
uint8_t uint8
Definition Define.h:156
int64_t int64
Definition Define.h:149
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
uint32_t uint32
Definition Define.h:154
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
std::chrono::seconds Seconds
Seconds shorthand typedef.
Definition Duration.h:28
@ GRID_MAP_TYPE_MASK_PLAYER
Definition GridDefines.h:80
@ GRID_MAP_TYPE_MASK_CREATURE
Definition GridDefines.h:77
#define EXTRA_CELL_SEARCH_RADIUS
std::unordered_set< ObjectGuid > GuidUnorderedSet
Definition ObjectGuid.h:435
@ TYPEID_PLAYER
Definition ObjectGuid.h:44
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ EQUIPMENT_SLOT_MAINHAND
Definition Player.h:744
@ EQUIPMENT_SLOT_OFFHAND
Definition Player.h:745
#define INVENTORY_SLOT_BAG_0
Definition Player.h:723
bool roll_chance(T chance)
Definition Random.h:55
#define RegisterSpellAndAuraScriptPair(script_1, script_2)
Definition ScriptMgr.h:1381
#define RegisterAreaTriggerAI(ai_name)
Definition ScriptMgr.h:1428
#define RegisterSpellScript(spell_script)
Definition ScriptMgr.h:1383
#define RegisterSpellScriptWithArgs(spell_script, script_name,...)
Definition ScriptMgr.h:1382
SpellEffIndex
@ EFFECT_3
@ EFFECT_8
@ EFFECT_6
@ EFFECT_1
@ EFFECT_5
@ EFFECT_0
@ EFFECT_4
@ EFFECT_2
@ CLASS_HUNTER
@ CLASS_DRUID
@ CLASS_SHAMAN
@ CLASS_PRIEST
@ CLASS_WARRIOR
@ CLASS_WARLOCK
@ CLASS_MAGE
@ CLASS_PALADIN
@ CLASS_ROGUE
@ TARGET_UNIT_DEST_AREA_ALLY
@ TARGET_UNIT_RECT_CASTER_ENEMY
@ TARGET_UNIT_DEST_AREA_ENEMY
@ TARGET_UNIT_CASTER_AREA_RAID
@ TARGET_UNIT_CASTER
@ SPELL_EFFECT_CREATE_AREATRIGGER
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_TRIGGER_MISSILE
@ SPELL_EFFECT_HEAL
@ SPELL_EFFECT_TRIGGER_SPELL
@ SPELL_EFFECT_SCHOOL_DAMAGE
@ BASE_ATTACK
@ POWER_MAELSTROM
@ POWER_MANA
@ SPELLFAMILY_SHAMAN
AuraEffectHandleModes
@ AURA_EFFECT_HANDLE_REAL
AuraRemoveMode
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_ADD_PCT_MODIFIER
@ SPELL_AURA_PROC_TRIGGER_SPELL
@ SPELL_AURA_MOD_ATTACKER_SPELL_AND_WEAPON_CRIT_CHANCE
@ SPELL_AURA_DUMMY
@ SPELL_AURA_PERIODIC_DUMMY
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL
@ SPELLVALUE_AURA_STACK
@ SPELLVALUE_DURATION
double SpellEffectValue
This is a double instead of float to be able to store full range of int32.
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
@ TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD
Will ignore Spell and Category cooldowns.
@ TRIGGERED_IGNORE_CAST_IN_PROGRESS
Will not check if a current cast is in progress.
@ TRIGGERED_IGNORE_POWER_COST
Will ignore power and reagent cost.
@ TRIGGERED_IGNORE_GCD
Will ignore GCD.
@ TRIGGERED_DONT_REPORT_CAST_ERROR
Will return SPELL_FAILED_DONT_REPORT in CheckCast functions.
@ TRIGGERED_IGNORE_CAST_TIME
Will always be instantly cast.
@ SPELLVALUE_BASE_POINT1
@ SPELLVALUE_BASE_POINT0
@ TARGET_CHECK_ENEMY
Definition SpellInfo.h:83
@ TARGET_OBJECT_TYPE_UNIT
Definition SpellInfo.h:68
#define sSpellMgr
Definition SpellMgr.h:812
#define AuraProcFn(F)
#define SpellOnCalcCritChanceFn(F)
#define SpellObjectTargetSelectFn(F, I, N)
#define AuraEffectProcFn(F, I, N)
#define SpellEffectFn(F, I, N)
#define SpellObjectAreaTargetSelectFn(F, I, N)
#define AuraEffectPeriodicFn(F, I, N)
#define AuraCheckEffectProcFn(F, I, N)
#define SpellCalcDamageFn(F)
#define SpellCastFn(F)
#define AuraEffectApplyFn(F, I, N, M)
#define AuraCheckProcFn(F)
#define SpellHitFn(F)
#define SPELL_AURA_ANY
Definition SpellScript.h:61
#define AuraHeartbeatFn(F)
#define AuraEffectCalcSpellModFn(F, I, N)
#define SpellCalcHealingFn(F)
#define AuraEffectRemoveFn(F, I, N, M)
#define CAST_AI(a, b)
Definition UnitAI.h:29
T AddPct(T &base, U pct)
Definition Util.h:85
T ApplyPct(T &base, U pct)
Definition Util.h:91
T CalculatePct(T base, U pct)
Definition Util.h:72
AreaTrigger *const at
AreaTriggerAI(AreaTrigger *a, uint32 scriptId={}) noexcept
GuidUnorderedSet const & GetInsideUnits() const
ObjectGuid const & GetCasterGuid() const
Unit * GetCaster() const
AuraRemoveMode GetRemoveMode() const
Definition SpellAuras.h:96
int32 GetAmountAsInt() const
SpellEffectValue GetBaseAmount() const
Aura * GetBase() const
SpellEffectValue GetAmount() const
void PreventDefaultAction()
AuraApplication const * GetTargetApplication() const
HookList< AuraHeartbeatHandler > OnHeartbeat
HookList< EffectApplyHandler > AfterEffectRemove
HookList< CheckEffectProcHandler > DoCheckEffectProc
HookList< EffectPeriodicHandler > OnEffectPeriodic
HookList< EffectApplyHandler > AfterEffectApply
Unit * GetCaster() const
HookList< EffectCalcSpellModHandler > DoEffectCalcSpellMod
AuraEffect * GetEffect(uint8 effIndex) const
Aura * GetAura() const
Unit * GetTarget() const
ObjectGuid GetCasterGUID() const
HookList< AuraProcHandler > AfterProc
Difficulty GetCastDifficulty() const
HookList< CheckProcHandler > DoCheckProc
HookList< EffectApplyHandler > OnEffectRemove
HookList< EffectProcHandler > OnEffectProc
Unit * GetUnitOwner() const
HookList< AuraProcHandler > OnProc
bool HasEffect(uint8 effIndex) const
uint8 GetStackAmount() const
uint32 GetId() const
int32 GetMaxDuration() const
Definition SpellAuras.h:217
void DropChargeDelayed(uint32 delay, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Unit * GetUnitOwner() const
Definition SpellAuras.h:196
int32 GetDuration() const
Definition SpellAuras.h:222
AuraEffect * GetEffect(uint32 index) const
void SetDuration(int32 duration, bool withMods=false)
uint8 GetStackAmount() const
Definition SpellAuras.h:238
void SetMaxDuration(int32 duration)
Definition SpellAuras.h:218
Script * GetScript() const
Definition SpellAuras.h:355
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
bool IsPlayer() const
Definition BaseEntity.h:173
TypeID GetTypeId() const
Definition BaseEntity.h:166
uint32 GetDamage() const
Definition Unit.h:452
void AddEvent(BasicEvent *event, Milliseconds e_time, bool set_addtime=true)
void AddEventAtOffset(BasicEvent *event, Milliseconds offset)
uint32 GetOriginalHeal() const
Definition Unit.h:483
uint32 GetHeal() const
Definition Unit.h:482
Definition Item.h:179
ItemTemplate const * GetTemplate() const
Definition Item.cpp:1233
TempSummon * SummonCreature(uint32 entry, Position const &pos, SummonPropertiesEntry const *properties=nullptr, Milliseconds duration=0ms, WorldObject *summoner=nullptr, uint32 spellId=0, uint32 vehId=0, ObjectGuid privateObjectOwner=ObjectGuid::Empty, SmoothPhasingInfo const *smoothPhasingInfo=nullptr)
Definition Object.cpp:1186
static ObjectGuid const Empty
Definition ObjectGuid.h:314
Player * ToPlayer()
Definition Object.h:126
ChrSpecialization GetPrimarySpecialization() const
Definition Player.h:2008
Item * GetItemByPos(uint16 pos) const
Definition Player.cpp:9630
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition Player.cpp:9669
HealInfo * GetHealInfo() const
Definition Unit.h:512
Unit * GetActionTarget() const
Definition Unit.h:500
Spell const * GetProcSpell() const
Definition Unit.h:514
SpellInfo const * GetSpellInfo() const
Definition Unit.cpp:281
DamageInfo * GetDamageInfo() const
Definition Unit.h:511
Unit * GetProcTarget() const
Definition Unit.h:501
Unit * GetActor() const
Definition Unit.h:499
uint32 GetPeriodicTickCount() const
bool IsAura() const
bool IsEffect() const
void ResetCooldown(uint32 spellId, bool update=false)
void RestoreCharge(uint32 chargeCategoryId)
static void GetCooldownDurations(SpellInfo const *spellInfo, uint32 itemId, Duration *cooldown, uint32 *categoryId, Duration *categoryCooldown)
void ModifyCooldown(uint32 spellId, Duration cooldownMod, bool withoutCategoryCooldown=false)
bool HasCharge(uint32 chargeCategoryId) const
Milliseconds Duration
void StartCooldown(SpellInfo const *spellInfo, uint32 itemId, Spell *spell=nullptr, bool onHold=false, Optional< Duration > forcedCooldown={})
bool IsAffected(uint32 familyName, flag128 const &familyFlags) const
uint32 const Id
Definition SpellInfo.h:328
flag128 SpellFamilyFlags
Definition SpellInfo.h:415
uint32 ChargeCategoryId
Definition SpellInfo.h:420
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition SpellInfo.h:588
bool HasLabel(uint32 labelId) const
static bool ValidateSpellInfo(std::initializer_list< uint32 > spellIds)
static bool ValidateSpellEffect(std::initializer_list< std::pair< uint32, SpellEffIndex > > effects)
HookList< DamageAndHealingCalcHandler > CalcDamage
HookList< CastHandler > AfterCast
Aura * GetHitAura(bool dynObjAura=false, bool withRemoved=false) const
int32 GetHitDamage() const
Unit * GetCaster() const
HookList< HitHandler > AfterHit
int32 GetEffectValueAsInt() const
HookList< HitHandler > OnHit
HookList< EffectHandler > OnEffectHit
void PreventHitDefaultEffect(SpellEffIndex effIndex)
int64 GetUnitTargetCountForEffect(SpellEffIndex effect) const
Unit * GetHitUnit() const
SpellEffectInfo const & GetEffectInfo() const
HookList< EffectHandler > OnEffectHitTarget
HookList< ObjectTargetSelectHandler > OnObjectTargetSelect
HookList< CastHandler > OnCast
Spell * GetSpell() const
Difficulty GetCastDifficulty() const
int32 GetHitHeal() const
void SetHitDamage(int32 damage)
HookList< OnCalcCritChanceHandler > OnCalcCritChance
WorldLocation const * GetExplTargetDest() const
HookList< EffectHandler > OnEffectLaunch
void SetHitHeal(int32 heal)
HookList< DamageAndHealingCalcHandler > CalcHealing
Unit * GetExplTargetUnit() const
SpellInfo const * GetSpellInfo() const
HookList< ObjectAreaTargetSelectHandler > OnObjectAreaTargetSelect
Unit * GetOriginalCaster() const
Definition Spell.h:277
ObjectGuid m_originalCastId
Definition Spell.h:605
std::any m_customArg
Definition Spell.h:649
Optional< int32 > GetPowerTypeCostAmount(Powers power) const
Definition Spell.cpp:8157
SpellRange GetMinMaxRange(bool strict) const
Definition Spell.cpp:7399
UsedSpellMods m_appliedMods
Definition Spell.h:654
ObjectGuid m_castId
Definition Spell.h:604
ObjectGuid _originalCastId
SpellEffectValue _procChance
SpellEffectValue _damagePercent
bool Execute(uint64 time, uint32) override
StormflurryEvent(Unit *caster, Unit *target, ObjectGuid const &originalCastId, SpellEffectValue damagePercent, uint32 mainHandDamageSpellId, uint32 offHandDamageSpellId, SpellEffectValue procChance)
CastSpellTargetArg _target
Definition Unit.h:635
uint8 GetClass() const
Definition Unit.h:764
AuraEffect * GetAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid casterGUID=ObjectGuid::Empty) const
Definition Unit.cpp:4604
virtual bool HasSpell(uint32) const
Definition Unit.h:1084
uint32 GetAuraCount(uint32 spellId) const
Definition Unit.cpp:4788
bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster=ObjectGuid::Empty) const
Definition Unit.cpp:4774
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4700
float GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:5069
void RemoveAuraFromStack(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, uint16 num=1)
Definition Unit.cpp:3990
bool HealthBelowPct(float pct) const
Definition Unit.h:792
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4804
SpellHistory * GetSpellHistory()
Definition Unit.h:1498
std::vector< AreaTrigger * > GetAreaTriggers(uint32 spellId) const
Definition Unit.cpp:5475
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3974
GetCastSpellInfoResult GetCastSpellInfo(SpellInfo const *spellInfo) const
Definition Unit.h:1480
EventInfoIterator _end
bool Execute(uint64 time, uint32) override
static constexpr std::array< WindfuryProcEventInfo, 3 > Sequence
CastSpellTargetArg _target
decltype(Sequence)::const_iterator EventInfoIterator
WindfuryProcEvent(Unit *shaman, Unit *target, std::ptrdiff_t attacks)
EventInfoIterator _itr
static void Trigger(Unit *shaman, Unit *target)
bool IsWithinDist3d(float x, float y, float z, float dist) const
Definition Object.cpp:476
Map * GetMap() const
Definition Object.h:411
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2217
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2482
EventProcessor m_Events
Definition Object.h:561
void Register() override
static bool CheckProc(AuraScript const &, AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
static void HandleEffectProc(AuraScript const &, AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
static void ResizeTargets(SpellScript const &, std::list< WorldObject * > &targets)
void HandleEffectProc(AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
static bool CheckProc(AuraScript const &, ProcEventInfo const &eventInfo)
static void HandleEffectProc(AuraScript const &, AuraEffect const *, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
void TriggerBuff(SpellEffIndex effIndex) const
void HandleEffectPeriodic(AuraEffect const *aurEff)
static bool CheckProc(AuraScript const &, ProcEventInfo const &procInfo)
void OnProcHeal(AuraEffect const *aurEff, ProcEventInfo const &procInfo)
bool Validate(SpellInfo const *) override
void ReduceLavaLashCooldown(AuraEffect const *aurEff, ProcEventInfo const &) const
bool Validate(SpellInfo const *) override
void HandleDamageBuff(SpellEffIndex effIndex) const
bool Validate(SpellInfo const *) override
void HandleCooldownReduction(SpellEffIndex) const
bool Validate(SpellInfo const *) override
void HandleScript(SpellEffIndex) const
void HandleScript(SpellEffIndex) const
bool Validate(SpellInfo const *) override
void TriggerBuff(SpellEffIndex effIndex) const
bool Validate(SpellInfo const *) override
void TriggerCleaveBuff(SpellEffIndex effIndex) const
bool Validate(SpellInfo const *) override
void HandleProc(AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *spellInfo) override
bool CheckProc(AuraEffect const *, ProcEventInfo const &procInfo)
bool Validate(SpellInfo const *) override
void HandleEffectPeriodic(AuraEffect const *) const
bool Validate(SpellInfo const *) override
void Register() override
void CalculateHealingBonus(SpellEffectInfo const &, Unit const *victim, int32 &, int32 &, float &pctMod) const
bool Validate(SpellInfo const *) override
bool CheckProc(AuraEffect const *, ProcEventInfo const &procInfo) const
bool Validate(SpellInfo const *) override
void PeriodicTick(AuraEffect const *aurEff) const
void Register() override
void Register() override
void CountEffectivelyHealedTarget()
static void FilterTargets(SpellScript const &, std::list< WorldObject * > &targets)
void HandleCooldown() const
bool Validate(SpellInfo const *spellInfo) override
void Register() override
void HandleProc(AuraEffect const *aurEff, ProcEventInfo const &)
bool Validate(SpellInfo const *) override
bool CheckProc(ProcEventInfo const &eventInfo) const
bool Validate(SpellInfo const *) override
void Register() override
void HandleEffectProc(AuraEffect const *, ProcEventInfo const &eventInfo)
static bool CheckProc(AuraScript const &, ProcEventInfo const &procInfo)
ObjectGuid const & GetProcTargetGuid() const
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
void HandleEffectPeriodic(AuraEffect const *)
bool Validate(SpellInfo const *spellInfo) override
void SnapshotDamageMultiplier(SpellEffIndex) const
void Register() override
static constexpr std::array< std::pair< uint32, SpellEffIndex >, 3 > DamageBuffs
bool Validate(SpellInfo const *) override
static constexpr std::array< uint32, 3 > BuffSpells
bool Validate(SpellInfo const *) override
void RemoveAllBuffs(AuraEffect const *, AuraEffectHandleModes) const
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
void HandleHit(SpellEffIndex) const
void Register() override
bool Validate(SpellInfo const *) override
void OnPrecast() override
bool Validate(SpellInfo const *) override
void Register() override
void TriggerDamage(SpellEffIndex) const
void CheckFlameShocks(AuraEffect const *aurEff) const
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
void HandleEffectProc(AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
void HandleEffectHitTarget(SpellEffIndex) const
void CalcCleaveMod(AuraEffect const *aurEff, SpellModifier *&spellMod) const
void Register() override
void HandleEffectPeriodic(AuraEffect const *aurEff) const
void HandleEffecRemoved(AuraEffect const *, AuraEffectHandleModes) const
void SetVisualDummy(TempSummon const *summon)
static void SelectTargets(SpellScript const &, std::list< WorldObject * > &targets)
void InitializeVisualStalker() const
static void SelectTargets(SpellScript const &, std::list< WorldObject * > &targets)
void Register() override
static bool CheckProc(AuraScript const &, AuraEffect const *, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
void EnergizeMaelstrom(SpellEffIndex) const
bool Validate(SpellInfo const *) override
void Register() override
void Register() override
bool Validate(SpellInfo const *) override
void HandleEffectProc(AuraEffect const *, ProcEventInfo const &) const
bool Validate(SpellInfo const *) override
void HandleProc(AuraEffect const *aurEff, ProcEventInfo const &)
bool Validate(SpellInfo const *) override
void HandleProc(AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
static bool CheckProc(AuraScript const &, ProcEventInfo const &eventInfo)
void HandleProc(AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
void HandleEffectProc(AuraEffect const *aurEff, ProcEventInfo const &)
void DiminishHaste(AuraEffect const *aurEff)
bool Validate(SpellInfo const *) override
void HandleProc(AuraEffect const *, ProcEventInfo const &eventInfo)
void HandleScript(SpellEffIndex) const
void EnsureLavaSurgeCanBeImmediatelyConsumed() const
bool Validate(SpellInfo const *) override
void Register() override
void CalcCritChance(Unit const *victim, float &chance) const
bool Validate(SpellInfo const *) override
void Register() override
bool Validate(SpellInfo const *spellInfo) override
bool Load() override
void AddBonusFlametongueDamage(SpellEffectInfo const &, Unit const *victim, int32 &, int32 &, float &pctMod) const
bool Validate(SpellInfo const *) override
void HandleEffectProc(AuraEffect const *, ProcEventInfo const &)
SpellEffectValue _normalizedTicks
bool CheckProcChance(AuraEffect const *aurEff, ProcEventInfo const &)
bool Validate(SpellInfo const *) override
void Register() override
bool Validate(SpellInfo const *) override
void HandleScript(SpellEffIndex) const
void HandleScript(SpellEffIndex) const
bool Validate(SpellInfo const *) override
static void HandleTargetSelect(SpellScript const &, std::list< WorldObject * > &targets)
void HandleEffectHitTarget(SpellEffIndex) const
bool Validate(SpellInfo const *) override
bool CheckProc(ProcEventInfo const &procEvent) const
void ExpireMaelstromAuras(AuraEffect const *, AuraEffectHandleModes) const
void RemoveMaelstromAuras(ProcEventInfo const &procEvent) const
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
void HandleProc(AuraEffect const *, ProcEventInfo const &) const
bool Validate(SpellInfo const *) override
static uint32 GetTriggeredSpellId(uint32 triggeringSpellId)
static bool CheckProc(AuraScript const &, AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
void HandleProc(AuraEffect const *, ProcEventInfo const &procInfo)
bool Validate(SpellInfo const *) override
void TriggerFlameShocks(SpellEffIndex) const
static void RemoveIncapacitateEffect(SpellScript const &, std::list< WorldObject * > &targets)
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
static void StartCooldown(AuraScript const &, AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
static bool CheckProc(AuraScript const &, AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
void HandleScript(SpellEffIndex) const
void FilterTargets(std::list< WorldObject * > &targets) const
bool Validate(SpellInfo const *) override
void EnergizeMaelstrom(SpellEffIndex) const
void TriggerDamage(SpellEffIndex) const
void PreventLavaSurge(SpellEffIndex effIndex)
bool Validate(SpellInfo const *) override
void HandleHeal(SpellEffIndex effIndex)
bool Validate(SpellInfo const *) override
void OnRemove(AuraEffect const *, AuraEffectHandleModes) const
void OnApply(AuraEffect const *aurEff, AuraEffectHandleModes) const
void Register() override
bool Validate(SpellInfo const *) override
ObjectGuid AllowedOriginalCastId
void Register() override
void ApplyModifier(SpellEffectInfo const &, Unit *, int32 &, int32 &, float &pctMod) const
bool Validate(SpellInfo const *spellInfo) override
spell_sha_stormflurry(uint32 stormflurrySpellId, uint32 mainHandDamageSpellId, uint32 offHandDamageSpellId)
void HandleProc(SpellEffIndex) const
void Register() override
static void HandleProc(AuraScript const &, AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
void Register() override
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
static void PreventAffectingHealingSpells(SpellScript const &, WorldObject *&target)
void Register() override
bool Validate(SpellInfo const *spellInfo) override
void EnergizeMaelstrom(AuraEffect const *aurEff, ProcEventInfo const &) const
bool CheckHailstormProc(ProcEventInfo const &eventInfo) const
void HandleProc(AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
void HandleProc(AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
void HandleProc(AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
void Register() override
void PeriodicTick(AuraEffect const *)
void Register() override
bool Validate(SpellInfo const *) override
void HandleProc(AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
void HandleProc(AuraEffect const *aurEff, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *spellInfo) override
void TriggerLightningSpell(SpellEffIndex) const
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
void HandleEffectProc(AuraEffect const *aurEff, ProcEventInfo const &)
void Register() override
bool Validate(SpellInfo const *) override
void HandleProc(AuraEffect const *, ProcEventInfo const &)
bool Validate(SpellInfo const *) override
static void HandleProc(AuraScript const &, AuraEffect const *, ProcEventInfo const &procInfo)
bool Validate(SpellInfo const *) override
bool Validate(SpellInfo const *) override
void Trigger(SpellEffIndex effIndex) const
static bool CheckProc(AuraScript const &, ProcEventInfo const &eventInfo)
static bool CheckProc(AuraScript const &, AuraEffect const *aurEff, ProcEventInfo const &)
static void HandleProc(AuraScript const &, AuraEffect const *, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
void EnergizeMaelstrom(SpellEffIndex) const
void ApplyFlameShock(SpellEffIndex) const
void HandleEffectProc(AuraEffect const *, ProcEventInfo const &eventInfo)
bool Validate(SpellInfo const *) override
void HandleEffect(SpellEffIndex effIndex)
bool Validate(SpellInfo const *) override
Position GetHealingRainPosition(Aura const *healingRain)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
auto SelectRandomWeightedContainerElement(C const &container, std::span< double > const &weights) -> decltype(std::ranges::begin(container))
Definition Containers.h:127
void RandomShuffle(Iterator begin, Iterator end)
Reorder the elements of the iterator range randomly.
Definition Containers.h:171
auto SelectRandomContainerElement(C const &container) -> std::add_const_t< decltype(*std::ranges::begin(container))> &
Definition Containers.h:110
void RandomResize(C &container, std::size_t requestedSize)
Definition Containers.h:67
void SelectRandomInjuredTargets(std::list< WorldObject * > &targets, size_t maxTargets, bool prioritizePlayers, Unit const *prioritizeGroupMembersOf)
Definition Spell.cpp:9577
ShamanSpells
void AddSC_shaman_spell_scripts()
ShamanSpellLabels
@ SPELL_LABEL_SHAMAN_WINDFURY_TOTEM
@ SPELL_SHAMAN_MOLTEN_THUNDER_TALENT
@ SPELL_SHAMAN_ICE_STRIKE_PROC
@ SPELL_SHAMAN_FLAMETONGUE_WEAPON_AURA
@ SPELL_SHAMAN_FIRE_NOVA_DAMAGE
@ SPELL_SHAMAN_DELUGE_TALENT
@ SPELL_SHAMAN_WINDSTRIKE_DAMAGE_OFF_HAND
@ SPELL_SHAMAN_EARTHEN_RAGE_PERIODIC
@ SPELL_SHAMAN_EARTHQUAKE
@ SPELL_SHAMAN_ARCTIC_SNOWSTORM_SLOW
@ SPELL_SHAMAN_DELUGE_AURA
@ SPELL_SHAMAN_CRASH_LIGHTNING_DAMAGE_BUFF
@ SPELL_SHAMAN_ELEMENTAL_BLAST_HASTE
@ SPELL_SHAMAN_MAELSTROM_WEAPON_MOD_AURA
@ SPELL_SHAMAN_FORCEFUL_WINDS_TALENT
@ SPELL_SHAMAN_UNRELENTING_STORMS_TALENT
@ SPELL_SHAMAN_ICEFURY_OVERLOAD
@ SPELL_SHAMAN_CRASH_LIGHTNING
@ SPELL_SHAMAN_LIGHTNING_BOLT_ENERGIZE
@ SPELL_SHAMAN_ASCENDANCE_RESTORATION
@ SPELL_SHAMAN_VOLTAIC_BLAZE_OVERRIDE
@ SPELL_SHAMAN_FLAMETONGUE_ATTACK
@ SPELL_SHAMAN_FERAL_LUNGE
@ SPELL_SHAMAN_MOLTEN_ASSAULT
@ SPELL_SHAMAN_CRASH_LIGHTNING_CLEAVE
@ SPELL_SHAMAN_FIRE_NOVA_ENABLER
@ SPELL_SHAMAN_WINDFURY_VISUAL_1
@ SPELL_SHAMAN_LAVA_SURGE
@ SPELL_SHAMAN_LIQUID_MAGMA_HIT
@ SPELL_SHAMAN_UNLIMITED_POWER_BUFF
@ SPELL_SHAMAN_SPIRIT_WOLF_AURA
@ SPELL_SHAMAN_HEALING_RAIN_HEAL
@ SPELL_SHAMAN_TOTEMIC_POWER_SPELL_POWER
@ SPELL_SHAMAN_STORMSTRIKE_DAMAGE_MAIN_HAND
@ SPELL_SHAMAN_PRIMORDIAL_WAVE_DAMAGE
@ SPELL_SHAMAN_STORMBLAST_PROC
@ SPELL_SHAMAN_STORMWEAVER_PVP_TALENT
@ SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD
@ SPELL_SHAMAN_LAVA_BURST_BONUS_DAMAGE
@ SPELL_SHAMAN_CHAIN_LIGHTNING
@ SPELL_SHAMAN_PATH_OF_FLAMES_TALENT
@ SPELL_SHAMAN_MASTERY_ELEMENTAL_OVERLOAD
@ SPELL_SHAMAN_MOLTEN_THUNDER_PROC
@ SPELL_SHAMAN_FLAME_SHOCK
@ SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD_ENERGIZE
@ SPELL_SHAMAN_ITEM_LIGHTNING_SHIELD_DAMAGE
@ SPELL_SHAMAN_WINDFURY_VISUAL_3
@ SPELL_SHAMAN_EARTHEN_RAGE_DAMAGE
@ SPELL_SHAMAN_STORMFLURRY
@ SPELL_SHAMAN_STORMWEAVER_PVP_TALENT_BUFF
@ SPELL_SHAMAN_MAELSTROM_WEAPON_VISIBLE_AURA
@ SPELL_SHAMAN_LIGHTNING_BOLT
@ SPELL_SHAMAN_DOOM_WINDS_LEGENDARY_COOLDOWN
@ SPELL_SHAMAN_EARTHQUAKE_KNOCKING_DOWN
@ SPELL_SHAMAN_MAELSTROM_WEAPON_OVERLAY_HEALS
@ SPELL_SHAMAN_FROST_SHOCK
@ SPELL_SHAMAN_STORMSTRIKE
@ SPELL_SHAMAN_STORMKEEPER
@ SPELL_SHAMAN_POWER_SURGE
@ SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD
@ SPELL_SHAMAN_ICEFURY
@ SPELL_SHAMAN_STORMBLAST_DAMAGE
@ SPELL_SHAMAN_TOTEMIC_POWER_MP5
@ SPELL_SHAMAN_ELEMENTAL_BLAST_OVERLOAD
@ SPELL_SHAMAN_ELEMENTAL_MASTERY
@ SPELL_SHAMAN_ELEMENTAL_BLAST_CRIT
@ SPELL_SHAMAN_CHAINED_HEAL
@ SPELL_SHAMAN_THORIMS_INVOCATION
@ SPELL_SHAMAN_UNRELENTING_STORMS_REDUCTION
@ SPELL_SHAMAN_RESTORATIVE_MISTS_INITIAL
@ SPELL_SHAMAN_OVERFLOWING_MAELSTROM_AURA
@ SPELL_SHAMAN_FORCEFUL_WINDS_PROC
@ SPELL_SHAMAN_MAELSTROM_WEAPON_OVERLAY
@ SPELL_SHAMAN_LAVA_BURST_OVERLOAD
@ SPELL_SHAMAN_LIGHTNING_BOLT_OVERLOAD_ENERGIZE
@ SPELL_SHAMAN_RESTORATIVE_MISTS
@ SPELL_SHAMAN_OVERFLOWING_MAELSTROM_TALENT
@ SPELL_SHAMAN_STORMSTRIKE_DAMAGE_OFF_HAND
@ SPELL_SHAMAN_ICE_STRIKE_OVERRIDE_AURA
@ SPELL_SHAMAN_GATHERING_STORMS
@ SPELL_SHAMAN_SPIRIT_WOLF_TALENT
@ SPELL_SHAMAN_HEALING_RAIN
@ SPELL_SHAMAN_WINDSTRIKE_DAMAGE_MAIN_HAND
@ SPELL_SHAMAN_LAVA_LASH
@ SPELL_SHAMAN_DOOM_WINDS_DAMAGE
@ SPELL_SHAMAN_UNRULY_WINDS
@ SPELL_SHAMAN_UNDULATION_PROC
@ SPELL_SHAMAN_IGNEOUS_POTENTIAL
@ SPELL_SHAMAN_FLAMETONGUE_WEAPON_ENCHANT
@ SPELL_SHAMAN_GATHERING_STORMS_BUFF
@ SPELL_SHAMAN_TOTEMIC_POWER_ARMOR
@ SPELL_SHAMAN_T29_2P_ELEMENTAL_DAMAGE_BUFF
@ SPELL_SHAMAN_GHOST_WOLF
@ SPELL_SHAMAN_LAVA_BURST
@ SPELL_SHAMAN_ELECTRIFIED
@ SPELL_SHAMAN_ECHOES_OF_GREAT_SUNDERING_LEGENDARY
@ SPELL_SHAMAN_CHAIN_LIGHTNING_ENERGIZE
@ SPELL_SHAMAN_AFTERSHOCK_ENERGIZE
@ SPELL_SHAMAN_MAELSTROM_CONTROLLER
@ SPELL_SHAMAN_WINDFURY_ATTACK
@ SPELL_SHAMAN_WINDFURY_VISUAL_2
@ SPELL_SHAMAN_TOTEMIC_POWER_ATTACK_POWER
@ SPELL_SHAMAN_NATURES_GUARDIAN_COOLDOWN
@ SPELL_SHAMAN_WINDFURY_ENCHANTMENT
@ SPELL_SHAMAN_CONVERGING_STORMS
@ SPELL_SHAMAN_ENERGY_SURGE
@ SPELL_SHAMAN_WINDFURY_AURA
@ SPELL_SHAMAN_SPIRIT_WOLF_PERIODIC
@ SPELL_SHAMAN_WIND_RUSH
@ SPELL_SHAMAN_ASCENDANCE_ELEMENTAL
@ SPELL_SHAMAN_ASCENDANCE_ENHANCEMENT
@ SPELL_SHAMAN_HAILSTORM_BUFF
@ SPELL_SHAMAN_STORMFLURRY_ARTIFACT
@ SPELL_SHAMAN_PATH_OF_FLAMES_SPREAD
@ SPELL_SHAMAN_FERAL_LUNGE_DAMAGE
@ SPELL_SHAMAN_EARTHEN_RAGE_PASSIVE
@ SPELL_SHAMAN_HAILSTORM_TALENT
@ SPELL_SHAMAN_ELEMENTAL_BLAST
@ SPELL_SHAMAN_VOLTAIC_BLAZE_DAMAGE
@ SPELL_SHAMAN_STORMSURGE_PROC
@ SPELL_SHAMAN_ANCESTRAL_GUIDANCE
@ SPELL_SHAMAN_EARTHQUAKE_TICK
@ SPELL_SHAMAN_EARTH_SHIELD_HEAL
@ SPELL_SHAMAN_ARCTIC_SNOWSTORM_AREATRIGGER
@ SPELL_SHAMAN_CHAIN_LIGHTNING_OVERLOAD
@ SPELL_SHAMAN_ECHOES_OF_GREAT_SUNDERING_TALENT
@ SPELL_SHAMAN_ITEM_MANA_SURGE
@ SPELL_SHAMAN_ELEMENTAL_WEAPONS_BUFF
@ SPELL_SHAMAN_ELEMENTAL_BLAST_MASTERY
@ SPELL_SHAMAN_ENHANCED_ELEMENTS
@ SPELL_SHAMAN_HEALING_RAIN_VISUAL
@ SPELL_SHAMAN_ANCESTRAL_GUIDANCE_HEAL
@ SPELL_SHAMAN_FROST_SHOCK_ENERGIZE
@ SPELL_SHAMAN_STORMBLAST_TALENT
@ SPELL_SHAMAN_TIDAL_WAVES
@ SPELL_SHAMAN_RIPTIDE
MiscNpcs
@ NPC_HEALING_RAIN_INVISIBLE_STALKER
TriggerCastFlags TriggerFlags
AuraEffect const * TriggeringAura
CastSpellExtraArgs & SetTriggeringSpell(Spell const *triggeringSpell)
Definition Spell.cpp:9707
CastSpellExtraArgs & SetTriggerFlags(TriggerCastFlags flag)
Optional< SpellCastTargets > Targets
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:203
bool operator()(Unit const *candidate) const
bool IsWeapon() const
constexpr void GetPosition(float &x, float &y) const
Definition Position.h:92
SpellEffectValue DamagePercent
void OnUnitExit(Unit *unit, AreaTriggerExitReason) override
void OnUnitEnter(Unit *unit) override
GuidUnorderedSet _stunnedUnits
void OnCreate(Spell const *creatingSpell) override
void OnUpdate(uint32 diff) override
bool AddStunnedTarget(ObjectGuid const &guid)
void OnUpdate(uint32 diff) override
static void CastSpeedBuff(Unit *caster, Unit *unit)
void OnUnitEnter(Unit *unit) override
static constexpr uint32 REFRESH_TIME
static void GenerateMaelstromWeapon(Unit *shaman, int32 stacks)
static void ConsumeMaelstromWeapon(Unit *shaman, Aura *maelstromWeaponVisibleAura, int32 stacks, Spell const *consumingSpell=nullptr)