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