TrinityCore
Loading...
Searching...
No Matches
SpellMgr.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#include "SpellMgr.h"
19#include "BattlePetMgr.h"
20#include "BattlefieldMgr.h"
21#include "BattlegroundMgr.h"
22#include "Chat.h"
23#include "DB2HotfixGenerator.h"
24#include "DB2Stores.h"
25#include "DatabaseEnv.h"
26#include "LanguageMgr.h"
27#include "Log.h"
28#include "MapUtils.h"
29#include "MotionMaster.h"
30#include "ObjectMgr.h"
31#include "Player.h"
32#include "SharedDefines.h"
33#include "Spell.h"
34#include "SpellAuraDefines.h"
35#include "SpellInfo.h"
36#include "StringConvert.h"
37#include <G3D/g3dmath.h>
38#include <boost/multi_index/composite_key.hpp>
39#include <boost/multi_index/hashed_index.hpp>
40#include <boost/multi_index/member.hpp>
41#include <boost/multi_index_container.hpp>
42
43namespace
44{
45 struct SpellIdDifficultyIndex;
46 struct SpellIdIndex;
47
48 boost::multi_index::multi_index_container<
50 boost::multi_index::indexed_by<
51 boost::multi_index::hashed_unique<
52 boost::multi_index::tag<SpellIdDifficultyIndex>,
53 boost::multi_index::composite_key<
55 boost::multi_index::member<SpellInfo, uint32 const, &SpellInfo::Id>,
56 boost::multi_index::member<SpellInfo, Difficulty const, &SpellInfo::Difficulty>
57 >
58 >,
59 boost::multi_index::hashed_non_unique<
60 boost::multi_index::tag<SpellIdIndex>,
61 boost::multi_index::member<SpellInfo, uint32 const, &SpellInfo::Id>
62 >
63 >
64 > mSpellInfoMap;
65
66 class ServersideSpellName
67 {
68 public:
69 explicit ServersideSpellName(uint32 id, std::string_view name) : _nameStorage(name)
70 {
71 Name.ID = id;
72 InitPointers();
73 }
74
75 ServersideSpellName(ServersideSpellName const& right) : _nameStorage(right._nameStorage)
76 {
77 Name.ID = right.Name.ID;
78 InitPointers();
79 }
80
81 ServersideSpellName(ServersideSpellName&& right) noexcept : _nameStorage(std::move(right._nameStorage))
82 {
83 Name.ID = right.Name.ID;
84 InitPointers();
85 right.InitPointers();
86 }
87
89
90 private:
91 void InitPointers()
92 {
93 std::fill(std::begin(Name.Name.Str), std::end(Name.Name.Str), _nameStorage.c_str());
94 }
95
96 std::string _nameStorage;
97 };
98
99 std::vector<ServersideSpellName> mServersideSpellNames;
100
101 std::unordered_map<std::pair<uint32, Difficulty>, SpellProcEntry> mSpellProcMap;
102 std::unordered_map<int32, CreatureImmunities> mCreatureImmunities;
103}
104
106
108{
109 SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(skill);
110 return pSkill && pSkill->CategoryID == SKILL_CATEGORY_PROFESSION && !pSkill->ParentSkillLineID;
111}
112
114{
115 SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(skill);
116 return pSkill && pSkill->CategoryID == SKILL_CATEGORY_WEAPON;
117}
118
119bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
120{
121 SkillLineAbilityMapBounds skillBounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
122 for (SkillLineAbilityMap::const_iterator itr = skillBounds.first; itr != skillBounds.second; ++itr)
123 if (itr->second->SkillLine == skillId)
124 return true;
125
126 return false;
127}
128
130
135
137{
138 static SpellMgr instance;
139 return &instance;
140}
141
143bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg)
144{
145 // not exist
146 if (!spellInfo)
147 return false;
148
149 bool needCheckReagents = false;
150
151 // check effects
152 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
153 {
154 switch (spellEffectInfo.Effect)
155 {
156 // craft spell for crafting non-existed item (break client recipes list show)
159 {
160 if (spellEffectInfo.ItemType == 0)
161 {
162 // skip auto-loot crafting spells, it does not need explicit item info (but has special fake items sometimes).
163 if (!spellInfo->IsLootCrafting())
164 {
165 if (msg)
166 {
167 if (player)
168 ChatHandler(player->GetSession()).PSendSysMessage("The craft spell %u does not have a create item entry.", spellInfo->Id);
169 else
170 TC_LOG_ERROR("sql.sql", "The craft spell {} does not have a create item entry.", spellInfo->Id);
171 }
172 return false;
173 }
174
175 }
176 // also possible IsLootCrafting case but fake items must exist anyway
177 else if (!sObjectMgr->GetItemTemplate(spellEffectInfo.ItemType))
178 {
179 if (msg)
180 {
181 if (player)
182 ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u has created a non-existing in DB item (Entry: %u) and then...", spellInfo->Id, spellEffectInfo.ItemType);
183 else
184 TC_LOG_ERROR("sql.sql", "Craft spell {} has created a non-existing item in DB item (Entry: {}) and then...", spellInfo->Id, spellEffectInfo.ItemType);
185 }
186 return false;
187 }
188
189 needCheckReagents = true;
190 break;
191 }
193 {
194 SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, DIFFICULTY_NONE);
195 if (!IsSpellValid(spellInfo2, player, msg))
196 {
197 if (msg)
198 {
199 if (player)
200 ChatHandler(player->GetSession()).PSendSysMessage("Spell %u learn to broken spell %u, and then...", spellInfo->Id, spellEffectInfo.TriggerSpell);
201 else
202 TC_LOG_ERROR("sql.sql", "Spell {} learn to invalid spell {}, and then...", spellInfo->Id, spellEffectInfo.TriggerSpell);
203 }
204 return false;
205 }
206 break;
207 }
208 default:
209 break;
210 }
211 }
212
213 if (needCheckReagents)
214 {
215 for (uint8 j = 0; j < MAX_SPELL_REAGENTS; ++j)
216 {
217 if (spellInfo->Reagent[j] > 0 && !sObjectMgr->GetItemTemplate(spellInfo->Reagent[j]))
218 {
219 if (msg)
220 {
221 if (player)
222 ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u refers a non-existing reagent in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Reagent[j]);
223 else
224 TC_LOG_ERROR("sql.sql", "Craft spell {} refers to a non-existing reagent in DB, item (Entry: {}) and then...", spellInfo->Id, spellInfo->Reagent[j]);
225 }
226 return false;
227 }
228 }
229 }
230
231 return true;
232}
233
235{
236 SpellChainMap::const_iterator itr = mSpellChains.find(spell_id);
237 if (itr == mSpellChains.end())
238 return nullptr;
239
240 return &itr->second;
241}
242
244{
245 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
246 return node->first->Id;
247
248 return spell_id;
249}
250
252{
253 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
254 return node->last->Id;
255
256 return spell_id;
257}
258
260{
261 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
262 if (node->next)
263 return node->next->Id;
264
265 return 0;
266}
267
269{
270 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
271 if (node->prev)
272 return node->prev->Id;
273
274 return 0;
275}
276
278{
279 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
280 return node->rank;
281
282 return 0;
283}
284
285uint32 SpellMgr::GetSpellWithRank(uint32 spell_id, uint32 rank, bool strict) const
286{
287 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
288 {
289 if (rank != node->rank)
290 return GetSpellWithRank(node->rank < rank ? node->next->Id : node->prev->Id, rank, strict);
291 }
292 else if (strict && rank > 1)
293 return 0;
294 return spell_id;
295}
296
301
303{
304 return mSpellsReqSpell.equal_range(spell_id);
305}
306
307bool SpellMgr::IsSpellRequiringSpell(uint32 spellid, uint32 req_spellid) const
308{
309 SpellsRequiringSpellMapBounds spellsRequiringSpell = GetSpellsRequiringSpellBounds(req_spellid);
310 for (SpellsRequiringSpellMap::const_iterator itr = spellsRequiringSpell.first; itr != spellsRequiringSpell.second; ++itr)
311 {
312 if (itr->second == spellid)
313 return true;
314 }
315 return false;
316}
317
319{
320 SpellLearnSkillMap::const_iterator itr = mSpellLearnSkills.find(spell_id);
321 if (itr != mSpellLearnSkills.end())
322 return &itr->second;
323 else
324 return nullptr;
325}
326
328{
329 return mSpellLearnSpells.equal_range(spell_id);
330}
331
333{
334 return mSpellLearnSpells.find(spell_id) != mSpellLearnSpells.end();
335}
336
337bool SpellMgr::IsSpellLearnToSpell(uint32 spell_id1, uint32 spell_id2) const
338{
340 for (SpellLearnSpellMap::const_iterator i = bounds.first; i != bounds.second; ++i)
341 if (i->second.Spell == spell_id2)
342 return true;
343 return false;
344}
345
350
352{
353 SpellTargetPositionMap::const_iterator itr = mSpellTargetPositions.find(std::make_pair(spell_id, effIndex));
354 if (itr != mSpellTargetPositions.end())
355 return &itr->second;
356 return nullptr;
357}
358
363
365{
366 spell_id = GetFirstSpellInChain(spell_id);
367 return mSpellSpellGroup.equal_range(spell_id);
368}
369
371{
373 for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second; ++itr)
374 {
375 if (itr->second == groupid)
376 return true;
377 }
378 return false;
379}
380
382{
383 return mSpellGroupSpell.equal_range(group_id);
384}
385
386void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const
387{
388 std::set<SpellGroup> usedGroups;
389 GetSetOfSpellsInSpellGroup(group_id, foundSpells, usedGroups);
390}
391
392void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const
393{
394 if (usedGroups.find(group_id) != usedGroups.end())
395 return;
396 usedGroups.insert(group_id);
397
399 for (SpellGroupSpellMap::const_iterator itr = groupSpell.first; itr != groupSpell.second; ++itr)
400 {
401 if (itr->second < 0)
402 {
403 SpellGroup currGroup = (SpellGroup)abs(itr->second);
404 GetSetOfSpellsInSpellGroup(currGroup, foundSpells, usedGroups);
405 }
406 else
407 {
408 foundSpells.insert(itr->second);
409 }
410 }
411}
412
413bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, AuraType auraType, SpellEffectValue amount, std::map<SpellGroup, SpellEffectValue>& groups) const
414{
415 uint32 spellId = spellInfo->GetFirstRankSpell()->Id;
416 auto spellGroupBounds = GetSpellSpellGroupMapBounds(spellId);
417 // Find group with SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT if it belongs to one
418 for (auto itr = spellGroupBounds.first; itr != spellGroupBounds.second; ++itr)
419 {
420 SpellGroup group = itr->second;
421 auto found = mSpellSameEffectStack.find(group);
422 if (found != mSpellSameEffectStack.end())
423 {
424 // check auraTypes
425 if (!found->second.contains(auraType))
426 continue;
427
428 // Put the highest amount in the map
429 auto groupItr = groups.find(group);
430 if (groupItr == groups.end())
431 groups.emplace(group, amount);
432 else
433 {
434 SpellEffectValue curr_amount = groupItr->second;
435 // Take absolute value because this also counts for the highest negative aura
436 if (std::abs(curr_amount) < std::abs(amount))
437 groupItr->second = amount;
438 }
439 // return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group per auraType
440 return true;
441 }
442 }
443 // Not in a SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group, so return false
444 return false;
445}
446
448{
449 ASSERT(spellInfo1);
450 ASSERT(spellInfo2);
451
452 uint32 spellid_1 = spellInfo1->GetFirstRankSpell()->Id;
453 uint32 spellid_2 = spellInfo2->GetFirstRankSpell()->Id;
454
455 // find SpellGroups which are common for both spells
457 std::set<SpellGroup> groups;
458 for (SpellSpellGroupMap::const_iterator itr = spellGroup1.first; itr != spellGroup1.second; ++itr)
459 {
460 if (IsSpellMemberOfSpellGroup(spellid_2, itr->second))
461 {
462 bool add = true;
464 for (SpellGroupSpellMap::const_iterator itr2 = groupSpell.first; itr2 != groupSpell.second; ++itr2)
465 {
466 if (itr2->second < 0)
467 {
468 SpellGroup currGroup = (SpellGroup)abs(itr2->second);
469 if (IsSpellMemberOfSpellGroup(spellid_1, currGroup) && IsSpellMemberOfSpellGroup(spellid_2, currGroup))
470 {
471 add = false;
472 break;
473 }
474 }
475 }
476 if (add)
477 groups.insert(itr->second);
478 }
479 }
480
482
483 for (std::set<SpellGroup>::iterator itr = groups.begin(); itr!= groups.end(); ++itr)
484 {
485 SpellGroupStackMap::const_iterator found = mSpellGroupStack.find(*itr);
486 if (found != mSpellGroupStack.end())
487 rule = found->second;
488 if (rule)
489 break;
490 }
491 return rule;
492}
493
495{
496 SpellGroupStackMap::const_iterator itr = mSpellGroupStack.find(group);
497 if (itr != mSpellGroupStack.end())
498 return itr->second;
499
501}
502
504{
505 SpellProcEntry const* procEntry = Trinity::Containers::MapGetValuePtr(mSpellProcMap, { spellInfo->Id, spellInfo->Difficulty });
506 if (procEntry)
507 return procEntry;
508
509 if (DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(spellInfo->Difficulty))
510 {
511 do
512 {
513 procEntry = Trinity::Containers::MapGetValuePtr(mSpellProcMap, { spellInfo->Id, Difficulty(difficulty->FallbackDifficultyID) });
514 if (procEntry)
515 return procEntry;
516
517 difficulty = sDifficultyStore.LookupEntry(difficulty->FallbackDifficultyID);
518 } while (difficulty);
519 }
520
521 return nullptr;
522}
523
525{
526 // proc type doesn't match
527 if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags))
528 return false;
529
530 // check XP or honor target requirement
532 if (Player* actor = eventInfo.GetActor()->ToPlayer())
533 if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget()))
534 return false;
535
536 // check power requirement
538 {
539 if (!eventInfo.GetProcSpell())
540 return false;
541
542 std::vector<SpellPowerCost> const& costs = eventInfo.GetProcSpell()->GetPowerCost();
543 if (std::ranges::none_of(costs, [](SpellPowerCost const& cost) { return cost.Amount > 0; }))
544 return false;
545 }
546
547 // always trigger for these types
549 return true;
550
551 // check school mask (if set) for other trigger types
552 if (procEntry.SchoolMask && !(eventInfo.GetSchoolMask() & procEntry.SchoolMask))
553 return false;
554
555 // check spell family name/flags (if set) for spells
556 if (eventInfo.GetTypeMask() & SPELL_PROC_FLAG_MASK)
557 {
558 if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo())
559 if (!eventSpellInfo->IsAffected(procEntry.SpellFamilyName, procEntry.SpellFamilyMask))
560 return false;
561
562 // check spell type mask (if set)
563 if (procEntry.SpellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.SpellTypeMask))
564 return false;
565 }
566
567 // check spell phase mask
569 {
570 if (!(eventInfo.GetSpellPhaseMask() & procEntry.SpellPhaseMask))
571 return false;
572 }
573
574 // check hit mask (on taken hit or on done hit, but not on spell cast phase)
575 if ((eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) || ((eventInfo.GetTypeMask() & DONE_HIT_PROC_FLAG_MASK) && !(eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST)))
576 {
577 uint32 hitMask = procEntry.HitMask;
578 // get default values if hit mask not set
579 if (!hitMask)
580 {
581 // for taken procs allow normal + critical hits by default
582 if (eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK)
584 // for done procs allow normal + critical + absorbs by default
585 else
587 }
588 if (!(eventInfo.GetHitMask() & hitMask))
589 return false;
590 }
591
592 return true;
593}
594
596{
597 SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellID);
598 if (itr != mSpellThreatMap.end())
599 return &itr->second;
600 else
601 {
602 uint32 firstSpell = GetFirstSpellInChain(spellID);
603 itr = mSpellThreatMap.find(firstSpell);
604 if (itr != mSpellThreatMap.end())
605 return &itr->second;
606 }
607 return nullptr;
608}
609
611{
612 return mSkillLineAbilityMap.equal_range(spell_id);
613}
614
615PetAura const* SpellMgr::GetPetAura(uint32 spell_id, uint8 eff) const
616{
617 SpellPetAuraMap::const_iterator itr = mSpellPetAuraMap.find((spell_id<<8) + eff);
618 if (itr != mSpellPetAuraMap.end())
619 return &itr->second;
620 else
621 return nullptr;
622}
623
625{
626 SpellEnchantProcEventMap::const_iterator itr = mSpellEnchantProcEventMap.find(enchId);
627 if (itr != mSpellEnchantProcEventMap.end())
628 return &itr->second;
629 return nullptr;
630}
631
633{
634 if (SpellItemEnchantmentEntry const* enchantment = sSpellItemEnchantmentStore.LookupEntry(ench_id))
635 return enchantment->GetFlags().HasFlag(SpellItemEnchantmentFlags::AllowEnteringArena);
636
637 return false;
638}
639
640std::vector<int32> const* SpellMgr::GetSpellLinked(SpellLinkedType type, uint32 spell_id) const
641{
642 return Trinity::Containers::MapGetValuePtr(mSpellLinkedMap, { type, spell_id });
643}
644
646{
647 PetLevelupSpellMap::const_iterator itr = mPetLevelupSpellMap.find(petFamily);
648 if (itr != mPetLevelupSpellMap.end())
649 return &itr->second;
650 else
651 return nullptr;
652}
653
655{
656 PetDefaultSpellsMap::const_iterator itr = mPetDefaultSpellsMap.find(id);
657 if (itr != mPetDefaultSpellsMap.end())
658 return &itr->second;
659 return nullptr;
660}
661
663{
664 return mSpellAreaMap.equal_range(spell_id);
665}
666
668{
669 return mSpellAreaForQuestMap.equal_range(quest_id);
670}
671
676
678{
679 return mSpellAreaForAuraMap.equal_range(spell_id);
680}
681
683{
684 return mSpellAreaForAreaMap.equal_range(area_id);
685}
686
688{
689 return Trinity::Containers::MapGetValuePtr(mCreatureImmunities, creatureImmunitiesId);
690}
691
692SpellInfo const* SpellMgr::GetSpellInfo(uint32 spellId, Difficulty difficulty) const
693{
694 auto itr = mSpellInfoMap.find(boost::make_tuple(spellId, difficulty));
695 if (itr != mSpellInfoMap.end())
696 return &*itr;
697
698 if (DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty))
699 {
700 do
701 {
702 itr = mSpellInfoMap.find(boost::make_tuple(spellId, Difficulty(difficultyEntry->FallbackDifficultyID)));
703 if (itr != mSpellInfoMap.end())
704 return &*itr;
705
706 difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID);
707 } while (difficultyEntry);
708 }
709
710 return nullptr;
711}
712
714{
715 return Trinity::Containers::MakeIteratorPair(mSpellInfoMap.get<SpellIdIndex>().equal_range(spellId));
716}
717
718void SpellMgr::ForEachSpellInfo(std::function<void(SpellInfo const*)> callback)
719{
720 for (SpellInfo const& spellInfo : mSpellInfoMap)
721 callback(&spellInfo);
722}
723
724void SpellMgr::ForEachSpellInfoDifficulty(uint32 spellId, std::function<void(SpellInfo const*)> callback)
725{
726 for (SpellInfo const& spellInfo : _GetSpellInfo(spellId))
727 callback(&spellInfo);
728}
729
730bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const
731{
732 if (gender != GENDER_NONE) // is not expected gender
733 if (!player || gender != player->GetNativeGender())
734 return false;
735
736 if (!raceMask.IsEmpty()) // is not expected race
737 if (!player || !raceMask.HasRace(player->GetRace()))
738 return false;
739
740 if (areaId) // is not in expected zone
741 if (newZone != areaId && newArea != areaId)
742 return false;
743
744 if (questStart) // is not in expected required quest state
745 if (!player || (((1 << player->GetQuestStatus(questStart)) & questStartStatus) == 0))
746 return false;
747
748 if (questEnd) // is not in expected forbidden quest state
749 if (!player || (((1 << player->GetQuestStatus(questEnd)) & questEndStatus) == 0))
750 return false;
751
752 if (auraSpell) // does not have expected aura
753 if (!player || (auraSpell > 0 && !player->HasAura(auraSpell)) || (auraSpell < 0 && player->HasAura(-auraSpell)))
754 return false;
755
756 // Extra conditions
757 switch (spellId)
758 {
759 case 91604: // No fly Zone - Wintergrasp
760 {
761 if (!player)
762 return false;
763
764 Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetMap(), player->GetZoneId());
766 return false;
767 break;
768 }
769 case 56618: // Horde Controls Factory Phase Shift
770 case 56617: // Alliance Controls Factory Phase Shift
771 {
772 if (!player)
773 return false;
774
775 Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetMap(), player->GetZoneId());
776
777 if (!bf || bf->GetTypeId() != BATTLEFIELD_WG)
778 return false;
779
780 // team that controls the workshop in the specified area
781 uint32 team = bf->GetData(newArea);
782
783 if (team == TEAM_HORDE)
784 return spellId == 56618;
785 else if (team == TEAM_ALLIANCE)
786 return spellId == 56617;
787 break;
788 }
789 case 57940: // Essence of Wintergrasp - Northrend
790 case 58045: // Essence of Wintergrasp - Wintergrasp
791 {
792 if (!player)
793 return false;
794
795 if (Battlefield* battlefieldWG = sBattlefieldMgr->GetBattlefieldByBattleId(player->GetMap(), BATTLEFIELD_BATTLEID_WG))
796 return battlefieldWG->IsEnabled() && (player->GetTeamId() == battlefieldWG->GetDefenderTeam()) && !battlefieldWG->IsWarTime();
797 break;
798 }
799 case 74411: // Battleground - Dampening
800 {
801 if (!player)
802 return false;
803
804 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetMap(), player->GetZoneId()))
805 return bf->IsWarTime();
806 break;
807 }
808
809 }
810
811 return true;
812}
813
815{
816 for (SpellChainMap::iterator itr = mSpellChains.begin(); itr != mSpellChains.end(); ++itr)
817 for (SpellInfo const& spellInfo : _GetSpellInfo(itr->first))
818 const_cast<SpellInfo&>(spellInfo).ChainEntry = nullptr;
819
820 mSpellChains.clear();
821}
822
824{
825 uint32 oldMSTime = getMSTime();
826
827 std::map<uint32 /*spell*/, uint32 /*next*/> chains;
828 std::set<uint32> hasPrev;
829 for (SkillLineAbilityEntry const* skillAbility : sSkillLineAbilityStore)
830 {
831 if (!skillAbility->SupercedesSpell)
832 continue;
833
834 if (!GetSpellInfo(skillAbility->SupercedesSpell, DIFFICULTY_NONE) || !GetSpellInfo(skillAbility->Spell, DIFFICULTY_NONE))
835 continue;
836
837 chains[skillAbility->SupercedesSpell] = skillAbility->Spell;
838 hasPrev.insert(skillAbility->Spell);
839 }
840
841 // each key in chains that isn't present in hasPrev is a first rank
842 for (auto itr = chains.begin(); itr != chains.end(); ++itr)
843 {
844 if (hasPrev.count(itr->first))
845 continue;
846
847 SpellInfo const* first = AssertSpellInfo(itr->first, DIFFICULTY_NONE);
848 SpellInfo const* next = AssertSpellInfo(itr->second, DIFFICULTY_NONE);
849
850 mSpellChains[itr->first].first = first;
851 mSpellChains[itr->first].prev = nullptr;
852 mSpellChains[itr->first].next = next;
853 mSpellChains[itr->first].last = next;
854 mSpellChains[itr->first].rank = 1;
855 for (SpellInfo const& difficultyInfo : _GetSpellInfo(itr->first))
856 const_cast<SpellInfo&>(difficultyInfo).ChainEntry = &mSpellChains[itr->first];
857
858 mSpellChains[itr->second].first = first;
859 mSpellChains[itr->second].prev = first;
860 mSpellChains[itr->second].next = nullptr;
861 mSpellChains[itr->second].last = next;
862 mSpellChains[itr->second].rank = 2;
863 for (SpellInfo const& difficultyInfo : _GetSpellInfo(itr->second))
864 const_cast<SpellInfo&>(difficultyInfo).ChainEntry = &mSpellChains[itr->second];
865
866 uint8 rank = 3;
867 auto nextItr = chains.find(itr->second);
868 while (nextItr != chains.end())
869 {
870 SpellInfo const* prev = AssertSpellInfo(nextItr->first, DIFFICULTY_NONE); // already checked in previous iteration (or above, in case this is the first one)
871 SpellInfo const* last = AssertSpellInfo(nextItr->second, DIFFICULTY_NONE);
872
873 mSpellChains[nextItr->first].next = last;
874
875 mSpellChains[nextItr->second].first = first;
876 mSpellChains[nextItr->second].prev = prev;
877 mSpellChains[nextItr->second].next = nullptr;
878 mSpellChains[nextItr->second].last = last;
879 mSpellChains[nextItr->second].rank = rank++;
880 for (SpellInfo const& difficultyInfo : _GetSpellInfo(nextItr->second))
881 const_cast<SpellInfo&>(difficultyInfo).ChainEntry = &mSpellChains[nextItr->second];
882
883 // fill 'last'
884 do
885 {
886 mSpellChains[prev->Id].last = last;
887 prev = mSpellChains[prev->Id].prev;
888 } while (prev);
889
890 nextItr = chains.find(nextItr->second);
891 }
892 }
893
894 TC_LOG_INFO("server.loading", ">> Loaded {} spell rank records in {} ms", uint32(mSpellChains.size()), GetMSTimeDiffToNow(oldMSTime));
895}
896
898{
899 uint32 oldMSTime = getMSTime();
900
901 mSpellsReqSpell.clear(); // need for reload case
902 mSpellReq.clear(); // need for reload case
903
904 // 0 1
905 QueryResult result = WorldDatabase.Query("SELECT spell_id, req_spell from spell_required");
906
907 if (!result)
908 {
909 TC_LOG_INFO("server.loading", ">> Loaded 0 spell required records. DB table `spell_required` is empty.");
910
911 return;
912 }
913
914 uint32 count = 0;
915 do
916 {
917 Field* fields = result->Fetch();
918
919 uint32 spell_id = fields[0].GetUInt32();
920 uint32 spell_req = fields[1].GetUInt32();
921
922 // check if chain is made with valid first spell
923 SpellInfo const* spell = GetSpellInfo(spell_id, DIFFICULTY_NONE);
924 if (!spell)
925 {
926 TC_LOG_ERROR("sql.sql", "spell_id {} in `spell_required` table could not be found in dbc, skipped.", spell_id);
927 continue;
928 }
929
930 SpellInfo const* reqSpell = GetSpellInfo(spell_req, DIFFICULTY_NONE);
931 if (!reqSpell)
932 {
933 TC_LOG_ERROR("sql.sql", "req_spell {} in `spell_required` table could not be found in dbc, skipped.", spell_req);
934 continue;
935 }
936
937 if (spell->IsRankOf(reqSpell))
938 {
939 TC_LOG_ERROR("sql.sql", "req_spell {} and spell_id {} in `spell_required` table are ranks of the same spell, entry not needed, skipped.", spell_req, spell_id);
940 continue;
941 }
942
943 if (IsSpellRequiringSpell(spell_id, spell_req))
944 {
945 TC_LOG_ERROR("sql.sql", "Duplicate entry of req_spell {} and spell_id {} in `spell_required`, skipped.", spell_req, spell_id);
946 continue;
947 }
948
949 mSpellReq.insert (std::pair<uint32, uint32>(spell_id, spell_req));
950 mSpellsReqSpell.insert (std::pair<uint32, uint32>(spell_req, spell_id));
951 ++count;
952 } while (result->NextRow());
953
954 TC_LOG_INFO("server.loading", ">> Loaded {} spell required records in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
955
956}
957
959{
960 uint32 oldMSTime = getMSTime();
961
962 mSpellLearnSkills.clear(); // need for reload case
963
964 // search auto-learned skills and add its to map also for use in unlearn spells/talents
965 uint32 dbc_count = 0;
966 for (SpellInfo const& entry : mSpellInfoMap)
967 {
968 if (entry.Difficulty != DIFFICULTY_NONE)
969 continue;
970
971 for (SpellEffectInfo const& spellEffectInfo : entry.GetEffects())
972 {
973 SpellLearnSkillNode dbc_node;
974 switch (spellEffectInfo.Effect)
975 {
977 dbc_node.skill = uint16(spellEffectInfo.MiscValue);
978 dbc_node.step = uint16(spellEffectInfo.CalcValueAsInt());
979 dbc_node.value = 0;
980 dbc_node.maxvalue = 0;
981 break;
983 dbc_node.skill = SKILL_DUAL_WIELD;
984 dbc_node.step = 1;
985 dbc_node.value = 1;
986 dbc_node.maxvalue = 1;
987 break;
988 default:
989 continue;
990 }
991
992 mSpellLearnSkills[entry.Id] = dbc_node;
993 ++dbc_count;
994 break;
995 }
996 }
997
998 TC_LOG_INFO("server.loading", ">> Loaded {} Spell Learn Skills from DBC in {} ms", dbc_count, GetMSTimeDiffToNow(oldMSTime));
999}
1000
1002{
1003 uint32 oldMSTime = getMSTime();
1004
1005 mSpellLearnedBySpells.clear();
1006 mSpellLearnSpells.clear(); // need for reload case
1007
1008 // 0 1 2
1009 QueryResult result = WorldDatabase.Query("SELECT entry, SpellID, Active FROM spell_learn_spell");
1010 if (!result)
1011 {
1012 TC_LOG_INFO("server.loading", ">> Loaded 0 spell learn spells. DB table `spell_learn_spell` is empty.");
1013 return;
1014 }
1015
1016 uint32 count = 0;
1017 do
1018 {
1019 Field* fields = result->Fetch();
1020
1021 uint32 spell_id = fields[0].GetUInt32();
1022
1024 node.SourceSpell = spell_id;
1025 node.Spell = fields[1].GetUInt32();
1026 node.OverridesSpell = 0;
1027 node.Active = fields[2].GetBool();
1028 node.AutoLearned = false;
1029
1030 SpellInfo const* spellInfo = GetSpellInfo(spell_id, DIFFICULTY_NONE);
1031 if (!spellInfo)
1032 {
1033 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_learn_spell` does not exist.", spell_id);
1034 continue;
1035 }
1036
1038 {
1039 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_learn_spell` learning non-existing spell {}.", spell_id, node.Spell);
1040 continue;
1041 }
1042
1043 if (spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT))
1044 {
1045 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_learn_spell` attempts learning talent spell {}, skipped.", spell_id, node.Spell);
1046 continue;
1047 }
1048
1049 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell_id, node));
1050
1051 ++count;
1052 } while (result->NextRow());
1053
1054 // copy state loaded from db
1055 SpellLearnSpellMap dbSpellLearnSpells = mSpellLearnSpells;
1056
1057 // search auto-learned spells and add its to map also for use in unlearn spells/talents
1058 uint32 dbc_count = 0;
1059 for (SpellInfo const& entry : mSpellInfoMap)
1060 {
1061 if (entry.Difficulty != DIFFICULTY_NONE)
1062 continue;
1063
1064 for (SpellEffectInfo const& spellEffectInfo : entry.GetEffects())
1065 {
1066 if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL))
1067 {
1068 SpellLearnSpellNode dbc_node;
1069 dbc_node.SourceSpell = entry.Id;
1070 dbc_node.Spell = spellEffectInfo.TriggerSpell;
1071 dbc_node.Active = true; // all dbc based learned spells is active (show in spell book or hide by client itself)
1072 dbc_node.OverridesSpell = 0;
1073
1074 // ignore learning not existed spells (broken/outdated/or generic learnig spell 483
1075 if (!GetSpellInfo(dbc_node.Spell, DIFFICULTY_NONE))
1076 continue;
1077
1078 // talent or passive spells or skill-step spells auto-cast and not need dependent learning,
1079 // pet teaching spells must not be dependent learning (cast)
1080 // other required explicit dependent learning
1081 dbc_node.AutoLearned = spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET || entry.HasAttribute(SPELL_ATTR0_CU_IS_TALENT) || entry.IsPassive() || entry.HasEffect(SPELL_EFFECT_SKILL_STEP);
1082
1083 SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(entry.Id);
1084
1085 bool found = false;
1086 for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
1087 {
1088 if (itr->second.Spell == dbc_node.Spell)
1089 {
1090 TC_LOG_ERROR("sql.sql", "The spell {} is an auto-learn spell {} in spell.dbc and the record in `spell_learn_spell` is redundant. Please update your DB.",
1091 entry.Id, dbc_node.Spell);
1092 found = true;
1093 break;
1094 }
1095 }
1096
1097 if (!found) // add new spell-spell pair if not found
1098 {
1099 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(entry.Id, dbc_node));
1100 ++dbc_count;
1101 }
1102 }
1103 }
1104 }
1105
1106 for (SpellLearnSpellEntry const* spellLearnSpell : sSpellLearnSpellStore)
1107 {
1108 if (!GetSpellInfo(spellLearnSpell->SpellID, DIFFICULTY_NONE) ||
1109 !GetSpellInfo(spellLearnSpell->LearnSpellID, DIFFICULTY_NONE))
1110 continue;
1111
1112 SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(spellLearnSpell->SpellID);
1113 bool found = false;
1114 for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
1115 {
1116 if (int32(itr->second.Spell) == spellLearnSpell->LearnSpellID)
1117 {
1118 TC_LOG_ERROR("sql.sql", "Found redundant record (entry: {}, SpellID: {}) in `spell_learn_spell`, spell added automatically from SpellLearnSpell.db2", spellLearnSpell->SpellID, spellLearnSpell->LearnSpellID);
1119 found = true;
1120 break;
1121 }
1122 }
1123
1124 if (found)
1125 continue;
1126
1127 // Check if it is already found in Spell.dbc, ignore silently if yes
1128 SpellLearnSpellMapBounds dbc_node_bounds = GetSpellLearnSpellMapBounds(spellLearnSpell->SpellID);
1129 found = false;
1130 for (SpellLearnSpellMap::const_iterator itr = dbc_node_bounds.first; itr != dbc_node_bounds.second; ++itr)
1131 {
1132 if (int32(itr->second.Spell) == spellLearnSpell->LearnSpellID)
1133 {
1134 found = true;
1135 break;
1136 }
1137 }
1138
1139 if (found)
1140 continue;
1141
1142 SpellLearnSpellNode dbcLearnNode;
1143 dbcLearnNode.SourceSpell = spellLearnSpell->SpellID;
1144 dbcLearnNode.Spell = spellLearnSpell->LearnSpellID;
1145 dbcLearnNode.OverridesSpell = spellLearnSpell->OverridesSpellID;
1146 dbcLearnNode.Active = true;
1147 dbcLearnNode.AutoLearned = false;
1148
1149 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spellLearnSpell->SpellID, dbcLearnNode));
1150 ++dbc_count;
1151 }
1152
1153 for (auto const& [spellId, learnedSpellNode] : mSpellLearnSpells)
1154 mSpellLearnedBySpells.emplace(learnedSpellNode.Spell, &learnedSpellNode);
1155
1156 TC_LOG_INFO("server.loading", ">> Loaded {} spell learn spells, {} found in Spell.dbc in {} ms", count, dbc_count, GetMSTimeDiffToNow(oldMSTime));
1157}
1158
1160{
1161 uint32 oldMSTime = getMSTime();
1162
1163 mSpellTargetPositions.clear(); // need for reload case
1164
1165 // 0 1 2 3 4 5 6 7
1166 QueryResult result = WorldDatabase.Query("SELECT ID, EffectIndex, OrderIndex, MapID, PositionX, PositionY, PositionZ, Orientation FROM spell_target_position");
1167 if (!result)
1168 {
1169 TC_LOG_INFO("server.loading", ">> Loaded 0 spell target coordinates. DB table `spell_target_position` is empty.");
1170 return;
1171 }
1172
1173 do
1174 {
1175 Field* fields = result->Fetch();
1176
1177 uint32 spellId = fields[0].GetUInt32();
1178 SpellEffIndex effIndex = SpellEffIndex(fields[1].GetUInt8());
1179
1180 SpellTargetPosition st(fields[3].GetUInt16(), fields[4].GetFloat(), fields[5].GetFloat(), fields[6].GetFloat());
1181
1182 MapEntry const* mapEntry = sMapStore.LookupEntry(st.GetMapId());
1183 if (!mapEntry)
1184 {
1185 TC_LOG_ERROR("sql.sql", "Spell (Id: {}, EffectIndex: {}) is using a non-existant MapID (ID: {}).", spellId, uint32(effIndex), st.GetMapId());
1186 continue;
1187 }
1188
1189 if (st.GetPositionX() == 0 && st.GetPositionY() == 0 && st.GetPositionZ() == 0)
1190 {
1191 TC_LOG_ERROR("sql.sql", "Spell (Id: {}, EffectIndex: {}): target coordinates not provided.", spellId, uint32(effIndex));
1192 continue;
1193 }
1194
1195 SpellInfo const* spellInfo = GetSpellInfo(spellId, DIFFICULTY_NONE);
1196 if (!spellInfo)
1197 {
1198 TC_LOG_ERROR("sql.sql", "Spell (Id: {}) listed in `spell_target_position` does not exist.", spellId);
1199 continue;
1200 }
1201
1202 if (effIndex >= spellInfo->GetEffects().size())
1203 {
1204 TC_LOG_ERROR("sql.sql", "Spell (Id: {}, EffectIndex: {}) listed in `spell_target_position` does not have an effect at index {}.", spellId, uint32(effIndex), uint32(effIndex));
1205 continue;
1206 }
1207
1208 SpellEffectInfo const& spellEffectInfo = spellInfo->GetEffect(effIndex);
1209 if (Optional<float> orientiation = fields[7].GetFloatOrNull())
1210 st.SetOrientation(*orientiation);
1211 else
1212 {
1213 // target facing is in degrees for 6484 & 9268...
1214 if (spellEffectInfo.PositionFacing > 2 * float(M_PI))
1215 st.SetOrientation(spellEffectInfo.PositionFacing * float(M_PI) / 180);
1216 else
1217 st.SetOrientation(spellEffectInfo.PositionFacing);
1218 }
1219
1220 auto hasTarget = [&](Targets target)
1221 {
1222 return spellEffectInfo.TargetA.GetTarget() == target || spellEffectInfo.TargetB.GetTarget() == target;
1223 };
1224
1225 if (!hasTarget(TARGET_DEST_NEARBY_DB))
1226 {
1227 if (!hasTarget(TARGET_DEST_DB) && !hasTarget(TARGET_DEST_NEARBY_ENTRY_OR_DB))
1228 {
1229 TC_LOG_ERROR("sql.sql", "Spell (Id: {}, effIndex: {}) listed in `spell_target_position` does not have a target TARGET_DEST_DB ({}) or TARGET_DEST_NEARBY_DB ({}) or TARGET_DEST_NEARBY_ENTRY_OR_DB ({}).",
1231 continue;
1232 }
1233 if (fields[2].GetInt32() != 0)
1234 {
1235 TC_LOG_ERROR("sql.sql", "Spell (Id: {}, effIndex: {}) listed in `spell_target_position` does not have a target TARGET_DEST_NEARBY_DB ({}) but lists multiple points, only one is allowed.",
1236 spellId, uint32(effIndex), TARGET_DEST_NEARBY_DB);
1237 continue;
1238 }
1239 }
1240
1241 mSpellTargetPositions.emplace(std::make_pair(spellId, effIndex), st);
1242
1243 } while (result->NextRow());
1244
1245 /*
1246 // Check all spells
1247 for (SpellInfo const& spellInfo : mSpellInfoMap)
1248 {
1249 if (spellInfo.Difficulty != DIFFICULTY_NONE)
1250 continue;
1251
1252 for (SpellEffectInfo const& effect : spellInfo.GetEffects())
1253 {
1254 if (effect.TargetA.GetTarget() != TARGET_DEST_DB && effect.TargetB.GetTarget() != TARGET_DEST_DB)
1255 continue;
1256
1257 if (!GetSpellTargetPosition(spellInfo.Id, effect.EffectIndex))
1258 TC_LOG_DEBUG("spells", "Spell (Id: {}, EffectIndex: {}) does not have record in `spell_target_position`.", spellInfo.Id, effect.EffectIndex);
1259 }
1260 }
1261 */
1262
1263 TC_LOG_INFO("server.loading", ">> Loaded {} spell teleport coordinates in {} ms", mSpellTargetPositions.size(), GetMSTimeDiffToNow(oldMSTime));
1264}
1265
1267{
1268 uint32 oldMSTime = getMSTime();
1269
1270 mSpellSpellGroup.clear(); // need for reload case
1271 mSpellGroupSpell.clear();
1272
1273 // 0 1
1274 QueryResult result = WorldDatabase.Query("SELECT id, spell_id FROM spell_group");
1275 if (!result)
1276 {
1277 TC_LOG_INFO("server.loading", ">> Loaded 0 spell group definitions. DB table `spell_group` is empty.");
1278 return;
1279 }
1280
1281 std::set<uint32> groups;
1282 uint32 count = 0;
1283 do
1284 {
1285 Field* fields = result->Fetch();
1286
1287 uint32 group_id = fields[0].GetUInt32();
1288 if (group_id <= SPELL_GROUP_DB_RANGE_MIN && group_id >= SPELL_GROUP_CORE_RANGE_MAX)
1289 {
1290 TC_LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` is in core range, but is not defined in core!", group_id);
1291 continue;
1292 }
1293 int32 spell_id = fields[1].GetInt32();
1294
1295 groups.insert(group_id);
1296 mSpellGroupSpell.emplace(SpellGroup(group_id), spell_id);
1297
1298 } while (result->NextRow());
1299
1300 for (auto itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
1301 {
1302 if (itr->second < 0)
1303 {
1304 if (groups.find(abs(itr->second)) == groups.end())
1305 {
1306 TC_LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` does not exist", abs(itr->second));
1307 itr = mSpellGroupSpell.erase(itr);
1308 }
1309 else
1310 ++itr;
1311 }
1312 else
1313 {
1314 SpellInfo const* spellInfo = GetSpellInfo(itr->second, DIFFICULTY_NONE);
1315 if (!spellInfo)
1316 {
1317 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_group` does not exist", itr->second);
1318 itr = mSpellGroupSpell.erase(itr);
1319 }
1320 else if (spellInfo->GetRank() > 1)
1321 {
1322 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_group` is not the first rank of the spell.", itr->second);
1323 itr = mSpellGroupSpell.erase(itr);
1324 }
1325 else
1326 ++itr;
1327 }
1328 }
1329
1330 for (auto groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
1331 {
1332 std::set<uint32> spells;
1333 GetSetOfSpellsInSpellGroup(SpellGroup(*groupItr), spells);
1334
1335 for (auto spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
1336 {
1337 ++count;
1338 mSpellSpellGroup.emplace(*spellItr, SpellGroup(*groupItr));
1339 }
1340 }
1341
1342 TC_LOG_INFO("server.loading", ">> Loaded {} spell group definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1343}
1344
1346{
1347 uint32 oldMSTime = getMSTime();
1348
1349 mSpellGroupStack.clear(); // need for reload case
1350 mSpellSameEffectStack.clear();
1351
1352 std::vector<uint32> sameEffectGroups;
1353
1354 // 0 1
1355 QueryResult result = WorldDatabase.Query("SELECT group_id, stack_rule FROM spell_group_stack_rules");
1356 if (!result)
1357 {
1358 TC_LOG_INFO("server.loading", ">> Loaded 0 spell group stack rules. DB table `spell_group_stack_rules` is empty.");
1359 return;
1360 }
1361
1362 uint32 count = 0;
1363 do
1364 {
1365 Field* fields = result->Fetch();
1366
1367 uint32 group_id = fields[0].GetUInt32();
1368 uint8 stack_rule = fields[1].GetInt8();
1369 if (stack_rule >= SPELL_GROUP_STACK_RULE_MAX)
1370 {
1371 TC_LOG_ERROR("sql.sql", "SpellGroupStackRule {} listed in `spell_group_stack_rules` does not exist.", stack_rule);
1372 continue;
1373 }
1374
1375 auto bounds = GetSpellGroupSpellMapBounds((SpellGroup)group_id);
1376 if (bounds.first == bounds.second)
1377 {
1378 TC_LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group_stack_rules` does not exist.", group_id);
1379 continue;
1380 }
1381
1382 mSpellGroupStack.emplace(SpellGroup(group_id), SpellGroupStackRule(stack_rule));
1383
1384 // different container for same effect stack rules, need to check effect types
1386 sameEffectGroups.push_back(group_id);
1387
1388 ++count;
1389 } while (result->NextRow());
1390
1391 TC_LOG_INFO("server.loading", ">> Loaded {} spell group stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1392
1393 count = 0;
1394 oldMSTime = getMSTime();
1395 TC_LOG_INFO("server.loading", ">> Parsing SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules...");
1396
1397 for (uint32 group_id : sameEffectGroups)
1398 {
1399 std::set<uint32> spellIds;
1400 GetSetOfSpellsInSpellGroup(SpellGroup(group_id), spellIds);
1401
1402 std::unordered_set<uint32> auraTypes;
1403
1404 // we have to 'guess' what effect this group corresponds to
1405 {
1406 std::unordered_multiset<uint32 /*auraName*/> frequencyContainer;
1407
1408 // only waylay for the moment (shared group)
1409 std::vector<std::vector<uint32 /*auraName*/>> const SubGroups =
1410 {
1412 };
1413
1414 for (uint32 spellId : spellIds)
1415 {
1416 SpellInfo const* spellInfo = AssertSpellInfo(spellId, DIFFICULTY_NONE);
1417 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1418 {
1419 if (!spellEffectInfo.IsAura())
1420 continue;
1421
1422 uint32 auraName = spellEffectInfo.ApplyAuraName;
1423 for (std::vector<uint32> const& subGroup : SubGroups)
1424 {
1425 if (std::find(subGroup.begin(), subGroup.end(), auraName) != subGroup.end())
1426 {
1427 // count as first aura
1428 auraName = subGroup.front();
1429 break;
1430 }
1431 }
1432
1433 frequencyContainer.insert(auraName);
1434 }
1435 }
1436
1437 uint32 auraType = 0;
1438 size_t auraTypeCount = 0;
1439 for (uint32 auraName : frequencyContainer)
1440 {
1441 size_t currentCount = frequencyContainer.count(auraName);
1442 if (currentCount > auraTypeCount)
1443 {
1444 auraType = auraName;
1445 auraTypeCount = currentCount;
1446 }
1447 }
1448
1449 for (std::vector<uint32> const& subGroup : SubGroups)
1450 {
1451 if (auraType == subGroup.front())
1452 {
1453 auraTypes.insert(subGroup.begin(), subGroup.end());
1454 break;
1455 }
1456 }
1457
1458 if (auraTypes.empty())
1459 auraTypes.insert(auraType);
1460 }
1461
1462 // re-check spells against guessed group
1463 for (uint32 spellId : spellIds)
1464 {
1465 SpellInfo const* spellInfo = AssertSpellInfo(spellId, DIFFICULTY_NONE);
1466
1467 bool found = false;
1468 while (spellInfo)
1469 {
1470 for (uint32 auraType : auraTypes)
1471 {
1472 if (spellInfo->HasAura(AuraType(auraType)))
1473 {
1474 found = true;
1475 break;
1476 }
1477 }
1478
1479 if (found)
1480 break;
1481
1482 spellInfo = spellInfo->GetNextRankSpell();
1483 }
1484
1485 // not found either, log error
1486 if (!found)
1487 TC_LOG_ERROR("sql.sql", "SpellId {} listed in `spell_group` with stack rule 3 does not share aura assigned for group {}", spellId, group_id);
1488 }
1489
1490 mSpellSameEffectStack[SpellGroup(group_id)] = auraTypes;
1491 ++count;
1492 }
1493
1494 TC_LOG_INFO("server.loading", ">> Parsed {} SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1495}
1496
1498{
1499 uint32 oldMSTime = getMSTime();
1500
1501 mSpellProcMap.clear(); // need for reload case
1502
1503 // 0 1 2 3 4 5 6
1504 QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, SpellFamilyMask3, "
1505 // 7 8 9 10 11 12 13 14 15 16 17
1506 "ProcFlags, ProcFlags2, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, DisableEffectsMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
1507
1508 uint32 count = 0;
1509 if (result)
1510 {
1511 do
1512 {
1513 Field* fields = result->Fetch();
1514
1515 int32 spellId = fields[0].GetInt32();
1516
1517 bool allRanks = false;
1518 if (spellId < 0)
1519 {
1520 allRanks = true;
1521 spellId = -spellId;
1522 }
1523
1524 SpellInfo const* spellInfo = GetSpellInfo(spellId, DIFFICULTY_NONE);
1525 if (!spellInfo)
1526 {
1527 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` does not exist", spellId);
1528 continue;
1529 }
1530
1531 if (allRanks)
1532 {
1533 if (!spellInfo->IsRanked())
1534 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` with all ranks, but spell has no ranks.", spellId);
1535
1536 if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
1537 {
1538 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` is not the first rank of the spell.", spellId);
1539 continue;
1540 }
1541 }
1542
1543 SpellProcEntry baseProcEntry;
1544
1545 baseProcEntry.SchoolMask = fields[1].GetUInt8();
1546 baseProcEntry.SpellFamilyName = fields[2].GetUInt16();
1547 baseProcEntry.SpellFamilyMask[0] = fields[3].GetUInt32();
1548 baseProcEntry.SpellFamilyMask[1] = fields[4].GetUInt32();
1549 baseProcEntry.SpellFamilyMask[2] = fields[5].GetUInt32();
1550 baseProcEntry.SpellFamilyMask[3] = fields[6].GetUInt32();
1551 baseProcEntry.ProcFlags[0] = fields[7].GetUInt32();
1552 baseProcEntry.ProcFlags[1] = fields[8].GetUInt32();
1553 baseProcEntry.SpellTypeMask = ProcFlagsSpellType(fields[9].GetUInt32());
1554 baseProcEntry.SpellPhaseMask = ProcFlagsSpellPhase(fields[10].GetUInt32());
1555 baseProcEntry.HitMask = ProcFlagsHit(fields[11].GetUInt32());
1556 baseProcEntry.AttributesMask = ProcAttributes(fields[12].GetUInt32());
1557 baseProcEntry.DisableEffectsMask = fields[13].GetUInt32();
1558 baseProcEntry.ProcsPerMinute = fields[14].GetFloat();
1559 baseProcEntry.Chance = fields[15].GetFloat();
1560 baseProcEntry.Cooldown = Milliseconds(fields[16].GetUInt32());
1561 baseProcEntry.Charges = fields[17].GetUInt8();
1562
1563 while (spellInfo)
1564 {
1565 if (mSpellProcMap.find({ spellInfo->Id, spellInfo->Difficulty }) != mSpellProcMap.end())
1566 {
1567 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` already has its first rank in the table.", spellInfo->Id);
1568 break;
1569 }
1570
1571 SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
1572
1573 // take defaults from dbcs
1574 if (!procEntry.ProcFlags)
1575 procEntry.ProcFlags = spellInfo->ProcFlags;
1576 if (!procEntry.Charges)
1577 procEntry.Charges = spellInfo->ProcCharges;
1578 if (!procEntry.Chance && !procEntry.ProcsPerMinute)
1579 procEntry.Chance = float(spellInfo->ProcChance);
1580 if (procEntry.Cooldown == Milliseconds::zero())
1581 procEntry.Cooldown = Milliseconds(spellInfo->ProcCooldown);
1582
1583 // validate data
1584 if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL)
1585 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `SchoolMask` set: {}", spellInfo->Id, procEntry.SchoolMask);
1587 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `SpellFamilyName` set: {}", spellInfo->Id, procEntry.SpellFamilyName);
1588 if (procEntry.Chance < 0)
1589 {
1590 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in the `Chance` field", spellInfo->Id);
1591 procEntry.Chance = 0;
1592 }
1593 if (procEntry.ProcsPerMinute < 0)
1594 {
1595 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in the `ProcsPerMinute` field", spellInfo->Id);
1596 procEntry.ProcsPerMinute = 0;
1597 }
1598 if (!procEntry.ProcFlags)
1599 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} doesn't have any `ProcFlags` value defined, proc will not be triggered.", spellInfo->Id);
1600 if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
1601 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `SpellTypeMask` set: {}", spellInfo->Id, procEntry.SpellTypeMask);
1602 if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & SPELL_PROC_FLAG_MASK))
1603 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has `SpellTypeMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
1604 if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
1605 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} doesn't have any `SpellPhaseMask` value defined, but it is required for the defined `ProcFlags` value. Proc will not be triggered.", spellInfo->Id);
1607 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has wrong `SpellPhaseMask` set: {}", spellInfo->Id, procEntry.SpellPhaseMask);
1608 if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
1609 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has a `SpellPhaseMask` value defined, but it will not be used for the defined `ProcFlags` value.", spellInfo->Id);
1611 procEntry.SpellPhaseMask = PROC_SPELL_PHASE_CAST; // set default phase for PROC_FLAG_2_CAST_SUCCESSFUL
1612 if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
1613 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has wrong `HitMask` set: {}", spellInfo->Id, procEntry.HitMask);
1614 if (procEntry.HitMask && !(procEntry.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.ProcFlags & DONE_HIT_PROC_FLAG_MASK && (!procEntry.SpellPhaseMask || procEntry.SpellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
1615 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has `HitMask` value defined, but it will not be used for defined `ProcFlags` and `SpellPhaseMask` values.", spellInfo->Id);
1616 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1617 if ((procEntry.DisableEffectsMask & (1u << spellEffectInfo.EffectIndex)) && !spellEffectInfo.IsAura())
1618 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has DisableEffectsMask with effect {}, but effect {} is not an aura effect", spellInfo->Id, static_cast<uint32>(spellEffectInfo.EffectIndex), static_cast<uint32>(spellEffectInfo.EffectIndex));
1619 if (procEntry.AttributesMask & PROC_ATTR_REQ_SPELLMOD)
1620 {
1621 bool found = false;
1622 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1623 {
1624 if (!spellEffectInfo.IsAura())
1625 continue;
1626
1627 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_ADD_PCT_MODIFIER || spellEffectInfo.ApplyAuraName == SPELL_AURA_ADD_FLAT_MODIFIER
1628 || spellEffectInfo.ApplyAuraName == SPELL_AURA_ADD_PCT_MODIFIER_BY_SPELL_LABEL || spellEffectInfo.ApplyAuraName == SPELL_AURA_ADD_FLAT_MODIFIER_BY_SPELL_LABEL
1629 || spellEffectInfo.ApplyAuraName == SPELL_AURA_IGNORE_SPELL_COOLDOWN)
1630 {
1631 found = true;
1632 break;
1633 }
1634 }
1635
1636 if (!found)
1637 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has Attribute PROC_ATTR_REQ_SPELLMOD, but spell has no spell mods. Proc will not be triggered", spellInfo->Id);
1638 }
1639 if (procEntry.AttributesMask & ~PROC_ATTR_ALL_ALLOWED)
1640 {
1641 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has `AttributesMask` value specifying invalid attributes 0x{:02X}.", spellInfo->Id, procEntry.AttributesMask & ~PROC_ATTR_ALL_ALLOWED);
1643 }
1644
1645 mSpellProcMap[{ spellInfo->Id, spellInfo->Difficulty }] = procEntry;
1646
1647 if (allRanks)
1648 spellInfo = spellInfo->GetNextRankSpell();
1649 else
1650 break;
1651 }
1652 ++count;
1653 } while (result->NextRow());
1654 }
1655 else
1656 TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty.");
1657
1658 TC_LOG_INFO("server.loading", ">> Loaded {} spell proc conditions and data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1659
1660 // Define can trigger auras
1661 bool isTriggerAura[TOTAL_AURAS];
1662 // Triggered always, even from triggered spells
1663 bool isAlwaysTriggeredAura[TOTAL_AURAS];
1664 // SpellTypeMask to add to the proc
1665 ProcFlagsSpellType spellTypeMask[TOTAL_AURAS];
1666
1667 // List of auras that CAN trigger but may not exist in spell_proc
1668 // in most cases needed to drop charges
1669
1670 // some aura types need additional checks (eg SPELL_AURA_MECHANIC_IMMUNITY needs mechanic check)
1671 // see AuraEffect::CheckEffectProc
1672 for (uint16 i = 0; i < TOTAL_AURAS; ++i)
1673 {
1674 isTriggerAura[i] = false;
1675 isAlwaysTriggeredAura[i] = false;
1676 spellTypeMask[i] = PROC_SPELL_TYPE_MASK_ALL;
1677 }
1678
1679 isTriggerAura[SPELL_AURA_DUMMY] = true;
1680 isTriggerAura[SPELL_AURA_PERIODIC_DUMMY] = true;
1681 isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true;
1682 isTriggerAura[SPELL_AURA_MOD_THREAT] = true;
1683 isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger
1684 isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
1685 isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
1686 isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
1687 isTriggerAura[SPELL_AURA_MOD_STEALTH] = true;
1688 isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger
1689 isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
1690 isTriggerAura[SPELL_AURA_TRANSFORM] = true;
1691 isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
1692 isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
1693 isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
1694 isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
1695 isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true;
1696 isTriggerAura[SPELL_AURA_SCHOOL_ABSORB] = true; // Savage Defense untested
1697 isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
1698 isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
1699 isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
1700 isTriggerAura[SPELL_AURA_MECHANIC_IMMUNITY] = true;
1701 isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
1702 isTriggerAura[SPELL_AURA_SPELL_MAGNET] = true;
1703 isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
1704 isTriggerAura[SPELL_AURA_MOD_POWER_REGEN_PERCENT] = true;
1705 isTriggerAura[SPELL_AURA_INTERCEPT_MELEE_RANGED_ATTACKS] = true;
1706 isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
1707 isTriggerAura[SPELL_AURA_MOD_MECHANIC_RESISTANCE] = true;
1709 isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true;
1710 isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE_3] = true;
1711 isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true;
1712 isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
1714 isTriggerAura[SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER] = true;
1715 isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
1716 isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true;
1717 isTriggerAura[SPELL_AURA_MOD_INVISIBILITY] = true;
1718 isTriggerAura[SPELL_AURA_FORCE_REACTION] = true;
1719 isTriggerAura[SPELL_AURA_MOD_TAUNT] = true;
1720 isTriggerAura[SPELL_AURA_MOD_DETAUNT] = true;
1721 isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_DONE] = true;
1722 isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER_PCT] = true;
1723 isTriggerAura[SPELL_AURA_MOD_HIT_CHANCE] = true;
1724 isTriggerAura[SPELL_AURA_MOD_WEAPON_CRIT_PERCENT] = true;
1725 isTriggerAura[SPELL_AURA_MOD_BLOCK_PERCENT] = true;
1726 isTriggerAura[SPELL_AURA_MOD_ROOT_2] = true;
1727 isTriggerAura[SPELL_AURA_IGNORE_SPELL_COOLDOWN] = true;
1728
1729 isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
1730 isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
1731 isAlwaysTriggeredAura[SPELL_AURA_MOD_CONFUSE] = true;
1732 isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true;
1733 isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true;
1734 isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true;
1735 isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true;
1736 isAlwaysTriggeredAura[SPELL_AURA_MOD_INVISIBILITY] = true;
1737 isAlwaysTriggeredAura[SPELL_AURA_SPELL_MAGNET] = true;
1738 isAlwaysTriggeredAura[SPELL_AURA_SCHOOL_ABSORB] = true;
1739 isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
1740 isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT_2] = true;
1741
1750
1751 // This generates default procs to retain compatibility with previous proc system
1752 TC_LOG_INFO("server.loading", "Generating spell proc data from SpellMap...");
1753 count = 0;
1754 oldMSTime = getMSTime();
1755
1756 std::unordered_map<std::pair<uint32, Difficulty>, SpellProcEntry> generatedSpellProcMap;
1757
1758 for (SpellInfo const& spellInfo : mSpellInfoMap)
1759 {
1760 // Data already present in DB, overwrites default proc
1761 if (GetSpellProcEntry(&spellInfo) != nullptr)
1762 continue;
1763
1764 // Nothing to do if no flags set
1765 if (!spellInfo.ProcFlags)
1766 continue;
1767
1768 bool addTriggerFlag = false;
1769 ProcFlagsSpellType procSpellTypeMask = PROC_SPELL_TYPE_NONE;
1770 uint32 nonProcMask = 0;
1771 for (SpellEffectInfo const& spellEffectInfo : spellInfo.GetEffects())
1772 {
1773 if (!spellEffectInfo.IsEffect())
1774 continue;
1775
1776 uint32 auraName = spellEffectInfo.ApplyAuraName;
1777 if (!auraName)
1778 continue;
1779
1780 if (!isTriggerAura[auraName])
1781 {
1782 // explicitly disable non proccing auras to avoid losing charges on self proc
1783 nonProcMask |= 1 << spellEffectInfo.EffectIndex;
1784 continue;
1785 }
1786
1787 procSpellTypeMask |= spellTypeMask[auraName];
1788 if (isAlwaysTriggeredAura[auraName])
1789 addTriggerFlag = true;
1790
1791 // many proc auras with taken procFlag mask don't have attribute "can proc with triggered"
1792 // they should proc nevertheless (example mage armor spells with judgement)
1793 if (!addTriggerFlag && (spellInfo.ProcFlags & TAKEN_HIT_PROC_FLAG_MASK) != 0)
1794 {
1795 switch (auraName)
1796 {
1799 addTriggerFlag = true;
1800 break;
1801 default:
1802 break;
1803 }
1804 }
1805 }
1806
1807 if (!procSpellTypeMask)
1808 {
1809 for (SpellEffectInfo const& spellEffectInfo : spellInfo.GetEffects())
1810 {
1811 if (spellEffectInfo.IsAura())
1812 {
1813 TC_LOG_ERROR("sql.sql", "Spell Id {} has DBC ProcFlags 0x{:X} 0x{:X}, but it's of non-proc aura type, it probably needs an entry in `spell_proc` table to be handled correctly.",
1814 spellInfo.Id, uint32(spellInfo.ProcFlags[0]), uint32(spellInfo.ProcFlags[1]));
1815 break;
1816 }
1817 }
1818
1819 continue;
1820 }
1821
1822 SpellProcEntry procEntry;
1823 procEntry.SchoolMask = 0;
1824 procEntry.ProcFlags = spellInfo.ProcFlags;
1825 procEntry.SpellFamilyName = 0;
1826 for (SpellEffectInfo const& spellEffectInfo : spellInfo.GetEffects())
1827 if (spellEffectInfo.IsEffect() && isTriggerAura[spellEffectInfo.ApplyAuraName])
1828 procEntry.SpellFamilyMask |= spellEffectInfo.SpellClassMask;
1829
1830 if (procEntry.SpellFamilyMask)
1831 procEntry.SpellFamilyName = spellInfo.SpellFamilyName;
1832
1833 procEntry.SpellTypeMask = procSpellTypeMask;
1835 procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent
1836
1838 procEntry.SpellPhaseMask = PROC_SPELL_PHASE_CAST; // set default phase for PROC_FLAG_2_CAST_SUCCESSFUL
1839
1840 bool triggersSpell = false;
1841 for (SpellEffectInfo const& spellEffectInfo : spellInfo.GetEffects())
1842 {
1843 if (!spellEffectInfo.IsAura())
1844 continue;
1845
1846 switch (spellEffectInfo.ApplyAuraName)
1847 {
1848 // Reflect auras should only proc off reflects
1851 procEntry.HitMask = PROC_HIT_REFLECT;
1852 break;
1853 // Only drop charge on crit
1855 procEntry.HitMask = PROC_HIT_CRITICAL;
1856 break;
1857 // Only drop charge on block
1859 procEntry.HitMask = PROC_HIT_BLOCK;
1860 break;
1861 // proc auras with another aura reducing hit chance (eg 63767) only proc on missed attack
1863 if (spellEffectInfo.CalcValueAsInt() <= -100)
1864 procEntry.HitMask = PROC_HIT_MISS;
1865 break;
1868 triggersSpell = spellEffectInfo.TriggerSpell != 0;
1869 break;
1870 default:
1871 continue;
1872 }
1873 break;
1874 }
1875
1876 procEntry.AttributesMask = PROC_ATTR_NONE;
1877 procEntry.DisableEffectsMask = nonProcMask;
1878 if (spellInfo.ProcFlags & PROC_FLAG_KILL)
1880 if (addTriggerFlag)
1882
1883 procEntry.ProcsPerMinute = 0;
1884 procEntry.Chance = spellInfo.ProcChance;
1885 procEntry.Cooldown = Milliseconds(spellInfo.ProcCooldown);
1886 procEntry.Charges = spellInfo.ProcCharges;
1887
1888 if (spellInfo.HasAttribute(SPELL_ATTR3_CAN_PROC_FROM_PROCS) && !procEntry.SpellFamilyMask
1889 && procEntry.Chance >= 100
1890 && spellInfo.ProcBasePPM <= 0.0f
1891 && procEntry.Cooldown <= 0ms
1892 && procEntry.Charges <= 0
1896 && triggersSpell)
1897 {
1898 TC_LOG_ERROR("sql.sql", "Spell Id {} has SPELL_ATTR3_CAN_PROC_FROM_PROCS attribute and no restriction on what spells can cause it to proc and no cooldown. "
1899 "This spell can cause infinite proc loops. Proc data for this spell was not generated, data in `spell_proc` table is required for it to function!",
1900 spellInfo.Id);
1901 continue;
1902 }
1903
1904 generatedSpellProcMap[{ spellInfo.Id, spellInfo.Difficulty }] = procEntry;
1905 ++count;
1906 }
1907
1908 mSpellProcMap.merge(generatedSpellProcMap);
1909
1910 TC_LOG_INFO("server.loading", ">> Generated spell proc data for {} spells in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1911}
1912
1914{
1915 uint32 oldMSTime = getMSTime();
1916
1917 mSpellThreatMap.clear(); // need for reload case
1918
1919 // 0 1 2 3
1920 QueryResult result = WorldDatabase.Query("SELECT entry, flatMod, pctMod, apPctMod FROM spell_threat");
1921 if (!result)
1922 {
1923 TC_LOG_INFO("server.loading", ">> Loaded 0 aggro generating spells. DB table `spell_threat` is empty.");
1924 return;
1925 }
1926
1927 uint32 count = 0;
1928 do
1929 {
1930 Field* fields = result->Fetch();
1931
1932 uint32 entry = fields[0].GetUInt32();
1933
1934 if (!GetSpellInfo(entry, DIFFICULTY_NONE))
1935 {
1936 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_threat` does not exist.", entry);
1937 continue;
1938 }
1939
1940 SpellThreatEntry ste;
1941 ste.flatMod = fields[1].GetInt32();
1942 ste.pctMod = fields[2].GetFloat();
1943 ste.apPctMod = fields[3].GetFloat();
1944
1945 mSpellThreatMap[entry] = ste;
1946 ++count;
1947 } while (result->NextRow());
1948
1949 TC_LOG_INFO("server.loading", ">> Loaded {} SpellThreatEntries in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1950}
1951
1953{
1954 uint32 oldMSTime = getMSTime();
1955
1956 mSkillLineAbilityMap.clear();
1957
1958 for (SkillLineAbilityEntry const* skillLineAbility : sSkillLineAbilityStore)
1959 mSkillLineAbilityMap.emplace(skillLineAbility->Spell, skillLineAbility);
1960
1961 TC_LOG_INFO("server.loading", ">> Loaded {} SkillLineAbility MultiMap Data in {} ms",
1962 mSkillLineAbilityMap.size(), GetMSTimeDiffToNow(oldMSTime));
1963}
1964
1966{
1967 uint32 oldMSTime = getMSTime();
1968
1969 mSpellPetAuraMap.clear(); // need for reload case
1970
1971 // 0 1 2 3
1972 QueryResult result = WorldDatabase.Query("SELECT spell, effectId, pet, aura FROM spell_pet_auras");
1973 if (!result)
1974 {
1975 TC_LOG_INFO("server.loading", ">> Loaded 0 spell pet auras. DB table `spell_pet_auras` is empty.");
1976 return;
1977 }
1978
1979 uint32 count = 0;
1980 do
1981 {
1982 Field* fields = result->Fetch();
1983
1984 uint32 spell = fields[0].GetUInt32();
1985 SpellEffIndex eff = SpellEffIndex(fields[1].GetUInt8());
1986 uint32 pet = fields[2].GetUInt32();
1987 uint32 aura = fields[3].GetUInt32();
1988
1989 SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find((spell<<8) + eff);
1990 if (itr != mSpellPetAuraMap.end())
1991 itr->second.AddAura(pet, aura);
1992 else
1993 {
1994 SpellInfo const* spellInfo = GetSpellInfo(spell, DIFFICULTY_NONE);
1995 if (!spellInfo)
1996 {
1997 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_pet_auras` does not exist.", spell);
1998 continue;
1999 }
2000 if (eff >= spellInfo->GetEffects().size())
2001 {
2002 TC_LOG_ERROR("spells", "The spell {} listed in `spell_pet_auras` does not have any effect at index {}", spell, uint32(eff));
2003 continue;
2004 }
2005
2006 if (spellInfo->GetEffect(eff).Effect != SPELL_EFFECT_DUMMY &&
2007 (spellInfo->GetEffect(eff).Effect != SPELL_EFFECT_APPLY_AURA ||
2008 spellInfo->GetEffect(eff).ApplyAuraName != SPELL_AURA_DUMMY))
2009 {
2010 TC_LOG_ERROR("spells", "The spell {} listed in `spell_pet_auras` does not have any dummy aura or dummy effect.", spell);
2011 continue;
2012 }
2013
2014 SpellInfo const* spellInfo2 = GetSpellInfo(aura, DIFFICULTY_NONE);
2015 if (!spellInfo2)
2016 {
2017 TC_LOG_ERROR("sql.sql", "The aura {} listed in `spell_pet_auras` does not exist.", aura);
2018 continue;
2019 }
2020
2021 PetAura pa(pet, aura, spellInfo->GetEffect(eff).TargetA.GetTarget() == TARGET_UNIT_PET, spellInfo->GetEffect(eff).CalcValue());
2022 mSpellPetAuraMap[(spell<<8) + eff] = pa;
2023 }
2024
2025 ++count;
2026 } while (result->NextRow());
2027
2028 TC_LOG_INFO("server.loading", ">> Loaded {} spell pet auras in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2029}
2030
2032{
2033 uint32 oldMSTime = getMSTime();
2034
2035 mSpellEnchantProcEventMap.clear(); // need for reload case
2036
2037 // 0 1 2 3 4
2038 QueryResult result = WorldDatabase.Query("SELECT EnchantID, Chance, ProcsPerMinute, HitMask, AttributesMask FROM spell_enchant_proc_data");
2039 if (!result)
2040 {
2041 TC_LOG_INFO("server.loading", ">> Loaded 0 spell enchant proc event conditions. DB table `spell_enchant_proc_data` is empty.");
2042 return;
2043 }
2044
2045 uint32 count = 0;
2046 do
2047 {
2048 Field* fields = result->Fetch();
2049
2050 uint32 enchantId = fields[0].GetUInt32();
2051
2052 SpellItemEnchantmentEntry const* ench = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2053 if (!ench)
2054 {
2055 TC_LOG_ERROR("sql.sql", "The enchancment {} listed in `spell_enchant_proc_data` does not exist.", enchantId);
2056 continue;
2057 }
2058
2060
2061 spe.Chance = fields[1].GetFloat();
2062 spe.ProcsPerMinute = fields[2].GetFloat();
2063 spe.HitMask = fields[3].GetUInt32();
2064 spe.AttributesMask = fields[4].GetUInt32();
2065
2066 mSpellEnchantProcEventMap[enchantId] = spe;
2067
2068 ++count;
2069 } while (result->NextRow());
2070
2071 TC_LOG_INFO("server.loading", ">> Loaded {} enchant proc data definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2072}
2073
2075{
2076 uint32 oldMSTime = getMSTime();
2077
2078 mSpellLinkedMap.clear(); // need for reload case
2079
2080 // 0 1 2
2081 QueryResult result = WorldDatabase.Query("SELECT spell_trigger, spell_effect, type FROM spell_linked_spell");
2082 if (!result)
2083 {
2084 TC_LOG_INFO("server.loading", ">> Loaded 0 linked spells. DB table `spell_linked_spell` is empty.");
2085 return;
2086 }
2087
2088 uint32 count = 0;
2089 do
2090 {
2091 Field* fields = result->Fetch();
2092
2093 int32 trigger = fields[0].GetInt32();
2094 int32 effect = fields[1].GetInt32();
2095 SpellLinkedType type = SpellLinkedType(fields[2].GetUInt8());
2096
2097 SpellInfo const* spellInfo = GetSpellInfo(abs(trigger), DIFFICULTY_NONE);
2098 if (!spellInfo)
2099 {
2100 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_linked_spell` does not exist.", abs(trigger));
2101 continue;
2102 }
2103
2104 if (effect >= 0)
2105 {
2106 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2107 {
2108 if (spellEffectInfo.CalcValueAsInt() == abs(effect))
2109 TC_LOG_ERROR("sql.sql", "The spell {} Effect: {} listed in `spell_linked_spell` has same bp{} like effect (possible hack).", abs(trigger), abs(effect), uint32(spellEffectInfo.EffectIndex));
2110 }
2111 }
2112
2113 spellInfo = GetSpellInfo(abs(effect), DIFFICULTY_NONE);
2114 if (!spellInfo)
2115 {
2116 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_linked_spell` does not exist.", abs(effect));
2117 continue;
2118 }
2119
2120 if (type < SPELL_LINK_CAST || type > SPELL_LINK_REMOVE)
2121 {
2122 TC_LOG_ERROR("sql.sql", "The spell trigger {}, effect {} listed in `spell_linked_spell` has invalid link type {}, skipped.", trigger, effect, type);
2123 continue;
2124 }
2125
2126 if (trigger < 0)
2127 {
2128 if (type != SPELL_LINK_CAST)
2129 TC_LOG_ERROR("sql.sql", "The spell trigger {} listed in `spell_linked_spell` has invalid link type {}, changed to 0.", trigger, type);
2130
2131 trigger = -trigger;
2132 type = SPELL_LINK_REMOVE;
2133 }
2134
2135 if (type != SPELL_LINK_AURA)
2136 {
2137 if (trigger == effect)
2138 {
2139 TC_LOG_ERROR("sql.sql", "The spell trigger {}, effect {} listed in `spell_linked_spell` triggers itself (infinite loop), skipped.", trigger, effect);
2140 continue;
2141 }
2142 }
2143
2144 mSpellLinkedMap[{ type, trigger }].push_back(effect);
2145
2146 ++count;
2147 } while (result->NextRow());
2148
2149 TC_LOG_INFO("server.loading", ">> Loaded {} linked spells in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2150}
2151
2153{
2154 uint32 oldMSTime = getMSTime();
2155
2156 mPetLevelupSpellMap.clear(); // need for reload case
2157
2158 uint32 count = 0;
2159 uint32 family_count = 0;
2160
2161 for (uint32 i = 0; i < sCreatureFamilyStore.GetNumRows(); ++i)
2162 {
2163 CreatureFamilyEntry const* creatureFamily = sCreatureFamilyStore.LookupEntry(i);
2164 if (!creatureFamily) // not exist
2165 continue;
2166
2167 for (uint8 j = 0; j < 2; ++j)
2168 {
2169 if (!creatureFamily->SkillLine[j])
2170 continue;
2171
2172 std::vector<SkillLineAbilityEntry const*> const* skillLineAbilities = sDB2Manager.GetSkillLineAbilitiesBySkill(creatureFamily->SkillLine[j]);
2173 if (!skillLineAbilities)
2174 continue;
2175
2176 for (SkillLineAbilityEntry const* skillLine : *skillLineAbilities)
2177 {
2178 if (skillLine->GetAcquireMethod() != SkillLineAbilityAcquireMethod::AutomaticCharLevel)
2179 continue;
2180
2181 SpellInfo const* spell = GetSpellInfo(skillLine->Spell, DIFFICULTY_NONE);
2182 if (!spell) // not exist or triggered or talent
2183 continue;
2184
2185 if (!spell->SpellLevel)
2186 continue;
2187
2189 if (spellSet.empty())
2190 ++family_count;
2191
2192 spellSet.insert(PetLevelupSpellSet::value_type(spell->SpellLevel, spell->Id));
2193 ++count;
2194 }
2195 }
2196 }
2197
2198 TC_LOG_INFO("server.loading", ">> Loaded {} pet levelup and default spells for {} families in {} ms", count, family_count, GetMSTimeDiffToNow(oldMSTime));
2199}
2200
2202{
2203 // skip empty list;
2204 bool have_spell = false;
2205 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2206 {
2207 if (petDefSpells.spellid[j])
2208 {
2209 have_spell = true;
2210 break;
2211 }
2212 }
2213 if (!have_spell)
2214 return false;
2215
2216 // remove duplicates with levelupSpells if any
2217 if (PetLevelupSpellSet const* levelupSpells = cInfo->family ? sSpellMgr->GetPetLevelupSpellList(cInfo->family) : nullptr)
2218 {
2219 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2220 {
2221 if (!petDefSpells.spellid[j])
2222 continue;
2223
2224 for (PetLevelupSpellSet::const_iterator itr = levelupSpells->begin(); itr != levelupSpells->end(); ++itr)
2225 {
2226 if (itr->second == petDefSpells.spellid[j])
2227 {
2228 petDefSpells.spellid[j] = 0;
2229 break;
2230 }
2231 }
2232 }
2233 }
2234
2235 // skip empty list;
2236 have_spell = false;
2237 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2238 {
2239 if (petDefSpells.spellid[j])
2240 {
2241 have_spell = true;
2242 break;
2243 }
2244 }
2245
2246 return have_spell;
2247}
2248
2250{
2251 uint32 oldMSTime = getMSTime();
2252
2253 mPetDefaultSpellsMap.clear();
2254
2255 uint32 countCreature = 0;
2256
2257 TC_LOG_INFO("server.loading", "Loading summonable creature templates...");
2258 oldMSTime = getMSTime();
2259
2260 // different summon spells
2261 for (SpellInfo const& spellEntry : mSpellInfoMap)
2262 {
2263 if (spellEntry.Difficulty != DIFFICULTY_NONE)
2264 continue;
2265
2266 for (SpellEffectInfo const& spellEffectInfo : spellEntry.GetEffects())
2267 {
2268 if (spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON) || spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON_PET))
2269 {
2270 uint32 creature_id = spellEffectInfo.MiscValue;
2271 CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(creature_id);
2272 if (!cInfo)
2273 continue;
2274
2275 // get default pet spells from creature_template
2276 int32 petSpellsId = cInfo->Entry;
2277 if (mPetDefaultSpellsMap.find(cInfo->Entry) != mPetDefaultSpellsMap.end())
2278 continue;
2279
2280 PetDefaultSpellsEntry petDefSpells;
2281 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2282 petDefSpells.spellid[j] = cInfo->spells[j];
2283
2284 if (LoadPetDefaultSpells_helper(cInfo, petDefSpells))
2285 {
2286 mPetDefaultSpellsMap[petSpellsId] = petDefSpells;
2287 ++countCreature;
2288 }
2289 }
2290 }
2291 }
2292
2293 TC_LOG_INFO("server.loading", ">> Loaded {} summonable creature templates in {} ms", countCreature, GetMSTimeDiffToNow(oldMSTime));
2294}
2295
2297{
2298 uint32 oldMSTime = getMSTime();
2299
2300 mSpellAreaMap.clear(); // need for reload case
2301 mSpellAreaForAreaMap.clear();
2302 mSpellAreaForQuestMap.clear();
2304 mSpellAreaForAuraMap.clear();
2305
2306 // 0 1 2 3 4 5 6 7 8 9
2307 QueryResult result = WorldDatabase.Query("SELECT spell, area, quest_start, quest_start_status, quest_end_status, quest_end, aura_spell, racemask, gender, flags FROM spell_area");
2308 if (!result)
2309 {
2310 TC_LOG_INFO("server.loading", ">> Loaded 0 spell area requirements. DB table `spell_area` is empty.");
2311
2312 return;
2313 }
2314
2315 uint32 count = 0;
2316 do
2317 {
2318 Field* fields = result->Fetch();
2319
2320 uint32 spell = fields[0].GetUInt32();
2321 SpellArea spellArea;
2322 spellArea.spellId = spell;
2323 spellArea.areaId = fields[1].GetUInt32();
2324 spellArea.questStart = fields[2].GetUInt32();
2325 spellArea.questStartStatus = fields[3].GetUInt32();
2326 spellArea.questEndStatus = fields[4].GetUInt32();
2327 spellArea.questEnd = fields[5].GetUInt32();
2328 spellArea.auraSpell = fields[6].GetInt32();
2329 spellArea.raceMask = { fields[7].GetUInt64() };
2330 spellArea.gender = Gender(fields[8].GetUInt8());
2331 spellArea.flags = fields[9].GetUInt8();
2332
2333 if (SpellInfo const* spellInfo = GetSpellInfo(spell, DIFFICULTY_NONE))
2334 {
2335 if (spellArea.flags & SPELL_AREA_FLAG_AUTOCAST)
2336 const_cast<SpellInfo*>(spellInfo)->Attributes |= SPELL_ATTR0_NO_AURA_CANCEL;
2337 }
2338 else
2339 {
2340 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` does not exist", spell);
2341 continue;
2342 }
2343
2344 {
2345 bool ok = true;
2346 SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds(spellArea.spellId);
2347 for (SpellAreaMap::const_iterator itr = sa_bounds.first; itr != sa_bounds.second; ++itr)
2348 {
2349 if (spellArea.spellId != itr->second.spellId)
2350 continue;
2351 if (spellArea.areaId != itr->second.areaId)
2352 continue;
2353 if (spellArea.questStart != itr->second.questStart)
2354 continue;
2355 if (spellArea.auraSpell != itr->second.auraSpell)
2356 continue;
2357 if ((spellArea.raceMask & itr->second.raceMask).IsEmpty())
2358 continue;
2359 if (spellArea.gender != itr->second.gender)
2360 continue;
2361
2362 // duplicate by requirements
2363 ok = false;
2364 break;
2365 }
2366
2367 if (!ok)
2368 {
2369 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` is already listed with similar requirements.", spell);
2370 continue;
2371 }
2372 }
2373
2374 if (spellArea.areaId && !sAreaTableStore.LookupEntry(spellArea.areaId))
2375 {
2376 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has a wrong area ({}) requirement.", spell, spellArea.areaId);
2377 continue;
2378 }
2379
2380 if (spellArea.questStart && !sObjectMgr->GetQuestTemplate(spellArea.questStart))
2381 {
2382 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has a wrong start quest ({}) requirement.", spell, spellArea.questStart);
2383 continue;
2384 }
2385
2386 if (spellArea.questEnd)
2387 {
2388 if (!sObjectMgr->GetQuestTemplate(spellArea.questEnd))
2389 {
2390 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has a wrong ending quest ({}) requirement.", spell, spellArea.questEnd);
2391 continue;
2392 }
2393 }
2394
2395 if (spellArea.auraSpell)
2396 {
2397 SpellInfo const* spellInfo = GetSpellInfo(abs(spellArea.auraSpell), DIFFICULTY_NONE);
2398 if (!spellInfo)
2399 {
2400 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has wrong aura spell ({}) requirement", spell, abs(spellArea.auraSpell));
2401 continue;
2402 }
2403
2404 if (uint32(abs(spellArea.auraSpell)) == spellArea.spellId)
2405 {
2406 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has aura spell ({}) requirement for itself", spell, abs(spellArea.auraSpell));
2407 continue;
2408 }
2409
2410 // not allow autocast chains by auraSpell field (but allow use as alternative if not present)
2411 if (spellArea.flags & SPELL_AREA_FLAG_AUTOCAST && spellArea.auraSpell > 0)
2412 {
2413 bool chain = false;
2415 for (SpellAreaForAuraMap::const_iterator itr = saBound.first; itr != saBound.second; ++itr)
2416 {
2417 if (itr->second->flags & SPELL_AREA_FLAG_AUTOCAST && itr->second->auraSpell > 0)
2418 {
2419 chain = true;
2420 break;
2421 }
2422 }
2423
2424 if (chain)
2425 {
2426 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has the aura spell ({}) requirement that it autocasts itself from the aura.", spell, spellArea.auraSpell);
2427 continue;
2428 }
2429
2431 for (SpellAreaMap::const_iterator itr2 = saBound2.first; itr2 != saBound2.second; ++itr2)
2432 {
2433 if (itr2->second.flags & SPELL_AREA_FLAG_AUTOCAST && itr2->second.auraSpell > 0)
2434 {
2435 chain = true;
2436 break;
2437 }
2438 }
2439
2440 if (chain)
2441 {
2442 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has the aura spell ({}) requirement that the spell itself autocasts from the aura.", spell, spellArea.auraSpell);
2443 continue;
2444 }
2445 }
2446 }
2447
2448 if (!spellArea.raceMask.IsEmpty() && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE).IsEmpty())
2449 {
2450 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has wrong race mask ({}) requirement.", spell, spellArea.raceMask.RawValue);
2451 continue;
2452 }
2453
2454 if (spellArea.gender != GENDER_NONE && spellArea.gender != GENDER_FEMALE && spellArea.gender != GENDER_MALE)
2455 {
2456 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has wrong gender ({}) requirement.", spell, spellArea.gender);
2457 continue;
2458 }
2459
2460 SpellArea const* sa = &mSpellAreaMap.insert(SpellAreaMap::value_type(spell, spellArea))->second;
2461
2462 // for search by current zone/subzone at zone/subzone change
2463 if (spellArea.areaId)
2464 mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(spellArea.areaId, sa));
2465
2466 // for search at quest update checks
2467 if (spellArea.questStart || spellArea.questEnd)
2468 {
2469 if (spellArea.questStart == spellArea.questEnd)
2470 mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa));
2471 else
2472 {
2473 if (spellArea.questStart)
2474 mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa));
2475 if (spellArea.questEnd)
2476 mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd, sa));
2477 }
2478 }
2479
2480 // for search at quest start/reward
2481 if (spellArea.questEnd)
2482 mSpellAreaForQuestEndMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd, sa));
2483
2484 // for search at aura apply
2485 if (spellArea.auraSpell)
2486 mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(abs(spellArea.auraSpell), sa));
2487
2488 ++count;
2489 } while (result->NextRow());
2490
2491 TC_LOG_INFO("server.loading", ">> Loaded {} spell area requirements in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2492}
2493
2494typedef std::vector<SpellEffectEntry const*> SpellEffectVector;
2495
2497{
2498 uint32 oldMSTime = getMSTime();
2499
2501
2502 std::unordered_map<std::pair<uint32, Difficulty>, SpellInfoLoadHelper> loadData;
2503
2504 std::unordered_map<int32, BattlePetSpeciesEntry const*> battlePetSpeciesByCreature;
2505 for (BattlePetSpeciesEntry const* battlePetSpecies : sBattlePetSpeciesStore)
2506 if (battlePetSpecies->CreatureID)
2507 battlePetSpeciesByCreature[battlePetSpecies->CreatureID] = battlePetSpecies;
2508
2509 for (SpellEffectEntry const* effect : sSpellEffectStore)
2510 {
2511 ASSERT(effect->EffectIndex < MAX_SPELL_EFFECTS, "MAX_SPELL_EFFECTS must be at least %d", effect->EffectIndex + 1);
2512 ASSERT(effect->Effect < TOTAL_SPELL_EFFECTS, "TOTAL_SPELL_EFFECTS must be at least %u", effect->Effect + 1);
2513 ASSERT(effect->EffectAura < int32(TOTAL_AURAS), "TOTAL_AURAS must be at least %d", effect->EffectAura + 1);
2514 ASSERT(effect->ImplicitTarget[0] < TOTAL_SPELL_TARGETS, "TOTAL_SPELL_TARGETS must be at least %u", effect->ImplicitTarget[0] + 1);
2515 ASSERT(effect->ImplicitTarget[1] < TOTAL_SPELL_TARGETS, "TOTAL_SPELL_TARGETS must be at least %u", effect->ImplicitTarget[1] + 1);
2516
2517 loadData[{ effect->SpellID, Difficulty(effect->DifficultyID) }].Effects[effect->EffectIndex] = effect;
2518
2519 if (effect->Effect == SPELL_EFFECT_SUMMON)
2520 if (SummonPropertiesEntry const* summonProperties = sSummonPropertiesStore.LookupEntry(effect->EffectMiscValue[1]))
2521 if (summonProperties->Slot == SUMMON_SLOT_MINIPET && summonProperties->GetFlags().HasFlag(SummonPropertiesFlags::SummonFromBattlePetJournal))
2522 if (BattlePetSpeciesEntry const* battlePetSpecies = Trinity::Containers::MapGetValuePtr(battlePetSpeciesByCreature, effect->EffectMiscValue[0]))
2523 BattlePets::BattlePetMgr::AddBattlePetSpeciesBySpell(effect->SpellID, battlePetSpecies);
2524
2525 if (effect->Effect == SPELL_EFFECT_LANGUAGE)
2526 sLanguageMgr->LoadSpellEffectLanguage(effect);
2527
2528 switch (effect->EffectAura)
2529 {
2534 if (effect->EffectMiscValue[0] >= MAX_SPELLMOD)
2535 {
2536 TC_LOG_ERROR("server.loading", "Invalid spell modifier type {} found on spell {} effect index {}, consider increasing MAX_SPELLMOD",
2537 effect->EffectMiscValue[0], effect->SpellID, effect->EffectIndex);
2538 }
2539 break;
2540 default:
2541 break;
2542 }
2543 }
2544
2545 for (SpellAuraOptionsEntry const* auraOptions : sSpellAuraOptionsStore)
2546 loadData[{ auraOptions->SpellID, Difficulty(auraOptions->DifficultyID) }].AuraOptions = auraOptions;
2547
2548 for (SpellAuraRestrictionsEntry const* auraRestrictions : sSpellAuraRestrictionsStore)
2549 loadData[{ auraRestrictions->SpellID, Difficulty(auraRestrictions->DifficultyID) }].AuraRestrictions = auraRestrictions;
2550
2551 for (SpellCastingRequirementsEntry const* castingRequirements : sSpellCastingRequirementsStore)
2552 loadData[{ castingRequirements->SpellID, DIFFICULTY_NONE }].CastingRequirements = castingRequirements;
2553
2554 for (SpellCategoriesEntry const* categories : sSpellCategoriesStore)
2555 loadData[{ categories->SpellID, Difficulty(categories->DifficultyID) }].Categories = categories;
2556
2557 for (SpellClassOptionsEntry const* classOptions : sSpellClassOptionsStore)
2558 loadData[{ classOptions->SpellID, DIFFICULTY_NONE }].ClassOptions = classOptions;
2559
2560 for (SpellCooldownsEntry const* cooldowns : sSpellCooldownsStore)
2561 loadData[{ cooldowns->SpellID, Difficulty(cooldowns->DifficultyID) }].Cooldowns = cooldowns;
2562
2563 for (SpellEmpowerStageEntry const* empowerStage : sSpellEmpowerStageStore)
2564 {
2565 if (SpellEmpowerEntry const* empower = sSpellEmpowerStore.LookupEntry(empowerStage->SpellEmpowerID))
2566 {
2567 std::vector<SpellEmpowerStageEntry const*>& empowerStages = loadData[{empower->SpellID, DIFFICULTY_NONE}].EmpowerStages;
2568
2569 auto where = std::ranges::lower_bound(empowerStages, empowerStage->Stage, std::ranges::less(), &SpellEmpowerStageEntry::Stage);
2570
2571 empowerStages.insert(where, empowerStage);
2572 }
2573 }
2574
2575 for (SpellEquippedItemsEntry const* equippedItems : sSpellEquippedItemsStore)
2576 loadData[{ equippedItems->SpellID, DIFFICULTY_NONE }].EquippedItems = equippedItems;
2577
2578 for (SpellInterruptsEntry const* interrupts : sSpellInterruptsStore)
2579 loadData[{ interrupts->SpellID, Difficulty(interrupts->DifficultyID) }].Interrupts = interrupts;
2580
2581 for (SpellLabelEntry const* label : sSpellLabelStore)
2582 loadData[{ label->SpellID, DIFFICULTY_NONE }].Labels.push_back(label);
2583
2584 for (SpellLevelsEntry const* levels : sSpellLevelsStore)
2585 loadData[{ levels->SpellID, Difficulty(levels->DifficultyID) }].Levels = levels;
2586
2587 for (SpellMiscEntry const* misc : sSpellMiscStore)
2588 loadData[{ misc->SpellID, Difficulty(misc->DifficultyID) }].Misc = misc;
2589
2590 for (SpellPowerEntry const* power : sSpellPowerStore)
2591 {
2592 Difficulty difficulty = DIFFICULTY_NONE;
2593 uint8 index = power->OrderIndex;
2594 if (SpellPowerDifficultyEntry const* powerDifficulty = sSpellPowerDifficultyStore.LookupEntry(power->ID))
2595 {
2596 difficulty = Difficulty(powerDifficulty->DifficultyID);
2597 index = powerDifficulty->OrderIndex;
2598 }
2599
2600 loadData[{ power->SpellID, difficulty }].Powers[index] = power;
2601 }
2602
2603 for (SpellReagentsEntry const* reagents : sSpellReagentsStore)
2604 loadData[{ reagents->SpellID, DIFFICULTY_NONE }].Reagents = reagents;
2605
2606 for (SpellReagentsCurrencyEntry const* reagentsCurrency : sSpellReagentsCurrencyStore)
2607 loadData[{ reagentsCurrency->SpellID, DIFFICULTY_NONE }].ReagentsCurrency.push_back(reagentsCurrency);
2608
2609 for (SpellScalingEntry const* scaling : sSpellScalingStore)
2610 loadData[{ scaling->SpellID, DIFFICULTY_NONE }].Scaling = scaling;
2611
2612 for (SpellShapeshiftEntry const* shapeshift : sSpellShapeshiftStore)
2613 loadData[{ shapeshift->SpellID, DIFFICULTY_NONE }].Shapeshift = shapeshift;
2614
2615 for (SpellTargetRestrictionsEntry const* targetRestrictions : sSpellTargetRestrictionsStore)
2616 loadData[{ targetRestrictions->SpellID, Difficulty(targetRestrictions->DifficultyID) }].TargetRestrictions = targetRestrictions;
2617
2618 for (SpellTotemsEntry const* totems : sSpellTotemsStore)
2619 loadData[{ totems->SpellID, DIFFICULTY_NONE }].Totems = totems;
2620
2622 {
2623 SpellVisualVector& visuals = loadData[{ visual->SpellID, Difficulty(visual->DifficultyID) }].Visuals;
2624
2625 auto where = std::ranges::lower_bound(visuals, std::make_pair(visual->Priority, visual->CasterPlayerConditionID), std::ranges::greater(),
2626 [](SpellXSpellVisualEntry const* other) { return std::make_pair(other->Priority, other->CasterPlayerConditionID); });
2627
2628 // sorted with unconditional visuals being last at each priority level
2629 visuals.insert(where, visual);
2630 }
2631
2632 for (auto& [key, data] : loadData)
2633 {
2634 SpellNameEntry const* spellNameEntry = sSpellNameStore.LookupEntry(key.first);
2635 if (!spellNameEntry)
2636 continue;
2637
2638 // fill blanks
2639 if (DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(key.second))
2640 {
2641 do
2642 {
2643 if (SpellInfoLoadHelper const* fallbackData = Trinity::Containers::MapGetValuePtr(loadData, { key.first, Difficulty(difficultyEntry->FallbackDifficultyID) }))
2644 {
2645 if (!data.AuraOptions)
2646 data.AuraOptions = fallbackData->AuraOptions;
2647
2648 if (!data.AuraRestrictions)
2649 data.AuraRestrictions = fallbackData->AuraRestrictions;
2650
2651 if (!data.CastingRequirements)
2652 data.CastingRequirements = fallbackData->CastingRequirements;
2653
2654 if (!data.Categories)
2655 data.Categories = fallbackData->Categories;
2656
2657 if (!data.ClassOptions)
2658 data.ClassOptions = fallbackData->ClassOptions;
2659
2660 if (!data.Cooldowns)
2661 data.Cooldowns = fallbackData->Cooldowns;
2662
2663 for (std::size_t i = 0; i < data.Effects.size(); ++i)
2664 if (!data.Effects[i])
2665 data.Effects[i] = fallbackData->Effects[i];
2666
2667 if (data.EmpowerStages.empty())
2668 data.EmpowerStages = fallbackData->EmpowerStages;
2669
2670 if (!data.EquippedItems)
2671 data.EquippedItems = fallbackData->EquippedItems;
2672
2673 if (!data.Interrupts)
2674 data.Interrupts = fallbackData->Interrupts;
2675
2676 if (data.Labels.empty())
2677 data.Labels = fallbackData->Labels;
2678
2679 if (!data.Levels)
2680 data.Levels = fallbackData->Levels;
2681
2682 if (!data.Misc)
2683 data.Misc = fallbackData->Misc;
2684
2685 for (std::size_t i = 0; i < fallbackData->Powers.size(); ++i)
2686 if (!data.Powers[i])
2687 data.Powers[i] = fallbackData->Powers[i];
2688
2689 if (!data.Reagents)
2690 data.Reagents = fallbackData->Reagents;
2691
2692 if (data.ReagentsCurrency.empty())
2693 data.ReagentsCurrency = fallbackData->ReagentsCurrency;
2694
2695 if (!data.Scaling)
2696 data.Scaling = fallbackData->Scaling;
2697
2698 if (!data.Shapeshift)
2699 data.Shapeshift = fallbackData->Shapeshift;
2700
2701 if (!data.TargetRestrictions)
2702 data.TargetRestrictions = fallbackData->TargetRestrictions;
2703
2704 if (!data.Totems)
2705 data.Totems = fallbackData->Totems;
2706
2707 // visuals fall back only to first difficulty that defines any visual
2708 // they do not stack all difficulties in fallback chain
2709 if (data.Visuals.empty())
2710 data.Visuals = fallbackData->Visuals;
2711 }
2712
2713 difficultyEntry = sDifficultyStore.LookupEntry(difficultyEntry->FallbackDifficultyID);
2714 } while (difficultyEntry);
2715 }
2716
2717 mSpellInfoMap.emplace(spellNameEntry, key.second, data);
2718 }
2719
2720 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo store in {} ms", GetMSTimeDiffToNow(oldMSTime));
2721}
2722
2724{
2725 mSpellInfoMap.clear();
2726 mServersideSpellNames.clear();
2727}
2728
2730{
2731 for (SpellInfo const& spellInfo : mSpellInfoMap)
2732 const_cast<SpellInfo&>(spellInfo)._UnloadImplicitTargetConditionLists();
2733}
2734
2736{
2737 uint32 oldMSTime = getMSTime();
2738
2739 std::unordered_map<std::pair<uint32, Difficulty>, std::vector<SpellEffectEntry>> spellEffects;
2740
2741 // 0 1 2 3 4 5 6
2742 QueryResult effectsResult = WorldDatabase.Query("SELECT SpellID, EffectIndex, DifficultyID, Effect, EffectAura, EffectAmplitude, EffectAttributes, "
2743 // 7 8 9 10 11 12 13
2744 "EffectAuraPeriod, EffectBonusCoefficient, EffectChainAmplitude, EffectChainTargets, EffectItemType, EffectMechanic, EffectPointsPerResource, "
2745 // 14 15 16 17 18 19 20
2746 "EffectPosFacing, EffectRealPointsPerLevel, EffectTriggerSpell, BonusCoefficientFromAP, PvpMultiplier, Coefficient, Variance, "
2747 // 21 22 23 24 25 26
2748 "ResourceCoefficient, GroupSizeBasePointsCoefficient, EffectBasePoints, EffectMiscValue1, EffectMiscValue2, EffectRadiusIndex1, "
2749 // 27 28 29 30 31 32
2750 "EffectRadiusIndex2, EffectSpellClassMask1, EffectSpellClassMask2, EffectSpellClassMask3, EffectSpellClassMask4, ImplicitTarget1, "
2751 // 33
2752 "ImplicitTarget2 FROM serverside_spell_effect");
2753 if (effectsResult)
2754 {
2755 do
2756 {
2757 Field* fields = effectsResult->Fetch();
2758 uint32 spellId = fields[0].GetUInt32();
2759 Difficulty difficulty = Difficulty(fields[2].GetUInt32());
2760 SpellEffectEntry effect{ };
2761 effect.EffectIndex = fields[1].GetInt32();
2762 effect.Effect = fields[3].GetInt32();
2763 effect.EffectAura = fields[4].GetInt16();
2764 effect.EffectAmplitude = fields[5].GetFloat();
2765 effect.EffectAttributes = fields[6].GetInt32();
2766 effect.EffectAuraPeriod = fields[7].GetInt32();
2767 effect.EffectBonusCoefficient = fields[8].GetFloat();
2768 effect.EffectChainAmplitude = fields[9].GetFloat();
2769 effect.EffectChainTargets = fields[10].GetInt32();
2770 effect.EffectItemType = fields[11].GetInt32();
2771 effect.EffectMechanic = Mechanics(fields[12].GetInt32());
2772 effect.EffectPointsPerResource = fields[13].GetFloat();
2773 effect.EffectPosFacing = fields[14].GetFloat();
2774 effect.EffectRealPointsPerLevel = fields[15].GetFloat();
2775 effect.EffectTriggerSpell = fields[16].GetInt32();
2776 effect.BonusCoefficientFromAP = fields[17].GetFloat();
2777 effect.PvpMultiplier = fields[18].GetFloat();
2778 effect.Coefficient = fields[19].GetFloat();
2779 effect.Variance = fields[20].GetFloat();
2780 effect.ResourceCoefficient = fields[21].GetFloat();
2781 effect.GroupSizeBasePointsCoefficient = fields[22].GetFloat();
2782 effect.EffectBasePoints = fields[23].GetFloat();
2783 effect.EffectMiscValue[0] = fields[24].GetInt32();
2784 effect.EffectMiscValue[1] = fields[25].GetInt32();
2785 effect.EffectRadiusIndex[0] = fields[26].GetUInt32();
2786 effect.EffectRadiusIndex[1] = fields[27].GetUInt32();
2787 effect.EffectSpellClassMask = flag128(fields[28].GetInt32(), fields[29].GetInt32(), fields[30].GetInt32(), fields[31].GetInt32());
2788 effect.ImplicitTarget[0] = fields[32].GetInt16();
2789 effect.ImplicitTarget[1] = fields[33].GetInt16();
2790
2791 auto existingSpellBounds = _GetSpellInfo(spellId);
2792 if (existingSpellBounds.begin() != existingSpellBounds.end())
2793 {
2794 TC_LOG_ERROR("sql.sql", "Serverside spell {} difficulty {} effect index {} references a regular spell loaded from file. Adding serverside effects to existing spells is not allowed.",
2795 spellId, uint32(difficulty), effect.EffectIndex);
2796 continue;
2797 }
2798
2799 if (difficulty != DIFFICULTY_NONE && !sDifficultyStore.HasRecord(difficulty))
2800 {
2801 TC_LOG_ERROR("sql.sql", "Serverside spell {} effect index {} references non-existing difficulty {}, skipped",
2802 spellId, effect.EffectIndex, uint32(difficulty));
2803 continue;
2804 }
2805
2806 if (effect.EffectIndex >= MAX_SPELL_EFFECTS)
2807 {
2808 TC_LOG_ERROR("sql.sql", "Serverside spell {} difficulty {} has more than {} effects, effect at index {} skipped",
2809 spellId, uint32(difficulty), MAX_SPELL_EFFECTS, effect.EffectIndex);
2810 continue;
2811 }
2812
2813 if (effect.Effect >= TOTAL_SPELL_EFFECTS)
2814 {
2815 TC_LOG_ERROR("sql.sql", "Serverside spell {} difficulty {} has invalid effect type {} at index {}, skipped",
2816 spellId, uint32(difficulty), effect.Effect, effect.EffectIndex);
2817 continue;
2818 }
2819
2820 if (effect.EffectAura >= int32(TOTAL_AURAS))
2821 {
2822 TC_LOG_ERROR("sql.sql", "Serverside spell {} difficulty {} has invalid aura type {} at index {}, skipped",
2823 spellId, uint32(difficulty), effect.EffectAura, effect.EffectIndex);
2824 continue;
2825 }
2826
2827 if (effect.ImplicitTarget[0] >= TOTAL_SPELL_TARGETS)
2828 {
2829 TC_LOG_ERROR("sql.sql", "Serverside spell {} difficulty {} has invalid targetA type {} at index {}, skipped",
2830 spellId, uint32(difficulty), effect.ImplicitTarget[0], effect.EffectIndex);
2831 continue;
2832 }
2833
2834 if (effect.ImplicitTarget[1] >= TOTAL_SPELL_TARGETS)
2835 {
2836 TC_LOG_ERROR("sql.sql", "Serverside spell {} difficulty {} has invalid targetB type {} at index {}, skipped",
2837 spellId, uint32(difficulty), effect.ImplicitTarget[1], effect.EffectIndex);
2838 continue;
2839 }
2840
2841 if (effect.EffectRadiusIndex[0] && !sSpellRadiusStore.HasRecord(effect.EffectRadiusIndex[0]))
2842 {
2843 TC_LOG_ERROR("sql.sql", "Serverside spell {} difficulty {} has invalid radius id {} at index {}, set to 0",
2844 spellId, uint32(difficulty), effect.EffectRadiusIndex[0], effect.EffectIndex);
2845 }
2846
2847 if (effect.EffectRadiusIndex[1] && !sSpellRadiusStore.HasRecord(effect.EffectRadiusIndex[1]))
2848 {
2849 TC_LOG_ERROR("sql.sql", "Serverside spell {} difficulty {} has invalid max radius id {} at index {}, set to 0",
2850 spellId, uint32(difficulty), effect.EffectRadiusIndex[1], effect.EffectIndex);
2851 }
2852
2853 spellEffects[{ spellId, difficulty }].push_back(std::move(effect));
2854
2855 } while (effectsResult->NextRow());
2856 }
2857
2858 // 0 1 2 3 4 5 6 7 8
2859 QueryResult spellsResult = WorldDatabase.Query("SELECT Id, DifficultyID, CategoryId, Dispel, Mechanic, Attributes, AttributesEx, AttributesEx2, AttributesEx3, "
2860 // 9 10 11 12 13 14 15 16 17 18
2861 "AttributesEx4, AttributesEx5, AttributesEx6, AttributesEx7, AttributesEx8, AttributesEx9, AttributesEx10, AttributesEx11, AttributesEx12, AttributesEx13, "
2862 // 19 20 21 22 23 24 25 26 27
2863 "AttributesEx14, AttributesEx15, AttributesEx16, Stances, StancesNot, Targets, TargetCreatureType, RequiresSpellFocus, FacingCasterFlags, "
2864 // 28 29 30 31 32 33 34 35
2865 "CasterAuraState, TargetAuraState, ExcludeCasterAuraState, ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, "
2866 // 36 37 38 39 40
2867 "CasterAuraType, TargetAuraType, ExcludeCasterAuraType, ExcludeTargetAuraType, CastingTimeIndex, "
2868 // 41 42 43 44 45 46 47
2869 "RecoveryTime, CategoryRecoveryTime, StartRecoveryCategory, StartRecoveryTime, InterruptFlags, AuraInterruptFlags1, AuraInterruptFlags2, "
2870 // 48 49 50 51 52 53 54 55 56 57 58
2871 "ChannelInterruptFlags1, ChannelInterruptFlags2, ProcFlags, ProcFlags2, ProcChance, ProcCharges, ProcCooldown, ProcBasePPM, MaxLevel, BaseLevel, SpellLevel, "
2872 // 59 60 61 62 63 64 65 66 67
2873 "DurationIndex, RangeIndex, Speed, LaunchDelay, StackAmount, EquippedItemClass, EquippedItemSubClassMask, EquippedItemInventoryTypeMask, ContentTuningId, "
2874 // 68 69 70 71 72 73 74 75 76 77
2875 "SpellName, ConeAngle, ConeWidth, MaxTargetLevel, MaxAffectedTargets, SpellFamilyName, SpellFamilyFlags1, SpellFamilyFlags2, SpellFamilyFlags3, SpellFamilyFlags4, "
2876 // 78 79 80 81 82
2877 "DmgClass, PreventionType, AreaGroupId, SchoolMask, ChargeCategoryId FROM serverside_spell");
2878 if (spellsResult)
2879 {
2880 mServersideSpellNames.reserve(spellsResult->GetRowCount());
2881
2882 do
2883 {
2884 Field* fields = spellsResult->Fetch();
2885 uint32 spellId = fields[0].GetUInt32();
2886 Difficulty difficulty = Difficulty(fields[1].GetUInt32());
2887 if (sSpellNameStore.HasRecord(spellId))
2888 {
2889 TC_LOG_ERROR("sql.sql", "Serverside spell {} difficulty {} is already loaded from file. Overriding existing spells is not allowed.",
2890 spellId, uint32(difficulty));
2891 continue;
2892 }
2893
2894 mServersideSpellNames.emplace_back(spellId, fields[68].GetStringView());
2895
2896 SpellInfo& spellInfo = const_cast<SpellInfo&>(*mSpellInfoMap.emplace(&mServersideSpellNames.back().Name, difficulty, spellEffects[{ spellId, difficulty }]).first);
2897 spellInfo.CategoryId = fields[2].GetUInt32();
2898 spellInfo.Dispel = fields[3].GetUInt32();
2899 spellInfo.Mechanic = fields[4].GetUInt32();
2900 spellInfo.Attributes = fields[5].GetUInt32();
2901 spellInfo.AttributesEx = fields[6].GetUInt32();
2902 spellInfo.AttributesEx2 = fields[7].GetUInt32();
2903 spellInfo.AttributesEx3 = fields[8].GetUInt32();
2904 spellInfo.AttributesEx4 = fields[9].GetUInt32();
2905 spellInfo.AttributesEx5 = fields[10].GetUInt32();
2906 spellInfo.AttributesEx6 = fields[11].GetUInt32();
2907 spellInfo.AttributesEx7 = fields[12].GetUInt32();
2908 spellInfo.AttributesEx8 = fields[13].GetUInt32();
2909 spellInfo.AttributesEx9 = fields[14].GetUInt32();
2910 spellInfo.AttributesEx10 = fields[15].GetUInt32();
2911 spellInfo.AttributesEx11 = fields[16].GetUInt32();
2912 spellInfo.AttributesEx12 = fields[17].GetUInt32();
2913 spellInfo.AttributesEx13 = fields[18].GetUInt32();
2914 spellInfo.AttributesEx14 = fields[19].GetUInt32();
2915 spellInfo.AttributesEx15 = fields[20].GetUInt32();
2916 spellInfo.AttributesEx16 = fields[21].GetUInt32();
2917 spellInfo.Stances = fields[22].GetUInt64();
2918 spellInfo.StancesNot = fields[23].GetUInt64();
2919 spellInfo.Targets = fields[24].GetUInt32();
2920 spellInfo.TargetCreatureType = fields[25].GetUInt32();
2921 spellInfo.RequiresSpellFocus = fields[26].GetUInt32();
2922 spellInfo.FacingCasterFlags = fields[27].GetUInt32();
2923 spellInfo.CasterAuraState = fields[28].GetUInt32();
2924 spellInfo.TargetAuraState = fields[29].GetUInt32();
2925 spellInfo.ExcludeCasterAuraState = fields[30].GetUInt32();
2926 spellInfo.ExcludeTargetAuraState = fields[31].GetUInt32();
2927 spellInfo.CasterAuraSpell = fields[32].GetUInt32();
2928 spellInfo.TargetAuraSpell = fields[33].GetUInt32();
2929 spellInfo.ExcludeCasterAuraSpell = fields[34].GetUInt32();
2930 spellInfo.ExcludeTargetAuraSpell = fields[35].GetUInt32();
2931 spellInfo.CasterAuraType = AuraType(fields[36].GetInt32());
2932 spellInfo.TargetAuraType = AuraType(fields[37].GetInt32());
2933 spellInfo.ExcludeCasterAuraType = AuraType(fields[38].GetInt32());
2934 spellInfo.ExcludeTargetAuraType = AuraType(fields[39].GetInt32());
2935 spellInfo.CastTimeEntry = sSpellCastTimesStore.LookupEntry(fields[40].GetUInt32());
2936 spellInfo.RecoveryTime = fields[41].GetUInt32();
2937 spellInfo.CategoryRecoveryTime = fields[42].GetUInt32();
2938 spellInfo.StartRecoveryCategory = fields[43].GetUInt32();
2939 spellInfo.StartRecoveryTime = fields[44].GetUInt32();
2940 spellInfo.InterruptFlags = SpellInterruptFlags(fields[45].GetUInt32());
2941 spellInfo.AuraInterruptFlags = SpellAuraInterruptFlags(fields[46].GetUInt32());
2942 spellInfo.AuraInterruptFlags2 = SpellAuraInterruptFlags2(fields[47].GetUInt32());
2943 spellInfo.ChannelInterruptFlags = SpellAuraInterruptFlags(fields[48].GetUInt32());
2944 spellInfo.ChannelInterruptFlags2 = SpellAuraInterruptFlags2(fields[49].GetUInt32());
2945 spellInfo.ProcFlags[0] = fields[50].GetUInt32();
2946 spellInfo.ProcFlags[1] = fields[51].GetUInt32();
2947 spellInfo.ProcChance = fields[52].GetUInt32();
2948 spellInfo.ProcCharges = fields[53].GetUInt32();
2949 spellInfo.ProcCooldown = fields[54].GetUInt32();
2950 spellInfo.ProcBasePPM = fields[55].GetFloat();
2951 spellInfo.MaxLevel = fields[56].GetUInt32();
2952 spellInfo.BaseLevel = fields[57].GetUInt32();
2953 spellInfo.SpellLevel = fields[58].GetUInt32();
2954 spellInfo.DurationEntry = sSpellDurationStore.LookupEntry(fields[59].GetUInt32());
2955 spellInfo.RangeEntry = sSpellRangeStore.LookupEntry(fields[60].GetUInt32());
2956 spellInfo.Speed = fields[61].GetFloat();
2957 spellInfo.LaunchDelay = fields[62].GetFloat();
2958 spellInfo.StackAmount = fields[63].GetUInt32();
2959 spellInfo.EquippedItemClass = fields[64].GetInt32();
2960 spellInfo.EquippedItemSubClassMask = fields[65].GetInt32();
2961 spellInfo.EquippedItemInventoryTypeMask = fields[66].GetInt32();
2962 spellInfo.ContentTuningId = fields[67].GetUInt32();
2963 spellInfo.ConeAngle = fields[69].GetFloat();
2964 spellInfo.Width = fields[70].GetFloat();
2965 spellInfo.MaxTargetLevel = fields[71].GetUInt32();
2966 spellInfo.MaxAffectedTargets = fields[72].GetUInt32();
2967 spellInfo.SpellFamilyName = fields[73].GetUInt32();
2968 spellInfo.SpellFamilyFlags = flag128(fields[74].GetUInt32(), fields[75].GetUInt32(), fields[76].GetUInt32(), fields[77].GetUInt32());
2969 spellInfo.DmgClass = fields[78].GetUInt32();
2970 spellInfo.PreventionType = fields[79].GetUInt32();
2971 spellInfo.RequiredAreasID = fields[80].GetInt32();
2972 spellInfo.SchoolMask = fields[81].GetUInt32();
2973 spellInfo.ChargeCategoryId = fields[82].GetUInt32();
2974
2975 } while (spellsResult->NextRow());
2976 }
2977
2978 TC_LOG_INFO("server.loading", ">> Loaded {} serverside spells {} ms", mServersideSpellNames.size(), GetMSTimeDiffToNow(oldMSTime));
2979}
2980
2982{
2983 uint32 oldMSTime = getMSTime();
2984 uint32 oldMSTime2 = oldMSTime;
2985
2986 QueryResult result = WorldDatabase.Query("SELECT entry, attributes FROM spell_custom_attr");
2987
2988 if (!result)
2989 TC_LOG_INFO("server.loading", ">> Loaded 0 spell custom attributes from DB. DB table `spell_custom_attr` is empty.");
2990 else
2991 {
2992 uint32 count = 0;
2993 do
2994 {
2995 Field* fields = result->Fetch();
2996
2997 uint32 spellId = fields[0].GetUInt32();
2998 uint32 attributes = fields[1].GetUInt32();
2999
3000 auto spells = _GetSpellInfo(spellId);
3001 if (spells.begin() == spells.end())
3002 {
3003 TC_LOG_ERROR("sql.sql", "Table `spell_custom_attr` has wrong spell (entry: {}), ignored.", spellId);
3004 continue;
3005 }
3006
3007 for (SpellInfo const& spellInfo : spells)
3008 {
3009 if (attributes & SPELL_ATTR0_CU_SHARE_DAMAGE)
3010 {
3011 if (!spellInfo.HasEffect(SPELL_EFFECT_SCHOOL_DAMAGE))
3012 {
3013 TC_LOG_ERROR("sql.sql", "Spell {} listed in table `spell_custom_attr` with SPELL_ATTR0_CU_SHARE_DAMAGE has no SPELL_EFFECT_SCHOOL_DAMAGE, ignored.", spellId);
3014 continue;
3015 }
3016 }
3017
3018 const_cast<SpellInfo&>(spellInfo).AttributesCu |= attributes;
3019 }
3020 ++count;
3021 } while (result->NextRow());
3022
3023 TC_LOG_INFO("server.loading", ">> Loaded {} spell custom attributes from DB in {} ms", count, GetMSTimeDiffToNow(oldMSTime2));
3024 }
3025
3026 std::set<uint32> talentSpells;
3027 for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
3028 if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(i))
3029 talentSpells.insert(talentInfo->SpellID);
3030
3031 for (SpellInfo const& spellInfo : mSpellInfoMap)
3032 {
3033 SpellInfo* spellInfoMutable = const_cast<SpellInfo*>(&spellInfo);
3034 for (SpellEffectInfo const& spellEffectInfo : spellInfoMutable->GetEffects())
3035 {
3036 // all bleed effects and spells ignore armor
3037 if (spellInfo.GetEffectMechanicMask(spellEffectInfo.EffectIndex) & (UI64LIT(1) << MECHANIC_BLEED))
3038 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_IGNORE_ARMOR;
3039
3040 switch (spellEffectInfo.ApplyAuraName)
3041 {
3048 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
3049 break;
3050 default:
3051 break;
3052 }
3053
3054 switch (spellEffectInfo.ApplyAuraName)
3055 {
3056 case SPELL_AURA_OPEN_STABLE: // No point in saving this, since the stable dialog can't be open on aura load anyway.
3057 // Auras that require both caster & target to be in world cannot be saved
3064 // Controlled by Battleground
3068 break;
3069 default:
3070 break;
3071 }
3072
3073 switch (spellEffectInfo.Effect)
3074 {
3077 case SPELL_EFFECT_HEAL:
3086 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_CAN_CRIT;
3087 break;
3088 default:
3089 break;
3090 }
3091
3092 switch (spellEffectInfo.Effect)
3093 {
3099 case SPELL_EFFECT_HEAL:
3100 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_DIRECT_DAMAGE;
3101 break;
3111 break;
3114 case SPELL_EFFECT_JUMP:
3117 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_CHARGE;
3118 break;
3120 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_PICKPOCKET;
3121 break;
3126 {
3127 // only enchanting profession enchantments procs can stack
3128 if (IsPartOfSkillLine(SKILL_ENCHANTING, spellInfo.Id))
3129 {
3130 uint32 enchantId = spellEffectInfo.MiscValue;
3131 SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
3132 if (!enchant)
3133 break;
3134
3135 for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
3136 {
3137 if (enchant->Effect[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
3138 continue;
3139
3140 for (SpellInfo const& procInfo : _GetSpellInfo(enchant->EffectArg[s]))
3141 {
3142 // if proced directly from enchantment, not via proc aura
3143 // NOTE: Enchant Weapon - Blade Ward also has proc aura spell and is proced directly
3144 // however its not expected to stack so this check is good
3145 if (procInfo.HasAura(SPELL_AURA_PROC_TRIGGER_SPELL))
3146 continue;
3147
3148 const_cast<SpellInfo&>(procInfo).AttributesCu |= SPELL_ATTR0_CU_ENCHANT_PROC;
3149 }
3150 }
3151 }
3152 break;
3153 }
3154 default:
3155 break;
3156 }
3157 }
3158
3159 // spells ignoring hit result should not be binary
3160 if (!spellInfoMutable->HasAttribute(SPELL_ATTR3_ALWAYS_HIT))
3161 {
3162 bool setFlag = false;
3163 for (SpellEffectInfo const& spellEffectInfo : spellInfoMutable->GetEffects())
3164 {
3165 if (spellEffectInfo.IsEffect())
3166 {
3167 switch (spellEffectInfo.Effect)
3168 {
3176 break;
3188 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE ||
3189 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE_PERCENT ||
3190 spellEffectInfo.ApplyAuraName == SPELL_AURA_DUMMY ||
3191 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_LEECH ||
3192 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_HEALTH_FUNNEL ||
3193 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_DUMMY)
3194 break;
3195 [[fallthrough]];
3196 default:
3197 {
3198 // No value and not interrupt cast or crowd control without SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY flag
3199 if (!spellEffectInfo.CalcValueAsInt() && !((spellEffectInfo.Effect == SPELL_EFFECT_INTERRUPT_CAST || spellInfoMutable->HasAttribute(SPELL_ATTR0_CU_AURA_CC)) && !spellInfoMutable->HasAttribute(SPELL_ATTR0_NO_IMMUNITIES)))
3200 break;
3201
3202 // Sindragosa Frost Breath
3203 if (spellInfoMutable->Id == 69649 || spellInfoMutable->Id == 71056 || spellInfoMutable->Id == 71057 || spellInfoMutable->Id == 71058 || spellInfoMutable->Id == 73061 || spellInfoMutable->Id == 73062 || spellInfoMutable->Id == 73063 || spellInfoMutable->Id == 73064)
3204 break;
3205
3206 // Frostbolt
3207 if (spellInfoMutable->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfoMutable->SpellFamilyFlags[0] & 0x20))
3208 break;
3209
3210 // Frost Fever
3211 if (spellInfoMutable->Id == 55095)
3212 break;
3213
3214 // Haunt
3215 if (spellInfoMutable->SpellFamilyName == SPELLFAMILY_WARLOCK && (spellInfoMutable->SpellFamilyFlags[1] & 0x40000))
3216 break;
3217
3218 setFlag = true;
3219 break;
3220 }
3221 }
3222
3223 if (setFlag)
3224 {
3225 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_BINARY_SPELL;
3226 break;
3227 }
3228 }
3229 }
3230 }
3231
3232 // Remove normal school mask to properly calculate damage
3233 if ((spellInfoMutable->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) && (spellInfoMutable->SchoolMask & SPELL_SCHOOL_MASK_MAGIC))
3234 {
3235 spellInfoMutable->SchoolMask &= ~SPELL_SCHOOL_MASK_NORMAL;
3237 }
3238
3239 spellInfoMutable->_InitializeSpellPositivity();
3240
3241 if (talentSpells.count(spellInfoMutable->Id))
3242 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_IS_TALENT;
3243
3244 if (G3D::fuzzyNe(spellInfoMutable->Width, 0.0f))
3245 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_CONE_LINE;
3246
3247 switch (spellInfoMutable->SpellFamilyName)
3248 {
3250 // Shout / Piercing Howl
3251 if (spellInfoMutable->SpellFamilyFlags[0] & 0x20000/* || spellInfo->SpellFamilyFlags[1] & 0x20*/)
3252 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
3253 break;
3254 case SPELLFAMILY_DRUID:
3255 // Roar
3256 if (spellInfoMutable->SpellFamilyFlags[0] & 0x8)
3257 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
3258 break;
3260 // Stoneclaw Totem effect
3261 if (spellInfoMutable->Id == 5729)
3262 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
3263 break;
3264 default:
3265 break;
3266 }
3267
3268 spellInfoMutable->_InitializeExplicitTargetMask();
3269
3270 if (spellInfoMutable->Speed > 0.0f)
3271 {
3272 auto visualNeedsAmmo = [](SpellXSpellVisualEntry const* spellXspellVisual)
3273 {
3274 SpellVisualEntry const* spellVisual = sSpellVisualStore.LookupEntry(spellXspellVisual->SpellVisualID);
3275 if (!spellVisual)
3276 return false;
3277
3278 std::vector<SpellVisualMissileEntry const*> const* spellVisualMissiles = sDB2Manager.GetSpellVisualMissiles(spellVisual->SpellVisualMissileSetID);
3279 if (!spellVisualMissiles)
3280 return false;
3281
3282 for (SpellVisualMissileEntry const* spellVisualMissile : *spellVisualMissiles)
3283 {
3284 SpellVisualEffectNameEntry const* spellVisualEffectName = sSpellVisualEffectNameStore.LookupEntry(spellVisualMissile->SpellVisualEffectNameID);
3285 if (!spellVisualEffectName)
3286 continue;
3287
3288 SpellVisualEffectNameType type = SpellVisualEffectNameType(spellVisualEffectName->Type);
3290 return true;
3291 }
3292
3293 return false;
3294 };
3295
3296 for (SpellXSpellVisualEntry const* spellXspellVisual : spellInfoMutable->_visuals)
3297 {
3298 if (visualNeedsAmmo(spellXspellVisual))
3299 {
3300 spellInfoMutable->AttributesCu |= SPELL_ATTR0_CU_NEEDS_AMMO_DATA;
3301 break;
3302 }
3303 }
3304 }
3305
3306 // Saving to DB happens before removing from world - skip saving these auras
3309 }
3310
3311 // addition for binary spells, omit spells triggering other spells
3312 for (SpellInfo const& spellInfo : mSpellInfoMap)
3313 {
3314 SpellInfo* spellInfoMutable = const_cast<SpellInfo*>(&spellInfo);
3315 if (!spellInfoMutable->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
3316 {
3317 bool allNonBinary = true;
3318 bool overrideAttr = false;
3319 for (SpellEffectInfo const& spellEffectInfo : spellInfoMutable->GetEffects())
3320 {
3321 if (spellEffectInfo.IsAura() && spellEffectInfo.TriggerSpell)
3322 {
3323 switch (spellEffectInfo.ApplyAuraName)
3324 {
3328 if (SpellInfo const* triggerSpell = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, DIFFICULTY_NONE))
3329 {
3330 overrideAttr = true;
3331 if (triggerSpell->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
3332 allNonBinary = false;
3333 }
3334 break;
3335 default:
3336 break;
3337 }
3338 }
3339 }
3340
3341 if (overrideAttr && allNonBinary)
3342 spellInfoMutable->AttributesCu &= ~SPELL_ATTR0_CU_BINARY_SPELL;
3343 }
3344
3345 // remove attribute from spells that can't crit
3346 if (spellInfo.HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
3347 if (spellInfo.HasAttribute(SPELL_ATTR2_CANT_CRIT))
3348 spellInfoMutable->AttributesCu &= ~SPELL_ATTR0_CU_CAN_CRIT;
3349
3350 }
3351
3352 // add custom attribute to liquid auras
3353 for (LiquidTypeEntry const* liquid : sLiquidTypeStore)
3354 {
3355 if (liquid->SpellID)
3356 for (SpellInfo const& spellInfo : _GetSpellInfo(liquid->SpellID))
3358 }
3359
3360 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo custom attributes in {} ms", GetMSTimeDiffToNow(oldMSTime));
3361}
3362
3363inline void ApplySpellFix(std::initializer_list<uint32> spellIds, void(*fix)(SpellInfo*))
3364{
3365 for (uint32 spellId : spellIds)
3366 {
3367 auto range = _GetSpellInfo(spellId);
3368 if (range.begin() == range.end())
3369 {
3370 TC_LOG_ERROR("server.loading", "Spell info correction specified for non-existing spell {}", spellId);
3371 continue;
3372 }
3373
3374 for (SpellInfo const& spellInfo : range)
3375 fix(&const_cast<SpellInfo&>(spellInfo));
3376 }
3377}
3378
3379inline void ApplySpellEffectFix(SpellInfo* spellInfo, SpellEffIndex effectIndex, void(*fix)(SpellEffectInfo*))
3380{
3381 if (spellInfo->GetEffects().size() <= effectIndex)
3382 {
3383 TC_LOG_ERROR("server.loading", "Spell effect info correction specified for non-existing effect {} of spell {}", uint32(effectIndex), spellInfo->Id);
3384 return;
3385 }
3386
3387 fix(const_cast<SpellEffectInfo*>(&spellInfo->GetEffect(effectIndex)));
3388}
3389
3391{
3392 uint32 oldMSTime = getMSTime();
3393
3394 // Some spells have no amplitude set
3395 {
3397 6727, // Poison Mushroom
3398 7331, // Healing Aura (TEST) (Rank 1)
3399 /*
3400 30400, // Nether Beam - Perseverance
3401 Blizzlike to have it disabled? DBC says:
3402 "This is currently turned off to increase performance. Enable this to make it fire more frequently."
3403 */
3404 34589, // Dangerous Water
3405 52562, // Arthas Zombie Catcher
3406 57550, // Tirion Aggro
3407 65755
3408 }, [](SpellInfo* spellInfo)
3409 {
3410 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3411 {
3412 spellEffectInfo->ApplyAuraPeriod = 1 * IN_MILLISECONDS;
3413 });
3414 });
3415
3417 24707, // Food
3418 26263, // Dim Sum
3419 29055 // Refreshing Red Apple
3420 }, [](SpellInfo* spellInfo)
3421 {
3422 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
3423 {
3424 spellEffectInfo->ApplyAuraPeriod = 1 * IN_MILLISECONDS;
3425 });
3426 });
3427
3428 // Karazhan - Chess NPC AI, action timer
3429 ApplySpellFix({ 37504 }, [](SpellInfo* spellInfo)
3430 {
3431 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
3432 {
3433 spellEffectInfo->ApplyAuraPeriod = 5 * IN_MILLISECONDS;
3434 });
3435 });
3436
3437 // Vomit
3438 ApplySpellFix({ 43327 }, [](SpellInfo* spellInfo)
3439 {
3440 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
3441 {
3442 spellEffectInfo->ApplyAuraPeriod = 1 * IN_MILLISECONDS;
3443 });
3444 });
3445 }
3446
3447 // specific code for cases with no trigger spell provided in field
3448 {
3449 // Brood Affliction: Bronze
3450 ApplySpellFix({ 23170 }, [](SpellInfo* spellInfo)
3451 {
3452 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3453 {
3454 spellEffectInfo->TriggerSpell = 23171;
3455 });
3456 });
3457
3458 // Feed Captured Animal
3459 ApplySpellFix({ 29917 }, [](SpellInfo* spellInfo)
3460 {
3461 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3462 {
3463 spellEffectInfo->TriggerSpell = 29916;
3464 });
3465 });
3466
3467 // Remote Toy
3468 ApplySpellFix({ 37027 }, [](SpellInfo* spellInfo)
3469 {
3470 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3471 {
3472 spellEffectInfo->TriggerSpell = 37029;
3473 });
3474 });
3475
3476 // Eye of Grillok
3477 ApplySpellFix({ 38495 }, [](SpellInfo* spellInfo)
3478 {
3479 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3480 {
3481 spellEffectInfo->TriggerSpell = 38530;
3482 });
3483 });
3484
3485 // Tear of Azzinoth Summon Channel - it's not really supposed to do anything, and this only prevents the console spam
3486 ApplySpellFix({ 39857 }, [](SpellInfo* spellInfo)
3487 {
3488 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3489 {
3490 spellEffectInfo->TriggerSpell = 39856;
3491 });
3492 });
3493
3494 // Personalized Weather
3495 ApplySpellFix({ 46736 }, [](SpellInfo* spellInfo)
3496 {
3497 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3498 {
3499 spellEffectInfo->TriggerSpell = 46737;
3501 });
3502 });
3503 }
3504
3506 63026, // Summon Aspirant Test NPC (HACK: Target shouldn't be changed)
3507 63137 // Summon Valiant Test (HACK: Target shouldn't be changed; summon position should be untied from spell destination)
3508 }, [](SpellInfo* spellInfo)
3509 {
3510 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3511 {
3513 });
3514 });
3515
3516 // Summon Skeletons
3517 ApplySpellFix({ 52611, 52612 }, [](SpellInfo* spellInfo)
3518 {
3519 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3520 {
3521 spellEffectInfo->MiscValueB = 64;
3522 });
3523 });
3524
3526 40244, // Simon Game Visual
3527 40245, // Simon Game Visual
3528 40246, // Simon Game Visual
3529 40247, // Simon Game Visual
3530 42835 // Spout, remove damage effect, only anim is needed
3531 }, [](SpellInfo* spellInfo)
3532 {
3533 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3534 {
3535 spellEffectInfo->Effect = SPELL_EFFECT_NONE;
3536 });
3537 });
3538
3540 63665, // Charge (Argent Tournament emote on riders)
3541 31298, // Sleep (needs target selection script)
3542 51904, // Summon Ghouls On Scarlet Crusade (this should use conditions table, script for this spell needs to be fixed)
3543 68933, // Wrath of Air Totem rank 2 (Aura)
3544 29200 // Purify Helboar Meat
3545 }, [](SpellInfo* spellInfo)
3546 {
3547 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3548 {
3550 spellEffectInfo->TargetB = SpellImplicitTargetInfo();
3551 });
3552 });
3553
3555 56690, // Thrust Spear
3556 60586, // Mighty Spear Thrust
3557 60776, // Claw Swipe
3558 60881, // Fatal Strike
3559 60864 // Jaws of Death
3560 }, [](SpellInfo* spellInfo)
3561 {
3563 });
3564
3565 // Howl of Azgalor
3566 ApplySpellFix({ 31344 }, [](SpellInfo* spellInfo)
3567 {
3568 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3569 {
3570 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yards instead of 50000?!
3571 });
3572 });
3573
3575 42818, // Headless Horseman - Wisp Flight Port
3576 42821 // Headless Horseman - Wisp Flight Missile
3577 }, [](SpellInfo* spellInfo)
3578 {
3579 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100 yards
3580 });
3581
3582 // They Must Burn Bomb Aura (self)
3583 ApplySpellFix({ 36350 }, [](SpellInfo* spellInfo)
3584 {
3585 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3586 {
3587 spellEffectInfo->TriggerSpell = 36325; // They Must Burn Bomb Drop (DND)
3588 });
3589 });
3590
3592 31347, // Doom
3593 36327, // Shoot Arcane Explosion Arrow
3594 39365, // Thundering Storm
3595 41071, // Raise Dead (HACK)
3596 42442, // Vengeance Landing Cannonfire
3597 42611, // Shoot
3598 44978, // Wild Magic
3599 45001, // Wild Magic
3600 45002, // Wild Magic
3601 45004, // Wild Magic
3602 45006, // Wild Magic
3603 45010, // Wild Magic
3604 45761, // Shoot Gun
3605 45863, // Cosmetic - Incinerate to Random Target
3606 48246, // Ball of Flame
3607 41635, // Prayer of Mending
3608 44869, // Spectral Blast
3609 45027, // Revitalize
3610 45976, // Muru Portal Channel
3611 52124, // Sky Darkener Assault
3612 52479, // Gift of the Harvester
3613 61588, // Blazing Harpoon
3614 55479, // Force Obedience
3615 28560, // Summon Blizzard (Sapphiron)
3616 53096, // Quetz'lun's Judgment
3617 70743, // AoD Special
3618 70614, // AoD Special - Vegard
3619 4020, // Safirdrang's Chill
3620 52438, // Summon Skittering Swarmer (Force Cast)
3621 52449, // Summon Skittering Infector (Force Cast)
3622 53609, // Summon Anub'ar Assassin (Force Cast)
3623 53457, // Summon Impale Trigger (AoE)
3624 45907, // Torch Target Picker
3625 52953, // Torch
3626 58121, // Torch
3627 43109, // Throw Torch
3628 58552, // Return to Orgrimmar
3629 58533, // Return to Stormwind
3630 21855, // Challenge Flag
3631 38762, // Force of Neltharaku
3632 51122, // Fierce Lightning Stike
3633 71848, // Toxic Wasteling Find Target
3634 36146, // Chains of Naberius
3635 33711, // Murmur's Touch
3636 38794 // Murmur's Touch
3637 }, [](SpellInfo* spellInfo)
3638 {
3639 spellInfo->MaxAffectedTargets = 1;
3640 });
3641
3643 36384, // Skartax Purple Beam
3644 47731 // Critter
3645 }, [](SpellInfo* spellInfo)
3646 {
3647 spellInfo->MaxAffectedTargets = 2;
3648 });
3649
3651 28542, // Life Drain - Sapphiron
3652 29213, // Curse of the Plaguebringer - Noth
3653 29576, // Multi-Shot
3654 37790, // Spread Shot
3655 39992, // Needle Spine
3656 40816, // Saber Lash
3657 41303, // Soul Drain
3658 41376, // Spite
3659 45248, // Shadow Blades
3660 46771, // Flame Sear
3661 66588 // Flaming Spear
3662 }, [](SpellInfo* spellInfo)
3663 {
3664 spellInfo->MaxAffectedTargets = 3;
3665 });
3666
3668 38310, // Multi-Shot
3669 53385 // Divine Storm (Damage)
3670 }, [](SpellInfo* spellInfo)
3671 {
3672 spellInfo->MaxAffectedTargets = 4;
3673 });
3674
3676 42005, // Bloodboil
3677 38296, // Spitfire Totem
3678 37676, // Insidious Whisper
3679 46008, // Negative Energy
3680 45641, // Fire Bloom
3681 55665, // Life Drain - Sapphiron (H)
3682 28796, // Poison Bolt Volly - Faerlina
3683 37135 // Domination
3684 }, [](SpellInfo* spellInfo)
3685 {
3686 spellInfo->MaxAffectedTargets = 5;
3687 });
3688
3690 40827, // Sinful Beam
3691 40859, // Sinister Beam
3692 40860, // Vile Beam
3693 40861, // Wicked Beam
3694 54098, // Poison Bolt Volly - Faerlina (H)
3695 54835 // Curse of the Plaguebringer - Noth (H)
3696 }, [](SpellInfo* spellInfo)
3697 {
3698 spellInfo->MaxAffectedTargets = 10;
3699 });
3700
3701 // Unholy Frenzy
3702 ApplySpellFix({ 50312 }, [](SpellInfo* spellInfo)
3703 {
3704 spellInfo->MaxAffectedTargets = 15;
3705 });
3706
3707 // Fingers of Frost
3708 ApplySpellFix({ 44544 }, [](SpellInfo* spellInfo)
3709 {
3710 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3711 {
3712 spellEffectInfo->SpellClassMask[0] |= 0x20000;
3713 });
3714 });
3715
3717 52212, // Death and Decay
3718 41485, // Deadly Poison - Black Temple
3719 41487 // Envenom - Black Temple
3720 }, [](SpellInfo* spellInfo)
3721 {
3723 });
3724
3725 // Oscillation Field
3726 ApplySpellFix({ 37408 }, [](SpellInfo* spellInfo)
3727 {
3729 });
3730
3731 // Crafty's Ultra-Advanced Proto-Typical Shortening Blaster
3732 ApplySpellFix({ 51912 }, [](SpellInfo* spellInfo)
3733 {
3734 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3735 {
3736 spellEffectInfo->ApplyAuraPeriod = 3000;
3737 });
3738 });
3739
3740 // Nether Portal - Perseverence
3741 ApplySpellFix({ 30421 }, [](SpellInfo* spellInfo)
3742 {
3743 ApplySpellEffectFix(spellInfo, EFFECT_2, [](SpellEffectInfo* spellEffectInfo)
3744 {
3745 spellEffectInfo->BasePoints += 30000;
3746 });
3747 });
3748
3749 // Parasitic Shadowfiend Passive
3750 ApplySpellFix({ 41913 }, [](SpellInfo* spellInfo)
3751 {
3752 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3753 {
3754 spellEffectInfo->ApplyAuraName = SPELL_AURA_DUMMY; // proc debuff, and summon infinite fiends
3755 });
3756 });
3757
3759 27892, // To Anchor 1
3760 27928, // To Anchor 1
3761 27935, // To Anchor 1
3762 }, [](SpellInfo* spellInfo)
3763 {
3764 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3765 {
3766 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS);
3767 });
3768 });
3769
3770 // Wrath of the Plaguebringer
3771 ApplySpellFix({ 29214, 54836 }, [](SpellInfo* spellInfo)
3772 {
3773 // target allys instead of enemies, target A is src_caster, spells with effect like that have ally target
3774 // this is the only known exception, probably just wrong data
3775 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3776 {
3778 });
3779 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
3780 {
3782 });
3783 });
3784
3785 // Earthbind Totem (instant pulse)
3786 ApplySpellFix({ 6474 }, [](SpellInfo* spellInfo)
3787 {
3789 });
3790
3792 70728, // Exploit Weakness (needs target selection script)
3793 70840 // Devious Minds (needs target selection script)
3794 }, [](SpellInfo* spellInfo)
3795 {
3796 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3797 {
3800 });
3801 });
3802
3803 // Ride Carpet
3804 ApplySpellFix({ 45602 }, [](SpellInfo* spellInfo)
3805 {
3806 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3807 {
3808 spellEffectInfo->BasePoints = 0; // force seat 0, vehicle doesn't have the required seat flags for "no seat specified (-1)"
3809 });
3810 });
3811
3812 // Easter Lay Noblegarden Egg Aura - Interrupt flags copied from aura which this aura is linked with
3813 ApplySpellFix({ 61719 }, [](SpellInfo* spellInfo)
3814 {
3816 });
3817
3819 71838, // Drain Life - Bryntroll Normal
3820 71839 // Drain Life - Bryntroll Heroic
3821 }, [](SpellInfo* spellInfo)
3822 {
3824 });
3825
3827 51597, // Summon Scourged Captive
3828 56606, // Ride Jokkum
3829 61791 // Ride Vehicle (Yogg-Saron)
3830 }, [](SpellInfo* spellInfo)
3831 {
3833 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3834 {
3835 spellEffectInfo->BasePoints = 1;
3836 });
3837 });
3838
3839 // Summon Scourged Captive
3840 ApplySpellFix({ 51597 }, [](SpellInfo* spellInfo)
3841 {
3842 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3843 {
3844 spellEffectInfo->Scaling.Variance = 0.0f;
3845 });
3846 });
3847
3848 // Black Magic
3849 ApplySpellFix({ 59630 }, [](SpellInfo* spellInfo)
3850 {
3851 spellInfo->Attributes |= SPELL_ATTR0_PASSIVE;
3852 });
3853
3854 // Paralyze
3855 ApplySpellFix({ 48278 }, [](SpellInfo* spellInfo)
3856 {
3858 });
3859
3861 51798, // Brewfest - Relay Race - Intro - Quest Complete
3862 47134 // Quest Complete
3863 }, [](SpellInfo* spellInfo)
3864 {
3866 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3867 {
3868 spellEffectInfo->Effect = SPELL_EFFECT_NONE;
3869 });
3870 });
3871
3872 // Siege Cannon (Tol Barad)
3873 ApplySpellFix({ 85123 }, [](SpellInfo* spellInfo)
3874 {
3875 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3876 {
3877 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS);
3879 });
3880 });
3881
3882 // Maelstrom Weapon
3883 ApplySpellFix({ 187881 }, [](SpellInfo* spellInfo)
3884 {
3885 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
3886 {
3887 // Add Lava Burst to spells that benefit from it
3888 spellEffectInfo->SpellClassMask[1] |= 0x1000;
3889 });
3890 });
3891
3893 15538, // Gout of Flame
3894 42490, // Energized!
3895 42492, // Cast Energized
3896 43115 // Plague Vial
3897 }, [](SpellInfo* spellInfo)
3898 {
3899 spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT;
3900 });
3901
3902 // Test Ribbon Pole Channel
3903 ApplySpellFix({ 29726 }, [](SpellInfo* spellInfo)
3904 {
3906 });
3907
3908 // Sic'em
3909 ApplySpellFix({ 42767 }, [](SpellInfo* spellInfo)
3910 {
3911 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3912 {
3914 });
3915 });
3916
3917 // Burn Body
3918 ApplySpellFix({ 42793 }, [](SpellInfo* spellInfo)
3919 {
3920 ApplySpellEffectFix(spellInfo, EFFECT_2, [](SpellEffectInfo* spellEffectInfo)
3921 {
3922 spellEffectInfo->MiscValue = 24008; // Fallen Combatant
3923 });
3924 });
3925
3926 // Gift of the Naaru (priest and monk variants)
3927 ApplySpellFix({ 59544, 121093 }, [](SpellInfo* spellInfo)
3928 {
3929 spellInfo->SpellFamilyFlags[2] = 0x80000000;
3930 });
3931
3933 50661, // Weakened Resolve
3934 68979, // Unleashed Souls
3935 48714, // Compelled
3936 7853, // The Art of Being a Water Terror: Force Cast on Player
3937 }, [](SpellInfo* spellInfo)
3938 {
3939 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
3940 });
3941
3943 44327, // Trained Rock Falcon/Hawk Hunting
3944 44408 // Trained Rock Falcon/Hawk Hunting
3945 }, [](SpellInfo* spellInfo)
3946 {
3947 spellInfo->Speed = 0.f;
3948 });
3949
3950 // Summon Corpse Scarabs
3951 ApplySpellFix({ 28864, 29105 }, [](SpellInfo* spellInfo)
3952 {
3953 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
3954 {
3955 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS);
3956 });
3957 });
3958
3960 37851, // Tag Greater Felfire Diemetradon
3961 37918 // Arcano-pince
3962 }, [](SpellInfo* spellInfo)
3963 {
3964 spellInfo->RecoveryTime = 3000;
3965 });
3966
3967 // Jormungar Strike
3968 ApplySpellFix({ 56513 }, [](SpellInfo* spellInfo)
3969 {
3970 spellInfo->RecoveryTime = 2000;
3971 });
3972
3974 54997, // Cast Net (tooltip says 10s but sniffs say 6s)
3975 56524 // Acid Breath
3976 }, [](SpellInfo* spellInfo)
3977 {
3978 spellInfo->RecoveryTime = 6000;
3979 });
3980
3982 47911, // EMP
3983 48620, // Wing Buffet
3984 51752 // Stampy's Stompy-Stomp
3985 }, [](SpellInfo* spellInfo)
3986 {
3987 spellInfo->RecoveryTime = 10000;
3988 });
3989
3991 37727, // Touch of Darkness
3992 54996 // Ice Slick (tooltip says 20s but sniffs say 12s)
3993 }, [](SpellInfo* spellInfo)
3994 {
3995 spellInfo->RecoveryTime = 12000;
3996 });
3997
3998 // Signal Helmet to Attack
3999 ApplySpellFix({ 51748 }, [](SpellInfo* spellInfo)
4000 {
4001 spellInfo->RecoveryTime = 15000;
4002 });
4003
4005 51756, // Charge
4006 37919, //Arcano-dismantle
4007 37917 //Arcano-Cloak
4008 }, [](SpellInfo* spellInfo)
4009 {
4010 spellInfo->RecoveryTime = 20000;
4011 });
4012
4013 // Summon Frigid Bones
4014 ApplySpellFix({ 53525 }, [](SpellInfo* spellInfo)
4015 {
4016 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(4); // 2 minutes
4017 });
4018
4019 // Dark Conclave Ritualist Channel
4020 ApplySpellFix({ 38469 }, [](SpellInfo* spellInfo)
4021 {
4022 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100yd
4023 });
4024
4025 // Death and Decay (target increase)
4026 ApplySpellFix({ 188290 }, [](SpellInfo* spellInfo)
4027 {
4028 // Change SpellClassMask to exclude 49020 and only keep its triggered spells
4029 ApplySpellEffectFix(spellInfo, EFFECT_3, [](SpellEffectInfo* spellEffectInfo)
4030 {
4031 spellEffectInfo->SpellClassMask.Set(0x80, 0, 0, 0x8000);
4032 });
4033 });
4034
4035 // Chrono Shift (enemy slow part)
4036 ApplySpellFix({ 236299 }, [](SpellInfo* spellInfo)
4037 {
4038 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100yd
4039 });
4040
4041 // Inescapable Torment
4042 ApplySpellFix({ 373427 }, [](SpellInfo* spellInfo)
4043 {
4044 // Remove self-damage from passive aura on learn
4045 ApplySpellEffectFix(spellInfo, EFFECT_3, [](SpellEffectInfo* spellEffectInfo)
4046 {
4047 spellEffectInfo->Effect = SPELL_EFFECT_DUMMY;
4048 });
4049 });
4050
4051 // Summon Faol in Tirisfal
4052 ApplySpellFix({ 202112 }, [](SpellInfo* spellInfo)
4053 {
4054 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4055 {
4057 });
4058 });
4059
4060 //
4061 // VIOLET HOLD SPELLS
4062 //
4063 // Water Globule (Ichoron)
4064 ApplySpellFix({ 54258, 54264, 54265, 54266, 54267 }, [](SpellInfo* spellInfo)
4065 {
4066 // in 3.3.5 there is only one radius in dbc which is 0 yards in this case
4067 // use max radius from 4.3.4
4068 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4069 {
4070 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS);
4071 });
4072 });
4073 // ENDOF VIOLET HOLD
4074
4075 //
4076 // ULDUAR SPELLS
4077 //
4078 // Pursued (Flame Leviathan)
4079 ApplySpellFix({ 62374 }, [](SpellInfo* spellInfo)
4080 {
4081 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4082 {
4083 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4084 });
4085 });
4086
4087 // Focused Eyebeam Summon Trigger (Kologarn)
4088 ApplySpellFix({ 63342 }, [](SpellInfo* spellInfo)
4089 {
4090 spellInfo->MaxAffectedTargets = 1;
4091 });
4092
4094 65584, // Growth of Nature (Freya)
4095 64381 // Strength of the Pack (Auriaya)
4096 }, [](SpellInfo* spellInfo)
4097 {
4099 });
4100
4102 63018, // Searing Light (XT-002)
4103 65121, // Searing Light (25m) (XT-002)
4104 63024, // Gravity Bomb (XT-002)
4105 64234 // Gravity Bomb (25m) (XT-002)
4106 }, [](SpellInfo* spellInfo)
4107 {
4108 spellInfo->MaxAffectedTargets = 1;
4109 });
4110
4112 64386, // Terrifying Screech (Auriaya)
4113 64389, // Sentinel Blast (Auriaya)
4114 64678 // Sentinel Blast (Auriaya)
4115 }, [](SpellInfo* spellInfo)
4116 {
4117 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(28); // 5 seconds, wrong DBC data?
4118 });
4119
4120 // Potent Pheromones (Freya)
4121 ApplySpellFix({ 64321 }, [](SpellInfo* spellInfo)
4122 {
4123 // spell should dispel area aura, but doesn't have the attribute
4124 // may be db data bug, or blizz may keep reapplying area auras every update with checking immunity
4125 // that will be clear if we get more spells with problem like this
4127 });
4128
4129 // Blizzard (Thorim)
4130 ApplySpellFix({ 62576, 62602 }, [](SpellInfo* spellInfo)
4131 {
4132 // DBC data is wrong for EFFECT_0, it's a different dynobject target than EFFECT_1
4133 // Both effects should be shared by the same DynObject
4134 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4135 {
4137 });
4138 });
4139
4140 // Spinning Up (Mimiron)
4141 ApplySpellFix({ 63414 }, [](SpellInfo* spellInfo)
4142 {
4145 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4146 {
4148 });
4149 });
4150
4151 // Rocket Strike (Mimiron)
4152 ApplySpellFix({ 63036 }, [](SpellInfo* spellInfo)
4153 {
4154 spellInfo->Speed = 0;
4155 });
4156
4157 // Magnetic Field (Mimiron)
4158 ApplySpellFix({ 64668 }, [](SpellInfo* spellInfo)
4159 {
4160 spellInfo->Mechanic = MECHANIC_NONE;
4161 });
4162
4163 // Empowering Shadows (Yogg-Saron)
4164 ApplySpellFix({ 64468, 64486 }, [](SpellInfo* spellInfo)
4165 {
4166 spellInfo->MaxAffectedTargets = 3; // same for both modes?
4167 });
4168
4169 // Cosmic Smash (Algalon the Observer)
4170 ApplySpellFix({ 62301 }, [](SpellInfo* spellInfo)
4171 {
4172 spellInfo->MaxAffectedTargets = 1;
4173 });
4174
4175 // Cosmic Smash (Algalon the Observer)
4176 ApplySpellFix({ 64598 }, [](SpellInfo* spellInfo)
4177 {
4178 spellInfo->MaxAffectedTargets = 3;
4179 });
4180
4181 // Cosmic Smash (Algalon the Observer)
4182 ApplySpellFix({ 62293 }, [](SpellInfo* spellInfo)
4183 {
4184 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4185 {
4187 });
4188 });
4189
4190 // Cosmic Smash (Algalon the Observer)
4191 ApplySpellFix({ 62311, 64596 }, [](SpellInfo* spellInfo)
4192 {
4193 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100yd
4194 });
4195
4197 64014, // Expedition Base Camp Teleport
4198 64024, // Conservatory Teleport
4199 64025, // Halls of Invention Teleport
4200 64028, // Colossal Forge Teleport
4201 64029, // Shattered Walkway Teleport
4202 64030, // Antechamber Teleport
4203 64031, // Scrapyard Teleport
4204 64032, // Formation Grounds Teleport
4205 65042 // Prison of Yogg-Saron Teleport
4206 }, [](SpellInfo* spellInfo)
4207 {
4208 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4209 {
4211 });
4212 });
4213 // ENDOF ULDUAR SPELLS
4214
4215 //
4216 // TRIAL OF THE CRUSADER SPELLS
4217 //
4218 // Infernal Eruption
4219 ApplySpellFix({ 66258 }, [](SpellInfo* spellInfo)
4220 {
4221 // increase duration from 15 to 18 seconds because caster is already
4222 // unsummoned when spell missile hits the ground so nothing happen in result
4223 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(85);
4224 });
4225 // ENDOF TRIAL OF THE CRUSADER SPELLS
4226
4227 //
4228 // ICECROWN CITADEL SPELLS
4229 //
4231 70781, // Light's Hammer Teleport
4232 70856, // Oratory of the Damned Teleport
4233 70857, // Rampart of Skulls Teleport
4234 70858, // Deathbringer's Rise Teleport
4235 70859, // Upper Spire Teleport
4236 70860, // Frozen Throne Teleport
4237 70861 // Sindragosa's Lair Teleport
4238 }, [](SpellInfo* spellInfo)
4239 {
4240 // THESE SPELLS ARE WORKING CORRECTLY EVEN WITHOUT THIS HACK
4241 // THE ONLY REASON ITS HERE IS THAT CURRENT GRID SYSTEM
4242 // DOES NOT ALLOW FAR OBJECT SELECTION (dist > 333)
4243 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4244 {
4246 });
4247 });
4248
4249 // Shadow's Fate
4250 ApplySpellFix({ 71169 }, [](SpellInfo* spellInfo)
4251 {
4253 });
4254
4255 // Resistant Skin (Deathbringer Saurfang adds)
4256 ApplySpellFix({ 72723 }, [](SpellInfo* spellInfo)
4257 {
4258 // this spell initially granted Shadow damage immunity, however it was removed but the data was left in client
4259 ApplySpellEffectFix(spellInfo, EFFECT_2, [](SpellEffectInfo* spellEffectInfo)
4260 {
4261 spellEffectInfo->Effect = SPELL_EFFECT_NONE;
4262 });
4263 });
4264
4265 // Coldflame Jets (Traps after Saurfang)
4266 ApplySpellFix({ 70460 }, [](SpellInfo* spellInfo)
4267 {
4268 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(1); // 10 seconds
4269 });
4270
4272 71412, // Green Ooze Summon (Professor Putricide)
4273 71415 // Orange Ooze Summon (Professor Putricide)
4274 }, [](SpellInfo* spellInfo)
4275 {
4276 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4277 {
4279 });
4280 });
4281
4282 // Awaken Plagued Zombies
4283 ApplySpellFix({ 71159 }, [](SpellInfo* spellInfo)
4284 {
4285 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(21);
4286 });
4287
4288 // Volatile Ooze Beam Protection (Professor Putricide)
4289 ApplySpellFix({ 70530 }, [](SpellInfo* spellInfo)
4290 {
4291 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4292 {
4293 spellEffectInfo->Effect = SPELL_EFFECT_APPLY_AURA; // for an unknown reason this was SPELL_EFFECT_APPLY_AREA_AURA_RAID
4294 });
4295 });
4296
4297 // Mutated Strength (Professor Putricide)
4298 ApplySpellFix({ 71604 }, [](SpellInfo* spellInfo)
4299 {
4300 // THIS IS HERE BECAUSE COOLDOWN ON CREATURE PROCS WERE NOT IMPLEMENTED WHEN THE SCRIPT WAS WRITTEN
4301 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
4302 {
4303 spellEffectInfo->Effect = SPELL_EFFECT_NONE;
4304 });
4305 });
4306
4307 // Unbound Plague (Professor Putricide) (needs target selection script)
4308 ApplySpellFix({ 70911 }, [](SpellInfo* spellInfo)
4309 {
4310 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4311 {
4313 });
4314 });
4315
4316 // Empowered Flare (Blood Prince Council)
4317 ApplySpellFix({ 71708 }, [](SpellInfo* spellInfo)
4318 {
4320 });
4321
4322 // Swarming Shadows
4323 ApplySpellFix({ 71266 }, [](SpellInfo* spellInfo)
4324 {
4325 spellInfo->RequiredAreasID = 0; // originally, these require area 4522, which is... outside of Icecrown Citadel
4326 });
4327
4328 // Corruption
4329 ApplySpellFix({ 70602 }, [](SpellInfo* spellInfo)
4330 {
4332 });
4333
4334 // Column of Frost (visual marker)
4335 ApplySpellFix({ 70715 }, [](SpellInfo* spellInfo)
4336 {
4337 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(32); // 6 seconds (missing)
4338 });
4339
4340 // Mana Void (periodic aura)
4341 ApplySpellFix({ 71085 }, [](SpellInfo* spellInfo)
4342 {
4343 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(9); // 30 seconds (missing)
4344 });
4345
4346 // Summon Suppressor (needs target selection script)
4347 ApplySpellFix({ 70936 }, [](SpellInfo* spellInfo)
4348 {
4349 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(157); // 90yd
4350 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4351 {
4353 spellEffectInfo->TargetB = SpellImplicitTargetInfo();
4354 });
4355 });
4356
4357 // Sindragosa's Fury
4358 ApplySpellFix({ 70598 }, [](SpellInfo* spellInfo)
4359 {
4360 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4361 {
4363 });
4364 });
4365
4366 // Frost Bomb
4367 ApplySpellFix({ 69846 }, [](SpellInfo* spellInfo)
4368 {
4369 spellInfo->Speed = 0.0f; // This spell's summon happens instantly
4370 });
4371
4372 // Chilled to the Bone
4373 ApplySpellFix({ 70106 }, [](SpellInfo* spellInfo)
4374 {
4377 });
4378
4379 // Ice Lock
4380 ApplySpellFix({ 71614 }, [](SpellInfo* spellInfo)
4381 {
4382 spellInfo->Mechanic = MECHANIC_STUN;
4383 });
4384
4385 // Defile
4386 ApplySpellFix({ 72762 }, [](SpellInfo* spellInfo)
4387 {
4388 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(559); // 53 seconds
4389 });
4390
4391 // Defile
4392 ApplySpellFix({ 72743 }, [](SpellInfo* spellInfo)
4393 {
4394 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(22); // 45 seconds
4395 });
4396
4397 // Defile
4398 ApplySpellFix({ 72754 }, [](SpellInfo* spellInfo)
4399 {
4400 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4401 {
4402 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4403 });
4404 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
4405 {
4406 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4407 });
4408 });
4409
4410 // Val'kyr Target Search
4411 ApplySpellFix({ 69030 }, [](SpellInfo* spellInfo)
4412 {
4414 });
4415
4416 // Raging Spirit Visual
4417 ApplySpellFix({ 69198 }, [](SpellInfo* spellInfo)
4418 {
4419 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
4420 });
4421
4422 // Harvest Soul
4423 ApplySpellFix({ 73655 }, [](SpellInfo* spellInfo)
4424 {
4426 });
4427
4428 // Summon Shadow Trap
4429 ApplySpellFix({ 73540 }, [](SpellInfo* spellInfo)
4430 {
4431 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(3); // 60 seconds
4432 });
4433
4434 // Shadow Trap (visual)
4435 ApplySpellFix({ 73530 }, [](SpellInfo* spellInfo)
4436 {
4437 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(27); // 3 seconds
4438 });
4439
4440 // Summon Spirit Bomb
4441 ApplySpellFix({ 74302 }, [](SpellInfo* spellInfo)
4442 {
4443 spellInfo->MaxAffectedTargets = 2;
4444 });
4445
4446 // Summon Spirit Bomb
4447 ApplySpellFix({ 73579 }, [](SpellInfo* spellInfo)
4448 {
4449 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4450 {
4451 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS); // 25yd
4452 });
4453 });
4454
4455 // Raise Dead
4456 ApplySpellFix({ 72376 }, [](SpellInfo* spellInfo)
4457 {
4458 spellInfo->MaxAffectedTargets = 3;
4459 });
4460
4461 // Jump
4462 ApplySpellFix({ 71809 }, [](SpellInfo* spellInfo)
4463 {
4464 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(5); // 40yd
4465 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4466 {
4467 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS); // 10yd
4468 spellEffectInfo->MiscValue = 190;
4469 });
4470 });
4471 // ENDOF ICECROWN CITADEL SPELLS
4472
4473 //
4474 // RUBY SANCTUM SPELLS
4475 //
4476 // Soul Consumption
4477 ApplySpellFix({ 74799 }, [](SpellInfo* spellInfo)
4478 {
4479 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
4480 {
4481 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_12_YARDS);
4482 });
4483 });
4484
4485 // Twilight Mending
4486 ApplySpellFix({ 75509 }, [](SpellInfo* spellInfo)
4487 {
4490 });
4491
4492 // Awaken Flames
4493 ApplySpellFix({ 75888 }, [](SpellInfo* spellInfo)
4494 {
4496 });
4497 // ENDOF RUBY SANCTUM SPELLS
4498
4499 //
4500 // EYE OF ETERNITY SPELLS
4501 //
4503 57473, // Arcane Storm bonus explicit visual spell
4504 57431, // Summon Static Field
4505 56091, // Flame Spike (Wyrmrest Skytalon)
4506 56092, // Engulf in Flames (Wyrmrest Skytalon)
4507 57090, // Revivify (Wyrmrest Skytalon)
4508 57143 // Life Burst (Wyrmrest Skytalon)
4509 }, [](SpellInfo* spellInfo)
4510 {
4511 // All spells work even without these changes. The LOS attribute is due to problem
4512 // from collision between maps & gos with active destroyed state.
4514 });
4515
4516 // Arcane Barrage (cast by players and NONMELEEDAMAGELOG with caster Scion of Eternity (original caster)).
4517 ApplySpellFix({ 63934 }, [](SpellInfo* spellInfo)
4518 {
4519 // This would never crit on retail and it has attribute for SPELL_ATTR3_NO_DONE_BONUS because is handled from player,
4520 // until someone figures how to make scions not critting without hack and without making them main casters this should stay here.
4522 });
4523 // ENDOF EYE OF ETERNITY SPELLS
4524
4526 40055, // Introspection
4527 40165, // Introspection
4528 40166, // Introspection
4529 40167, // Introspection
4530 }, [](SpellInfo* spellInfo)
4531 {
4533 });
4534
4535 //
4536 // STONECORE SPELLS
4537 //
4539 95284, // Teleport (from entrance to Slabhide)
4540 95285 // Teleport (from Slabhide to entrance)
4541 }, [](SpellInfo* spellInfo)
4542 {
4543 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4544 {
4546 });
4547 });
4548 // ENDOF STONECORE SPELLS
4549
4550 //
4551 // HALLS OF ORIGINATION SPELLS
4552 //
4554 76606, // Disable Beacon Beams L
4555 76608 // Disable Beacon Beams R
4556 }, [](SpellInfo* spellInfo)
4557 {
4558 // Little hack, Increase the radius so it can hit the Cave In Stalkers in the platform.
4559 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4560 {
4561 spellEffectInfo->TargetBRadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_45_YARDS);
4562 });
4563 });
4564
4565 // ENDOF HALLS OF ORIGINATION SPELLS
4566
4567 // Threatening Gaze
4568 ApplySpellFix({ 24314 }, [](SpellInfo* spellInfo)
4569 {
4571 });
4572
4573 // Travel Form (dummy) - cannot be cast indoors.
4574 ApplySpellFix({ 783 }, [](SpellInfo* spellInfo)
4575 {
4577 });
4578
4579 // Tree of Life (Passive)
4580 ApplySpellFix({ 5420 }, [](SpellInfo* spellInfo)
4581 {
4582 spellInfo->Stances = UI64LIT(1) << (FORM_TREE_OF_LIFE - 1);
4583 });
4584
4585 // Gaze of Occu'thar
4586 ApplySpellFix({ 96942 }, [](SpellInfo* spellInfo)
4587 {
4588 spellInfo->AttributesEx &= ~SPELL_ATTR1_IS_CHANNELLED;
4589 });
4590
4591 // Evolution
4592 ApplySpellFix({ 75610 }, [](SpellInfo* spellInfo)
4593 {
4594 spellInfo->MaxAffectedTargets = 1;
4595 });
4596
4597 // Evolution
4598 ApplySpellFix({ 75697 }, [](SpellInfo* spellInfo)
4599 {
4600 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4601 {
4603 });
4604 });
4605
4606 //
4607 // ISLE OF CONQUEST SPELLS
4608 //
4609 // Teleport
4610 ApplySpellFix({ 66551 }, [](SpellInfo* spellInfo)
4611 {
4612 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
4613 });
4614 // ENDOF ISLE OF CONQUEST SPELLS
4615
4616 // Aura of Fear
4617 ApplySpellFix({ 40453 }, [](SpellInfo* spellInfo)
4618 {
4619 // Bad DBC data? Copying 25820 here due to spell description
4620 // either is a periodic with chance on tick, or a proc
4621
4622 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4623 {
4625 spellEffectInfo->ApplyAuraPeriod = 0;
4626 });
4627 spellInfo->ProcChance = 10;
4628 });
4629
4630 // Survey Sinkholes
4631 ApplySpellFix({ 45853 }, [](SpellInfo* spellInfo)
4632 {
4633 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(5); // 40 yards
4634 });
4635
4636 // Baron Rivendare (Stratholme) - Unholy Aura
4637 ApplySpellFix({ 17466, 17467 }, [](SpellInfo* spellInfo)
4638 {
4640 });
4641
4642 // Spore - Spore Visual
4643 ApplySpellFix({ 42525 }, [](SpellInfo* spellInfo)
4644 {
4647 });
4648
4649 // Soul Sickness (Forge of Souls)
4650 ApplySpellFix({ 69131 }, [](SpellInfo* spellInfo)
4651 {
4652 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
4653 {
4655 });
4656 });
4657
4658 //
4659 // FIRELANDS SPELLS
4660 //
4661 // Torment Searcher
4662 ApplySpellFix({ 99253 }, [](SpellInfo* spellInfo)
4663 {
4664 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4665 {
4666 spellEffectInfo->TargetBRadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_15_YARDS);
4667 });
4668 });
4669
4670 // Torment Damage
4671 ApplySpellFix({ 99256 }, [](SpellInfo* spellInfo)
4672 {
4674 });
4675
4676 // Blaze of Glory
4677 ApplySpellFix({ 99252 }, [](SpellInfo* spellInfo)
4678 {
4680 });
4681 // ENDOF FIRELANDS
4682
4683 //
4684 // SCARLET HALLS SPELLS
4685 //
4686
4687 // 111755 - Call Reinforcement
4688 ApplySpellFix({ 111755 }, [](SpellInfo* spellInfo)
4689 {
4691
4692 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4693 {
4695 });
4696 });
4697
4698 // 111756 - Call Reinforcement
4699 ApplySpellFix({ 111756 }, [](SpellInfo* spellInfo)
4700 {
4702
4703 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4704 {
4706 });
4707 });
4708
4709 // ENDOF SCARLET HALLS SPELLS
4710
4711 //
4712 // MARDUM SPELLS
4713 //
4714
4715 // 187382 - The Invasion Begins: Summon Wrath Warrior
4716 ApplySpellFix({ 187382 }, [](SpellInfo* spellInfo)
4717 {
4718 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000 yards
4719
4720 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4721 {
4723 });
4724 });
4725
4726 // 195061 - Beaming Gaze
4727 ApplySpellFix({ 195061 }, [](SpellInfo* spellInfo)
4728 {
4729 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4730 {
4732 });
4733 });
4734
4735 // ENDOF MARDUM SPELLS
4736
4737 //
4738 // MAW OF SOULS SPELLS
4739 //
4740
4741 // 193465 - Bane
4742 ApplySpellFix({ 193465 }, [](SpellInfo* spellInfo)
4743 {
4744 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4745 {
4746 // Normal difficulty should also be using the regular heroic+ AreaTriggerCreateProperties
4747 spellEffectInfo->MiscValue = 5838;
4748 });
4749 });
4750
4751 // ENDOF MAW OF SOULS SPELLS
4752
4753 //
4754 // BLACK ROOK HOLD SPELLS
4755 //
4756
4757 // Soul Echoes
4758 ApplySpellFix({ 194981 }, [](SpellInfo* spellInfo)
4759 {
4760 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // Vision Range (AOI)
4761 });
4762
4763 // Soulgorge
4764 ApplySpellFix({ 196930 }, [](SpellInfo* spellInfo)
4765 {
4766 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(7); // 10 yd
4767 });
4768
4769 // ENDOF BLACK ROOK HOLD SPELLS
4770
4771 //
4772 // EYE OF AZSHARA SPELLS
4773 //
4774
4775 // Gaseous Bubbles
4776 ApplySpellFix({ 193018 }, [](SpellInfo* spellInfo)
4777 {
4779 });
4780
4781 // ENDOF EYE OF AZSHARA SPELLS
4782
4783 //
4784 // ANTORUS THE BURNING THRONE SPELLS
4785 //
4786
4787 // Decimation
4788 ApplySpellFix({ 244449 }, [](SpellInfo* spellInfo)
4789 {
4790 // For some reason there is a instakill effect that serves absolutely no purpose.
4791 // Until we figure out what it's actually used for we disable it.
4792 ApplySpellEffectFix(spellInfo, EFFECT_2, [](SpellEffectInfo* spellEffectInfo)
4793 {
4794 spellEffectInfo->Effect = SPELL_EFFECT_NONE;
4795 });
4796 });
4797
4798 // ENDOF ANTORUS THE BURNING THRONE SPELLS
4799
4800 //
4801 // DRUSTVAR SPELLS
4802 //
4803
4804 // Shoot Wickerman
4805 ApplySpellFix({ 255416 }, [](SpellInfo* spellInfo)
4806 {
4808 });
4809
4810 //
4811 // ENDOF DRUSTVAR SPELLS
4812 //
4813
4814 //
4815 // STORMSONG VALLEY SPELLS
4816 //
4817
4818 // Void Orb
4819 ApplySpellFix({ 273467 }, [](SpellInfo* spellInfo)
4820 {
4821 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4822 {
4823 spellEffectInfo->TargetARadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_0_5_YARDS);
4824 });
4825 });
4826
4827 // ENDOF STORMSONG VALLEY SPELLS
4828
4829 //
4830 // KINGS REST SPELLS
4831 //
4832
4833 // Fixate
4834 ApplySpellFix({ 269936 }, [](SpellInfo* spellInfo)
4835 {
4837 });
4838
4839 // ENDOF KINGS REST SPELLS
4840
4841 //
4842 // WAYCREST MANOR SPELLS
4843 //
4844
4845 // Discordant Cadenza
4846 ApplySpellFix({ 268308 }, [](SpellInfo* spellInfo)
4847 {
4849 });
4850
4851 // Waycrest Manor - Waycrests Defeated (Horde)
4852 // Waycrest Manor - Waycrests Defeated (Alliance)
4853 ApplySpellFix({ 267595, 267597, 267609 }, [](SpellInfo* spellInfo)
4854 {
4855 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4856 {
4857 spellEffectInfo->Effect = SPELL_EFFECT_CREATE_CONVERSATION;
4858 });
4859 });
4860
4862 260566, // Wildfire Missile
4863 260570 // Wildfire Missile Impact
4864 }, [](SpellInfo* spellInfo)
4865 {
4868 });
4869
4870 // ENDOF WAYCREST MANOR SPELLS
4871
4872 //
4873 // SEPULCHER OF THE FIRST ONES
4874 //
4875
4876 // Wicked Star (Marker)
4877 ApplySpellFix({ 365021 }, [](SpellInfo* spellInfo)
4878 {
4880 });
4881
4882 // Empowered Wicked Star (Marker)
4883 ApplySpellFix({ 367632 }, [](SpellInfo* spellInfo)
4884 {
4886 });
4887
4888 // Wicked Star Areatrigger
4889 ApplySpellFix({ 365017 }, [](SpellInfo* spellInfo)
4890 {
4891 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4892 {
4894 });
4895 });
4896
4897 // Willpower Energize Large
4898 ApplySpellFix({ 365228 }, [](SpellInfo* spellInfo)
4899 {
4901 });
4902
4903 // Willpower Energize Small
4904 ApplySpellFix({ 365217 }, [](SpellInfo* spellInfo)
4905 {
4907 });
4908
4909 // Force of Will
4910 ApplySpellFix({ 368913 }, [](SpellInfo* spellInfo)
4911 {
4913 });
4914
4915 // Fragment of Hope Areatrigger
4916 ApplySpellFix({ 365816 }, [](SpellInfo* spellInfo)
4917 {
4918 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4919 {
4921 });
4922 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
4923 {
4925 });
4926 });
4927
4928 // Shadestep
4929 ApplySpellFix({ 363976 }, [](SpellInfo* spellInfo)
4930 {
4931 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4932 {
4934 });
4935 });
4936 // ENDOF SEPULCHER OF THE FIRST ONES
4937
4938 //
4939 // THE AZURE VAULT SPELLS
4940 //
4941
4942 // Stinging Sap
4943 ApplySpellFix({ 374523 }, [](SpellInfo* spellInfo)
4944 {
4946 });
4947
4948 // Jump to Center (DNT)
4949 ApplySpellFix({ 387981 }, [](SpellInfo* spellInfo)
4950 {
4951 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4952 {
4954 });
4955 });
4956
4957 // Jump to Platform (DNT)
4958 ApplySpellFix({ 388082 }, [](SpellInfo* spellInfo)
4959 {
4960 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4961 {
4963 });
4964 });
4965
4966 // ENDOF THE AZURE VAULT SPELLS
4967 //
4968
4969 //
4970 // SHRINE OF THE STORM SPELLS
4971 //
4972
4973 // These spells have TARGET_DEST_NEARBY_ENTRY for serverside unit
4975 274365, // Requiem of the Abyss
4976 274367, // Requiem of the Abyss
4977 264911, // Erupting Waters
4978 264912, // Erupting Waters
4979 264913, // Erupting Waters
4980 }, [](SpellInfo* spellInfo)
4981 {
4982 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4983 {
4985 });
4986 });
4987
4988 // Conversation
4989 ApplySpellFix({ 274668, 274669, 274622, 274640, 274641, 274674, 274675 }, [](SpellInfo* spellInfo)
4990 {
4991 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
4992 {
4993 spellEffectInfo->Effect = SPELL_EFFECT_CREATE_CONVERSATION;
4994 });
4995 });
4996
4997 // ENDOF SHRINE OF THE STORM SPELLS
4998 //
4999
5000 //
5001 // UNDERROT SPELLS
5002 //
5003
5004 // Boundless Rot
5005 ApplySpellFix({ 259845 }, [](SpellInfo* spellInfo)
5006 {
5007 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
5008 {
5010 });
5011 });
5012
5013 // ENDOF UNDERROT SPELLS
5014 //
5015
5016 //
5017 // ATAL DAZAR SPELLS
5018 //
5019
5020 // Reverse Cast Ride Vehicle
5021 ApplySpellFix({ 258344 }, [](SpellInfo* spellInfo)
5022 {
5023 spellInfo->AttributesEx8 &= ~SPELL_ATTR8_ONLY_TARGET_IF_SAME_CREATOR;
5024 });
5025
5026 // Ritual
5027 // Spirit of Gold
5028 // Summon Spirit of Gold
5030 258388,
5031 259205,
5032 259209
5033 }, [](SpellInfo* spellInfo)
5034 {
5035 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
5036 {
5038 });
5039 });
5040
5041 // Tainted Blood
5042 ApplySpellFix({ 255592 }, [](SpellInfo* spellInfo)
5043 {
5045 });
5046
5047 // ENDOF ATAL DAZAR SPELLS
5048 //
5049
5050 //
5051 // THE WANDERING ISLE SPELLS
5052 //
5053
5054 // Summon Master Li Fei
5055 ApplySpellFix({ 102445 }, [](SpellInfo* spellInfo)
5056 {
5057 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
5058 {
5060 });
5061 });
5062
5063 // Flame Spout
5064 ApplySpellFix({ 114685 }, [](SpellInfo* spellInfo)
5065 {
5066 spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT;
5068 });
5069
5070 // ENDOF THE WANDERING ISLE SPELLS
5071 //
5072
5073 //
5074 // JADE FOREST SPELLS
5075 //
5076
5077 // Shredder Round
5078 ApplySpellFix({ 130162 }, [](SpellInfo* spellInfo)
5079 {
5080 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(245); // Five Hundred Yards
5081 });
5082
5083 // Cannon Explosion
5084 ApplySpellFix({ 130237 }, [](SpellInfo* spellInfo)
5085 {
5086 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
5087 {
5088 spellEffectInfo->Effect = SPELL_EFFECT_NONE;
5089 });
5090 });
5091
5092 // Summon Gunship Turret, Left
5093 // Summon Gunship Turret, Middle
5094 // Summon Gunship Turret, Right
5095 ApplySpellFix({ 130996, 130997, 130998 }, [](SpellInfo* spellInfo)
5096 {
5097 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(12); // Interact Range
5098 spellInfo->AttributesEx4 &= ~SPELL_ATTR4_USE_FACING_FROM_SPELL;
5099 });
5100
5101 // Rappelling Rope
5102 ApplySpellFix({ 130960 }, [](SpellInfo* spellInfo)
5103 {
5105 });
5106
5107 // ENDOF JADE FOREST SPELLS
5108 //
5109
5110 //
5111 // DARKFLAME CLEFT SPELLS
5112 //
5113
5114 // Darkflame Pickaxe
5115 ApplySpellFix({ 421277 }, [](SpellInfo* spellInfo)
5116 {
5118 });
5119
5120 // Throw Darkflame
5121 ApplySpellFix({ 420696 }, [](SpellInfo* spellInfo)
5122 {
5124 });
5125
5126 // Throw Darkflame
5127 ApplySpellFix({ 421250 }, [](SpellInfo* spellInfo)
5128 {
5129 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(165); // 7s
5130 });
5131
5132 // ENDOF DARKFLAME CLEFT SPELLS
5133 //
5134
5135 // Earthquake
5136 ApplySpellFix({ 61882 }, [](SpellInfo* spellInfo)
5137 {
5138 spellInfo->NegativeEffects[EFFECT_2] = true;
5139 });
5140
5141 // Sundering
5142 ApplySpellFix({ 197214 }, [](SpellInfo* spellInfo)
5143 {
5144 ApplySpellEffectFix(spellInfo, EFFECT_2, [](SpellEffectInfo* spellEffectInfo)
5145 {
5146 spellEffectInfo->TargetB = SpellImplicitTargetInfo();
5147 });
5148 });
5149
5150 // Headless Horseman Climax - Return Head (Hallow End)
5151 // Headless Horseman Climax - Body Regen (confuse only - removed on death)
5152 // Headless Horseman Climax - Head Is Dead
5153 ApplySpellFix({ 42401, 43105, 42428 }, [](SpellInfo* spellInfo)
5154 {
5156 });
5157
5158 // Horde / Alliance switch (BG mercenary system)
5159 ApplySpellFix({ 195838, 195843 }, [](SpellInfo* spellInfo)
5160 {
5161 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
5162 {
5163 spellEffectInfo->Effect = SPELL_EFFECT_APPLY_AURA;
5164 });
5165 ApplySpellEffectFix(spellInfo, EFFECT_1, [](SpellEffectInfo* spellEffectInfo)
5166 {
5167 spellEffectInfo->Effect = SPELL_EFFECT_APPLY_AURA;
5168 });
5169 ApplySpellEffectFix(spellInfo, EFFECT_2, [](SpellEffectInfo* spellEffectInfo)
5170 {
5171 spellEffectInfo->Effect = SPELL_EFFECT_APPLY_AURA;
5172 });
5173 });
5174
5175 // Fire Cannon
5176 ApplySpellFix({ 181593 }, [](SpellInfo* spellInfo)
5177 {
5178 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
5179 {
5180 // This spell never triggers, theory is that it was supposed to be only triggered until target reaches some health percentage
5181 // but was broken and always caused visuals to break, then target was changed to immediately spawn with desired health
5182 // leaving old data in db2
5183 spellEffectInfo->TriggerSpell = 0;
5184 });
5185 });
5186
5187 ApplySpellFix({ 265057 }, [](SpellInfo* spellInfo)
5188 {
5189 ApplySpellEffectFix(spellInfo, EFFECT_0, [](SpellEffectInfo* spellEffectInfo)
5190 {
5191 // Fix incorrect spell id (it has self in TriggerSpell)
5192 spellEffectInfo->TriggerSpell = 16403;
5193 });
5194 });
5195
5196 // Ray of Frost (Fingers of Frost charges)
5197 ApplySpellFix({ 269748 }, [](SpellInfo* spellInfo)
5198 {
5199 spellInfo->AttributesEx &= ~SPELL_ATTR1_IS_CHANNELLED;
5200 });
5201
5202 // Burning Rush
5203 ApplySpellFix({ 111400 }, [](SpellInfo* spellInfo)
5204 {
5206 });
5207
5208 // TODO: temporary, remove with dragonriding
5209 ApplySpellFix({ 404468 }, [](SpellInfo* spellInfo)
5210 {
5212 });
5213
5214 // Sigil of Flame
5215 ApplySpellFix({ 204598 }, [](SpellInfo* spellInfo)
5216 {
5217 ApplySpellEffectFix(spellInfo, EFFECT_2, [](SpellEffectInfo* spellEffectInfo)
5218 {
5219 spellEffectInfo->Effect = SPELL_EFFECT_NONE;
5220 });
5221 });
5222
5223 // Eradicate, Reap, Cull
5224 ApplySpellFix({ 1225826, 1226019, 1245453 }, [](SpellInfo* spellInfo)
5225 {
5226 spellInfo->NegativeEffects[EFFECT_0] = true;
5227 });
5228
5229 // Collective Anguish channel hack (triggered by another channel)
5230 ApplySpellFix({ 391057, 393831 }, [](SpellInfo* spellInfo)
5231 {
5232 spellInfo->AttributesEx &= ~SPELL_ATTR1_IS_CHANNELLED;
5233 });
5234
5235 for (SpellInfo const& s : mSpellInfoMap)
5236 {
5237 SpellInfo* spellInfo = &const_cast<SpellInfo&>(s);
5238 if (!spellInfo)
5239 continue;
5240
5241 // Fix range for trajectory triggered spell
5242 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
5243 {
5244 if (spellEffectInfo.IsEffect() && (spellEffectInfo.TargetA.GetTarget() == TARGET_DEST_TRAJ || spellEffectInfo.TargetB.GetTarget() == TARGET_DEST_TRAJ))
5245 {
5246 // Get triggered spell if any
5247 for (SpellInfo const& spellInfoTrigger : _GetSpellInfo(spellEffectInfo.TriggerSpell))
5248 {
5249 float maxRangeMain = spellInfo->GetMaxRange();
5250 float maxRangeTrigger = spellInfoTrigger.GetMaxRange();
5251
5252 // check if triggered spell has enough max range to cover trajectory
5253 if (maxRangeTrigger < maxRangeMain)
5254 const_cast<SpellInfo&>(spellInfoTrigger).RangeEntry = spellInfo->RangeEntry;
5255 }
5256 }
5257
5258 switch (spellEffectInfo.Effect)
5259 {
5262 case SPELL_EFFECT_JUMP:
5265 if (!spellInfo->Speed && !spellInfo->SpellFamilyName && !spellInfo->HasAttribute(SPELL_ATTR9_MISSILE_SPEED_IS_DELAY_IN_SEC))
5266 spellInfo->Speed = SPEED_CHARGE;
5267 break;
5268 default:
5269 break;
5270 }
5271
5272 if (spellEffectInfo.TargetA.GetSelectionCategory() == TARGET_SELECT_CATEGORY_CONE || spellEffectInfo.TargetB.GetSelectionCategory() == TARGET_SELECT_CATEGORY_CONE)
5273 if (G3D::fuzzyEq(spellInfo->ConeAngle, 0.f))
5274 spellInfo->ConeAngle = 90.f;
5275
5276 // Area auras may not target area (they're self cast)
5277 if (spellEffectInfo.IsAreaAuraEffect() && spellEffectInfo.IsTargetingArea())
5278 {
5279 const_cast<SpellEffectInfo&>(spellEffectInfo).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
5280 const_cast<SpellEffectInfo&>(spellEffectInfo).TargetB = SpellImplicitTargetInfo(0);
5281 }
5282 }
5283
5284 // disable proc for magnet auras, they're handled differently
5285 if (spellInfo->HasAura(SPELL_AURA_SPELL_MAGNET))
5286 spellInfo->ProcFlags = std::array<int32, 2>{};
5287
5288 // due to the way spell system works, unit would change orientation in Spell::_cast
5289 if (spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
5291
5292 if (spellInfo->ActiveIconFileDataId == 135754) // flight
5293 spellInfo->Attributes |= SPELL_ATTR0_PASSIVE;
5294
5295 if (spellInfo->IsSingleTarget() && !spellInfo->MaxAffectedTargets)
5296 spellInfo->MaxAffectedTargets = 1;
5297 }
5298
5300 summonProperties.ApplyHotfix(121, [](SummonPropertiesEntry* properties)
5301 {
5303 });
5304 summonProperties.ApplyHotfix(647, [](SummonPropertiesEntry* properties) // 52893
5305 {
5307 });
5308 summonProperties.ApplyHotfix(628, [](SummonPropertiesEntry* properties) // Hungry Plaguehound
5309 {
5310 properties->Control = SUMMON_CATEGORY_PET;
5311 });
5312
5313 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo corrections in {} ms", GetMSTimeDiffToNow(oldMSTime));
5314}
5315
5317{
5318 uint32 oldMSTime = getMSTime();
5319
5320 for (SpellInfo const& spellInfo : mSpellInfoMap)
5321 {
5322 // AuraState depends on SpellSpecific
5323 const_cast<SpellInfo&>(spellInfo)._LoadSpellSpecific();
5324 const_cast<SpellInfo&>(spellInfo)._LoadAuraState();
5325 }
5326
5327 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo SpellSpecific and AuraState in {} ms", GetMSTimeDiffToNow(oldMSTime));
5328}
5329
5331{
5332 uint32 oldMSTime = getMSTime();
5333
5334 for (SpellInfo const& spellInfo : mSpellInfoMap)
5335 const_cast<SpellInfo&>(spellInfo)._LoadSpellDiminishInfo();
5336
5337 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo diminishing infos in {} ms", GetMSTimeDiffToNow(oldMSTime));
5338}
5339
5341{
5342 uint32 oldMSTime = getMSTime();
5343
5344 mCreatureImmunities.clear();
5345
5346 // 0 1 2 3 4 5 6 7
5347 if (QueryResult result = WorldDatabase.Query("SELECT ID, SchoolMask, DispelTypeMask, MechanicsMask, Effects, Auras, ImmuneAoE, ImmuneChain FROM creature_immunities"))
5348 {
5349 do
5350 {
5351 Field* fields = result->Fetch();
5352 int32 id = fields[0].GetInt32();
5353 uint8 school = fields[1].GetInt8();
5354 uint16 dispelType = fields[2].GetInt16();
5355 uint64 mechanics = fields[3].GetInt64();
5356
5357 CreatureImmunities& immunities = mCreatureImmunities[id];
5358 immunities.School = school;
5359 immunities.DispelType = dispelType;
5360 immunities.Mechanic = mechanics;
5361 if (fields[6].GetBool())
5363 if (fields[7].GetBool())
5365
5366 if (immunities.School.to_ullong() != school)
5367 TC_LOG_ERROR("sql.sql", "Invalid value in `SchoolMask` {} for creature immunities {}, truncated", school, id);
5368 if (immunities.DispelType.to_ullong() != dispelType)
5369 TC_LOG_ERROR("sql.sql", "Invalid value in `DispelTypeMask` {} for creature immunities {}, truncated", dispelType, id);
5370 if (immunities.Mechanic.to_ullong() != mechanics)
5371 TC_LOG_ERROR("sql.sql", "Invalid value in `MechanicsMask` {} for creature immunities {}, truncated", mechanics, id);
5372
5373 for (std::string_view token : Trinity::Tokenize(fields[4].GetStringView(), ',', false))
5374 {
5375 if (Optional<uint32> effect = Trinity::StringTo<uint32>(token); effect && effect < uint32(TOTAL_SPELL_EFFECTS))
5376 immunities.Effect.push_back(SpellEffectName(*effect));
5377 else
5378 TC_LOG_ERROR("sql.sql", "Invalid effect type in `Effects` {} for creature immunities {}, skipped", token, id);
5379 }
5380
5381 for (std::string_view token : Trinity::Tokenize(fields[5].GetStringView(), ',', false))
5382 {
5383 if (Optional<uint32> aura = Trinity::StringTo<uint32>(token); aura && aura < TOTAL_AURAS)
5384 immunities.Aura.push_back(AuraType(*aura));
5385 else
5386 TC_LOG_ERROR("sql.sql", "Invalid aura type in `Auras` {} for creature immunities {}, skipped", token, id);
5387 }
5388 }
5389 while (result->NextRow());
5390 }
5391
5392 for (SpellInfo const& spellInfo : mSpellInfoMap)
5393 const_cast<SpellInfo&>(spellInfo)._LoadImmunityInfo();
5394
5395 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo immunity infos in {} ms", GetMSTimeDiffToNow(oldMSTime));
5396}
5397
5399{
5400 uint32 oldMSTime = getMSTime();
5401
5402 // Eye Beam
5403 ApplySpellFix({ 198030 }, [](SpellInfo* spellInfo)
5404 {
5405 spellInfo->_LoadSqrtTargetLimit(5, 0, 198013, EFFECT_4, {}, {});
5406 });
5407
5408 // Volatile Agony
5409 ApplySpellFix({ 453035 }, [](SpellInfo* spellInfo)
5410 {
5411 spellInfo->_LoadSqrtTargetLimit(8, 0, 453034, EFFECT_1, {}, {});
5412 });
5413
5414 // Essence Break
5415 ApplySpellFix({ 258860 }, [](SpellInfo* spellInfo)
5416 {
5417 spellInfo->_LoadSqrtTargetLimit(8, 0, {}, EFFECT_1, {}, {});
5418 });
5419
5420 // Fel Barrage
5421 ApplySpellFix({ 258926 }, [](SpellInfo* spellInfo)
5422 {
5423 spellInfo->_LoadSqrtTargetLimit(5, 0, {}, EFFECT_1, {}, {});
5424 });
5425
5426 // Inner Demon
5427 ApplySpellFix({ 390137 }, [](SpellInfo* spellInfo)
5428 {
5429 spellInfo->_LoadSqrtTargetLimit(5, 0, 389693, EFFECT_1, {}, {});
5430 });
5431
5432 // Divine Storm
5433 ApplySpellFix({ 53385 }, [](SpellInfo* spellInfo)
5434 {
5435 spellInfo->_LoadSqrtTargetLimit(5, 0, {}, EFFECT_1, {}, {});
5436 });
5437
5438 // Blade of Justice
5439 ApplySpellFix({ 404358 }, [](SpellInfo* spellInfo)
5440 {
5441 spellInfo->_LoadSqrtTargetLimit(5, 0, {}, {}, {}, {});
5442 });
5443
5444 // Ice Nova
5445 ApplySpellFix({ 157997 }, [](SpellInfo* spellInfo)
5446 {
5447 spellInfo->_LoadSqrtTargetLimit(8, 0, {}, EFFECT_2, {}, {});
5448 });
5449
5450 // Raze
5451 ApplySpellFix({ 400254 }, [](SpellInfo* spellInfo)
5452 {
5453 spellInfo->_LoadSqrtTargetLimit(5, 0, {}, EFFECT_2, {}, {});
5454 });
5455
5456 // Explosive Shot
5457 ApplySpellFix({ 212680 }, [](SpellInfo* spellInfo)
5458 {
5459 spellInfo->_LoadSqrtTargetLimit(5, 0, 212431, EFFECT_1, {}, {});
5460 });
5461
5462 // Revival
5463 ApplySpellFix({ 115310 }, [](SpellInfo* spellInfo)
5464 {
5465 spellInfo->_LoadSqrtTargetLimit(5, 0, {}, EFFECT_4, {}, {});
5466 });
5467
5468 // Restoral
5469 ApplySpellFix({ 388615 }, [](SpellInfo* spellInfo)
5470 {
5471 spellInfo->_LoadSqrtTargetLimit(5, 0, {}, EFFECT_4, {}, {});
5472 });
5473
5474 // Keg Smash
5475 ApplySpellFix({ 121253 }, [](SpellInfo* spellInfo)
5476 {
5477 spellInfo->_LoadSqrtTargetLimit(5, 0, {}, EFFECT_6, {}, {});
5478 });
5479
5480 // Odyn's Fury
5481 ApplySpellFix({ 385060, 385061, 385062 }, [](SpellInfo* spellInfo)
5482 {
5483 spellInfo->_LoadSqrtTargetLimit(8, 0, 385059, EFFECT_5, {}, {});
5484 });
5485
5486 // Flame Patch
5487 ApplySpellFix({ 205472 }, [](SpellInfo* spellInfo)
5488 {
5489 spellInfo->_LoadSqrtTargetLimit(8, 0, {}, EFFECT_1, {}, {});
5490 });
5491
5492 // Flamestrike
5493 ApplySpellFix({ 2120, 1254851 }, [](SpellInfo* spellInfo)
5494 {
5495 spellInfo->_LoadSqrtTargetLimit(8, 0, {}, EFFECT_1, {}, {});
5496 });
5497
5498 // Meteor
5499 ApplySpellFix({ 351140 }, [](SpellInfo* spellInfo)
5500 {
5501 spellInfo->_LoadSqrtTargetLimit(8, 0, {}, {}, {}, {});
5502 });
5503
5504 // Whirlwind
5505 ApplySpellFix({ 199667, 44949, 199852, 199851 }, [](SpellInfo* spellInfo)
5506 {
5507 spellInfo->_LoadSqrtTargetLimit(5, 0, 190411, EFFECT_2, {}, {});
5508 });
5509
5510 // Elysian Decree (Kyrian)
5511 ApplySpellFix({ 307046 }, [](SpellInfo* spellInfo)
5512 {
5513 spellInfo->_LoadSqrtTargetLimit(5, 0, 306830, EFFECT_0, {}, {});
5514 });
5515
5516 // Sigil of Spite
5517 ApplySpellFix({ 389860 }, [](SpellInfo* spellInfo)
5518 {
5519 spellInfo->_LoadSqrtTargetLimit(5, 0, 390163, EFFECT_0, {}, {});
5520 });
5521
5522 // Burning Vehemence
5523 ApplySpellFix({ 400370 }, [](SpellInfo* spellInfo)
5524 {
5525 spellInfo->_LoadSqrtTargetLimit(5, 0, {}, EFFECT_1, {}, {});
5526 });
5527
5528 ApplySpellFix({ 435222 }, [](SpellInfo* spellInfo)
5529 {
5530 spellInfo->_LoadSqrtTargetLimit(5, 0, {}, EFFECT_4, {}, {});
5531 });
5532
5533 // Rampaging Ruin
5534 ApplySpellFix({ 1265579, 1265580, 1265581, 1265582 }, [](SpellInfo* spellInfo)
5535 {
5536 spellInfo->_LoadSqrtTargetLimit(5, 0, 1265357, EFFECT_0, {}, {});
5537 });
5538
5539 // Eradicate
5540 ApplySpellFix({ 1225827, 1279200 }, [](SpellInfo* spellInfo)
5541 {
5542 spellInfo->_LoadSqrtTargetLimit(5, 0, 1226033, EFFECT_0, {}, {});
5543 });
5544
5545 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo target caps in {} ms", GetMSTimeDiffToNow(oldMSTime));
5546}
5547
5549{
5550 std::unordered_map<uint32, SpellLevelsEntry const*> levelsBySpell;
5551 for (SpellLevelsEntry const* levels : sSpellLevelsStore)
5552 if (!levels->DifficultyID)
5553 levelsBySpell[levels->SpellID] = levels;
5554
5555 for (SkillLineAbilityEntry const* skillLine : sSkillLineAbilityStore)
5556 {
5557 SpellInfo const* spellInfo = GetSpellInfo(skillLine->Spell, DIFFICULTY_NONE);
5558 if (!spellInfo)
5559 continue;
5560
5561 auto levels = levelsBySpell.find(skillLine->Spell);
5562 if (levels != levelsBySpell.end() && levels->second->SpellLevel)
5563 continue;
5564
5565 if (spellInfo->IsPassive())
5566 {
5567 for (CreatureFamilyEntry const* cFamily : sCreatureFamilyStore)
5568 {
5569 if (skillLine->SkillLine != cFamily->SkillLine[0] && skillLine->SkillLine != cFamily->SkillLine[1])
5570 continue;
5571
5572 if (skillLine->GetAcquireMethod() != SkillLineAbilityAcquireMethod::AutomaticCharLevel)
5573 continue;
5574
5575 sPetFamilySpellsStore[cFamily->ID].insert(spellInfo->Id);
5576 }
5577 }
5578 }
5579}
5580
5582{
5583 uint32 oldMSTime = getMSTime();
5584
5585 QueryResult result = WorldDatabase.Query("SELECT SpellID, RaceID, DisplayID from spell_totem_model");
5586
5587 if (!result)
5588 {
5589 TC_LOG_INFO("server.loading", ">> Loaded 0 spell totem model records. DB table `spell_totem_model` is empty.");
5590 return;
5591 }
5592
5593 uint32 count = 0;
5594 do
5595 {
5596 Field* fields = result->Fetch();
5597
5598 uint32 spellId = fields[0].GetUInt32();
5599 uint8 race = fields[1].GetUInt8();
5600 uint32 displayId = fields[2].GetUInt32();
5601
5602 SpellInfo const* spellEntry = GetSpellInfo(spellId, DIFFICULTY_NONE);
5603 if (!spellEntry)
5604 {
5605 TC_LOG_ERROR("sql.sql", "SpellID: {} in `spell_totem_model` table could not be found in dbc, skipped.", spellId);
5606 continue;
5607 }
5608
5609 ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(race);
5610 if (!raceEntry)
5611 {
5612 TC_LOG_ERROR("sql.sql", "Race {} defined in `spell_totem_model` does not exists, skipped.", uint32(race));
5613 continue;
5614 }
5615
5616 CreatureDisplayInfoEntry const* displayEntry = sCreatureDisplayInfoStore.LookupEntry(displayId);
5617 if (!displayEntry)
5618 {
5619 TC_LOG_ERROR("sql.sql", "SpellID: {} defined in `spell_totem_model` has non-existing model ({}).", spellId, displayId);
5620 continue;
5621 }
5622
5623 mSpellTotemModel[std::make_pair(spellId, race)] = displayId;
5624 ++count;
5625
5626 } while (result->NextRow());
5627
5628 TC_LOG_INFO("server.loading", ">> Loaded {} spell totem model records in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
5629
5630}
5631
5633{
5634 auto itr = mSpellTotemModel.find(std::make_pair(spellId, race));
5635 if (itr != mSpellTotemModel.end())
5636 return itr->second;
5637
5638 return 0;
5639}
#define sBattlefieldMgr
@ BATTLEFIELD_WG
Definition Battlefield.h:29
@ BATTLEFIELD_BATTLEID_WG
Definition Battlefield.h:36
@ IN_MILLISECONDS
Definition Common.h:38
#define M_PI
Definition Common.h:118
DB2Storage< DifficultyEntry > sDifficultyStore("Difficulty.db2", &DifficultyLoadInfo::Instance)
DB2Storage< SpellVisualEntry > sSpellVisualStore("SpellVisual.db2", &SpellVisualLoadInfo::Instance)
DB2Storage< SpellInterruptsEntry > sSpellInterruptsStore("SpellInterrupts.db2", &SpellInterruptsLoadInfo::Instance)
DB2Storage< SkillLineEntry > sSkillLineStore("SkillLine.db2", &SkillLineLoadInfo::Instance)
DB2Storage< SpellAuraOptionsEntry > sSpellAuraOptionsStore("SpellAuraOptions.db2", &SpellAuraOptionsLoadInfo::Instance)
DB2Storage< SpellNameEntry > sSpellNameStore("SpellName.db2", &SpellNameLoadInfo::Instance)
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
DB2Storage< LiquidTypeEntry > sLiquidTypeStore("LiquidType.db2", &LiquidTypeLoadInfo::Instance)
DB2Storage< CreatureFamilyEntry > sCreatureFamilyStore("CreatureFamily.db2", &CreatureFamilyLoadInfo::Instance)
DB2Storage< SpellXSpellVisualEntry > sSpellXSpellVisualStore("SpellXSpellVisual.db2", &SpellXSpellVisualLoadInfo::Instance)
DB2Storage< SpellEquippedItemsEntry > sSpellEquippedItemsStore("SpellEquippedItems.db2", &SpellEquippedItemsLoadInfo::Instance)
DB2Storage< SpellReagentsEntry > sSpellReagentsStore("SpellReagents.db2", &SpellReagentsLoadInfo::Instance)
DB2Storage< SpellPowerDifficultyEntry > sSpellPowerDifficultyStore("SpellPowerDifficulty.db2", &SpellPowerDifficultyLoadInfo::Instance)
DB2Storage< SpellRangeEntry > sSpellRangeStore("SpellRange.db2", &SpellRangeLoadInfo::Instance)
DB2Storage< SpellAuraRestrictionsEntry > sSpellAuraRestrictionsStore("SpellAuraRestrictions.db2", &SpellAuraRestrictionsLoadInfo::Instance)
DB2Storage< SpellShapeshiftEntry > sSpellShapeshiftStore("SpellShapeshift.db2", &SpellShapeshiftLoadInfo::Instance)
DB2Storage< SpellVisualEffectNameEntry > sSpellVisualEffectNameStore("SpellVisualEffectName.db2", &SpellVisualEffectNameLoadInfo::Instance)
DB2Storage< SpellMiscEntry > sSpellMiscStore("SpellMisc.db2", &SpellMiscLoadInfo::Instance)
DB2Storage< SpellLevelsEntry > sSpellLevelsStore("SpellLevels.db2", &SpellLevelsLoadInfo::Instance)
DB2Storage< BattlePetSpeciesEntry > sBattlePetSpeciesStore("BattlePetSpecies.db2", &BattlePetSpeciesLoadInfo::Instance)
DB2Storage< SpellDurationEntry > sSpellDurationStore("SpellDuration.db2", &SpellDurationLoadInfo::Instance)
DB2Storage< SpellLearnSpellEntry > sSpellLearnSpellStore("SpellLearnSpell.db2", &SpellLearnSpellLoadInfo::Instance)
DB2Storage< SpellCooldownsEntry > sSpellCooldownsStore("SpellCooldowns.db2", &SpellCooldownsLoadInfo::Instance)
DB2Storage< SkillLineAbilityEntry > sSkillLineAbilityStore("SkillLineAbility.db2", &SkillLineAbilityLoadInfo::Instance)
DB2Storage< SummonPropertiesEntry > sSummonPropertiesStore("SummonProperties.db2", &SummonPropertiesLoadInfo::Instance)
DB2Storage< SpellReagentsCurrencyEntry > sSpellReagentsCurrencyStore("SpellReagentsCurrency.db2", &SpellReagentsCurrencyLoadInfo::Instance)
DB2Storage< SpellCastingRequirementsEntry > sSpellCastingRequirementsStore("SpellCastingRequirements.db2", &SpellCastingRequirementsLoadInfo::Instance)
DB2Storage< SpellEmpowerEntry > sSpellEmpowerStore("SpellEmpower.db2", &SpellEmpowerLoadInfo::Instance)
DB2Storage< SpellEffectEntry > sSpellEffectStore("SpellEffect.db2", &SpellEffectLoadInfo::Instance)
DB2Storage< SpellRadiusEntry > sSpellRadiusStore("SpellRadius.db2", &SpellRadiusLoadInfo::Instance)
DB2Storage< SpellEmpowerStageEntry > sSpellEmpowerStageStore("SpellEmpowerStage.db2", &SpellEmpowerStageLoadInfo::Instance)
DB2Storage< SpellTargetRestrictionsEntry > sSpellTargetRestrictionsStore("SpellTargetRestrictions.db2", &SpellTargetRestrictionsLoadInfo::Instance)
DB2Storage< ChrRacesEntry > sChrRacesStore("ChrRaces.db2", &ChrRacesLoadInfo::Instance)
DB2Storage< CreatureDisplayInfoEntry > sCreatureDisplayInfoStore("CreatureDisplayInfo.db2", &CreatureDisplayInfoLoadInfo::Instance)
DB2Storage< SpellItemEnchantmentEntry > sSpellItemEnchantmentStore("SpellItemEnchantment.db2", &SpellItemEnchantmentLoadInfo::Instance)
DB2Storage< SpellClassOptionsEntry > sSpellClassOptionsStore("SpellClassOptions.db2", &SpellClassOptionsLoadInfo::Instance)
DB2Storage< TalentEntry > sTalentStore("Talent.db2", &TalentLoadInfo::Instance)
DB2Storage< SpellTotemsEntry > sSpellTotemsStore("SpellTotems.db2", &SpellTotemsLoadInfo::Instance)
DB2Storage< SpellCategoriesEntry > sSpellCategoriesStore("SpellCategories.db2", &SpellCategoriesLoadInfo::Instance)
DB2Storage< SpellLabelEntry > sSpellLabelStore("SpellLabel.db2", &SpellLabelLoadInfo::Instance)
DB2Storage< AreaTableEntry > sAreaTableStore("AreaTable.db2", &AreaTableLoadInfo::Instance)
DB2Storage< SpellPowerEntry > sSpellPowerStore("SpellPower.db2", &SpellPowerLoadInfo::Instance)
DB2Storage< SpellCastTimesEntry > sSpellCastTimesStore("SpellCastTimes.db2", &SpellCastTimesLoadInfo::Instance)
DB2Storage< SpellScalingEntry > sSpellScalingStore("SpellScaling.db2", &SpellScalingLoadInfo::Instance)
#define sDB2Manager
Definition DB2Stores.h:569
#define MAX_SPELL_REAGENTS
#define MAX_ITEM_ENCHANTMENT_EFFECTS
@ ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL
Definition DBCEnums.h:1223
Difficulty
Definition DBCEnums.h:932
@ DIFFICULTY_NONE
Definition DBCEnums.h:933
SpellVisualEffectNameType
Definition DBCEnums.h:2489
#define MAX_SPELL_EFFECTS
Definition DBCEnums.h:2430
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
#define UI64LIT(N)
Definition Define.h:139
uint16_t uint16
Definition Define.h:155
uint32_t uint32
Definition Define.h:154
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
#define ASSERT
Definition Errors.h:80
#define sLanguageMgr
Definition LanguageMgr.h:97
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:190
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
#define SPEED_CHARGE
#define sObjectMgr
Definition ObjectMgr.h:1885
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
constexpr Trinity::RaceMask< uint64 > RACEMASK_ALL_PLAYABLE
Definition RaceMask.h:289
SpellEffIndex
@ EFFECT_3
@ EFFECT_6
@ EFFECT_1
@ EFFECT_5
@ EFFECT_0
@ EFFECT_4
@ EFFECT_2
@ SPELL_ATTR9_MISSILE_SPEED_IS_DELAY_IN_SEC
@ SPELL_ATTR9_FORCE_DEST_LOCATION
@ SKILL_CATEGORY_WEAPON
@ SKILL_CATEGORY_PROFESSION
Gender
@ GENDER_MALE
@ GENDER_FEMALE
@ GENDER_NONE
@ SPELL_ATTR5_AI_DOESNT_FACE_TARGET
@ SPELL_ATTR5_EXTRA_INITIAL_PERIOD
Targets
@ TARGET_DEST_CASTER_LEFT
@ TARGET_DEST_DB
@ TARGET_UNIT_SRC_AREA_ENTRY
@ TARGET_UNIT_SRC_AREA_ALLY
@ TARGET_DEST_NEARBY_DB
@ TARGET_DEST_NEARBY_ENTRY_OR_DB
@ TARGET_UNIT_TARGET_ANY
@ TARGET_DEST_DEST
@ TARGET_UNIT_PET
@ TARGET_UNIT_TARGET_ENEMY
@ TARGET_DEST_TRAJ
@ TOTAL_SPELL_TARGETS
@ TARGET_UNIT_NEARBY_ENTRY
@ TARGET_DEST_CASTER
@ TARGET_UNIT_CASTER
@ SPELL_SCHOOL_MASK_NORMAL
@ SPELL_SCHOOL_MASK_MAGIC
@ SPELL_SCHOOL_MASK_ALL
@ SPELL_ATTR2_CANT_CRIT
@ SPELL_ATTR2_NO_INITIAL_THREAT
@ SPELL_ATTR2_ALLOW_DEAD_TARGET
@ SPELL_ATTR2_IGNORE_LINE_OF_SIGHT
@ SPELL_ATTR1_NO_THREAT
@ SPELL_ATTR1_EXCLUDE_CASTER
@ SPELL_ATTR1_IMMUNITY_PURGES_EFFECT
@ SPELL_ATTR3_ALLOW_AURA_WHILE_DEAD
@ SPELL_ATTR3_ALWAYS_HIT
@ SPELL_ATTR3_DOT_STACKING_RULE
@ SPELL_ATTR3_CAN_PROC_FROM_PROCS
@ SPELL_ATTR3_IGNORE_CASTER_MODIFIERS
@ TEAM_ALLIANCE
@ TEAM_HORDE
SpellEffectName
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_POWER_BURN
@ SPELL_EFFECT_ENERGIZE_PCT
@ SPELL_EFFECT_SUMMON_PET
@ SPELL_EFFECT_APPLY_AREA_AURA_PARTY
@ SPELL_EFFECT_APPLY_AREA_AURA_FRIEND
@ SPELL_EFFECT_TRIGGER_SPELL_WITH_VALUE
@ SPELL_EFFECT_CREATE_CONVERSATION
@ SPELL_EFFECT_APPLY_AREA_AURA_PARTY_NONRANDOM
@ SPELL_EFFECT_ENCHANT_HELD_ITEM
@ SPELL_EFFECT_ENCHANT_ITEM
@ SPELL_EFFECT_CREATE_LOOT
@ SPELL_EFFECT_HEALTH_LEECH
@ SPELL_EFFECT_SKILL
@ SPELL_EFFECT_WEAPON_DAMAGE
@ SPELL_EFFECT_HEAL
@ SPELL_EFFECT_NORMALIZED_WEAPON_DMG
@ SPELL_EFFECT_APPLY_AURA_ON_PET
@ SPELL_EFFECT_TRIGGER_SPELL
@ SPELL_EFFECT_DAMAGE_FROM_MAX_HEALTH_PCT
@ SPELL_EFFECT_HEAL_MAX_HEALTH
@ SPELL_EFFECT_APPLY_AREA_AURA_PET
@ SPELL_EFFECT_NONE
@ SPELL_EFFECT_LANGUAGE
@ SPELL_EFFECT_JUMP_DEST
@ SPELL_EFFECT_PICKPOCKET
@ SPELL_EFFECT_HEAL_MECHANICAL
@ SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
@ SPELL_EFFECT_APPLY_AREA_AURA_RAID
@ SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
@ SPELL_EFFECT_PERSISTENT_AREA_AURA
@ SPELL_EFFECT_LEAP_BACK
@ SPELL_EFFECT_SUMMON
@ SPELL_EFFECT_ENERGIZE
@ SPELL_EFFECT_DUAL_WIELD
@ SPELL_EFFECT_POWER_DRAIN
@ SPELL_EFFECT_CHARGE
@ SPELL_EFFECT_SCHOOL_DAMAGE
@ TOTAL_SPELL_EFFECTS
@ SPELL_EFFECT_CHARGE_DEST
@ SPELL_EFFECT_LEARN_SPELL
@ SPELL_EFFECT_APPLY_AREA_AURA_ENEMY
@ SPELL_EFFECT_JUMP
@ SPELL_EFFECT_HEAL_PCT
@ SPELL_EFFECT_INTERRUPT_CAST
@ SPELL_EFFECT_APPLY_AREA_AURA_SUMMONS
@ SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
@ SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
@ SPELL_EFFECT_SKILL_STEP
@ SPELL_EFFECT_CREATE_ITEM
@ SPELL_EFFECT_APPLY_AURA
@ SPELL_EFFECT_APPLY_AREA_AURA_OWNER
@ SUMMON_SLOT_MINIPET
Mechanics
@ MECHANIC_NONE
@ MECHANIC_STUN
@ MECHANIC_BLEED
@ SPELL_ATTR0_AURA_IS_DEBUFF
@ SPELL_ATTR0_ONLY_OUTDOORS
@ SPELL_ATTR0_PASSIVE
@ SPELL_ATTR0_NO_IMMUNITIES
@ SPELL_ATTR0_NO_AURA_CANCEL
SpellFamilyNames
@ SPELLFAMILY_WARLOCK
@ SPELLFAMILY_MAGE
@ SPELLFAMILY_GENERIC
@ SPELLFAMILY_WARRIOR
@ SPELLFAMILY_DRUID
@ SPELL_ATTR4_AURA_IS_BUFF
@ SPELL_ATTR4_IGNORE_DAMAGE_TAKEN_MODIFIERS
@ SUMMON_CATEGORY_PET
@ SPELL_ATTR8_CAN_ATTACK_IMMUNE_PC
@ SKILL_DUAL_WIELD
@ SKILL_ENCHANTING
@ SPELL_ATTR6_IGNORE_CASTER_DAMAGE_MODIFIERS
@ SPELL_ATTR6_IGNORE_PHASE_SHIFT
@ SPELL_AURA_MOD_SCHOOL_MASK_DAMAGE_FROM_CASTER
@ SPELL_AURA_MOD_ATTACK_POWER
@ SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_ABILITY_IGNORE_AURASTATE
@ SPELL_AURA_MOD_THREAT
@ SPELL_AURA_PERIODIC_HEALTH_FUNNEL
@ SPELL_AURA_ADD_PCT_MODIFIER
@ TOTAL_AURAS
@ SPELL_AURA_MOD_POSSESS_PET
@ SPELL_AURA_MOD_RESISTANCE
@ SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
@ SPELL_AURA_PROC_TRIGGER_SPELL
@ SPELL_AURA_MOD_FEAR
@ SPELL_AURA_ADD_FLAT_MODIFIER
@ SPELL_AURA_REFLECT_SPELLS
@ SPELL_AURA_CONTROL_VEHICLE
@ SPELL_AURA_MOD_MELEE_HASTE
@ SPELL_AURA_MOD_ROOT_2
@ SPELL_AURA_MOD_SPELL_CRIT_CHANCE
@ SPELL_AURA_MOD_INVISIBILITY
@ SPELL_AURA_MOD_HIT_CHANCE
@ SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE
@ SPELL_AURA_PERIODIC_DAMAGE_PERCENT
@ SPELL_AURA_DUMMY
@ SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN
@ SPELL_AURA_FLY
@ SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT
@ SPELL_AURA_MOD_DETAUNT
@ SPELL_AURA_ADD_FLAT_MODIFIER_BY_SPELL_LABEL
@ SPELL_AURA_MOD_DAMAGE_PERCENT_DONE
@ SPELL_AURA_MOD_CHARM
@ SPELL_AURA_MOD_ROOT
@ SPELL_AURA_MOD_RANGED_HASTE
@ SPELL_AURA_IGNORE_SPELL_COOLDOWN
@ SPELL_AURA_MOD_POWER_COST_SCHOOL
@ SPELL_AURA_MECHANIC_IMMUNITY
@ SPELL_AURA_MOD_DAMAGE_TAKEN
@ SPELL_AURA_MOD_TAUNT
@ SPELL_AURA_MOD_SPELL_DAMAGE_FROM_CASTER
@ SPELL_AURA_AOE_CHARM
@ SPELL_AURA_MOD_DECREASE_SPEED
@ SPELL_AURA_TRANSFORM
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE
@ SPELL_AURA_SCHOOL_ABSORB
@ SPELL_AURA_BATTLEGROUND_PLAYER_POSITION_FACTIONAL
@ SPELL_AURA_MOD_WEAPON_CRIT_PERCENT
@ SPELL_AURA_SPELL_MAGNET
@ SPELL_AURA_PERIODIC_LEECH
@ SPELL_AURA_PROC_TRIGGER_DAMAGE
@ SPELL_AURA_MOD_POWER_REGEN_PERCENT
@ SPELL_AURA_DAMAGE_IMMUNITY
@ SPELL_AURA_OPEN_STABLE
@ SPELL_AURA_MOD_DAMAGE_DONE
@ SPELL_AURA_MOD_CONFUSE
@ SPELL_AURA_MOD_POSSESS
@ SPELL_AURA_REFLECT_SPELLS_SCHOOL
@ SPELL_AURA_PERIODIC_DUMMY
@ SPELL_AURA_MOD_MECHANIC_RESISTANCE
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT
@ SPELL_AURA_MOD_MELEE_HASTE_3
@ SPELL_AURA_ADD_PCT_MODIFIER_BY_SPELL_LABEL
@ SPELL_AURA_MOD_STEALTH
@ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
@ SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
@ SPELL_AURA_BATTLEGROUND_PLAYER_POSITION
@ SPELL_AURA_FORCE_REACTION
@ SPELL_AURA_MOD_MELEE_RANGED_HASTE
@ SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL
@ SPELL_AURA_MOD_ATTACK_POWER_PCT
@ SPELL_AURA_INTERCEPT_MELEE_RANGED_ATTACKS
@ SPELL_AURA_MOD_BLOCK_PERCENT
@ SPELL_AURA_MOD_STUN
@ SPELL_AURA_BIND_SIGHT
@ FORM_TREE_OF_LIFE
SpellInterruptFlags
double SpellEffectValue
This is a double instead of float to be able to store full range of int32.
SpellAuraInterruptFlags2
SpellAuraInterruptFlags
#define MAX_SPELLMOD
@ TARGET_SELECT_CATEGORY_CONE
Definition SpellInfo.h:47
@ SPELL_ATTR0_CU_IGNORE_ARMOR
Definition SpellInfo.h:159
@ SPELL_ATTR0_CU_ENCHANT_PROC
Definition SpellInfo.h:144
@ SPELL_ATTR0_CU_DIRECT_DAMAGE
Definition SpellInfo.h:152
@ SPELL_ATTR0_CU_CAN_CRIT
Definition SpellInfo.h:151
@ SPELL_ATTR0_CU_AURA_CANNOT_BE_SAVED
Definition SpellInfo.h:168
@ SPELL_ATTR0_CU_AURA_CC
Definition SpellInfo.h:149
@ SPELL_ATTR0_CU_CHARGE
Definition SpellInfo.h:153
@ SPELL_ATTR0_CU_NEEDS_AMMO_DATA
Definition SpellInfo.h:163
@ SPELL_ATTR0_CU_BINARY_SPELL
Definition SpellInfo.h:164
@ SPELL_ATTR0_CU_SHARE_DAMAGE
Definition SpellInfo.h:147
@ SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC
Definition SpellInfo.h:165
@ SPELL_ATTR0_CU_PICKPOCKET
Definition SpellInfo.h:154
@ SPELL_ATTR0_CU_CONE_LINE
Definition SpellInfo.h:146
@ SPELL_ATTR0_CU_NO_INITIAL_THREAT
Definition SpellInfo.h:148
@ SPELL_ATTR0_CU_IS_TALENT
Definition SpellInfo.h:167
std::vector< SpellXSpellVisualEntry const * > SpellVisualVector
Definition SpellInfo.h:302
bool IsPrimaryProfessionSkill(uint32 skill)
Definition SpellMgr.cpp:107
auto _GetSpellInfo(uint32 spellId)
Definition SpellMgr.cpp:713
bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
Definition SpellMgr.cpp:119
bool LoadPetDefaultSpells_helper(CreatureTemplate const *cInfo, PetDefaultSpellsEntry &petDefSpells)
bool IsWeaponSkill(uint32 skill)
Definition SpellMgr.cpp:113
std::vector< SpellEffectEntry const * > SpellEffectVector
void ApplySpellFix(std::initializer_list< uint32 > spellIds, void(*fix)(SpellInfo *))
PetFamilySpellsStore sPetFamilySpellsStore
Definition SpellMgr.cpp:105
void ApplySpellEffectFix(SpellInfo *spellInfo, SpellEffIndex effectIndex, void(*fix)(SpellEffectInfo *))
std::multimap< uint32, SpellLearnSpellNode > SpellLearnSpellMap
Definition SpellMgr.h:573
bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
Definition SpellMgr.cpp:119
#define PROC_ATTR_ALL_ALLOWED
Definition SpellMgr.h:270
std::pair< SpellsRequiringSpellMap::const_iterator, SpellsRequiringSpellMap::const_iterator > SpellsRequiringSpellMapBounds
Definition SpellMgr.h:532
std::pair< SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator > SpellSpellGroupMapBounds
Definition SpellMgr.h:337
std::pair< SpellAreaMap::const_iterator, SpellAreaMap::const_iterator > SpellAreaMapBounds
Definition SpellMgr.h:509
SpellGroup
Definition SpellMgr.h:312
@ SPELL_GROUP_CORE_RANGE_MAX
Definition SpellMgr.h:318
ProcAttributes
Definition SpellMgr.h:256
@ PROC_ATTR_NONE
Definition SpellMgr.h:257
@ PROC_ATTR_REQ_EXP_OR_HONOR
Definition SpellMgr.h:258
@ PROC_ATTR_TRIGGERED_CAN_PROC
Definition SpellMgr.h:259
@ PROC_ATTR_REQ_SPELLMOD
Definition SpellMgr.h:261
@ PROC_ATTR_REQ_POWER_COST
Definition SpellMgr.h:260
std::pair< SpellAreaForAreaMap::const_iterator, SpellAreaForAreaMap::const_iterator > SpellAreaForAreaMapBounds
Definition SpellMgr.h:512
ProcFlagsSpellPhase
Definition SpellMgr.h:222
@ PROC_SPELL_PHASE_FINISH
Definition SpellMgr.h:226
@ PROC_SPELL_PHASE_CAST
Definition SpellMgr.h:224
@ PROC_SPELL_PHASE_HIT
Definition SpellMgr.h:225
@ PROC_SPELL_PHASE_MASK_ALL
Definition SpellMgr.h:227
#define MAX_CREATURE_SPELL_DATA_SLOT
Definition SpellMgr.h:589
SpellGroupStackRule
Definition SpellMgr.h:344
@ SPELL_GROUP_STACK_RULE_DEFAULT
Definition SpellMgr.h:345
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition SpellMgr.h:348
@ SPELL_GROUP_STACK_RULE_MAX
Definition SpellMgr.h:350
#define sSpellMgr
Definition SpellMgr.h:812
ProcFlagsSpellType
Definition SpellMgr.h:211
@ PROC_SPELL_TYPE_NONE
Definition SpellMgr.h:212
@ PROC_SPELL_TYPE_MASK_ALL
Definition SpellMgr.h:216
@ PROC_SPELL_TYPE_DAMAGE
Definition SpellMgr.h:213
@ PROC_SPELL_TYPE_NO_DMG_HEAL
Definition SpellMgr.h:215
SpellLinkedType
Definition SpellMgr.h:82
@ SPELL_LINK_CAST
Definition SpellMgr.h:83
@ SPELL_LINK_AURA
Definition SpellMgr.h:85
@ SPELL_LINK_REMOVE
Definition SpellMgr.h:86
std::pair< SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_iterator > SpellGroupSpellMapBounds
Definition SpellMgr.h:341
TC_GAME_API PetFamilySpellsStore sPetFamilySpellsStore
Definition SpellMgr.cpp:105
@ SPELL_AREA_FLAG_AUTOCAST
Definition SpellMgr.h:483
std::pair< SpellAreaForAuraMap::const_iterator, SpellAreaForAuraMap::const_iterator > SpellAreaForAuraMapBounds
Definition SpellMgr.h:511
std::pair< SkillLineAbilityMap::const_iterator, SkillLineAbilityMap::const_iterator > SkillLineAbilityMapBounds
Definition SpellMgr.h:579
@ PROC_FLAG_DEAL_MELEE_ABILITY
Definition SpellMgr.h:100
@ PROC_FLAG_DEAL_RANGED_ABILITY
Definition SpellMgr.h:106
@ TAKEN_HIT_PROC_FLAG_MASK
Definition SpellMgr.h:175
@ PROC_FLAG_DEAL_HELPFUL_ABILITY
Definition SpellMgr.h:109
@ PROC_FLAG_HEARTBEAT
Definition SpellMgr.h:94
@ PROC_FLAG_DEAL_RANGED_ATTACK
Definition SpellMgr.h:103
@ PROC_FLAG_DEATH
Definition SpellMgr.h:131
@ PROC_FLAG_DEAL_HARMFUL_ABILITY
Definition SpellMgr.h:112
@ PROC_FLAG_DEAL_HARMFUL_PERIODIC
Definition SpellMgr.h:121
@ REQ_SPELL_PHASE_PROC_FLAG_MASK
Definition SpellMgr.h:182
@ PROC_FLAG_KILL
Definition SpellMgr.h:95
@ PROC_FLAG_DEAL_HELPFUL_SPELL
Definition SpellMgr.h:115
@ PROC_FLAG_DEAL_HELPFUL_PERIODIC
Definition SpellMgr.h:126
@ PROC_FLAG_DEAL_HARMFUL_SPELL
Definition SpellMgr.h:118
@ SPELL_PROC_FLAG_MASK
Definition SpellMgr.h:158
@ DONE_HIT_PROC_FLAG_MASK
Definition SpellMgr.h:168
@ EFFECT_RADIUS_100_YARDS
Definition SpellMgr.h:379
@ EFFECT_RADIUS_45_YARDS
Definition SpellMgr.h:378
@ EFFECT_RADIUS_15_YARDS
Definition SpellMgr.h:385
@ EFFECT_RADIUS_25_YARDS
Definition SpellMgr.h:387
@ EFFECT_RADIUS_50000_YARDS
Definition SpellMgr.h:395
@ EFFECT_RADIUS_200_YARDS
Definition SpellMgr.h:389
@ EFFECT_RADIUS_12_YARDS
Definition SpellMgr.h:399
@ EFFECT_RADIUS_10_YARDS
Definition SpellMgr.h:380
@ EFFECT_RADIUS_0_5_YARDS
Definition SpellMgr.h:410
@ PROC_FLAG_2_CAST_SUCCESSFUL
Definition SpellMgr.h:192
ProcFlagsHit
Definition SpellMgr.h:233
@ PROC_HIT_BLOCK
Definition SpellMgr.h:241
@ PROC_HIT_MISS
Definition SpellMgr.h:237
@ PROC_HIT_NONE
Definition SpellMgr.h:234
@ PROC_HIT_ABSORB
Definition SpellMgr.h:245
@ PROC_HIT_MASK_ALL
Definition SpellMgr.h:250
@ PROC_HIT_CRITICAL
Definition SpellMgr.h:236
@ PROC_HIT_NORMAL
Definition SpellMgr.h:235
@ PROC_HIT_REFLECT
Definition SpellMgr.h:246
std::map< uint32, PetFamilySpellsSet > PetFamilySpellsStore
Definition SpellMgr.h:582
std::pair< SpellAreaForQuestMap::const_iterator, SpellAreaForQuestMap::const_iterator > SpellAreaForQuestMapBounds
Definition SpellMgr.h:510
std::pair< SpellLearnSpellMap::const_iterator, SpellLearnSpellMap::const_iterator > SpellLearnSpellMapBounds
Definition SpellMgr.h:574
std::multimap< uint32, uint32 > PetLevelupSpellSet
Definition SpellMgr.h:584
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
Action
static void AddBattlePetSpeciesBySpell(uint32 spellId, BattlePetSpeciesEntry const *speciesEntry)
bool CanFlyIn()
Return if we can use mount in battlefield.
virtual uint32 GetData(uint32 dataId) const override
uint32 GetTypeId() const
void PSendSysMessage(char const *fmt, Args &&... args)
Definition Chat.h:62
static bool IsValidSpellFamiliyName(SpellFamilyNames family)
Class used to access individual fields of database query result.
Definition Field.h:94
float GetFloat() const noexcept
Definition Field.cpp:85
uint64 GetUInt64() const noexcept
Definition Field.cpp:71
int16 GetInt16() const noexcept
Definition Field.cpp:50
bool GetBool() const noexcept
Definition Field.h:102
uint32 GetUInt32() const noexcept
Definition Field.cpp:57
uint16 GetUInt16() const noexcept
Definition Field.cpp:43
uint8 GetUInt8() const noexcept
Definition Field.cpp:29
int32 GetInt32() const noexcept
Definition Field.cpp:64
int8 GetInt8() const noexcept
Definition Field.cpp:36
int64 GetInt64() const noexcept
Definition Field.cpp:78
Player * ToPlayer()
Definition Object.h:126
Gender GetNativeGender() const override
Definition Player.h:1350
WorldSession * GetSession() const
Definition Player.h:2272
TeamId GetTeamId() const
Definition Player.h:2424
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition Player.cpp:15962
SpellSchoolMask GetSchoolMask() const
Definition Unit.cpp:292
Unit * GetActionTarget() const
Definition Unit.h:500
ProcFlagsSpellType GetSpellTypeMask() const
Definition Unit.h:504
Spell const * GetProcSpell() const
Definition Unit.h:514
ProcFlagsHit GetHitMask() const
Definition Unit.h:506
SpellInfo const * GetSpellInfo() const
Definition Unit.cpp:281
ProcFlagsInit GetTypeMask() const
Definition Unit.h:503
ProcFlagsSpellPhase GetSpellPhaseMask() const
Definition Unit.h:505
Unit * GetActor() const
Definition Unit.h:499
float PositionFacing
Definition SpellInfo.h:227
SpellEffectValue CalcValue(WorldObject const *caster=nullptr, SpellEffectValue const *basePoints=nullptr, Unit const *target=nullptr, float *variance=nullptr, uint32 castItemId=0, int32 itemLevel=-1) const
AuraType ApplyAuraName
Definition SpellInfo.h:216
struct SpellEffectInfo::ScalingInfo Scaling
uint32 TriggerSpell
Definition SpellInfo.h:234
SpellEffectName Effect
Definition SpellInfo.h:215
SpellRadiusEntry const * TargetBRadiusEntry
Definition SpellInfo.h:231
flag128 SpellClassMask
Definition SpellInfo.h:235
SpellRadiusEntry const * TargetARadiusEntry
Definition SpellInfo.h:230
uint32 ApplyAuraPeriod
Definition SpellInfo.h:217
SpellImplicitTargetInfo TargetA
Definition SpellInfo.h:228
SpellImplicitTargetInfo TargetB
Definition SpellInfo.h:229
Targets GetTarget() const
uint32 RequiresSpellFocus
Definition SpellInfo.h:356
uint32 BaseLevel
Definition SpellInfo.h:388
void _LoadSpellDiminishInfo()
uint32 MaxLevel
Definition SpellInfo.h:387
uint32 SpellLevel
Definition SpellInfo.h:389
uint32 AttributesEx13
Definition SpellInfo.h:346
uint32 ActiveIconFileDataId
Definition SpellInfo.h:406
uint32 TargetAuraState
Definition SpellInfo.h:359
bool IsRankOf(SpellInfo const *spellInfo) const
std::array< int32, MAX_SPELL_REAGENTS > Reagent
Definition SpellInfo.h:399
uint32 ExcludeTargetAuraSpell
Definition SpellInfo.h:365
uint32 PreventionType
Definition SpellInfo.h:417
uint32 CasterAuraSpell
Definition SpellInfo.h:362
float Width
Definition SpellInfo.h:411
uint32 MaxTargetLevel
Definition SpellInfo.h:412
float GetMaxRange(bool positive=false, WorldObject const *caster=nullptr, Spell *spell=nullptr) const
SpellInfo const * GetFirstRankSpell() const
uint32 const Id
Definition SpellInfo.h:328
uint32 AttributesCu
Definition SpellInfo.h:350
uint32 RecoveryTime
Definition SpellInfo.h:371
EnumFlag< SpellAuraInterruptFlags2 > AuraInterruptFlags2
Definition SpellInfo.h:378
uint32 AttributesEx8
Definition SpellInfo.h:341
SpellVisualVector _visuals
Definition SpellInfo.h:628
uint64 Stances
Definition SpellInfo.h:352
EnumFlag< SpellAuraInterruptFlags > ChannelInterruptFlags
Definition SpellInfo.h:379
bool IsPassive() const
uint32 StackAmount
Definition SpellInfo.h:396
::Difficulty const Difficulty
Definition SpellInfo.h:329
uint32 Mechanic
Definition SpellInfo.h:332
uint8 GetRank() const
SpellRangeEntry const * RangeEntry
Definition SpellInfo.h:392
uint32 ProcCharges
Definition SpellInfo.h:383
bool IsLootCrafting() const
int32 RequiredAreasID
Definition SpellInfo.h:418
bool IsRanked() const
uint32 AttributesEx14
Definition SpellInfo.h:347
uint32 Dispel
Definition SpellInfo.h:331
uint32 ExcludeCasterAuraState
Definition SpellInfo.h:360
float Speed
Definition SpellInfo.h:393
void _UnloadImplicitTargetConditionLists()
int32 EquippedItemClass
Definition SpellInfo.h:402
uint32 SchoolMask
Definition SpellInfo.h:419
uint32 CasterAuraState
Definition SpellInfo.h:358
float ProcBasePPM
Definition SpellInfo.h:385
uint32 CategoryRecoveryTime
Definition SpellInfo.h:372
uint64 StancesNot
Definition SpellInfo.h:353
AuraType TargetAuraType
Definition SpellInfo.h:367
EnumFlag< SpellInterruptFlags > InterruptFlags
Definition SpellInfo.h:376
flag128 SpellFamilyFlags
Definition SpellInfo.h:415
ProcFlagsInit ProcFlags
Definition SpellInfo.h:381
uint32 AttributesEx3
Definition SpellInfo.h:336
float LaunchDelay
Definition SpellInfo.h:394
void _InitializeSpellPositivity()
void _LoadImmunityInfo()
bool HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:456
SpellDurationEntry const * DurationEntry
Definition SpellInfo.h:390
uint32 Attributes
Definition SpellInfo.h:333
uint32 AttributesEx
Definition SpellInfo.h:334
uint32 ChargeCategoryId
Definition SpellInfo.h:420
uint32 AttributesEx15
Definition SpellInfo.h:348
uint32 MaxAffectedTargets
Definition SpellInfo.h:413
uint32 AttributesEx12
Definition SpellInfo.h:345
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition SpellInfo.h:588
std::vector< SpellEffectInfo > const & GetEffects() const
Definition SpellInfo.h:587
uint32 AttributesEx6
Definition SpellInfo.h:339
uint32 AttributesEx7
Definition SpellInfo.h:340
int32 EquippedItemSubClassMask
Definition SpellInfo.h:403
uint32 AttributesEx9
Definition SpellInfo.h:342
uint32 FacingCasterFlags
Definition SpellInfo.h:357
uint32 StartRecoveryTime
Definition SpellInfo.h:374
uint32 ContentTuningId
Definition SpellInfo.h:407
uint32 TargetAuraSpell
Definition SpellInfo.h:363
SpellChainNode const * ChainEntry
Definition SpellInfo.h:433
AuraType ExcludeTargetAuraType
Definition SpellInfo.h:369
uint32 AttributesEx10
Definition SpellInfo.h:343
uint32 Targets
Definition SpellInfo.h:354
void _InitializeExplicitTargetMask()
uint32 ProcCooldown
Definition SpellInfo.h:384
SpellInfo const * GetNextRankSpell() const
SpellCastTimesEntry const * CastTimeEntry
Definition SpellInfo.h:370
int32 EquippedItemInventoryTypeMask
Definition SpellInfo.h:404
uint32 ExcludeTargetAuraState
Definition SpellInfo.h:361
std::bitset< MAX_SPELL_EFFECTS > NegativeEffects
Definition SpellInfo.h:351
EnumFlag< SpellAuraInterruptFlags2 > ChannelInterruptFlags2
Definition SpellInfo.h:380
AuraType ExcludeCasterAuraType
Definition SpellInfo.h:368
uint32 AttributesEx16
Definition SpellInfo.h:349
uint32 TargetCreatureType
Definition SpellInfo.h:355
uint32 ProcChance
Definition SpellInfo.h:382
uint32 AttributesEx2
Definition SpellInfo.h:335
uint32 DmgClass
Definition SpellInfo.h:416
AuraType CasterAuraType
Definition SpellInfo.h:366
uint32 AttributesEx5
Definition SpellInfo.h:338
uint32 AttributesEx4
Definition SpellInfo.h:337
EnumFlag< SpellAuraInterruptFlags > AuraInterruptFlags
Definition SpellInfo.h:377
uint32 ExcludeCasterAuraSpell
Definition SpellInfo.h:364
bool HasAura(AuraType aura) const
uint32 StartRecoveryCategory
Definition SpellInfo.h:373
bool HasAuraInterruptFlag(SpellAuraInterruptFlags flag) const
Definition SpellInfo.h:478
uint32 AttributesEx11
Definition SpellInfo.h:344
uint32 CategoryId
Definition SpellInfo.h:330
float ConeAngle
Definition SpellInfo.h:410
uint32 SpellFamilyName
Definition SpellInfo.h:414
bool IsSingleTarget() const
void _LoadSqrtTargetLimit(int32 maxTargets, int32 numNonDiminishedTargets, Optional< uint32 > maxTargetsValueHolderSpell, Optional< SpellEffIndex > maxTargetsValueHolderEffect, Optional< uint32 > numNonDiminishedTargetsValueHolderSpell, Optional< SpellEffIndex > numNonDiminishedTargetsValueHolderEffect)
SpellRequiredMap mSpellReq
Definition SpellMgr.h:788
static bool CanSpellTriggerProcOnEvent(SpellProcEntry const &procEntry, ProcEventInfo &eventInfo)
Definition SpellMgr.cpp:524
SpellLinkedMap mSpellLinkedMap
Definition SpellMgr.h:799
void LoadPetFamilySpellsStore()
SpellGroupStackRule GetSpellGroupStackRule(SpellGroup groupid) const
Definition SpellMgr.cpp:494
void LoadSpellLinked()
SkillLineAbilityMap mSkillLineAbilityMap
Definition SpellMgr.h:806
SpellAreaMapBounds GetSpellAreaMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:662
SpellLearnSpellMapBounds GetSpellLearnSpellMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:327
PetLevelupSpellSet const * GetPetLevelupSpellList(uint32 petFamily) const
Definition SpellMgr.cpp:645
void LoadSpellInfoStore()
SpellAreaForQuestMapBounds GetSpellAreaForQuestEndMapBounds(uint32 quest_id) const
Definition SpellMgr.cpp:672
SpellAreaForAuraMap mSpellAreaForAuraMap
Definition SpellMgr.h:804
SpellChainMap mSpellChains
Definition SpellMgr.h:786
void UnloadSpellInfoStore()
void LoadSpellAreas()
uint32 GetNextSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:259
static SpellMgr * instance()
Definition SpellMgr.cpp:136
SpellPetAuraMap mSpellPetAuraMap
Definition SpellMgr.h:798
SpellLearnSkillMap mSpellLearnSkills
Definition SpellMgr.h:789
SpellAreaForQuestMapBounds GetSpellAreaForQuestMapBounds(uint32 quest_id) const
Definition SpellMgr.cpp:667
void LoadSkillLineAbilityMap()
SkillLineAbilityMapBounds GetSkillLineAbilityMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:610
void ForEachSpellInfoDifficulty(uint32 spellId, std::function< void(SpellInfo const *)> callback)
Definition SpellMgr.cpp:724
SpellAreaForQuestMap mSpellAreaForQuestEndMap
Definition SpellMgr.h:803
SpellGroupSpellMapBounds GetSpellGroupSpellMapBounds(SpellGroup group_id) const
Definition SpellMgr.cpp:381
PetDefaultSpellsMap mPetDefaultSpellsMap
Definition SpellMgr.h:808
uint32 GetSpellWithRank(uint32 spell_id, uint32 rank, bool strict=false) const
Definition SpellMgr.cpp:285
SpellLearnSkillNode const * GetSpellLearnSkill(uint32 spell_id) const
Definition SpellMgr.cpp:318
void LoadSpellInfoCustomAttributes()
SpellProcEntry const * GetSpellProcEntry(SpellInfo const *spellInfo) const
Definition SpellMgr.cpp:503
std::vector< int32 > const * GetSpellLinked(SpellLinkedType type, uint32 spell_id) const
Definition SpellMgr.cpp:640
uint32 GetPrevSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:268
bool IsSpellRequiringSpell(uint32 spellid, uint32 req_spellid) const
Definition SpellMgr.cpp:307
void LoadSpellThreats()
bool IsSpellLearnToSpell(uint32 spell_id1, uint32 spell_id2) const
Definition SpellMgr.cpp:337
SpellAreaForAuraMapBounds GetSpellAreaForAuraMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:677
static CreatureImmunities const * GetCreatureImmunities(int32 creatureImmunitiesId)
Definition SpellMgr.cpp:687
void LoadSpellInfoDiminishing()
void LoadSpellRequired()
Definition SpellMgr.cpp:897
void LoadSpellTargetPositions()
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set< uint32 > &foundSpells) const
Definition SpellMgr.cpp:386
void LoadSpellInfoImmunities()
void LoadSpellLearnSkills()
Definition SpellMgr.cpp:958
uint32 GetLastSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:251
SpellTotemModelMap mSpellTotemModel
Definition SpellMgr.h:809
void ForEachSpellInfo(std::function< void(SpellInfo const *)> callback)
Definition SpellMgr.cpp:718
void LoadSpellInfoServerside()
SpellLearnedBySpellMap mSpellLearnedBySpells
Definition SpellMgr.h:791
bool IsSpellLearnSpell(uint32 spell_id) const
Definition SpellMgr.cpp:332
SpellThreatEntry const * GetSpellThreatEntry(uint32 spellID) const
Definition SpellMgr.cpp:595
void LoadSpellGroupStackRules()
Trinity::IteratorPair< SpellTargetPositionMap::const_iterator > GetSpellTargetPositions(uint32 spell_id, SpellEffIndex effIndex) const
Definition SpellMgr.cpp:359
SpellGroupStackMap mSpellGroupStack
Definition SpellMgr.h:795
uint32 GetFirstSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:243
bool AddSameEffectStackRuleSpellGroups(SpellInfo const *spellInfo, AuraType auraType, SpellEffectValue amount, std::map< SpellGroup, SpellEffectValue > &groups) const
Definition SpellMgr.cpp:413
SpellEnchantProcEventMap mSpellEnchantProcEventMap
Definition SpellMgr.h:800
void LoadPetDefaultSpells()
PetLevelupSpellMap mPetLevelupSpellMap
Definition SpellMgr.h:807
void LoadSpellLearnSpells()
Trinity::IteratorPair< SpellRequiredMap::const_iterator > GetSpellsRequiredForSpellBounds(uint32 spell_id) const
Definition SpellMgr.cpp:297
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const *spellInfo1, SpellInfo const *spellInfo2) const
Definition SpellMgr.cpp:447
SpellsRequiringSpellMap mSpellsReqSpell
Definition SpellMgr.h:787
void LoadSpellInfoCorrections()
SpellTargetPositionMap mSpellTargetPositions
Definition SpellMgr.h:792
void LoadSpellTotemModel()
SpellGroupSpellMap mSpellGroupSpell
Definition SpellMgr.h:794
PetDefaultSpellsEntry const * GetPetDefaultSpellsEntry(int32 id) const
Definition SpellMgr.cpp:654
SpellTargetPosition const * GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const
Definition SpellMgr.cpp:351
SameEffectStackMap mSpellSameEffectStack
Definition SpellMgr.h:796
SpellEnchantProcEntry const * GetSpellEnchantProcEvent(uint32 enchId) const
Definition SpellMgr.cpp:624
SpellAreaForAreaMap mSpellAreaForAreaMap
Definition SpellMgr.h:805
SpellInfo const * GetSpellInfo(uint32 spellId, Difficulty difficulty) const
Definition SpellMgr.cpp:692
static bool IsSpellValid(SpellInfo const *spellInfo, Player *player=nullptr, bool msg=true)
Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book,...
Definition SpellMgr.cpp:143
uint8 GetSpellRank(uint32 spell_id) const
Definition SpellMgr.cpp:277
void LoadSpellPetAuras()
void UnloadSpellInfoImplicitTargetConditionLists()
SpellSpellGroupMapBounds GetSpellSpellGroupMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:364
SpellAreaMap mSpellAreaMap
Definition SpellMgr.h:801
void LoadSpellEnchantProcData()
SpellChainNode const * GetSpellChainNode(uint32 spell_id) const
Definition SpellMgr.cpp:234
SpellsRequiringSpellMapBounds GetSpellsRequiringSpellBounds(uint32 spell_id) const
Definition SpellMgr.cpp:302
void LoadSpellRanks()
Definition SpellMgr.cpp:823
SpellInfo const * AssertSpellInfo(uint32 spellId, Difficulty difficulty) const
Definition SpellMgr.h:737
void LoadSpellGroups()
void LoadPetLevelupSpellMap()
SpellLearnSpellMap mSpellLearnSpells
Definition SpellMgr.h:790
void LoadSpellInfoSpellSpecificAndAuraState()
SpellSpellGroupMap mSpellSpellGroup
Definition SpellMgr.h:793
PetAura const * GetPetAura(uint32 spell_id, uint8 eff) const
Definition SpellMgr.cpp:615
void LoadSpellInfoTargetCaps()
SpellAreaForAreaMapBounds GetSpellAreaForAreaMapBounds(uint32 area_id) const
Definition SpellMgr.cpp:682
bool IsArenaAllowedEnchancment(uint32 ench_id) const
Definition SpellMgr.cpp:632
SpellThreatMap mSpellThreatMap
Definition SpellMgr.h:797
SpellAreaForQuestMap mSpellAreaForQuestMap
Definition SpellMgr.h:802
void LoadSpellProcs()
uint32 GetModelForTotem(uint32 spellId, uint8 race) const
Trinity::IteratorPair< SpellLearnedBySpellMap::const_iterator > GetSpellLearnedBySpellMapBounds(uint32 learnedSpellId) const
Definition SpellMgr.cpp:346
void UnloadSpellInfoChains()
Definition SpellMgr.cpp:814
bool IsSpellMemberOfSpellGroup(uint32 spellid, SpellGroup groupid) const
Definition SpellMgr.cpp:370
std::vector< SpellPowerCost > const & GetPowerCost() const
Definition Spell.h:704
Utility class to enable range for loop syntax for multimap.equal_range uses.
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4814
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4804
uint8 GetRace() const
Definition Unit.h:761
constexpr uint32 GetMapId() const
Definition Position.h:216
Map * GetMap() const
Definition Object.h:411
uint32 GetZoneId() const
Definition Object.h:332
constexpr void Set(uint32 p1=0, uint32 p2=0, uint32 p3=0, uint32 p4=0)
Definition FlagsArray.h:137
STAMP_AS_EXPECTED_SIGNATURE & noexcept
auto MapEqualRange(M &map, typename M::key_type const &key)
constexpr IteratorPair< iterator, end_iterator > MakeIteratorPair(iterator first, end_iterator second)
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:37
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition Util.cpp:57
std::array< int16, 2 > SkillLine
std::bitset< MAX_MECHANIC > Mechanic
Definition SpellMgr.h:567
std::vector< SpellEffectName > Effect
Definition SpellMgr.h:568
EnumFlag< SpellOtherImmunity > Other
Definition SpellMgr.h:570
std::bitset< MAX_SPELL_SCHOOL > School
Definition SpellMgr.h:565
std::bitset< DISPEL_MAX > DispelType
Definition SpellMgr.h:566
std::vector< AuraType > Aura
Definition SpellMgr.h:569
CreatureFamily family
uint32 spells[MAX_CREATURE_SPELLS]
uint32 spellid[MAX_CREATURE_SPELL_DATA_SLOT]
Definition SpellMgr.h:593
constexpr void SetOrientation(float orientation)
Definition Position.h:82
constexpr float GetPositionX() const
Definition Position.h:87
constexpr float GetPositionY() const
Definition Position.h:88
constexpr float GetPositionZ() const
Definition Position.h:89
uint32 ParentSkillLineID
uint32 questEnd
Definition SpellMgr.h:493
uint8 flags
Definition SpellMgr.h:499
uint32 questStartStatus
Definition SpellMgr.h:497
uint32 spellId
Definition SpellMgr.h:490
uint32 questEndStatus
Definition SpellMgr.h:498
int32 auraSpell
Definition SpellMgr.h:494
Trinity::RaceMask< uint64 > raceMask
Definition SpellMgr.h:495
bool IsFitToRequirements(Player const *player, uint32 newZone, uint32 newArea) const
Definition SpellMgr.cpp:730
Gender gender
Definition SpellMgr.h:496
uint32 areaId
Definition SpellMgr.h:491
uint32 questStart
Definition SpellMgr.h:492
SpellInfo const * last
Definition SpellMgr.h:520
SpellInfo const * first
Definition SpellMgr.h:519
std::array< uint32, MAX_ITEM_ENCHANTMENT_EFFECTS > EffectArg
std::array< uint8, MAX_ITEM_ENCHANTMENT_EFFECTS > Effect
uint32 SpellFamilyName
Definition SpellMgr.h:281
ProcFlagsHit HitMask
Definition SpellMgr.h:286
float ProcsPerMinute
Definition SpellMgr.h:289
Milliseconds Cooldown
Definition SpellMgr.h:291
uint32 Charges
Definition SpellMgr.h:292
ProcFlagsSpellPhase SpellPhaseMask
Definition SpellMgr.h:285
flag128 SpellFamilyMask
Definition SpellMgr.h:282
uint32 SchoolMask
Definition SpellMgr.h:280
ProcFlagsSpellType SpellTypeMask
Definition SpellMgr.h:284
uint32 DisableEffectsMask
Definition SpellMgr.h:288
ProcFlagsInit ProcFlags
Definition SpellMgr.h:283
ProcAttributes AttributesMask
Definition SpellMgr.h:287
uint16 SpellVisualMissileSetID
constexpr bool IsEmpty() const
Definition RaceMask.h:161
constexpr bool HasRace(uint32 raceId) const
Definition RaceMask.h:96