TrinityCore
Loading...
Searching...
No Matches
SpellMgr.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "SpellMgr.h"
19#include "BattlefieldMgr.h"
20#include "BattlegroundMgr.h"
21#include "Chat.h"
22#include "Containers.h"
23#include "DatabaseEnv.h"
24#include "DBCStores.h"
25#include "Log.h"
26#include "Map.h"
27#include "MotionMaster.h"
28#include "ObjectMgr.h"
29#include "Player.h"
30#include "SharedDefines.h"
31#include "Spell.h"
32#include "SpellAuraDefines.h"
33#include "SpellInfo.h"
34
36{
37 SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(skill);
38 if (!pSkill)
39 return false;
40
42 return false;
43
44 return true;
45}
46
47bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
48{
49 SkillLineAbilityMapBounds skillBounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
50 for (SkillLineAbilityMap::const_iterator itr = skillBounds.first; itr != skillBounds.second; ++itr)
51 if (itr->second->SkillLine == skillId)
52 return true;
53
54 return false;
55}
56
58
63
65{
66 static SpellMgr instance;
67 return &instance;
68}
69
71bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg)
72{
73 // not exist
74 if (!spellInfo)
75 return false;
76
77 bool needCheckReagents = false;
78
79 // check effects
80 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
81 {
82 switch (spellEffectInfo.Effect)
83 {
84 // craft spell for crafting non-existed item (break client recipes list show)
87 {
88 if (spellEffectInfo.ItemType == 0)
89 {
90 // skip auto-loot crafting spells, it does not need explicit item info (but has special fake items sometimes).
91 if (!spellInfo->IsLootCrafting())
92 {
93 if (msg)
94 {
95 if (player)
96 ChatHandler(player->GetSession()).PSendSysMessage("The craft spell %u does not have a create item entry.", spellInfo->Id);
97 else
98 TC_LOG_ERROR("sql.sql", "The craft spell {} does not have a create item entry.", spellInfo->Id);
99 }
100 return false;
101 }
102
103 }
104 // also possible IsLootCrafting case but fake items must exist anyway
105 else if (!sObjectMgr->GetItemTemplate(spellEffectInfo.ItemType))
106 {
107 if (msg)
108 {
109 if (player)
110 ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u has created a non-existing item in DB (Entry: %u) and then...", spellInfo->Id, spellEffectInfo.ItemType);
111 else
112 TC_LOG_ERROR("sql.sql", "Craft spell {} has created a non-existing item in DB (Entry: {}) and then...", spellInfo->Id, spellEffectInfo.ItemType);
113 }
114 return false;
115 }
116
117 needCheckReagents = true;
118 break;
119 }
121 {
122 SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell);
123 if (!IsSpellValid(spellInfo2, player, msg))
124 {
125 if (msg)
126 {
127 if (player)
128 ChatHandler(player->GetSession()).PSendSysMessage("Spell %u learn to broken spell %u, and then...", spellInfo->Id, spellEffectInfo.TriggerSpell);
129 else
130 TC_LOG_ERROR("sql.sql", "Spell {} learn to invalid spell {}, and then...", spellInfo->Id, spellEffectInfo.TriggerSpell);
131 }
132 return false;
133 }
134 break;
135 }
136 default:
137 break;
138 }
139 }
140
141 if (needCheckReagents)
142 {
143 for (uint8 j = 0; j < MAX_SPELL_REAGENTS; ++j)
144 {
145 if (spellInfo->Reagent[j] > 0 && !sObjectMgr->GetItemTemplate(spellInfo->Reagent[j]))
146 {
147 if (msg)
148 {
149 if (player)
150 ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u refers a non-existing reagent in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Reagent[j]);
151 else
152 TC_LOG_ERROR("sql.sql", "Craft spell {} refers to a non-existing reagent in DB, item (Entry: {}) and then...", spellInfo->Id, spellInfo->Reagent[j]);
153 }
154 return false;
155 }
156 }
157 }
158
159 return true;
160}
161
163{
164 SpellDifficultySearcherMap::const_iterator i = mSpellDifficultySearcherMap.find(spellId);
165 return i == mSpellDifficultySearcherMap.end() ? 0 : i->second;
166}
167
169{
170 if (uint32 i = GetSpellDifficultyId(spellId))
171 TC_LOG_ERROR("spells", "SpellMgr::SetSpellDifficultyId: The spell {} already has spellDifficultyId {}. Will override with spellDifficultyId {}.", spellId, i, id);
172 mSpellDifficultySearcherMap[spellId] = id;
173}
174
176{
177 if (!GetSpellInfo(spellId))
178 return spellId;
179
180 if (!caster || !caster->GetMap() || (!caster->GetMap()->IsDungeon() && !caster->GetMap()->IsBattleground()))
181 return spellId;
182
183 uint32 mode = uint32(caster->GetMap()->GetSpawnMode());
184 if (mode >= MAX_DIFFICULTY)
185 {
186 TC_LOG_ERROR("spells", "SpellMgr::GetSpellIdForDifficulty: Incorrect difficulty for spell {}.", spellId);
187 return spellId; //return source spell
188 }
189
190 uint32 difficultyId = GetSpellDifficultyId(spellId);
191 if (!difficultyId)
192 return spellId; //return source spell, it has only REGULAR_DIFFICULTY
193
194 SpellDifficultyEntry const* difficultyEntry = sSpellDifficultyStore.LookupEntry(difficultyId);
195 if (!difficultyEntry)
196 {
197 TC_LOG_ERROR("spells", "SpellMgr::GetSpellIdForDifficulty: SpellDifficultyEntry was not found for spell {}. This should never happen.", spellId);
198 return spellId; //return source spell
199 }
200
201 if (difficultyEntry->DifficultySpellID[mode] <= 0 && mode > DUNGEON_DIFFICULTY_HEROIC)
202 {
203 TC_LOG_DEBUG("spells", "SpellMgr::GetSpellIdForDifficulty: spell {} mode {} spell is NULL, using mode {}", spellId, mode, mode - 2);
204 mode -= 2;
205 }
206
207 if (difficultyEntry->DifficultySpellID[mode] <= 0)
208 {
209 TC_LOG_ERROR("sql.sql", "SpellMgr::GetSpellIdForDifficulty: spell {} mode {} spell is 0. Check spelldifficulty_dbc!", spellId, mode);
210 return spellId;
211 }
212
213 TC_LOG_DEBUG("spells", "SpellMgr::GetSpellIdForDifficulty: spellid for spell {} in mode {} is {}", spellId, mode, difficultyEntry->DifficultySpellID[mode]);
214 return uint32(difficultyEntry->DifficultySpellID[mode]);
215}
216
218{
219 if (!spell)
220 return nullptr;
221
222 uint32 newSpellId = GetSpellIdForDifficulty(spell->Id, caster);
223 SpellInfo const* newSpell = GetSpellInfo(newSpellId);
224 if (!newSpell)
225 {
226 TC_LOG_DEBUG("spells", "SpellMgr::GetSpellForDifficultyFromSpell: spell {} not found. Check spelldifficulty_dbc!", newSpellId);
227 return spell;
228 }
229
230 TC_LOG_DEBUG("spells", "SpellMgr::GetSpellForDifficultyFromSpell: Spell id for instance mode is {} (original {})", newSpell->Id, spell->Id);
231 return newSpell;
232}
233
235{
236 SpellChainMap::const_iterator itr = mSpellChains.find(spell_id);
237 if (itr == mSpellChains.end())
238 return nullptr;
239
240 return &itr->second;
241}
242
244{
245 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
246 return node->first->Id;
247
248 return spell_id;
249}
250
252{
253 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
254 return node->last->Id;
255
256 return spell_id;
257}
258
260{
261 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
262 if (node->next)
263 return node->next->Id;
264
265 return 0;
266}
267
269{
270 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
271 if (node->prev)
272 return node->prev->Id;
273
274 return 0;
275}
276
278{
279 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
280 return node->rank;
281
282 return 0;
283}
284
285uint32 SpellMgr::GetSpellWithRank(uint32 spell_id, uint32 rank, bool strict) const
286{
287 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
288 {
289 if (rank != node->rank)
290 return GetSpellWithRank(node->rank < rank ? node->next->Id : node->prev->Id, rank, strict);
291 }
292 else if (strict && rank > 1)
293 return 0;
294 return spell_id;
295}
296
301
303{
304 return mSpellsReqSpell.equal_range(spell_id);
305}
306
307bool SpellMgr::IsSpellRequiringSpell(uint32 spellid, uint32 req_spellid) const
308{
309 SpellsRequiringSpellMapBounds spellsRequiringSpell = GetSpellsRequiringSpellBounds(req_spellid);
310 for (SpellsRequiringSpellMap::const_iterator itr = spellsRequiringSpell.first; itr != spellsRequiringSpell.second; ++itr)
311 {
312 if (itr->second == spellid)
313 return true;
314 }
315 return false;
316}
317
319{
320 SpellLearnSkillMap::const_iterator itr = mSpellLearnSkills.find(spell_id);
321 if (itr != mSpellLearnSkills.end())
322 return &itr->second;
323 else
324 return nullptr;
325}
326
328{
329 return mSpellLearnSpells.equal_range(spell_id);
330}
331
333{
334 return mSpellLearnSpells.find(spell_id) != mSpellLearnSpells.end();
335}
336
337bool SpellMgr::IsSpellLearnToSpell(uint32 spell_id1, uint32 spell_id2) const
338{
340 for (SpellLearnSpellMap::const_iterator i = bounds.first; i != bounds.second; ++i)
341 if (i->second.spell == spell_id2)
342 return true;
343 return false;
344}
345
347{
348 SpellTargetPositionMap::const_iterator itr = mSpellTargetPositions.find(std::make_pair(spell_id, effIndex));
349 if (itr != mSpellTargetPositions.end())
350 return &itr->second;
351 return nullptr;
352}
353
355{
356 spell_id = GetFirstSpellInChain(spell_id);
357 return mSpellSpellGroup.equal_range(spell_id);
358}
359
361{
363 for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second; ++itr)
364 {
365 if (itr->second == groupid)
366 return true;
367 }
368 return false;
369}
370
372{
373 return mSpellGroupSpell.equal_range(group_id);
374}
375
376void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const
377{
378 std::set<SpellGroup> usedGroups;
379 GetSetOfSpellsInSpellGroup(group_id, foundSpells, usedGroups);
380}
381
382void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const
383{
384 if (usedGroups.find(group_id) != usedGroups.end())
385 return;
386 usedGroups.insert(group_id);
387
389 for (SpellGroupSpellMap::const_iterator itr = groupSpell.first; itr != groupSpell.second; ++itr)
390 {
391 if (itr->second < 0)
392 {
393 SpellGroup currGroup = (SpellGroup)abs(itr->second);
394 GetSetOfSpellsInSpellGroup(currGroup, foundSpells, usedGroups);
395 }
396 else
397 {
398 foundSpells.insert(itr->second);
399 }
400 }
401}
402
403bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, uint32 auraType, int32 amount, std::map<SpellGroup, int32>& groups) const
404{
405 uint32 spellId = spellInfo->GetFirstRankSpell()->Id;
406 auto spellGroupBounds = GetSpellSpellGroupMapBounds(spellId);
407 // Find group with SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT if it belongs to one
408 for (auto itr = spellGroupBounds.first; itr != spellGroupBounds.second; ++itr)
409 {
410 SpellGroup group = itr->second;
411 auto found = mSpellSameEffectStack.find(group);
412 if (found != mSpellSameEffectStack.end())
413 {
414 // check auraTypes
415 if (!found->second.count(auraType))
416 continue;
417
418 // Put the highest amount in the map
419 auto groupItr = groups.find(group);
420 if (groupItr == groups.end())
421 groups.emplace(group, amount);
422 else
423 {
424 int32 curr_amount = groups[group];
425 // Take absolute value because this also counts for the highest negative aura
426 if (std::abs(curr_amount) < std::abs(amount))
427 groupItr->second = amount;
428 }
429 // return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group per auraType
430 return true;
431 }
432 }
433 // Not in a SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group, so return false
434 return false;
435}
436
438{
439 ASSERT(spellInfo1);
440 ASSERT(spellInfo2);
441
442 uint32 spellid_1 = spellInfo1->GetFirstRankSpell()->Id;
443 uint32 spellid_2 = spellInfo2->GetFirstRankSpell()->Id;
444
445 // find SpellGroups which are common for both spells
447 std::set<SpellGroup> groups;
448 for (SpellSpellGroupMap::const_iterator itr = spellGroup1.first; itr != spellGroup1.second; ++itr)
449 {
450 if (IsSpellMemberOfSpellGroup(spellid_2, itr->second))
451 {
452 bool add = true;
454 for (SpellGroupSpellMap::const_iterator itr2 = groupSpell.first; itr2 != groupSpell.second; ++itr2)
455 {
456 if (itr2->second < 0)
457 {
458 SpellGroup currGroup = (SpellGroup)abs(itr2->second);
459 if (IsSpellMemberOfSpellGroup(spellid_1, currGroup) && IsSpellMemberOfSpellGroup(spellid_2, currGroup))
460 {
461 add = false;
462 break;
463 }
464 }
465 }
466 if (add)
467 groups.insert(itr->second);
468 }
469 }
470
472
473 for (std::set<SpellGroup>::iterator itr = groups.begin(); itr!= groups.end(); ++itr)
474 {
475 SpellGroupStackMap::const_iterator found = mSpellGroupStack.find(*itr);
476 if (found != mSpellGroupStack.end())
477 rule = found->second;
478 if (rule)
479 break;
480 }
481 return rule;
482}
483
485{
486 SpellGroupStackMap::const_iterator itr = mSpellGroupStack.find(group);
487 if (itr != mSpellGroupStack.end())
488 return itr->second;
489
491}
492
494{
495 SpellProcMap::const_iterator itr = mSpellProcMap.find(spellId);
496 if (itr != mSpellProcMap.end())
497 return &itr->second;
498 return nullptr;
499}
500
502{
503 // proc type doesn't match
504 if (!(eventInfo.GetTypeMask() & procEntry.ProcFlags))
505 return false;
506
507 // check XP or honor target requirement
509 if (Player* actor = eventInfo.GetActor()->ToPlayer())
510 if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget()))
511 return false;
512
513 // check mana requirement
515 if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo())
516 if (!eventSpellInfo->ManaCost && !eventSpellInfo->ManaCostPercentage)
517 return false;
518
519 // always trigger for these types
521 return true;
522
523 // check school mask (if set) for other trigger types
524 if (procEntry.SchoolMask && !(eventInfo.GetSchoolMask() & procEntry.SchoolMask))
525 return false;
526
527 // check spell family name/flags (if set) for spells
528 if (eventInfo.GetTypeMask() & SPELL_PROC_FLAG_MASK)
529 {
530 if (SpellInfo const* eventSpellInfo = eventInfo.GetSpellInfo())
531 if (!eventSpellInfo->IsAffected(procEntry.SpellFamilyName, procEntry.SpellFamilyMask))
532 return false;
533
534 // check spell type mask (if set)
535 if (procEntry.SpellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.SpellTypeMask))
536 return false;
537 }
538
539 // check spell phase mask
541 {
542 if (!(eventInfo.GetSpellPhaseMask() & procEntry.SpellPhaseMask))
543 return false;
544 }
545
546 // check hit mask (on taken hit or on done hit, but not on spell cast phase)
547 if ((eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) || ((eventInfo.GetTypeMask() & DONE_HIT_PROC_FLAG_MASK) && !(eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST)))
548 {
549 uint32 hitMask = procEntry.HitMask;
550 // get default values if hit mask not set
551 if (!hitMask)
552 {
553 // for taken procs allow normal + critical hits by default
554 if (eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK)
556 // for done procs allow normal + critical + absorbs by default
557 else
559 }
560 if (!(eventInfo.GetHitMask() & hitMask))
561 return false;
562 }
563
564 return true;
565}
566
568{
569 // Lookup data
570 SpellBonusMap::const_iterator itr = mSpellBonusMap.find(spellId);
571 if (itr != mSpellBonusMap.end())
572 return &itr->second;
573 // Not found, try lookup for 1 spell rank if exist
574 if (uint32 rank_1 = GetFirstSpellInChain(spellId))
575 {
576 SpellBonusMap::const_iterator itr2 = mSpellBonusMap.find(rank_1);
577 if (itr2 != mSpellBonusMap.end())
578 return &itr2->second;
579 }
580 return nullptr;
581}
582
584{
585 SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellID);
586 if (itr != mSpellThreatMap.end())
587 return &itr->second;
588 else
589 {
590 uint32 firstSpell = GetFirstSpellInChain(spellID);
591 itr = mSpellThreatMap.find(firstSpell);
592 if (itr != mSpellThreatMap.end())
593 return &itr->second;
594 }
595 return nullptr;
596}
597
599{
600 return mSkillLineAbilityMap.equal_range(spell_id);
601}
602
603PetAura const* SpellMgr::GetPetAura(uint32 spell_id, uint8 eff) const
604{
605 SpellPetAuraMap::const_iterator itr = mSpellPetAuraMap.find((spell_id<<8) + eff);
606 if (itr != mSpellPetAuraMap.end())
607 return &itr->second;
608 else
609 return nullptr;
610}
611
613{
614 SpellEnchantProcEventMap::const_iterator itr = mSpellEnchantProcEventMap.find(enchId);
615 if (itr != mSpellEnchantProcEventMap.end())
616 return &itr->second;
617 return nullptr;
618}
619
621{
622 return mEnchantCustomAttr[ench_id];
623}
624
625std::vector<int32> const* SpellMgr::GetSpellLinked(int32 spell_id) const
626{
628}
629
631{
632 PetLevelupSpellMap::const_iterator itr = mPetLevelupSpellMap.find(petFamily);
633 if (itr != mPetLevelupSpellMap.end())
634 return &itr->second;
635 else
636 return nullptr;
637}
638
640{
641 PetDefaultSpellsMap::const_iterator itr = mPetDefaultSpellsMap.find(id);
642 if (itr != mPetDefaultSpellsMap.end())
643 return &itr->second;
644 return nullptr;
645}
646
648{
649 return mSpellAreaMap.equal_range(spell_id);
650}
651
653{
654 return mSpellAreaForQuestMap.equal_range(quest_id);
655}
656
661
663{
664 return mSpellAreaForAuraMap.equal_range(spell_id);
665}
666
668{
669 return mSpellAreaForAreaMap.equal_range(area_id);
670}
671
672bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const
673{
674 if (gender != GENDER_NONE) // is not expected gender
675 if (!player || gender != player->GetNativeGender())
676 return false;
677
678 if (raceMask) // is not expected race
679 if (!player || !(raceMask & player->GetRaceMask()))
680 return false;
681
682 if (areaId) // is not in expected zone
683 if (newZone != areaId && newArea != areaId)
684 return false;
685
686 if (questStart) // is not in expected required quest state
687 if (!player || (((1 << player->GetQuestStatus(questStart)) & questStartStatus) == 0))
688 return false;
689
690 if (questEnd) // is not in expected forbidden quest state
691 if (!player || (((1 << player->GetQuestStatus(questEnd)) & questEndStatus) == 0))
692 return false;
693
694 if (auraSpell) // does not have expected aura
695 if (!player || (auraSpell > 0 && !player->HasAura(auraSpell)) || (auraSpell < 0 && player->HasAura(-auraSpell)))
696 return false;
697
698 if (player)
699 {
700 if (Battleground* bg = player->GetBattleground())
701 return bg->IsSpellAllowed(spellId, player);
702 }
703
704 // Extra conditions
705 switch (spellId)
706 {
707 case 58600: // No fly Zone - Dalaran
708 {
709 if (!player)
710 return false;
711
712 AreaTableEntry const* pArea = sAreaTableStore.LookupEntry(player->GetAreaId());
713 if (!(pArea && pArea->Flags & AREA_FLAG_NO_FLY_ZONE))
714 return false;
716 return false;
717 break;
718 }
719 case 58730: // No fly Zone - Wintergrasp
720 {
721 if (!player)
722 return false;
723
724 Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId());
726 return false;
727 break;
728 }
729 case 56618: // Horde Controls Factory Phase Shift
730 case 56617: // Alliance Controls Factory Phase Shift
731 {
732 if (!player)
733 return false;
734
735 Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId());
736
737 if (!bf || bf->GetTypeId() != BATTLEFIELD_WG)
738 return false;
739
740 // team that controls the workshop in the specified area
741 uint32 team = bf->GetData(newArea);
742
743 if (team == TEAM_HORDE)
744 return spellId == 56618;
745 else if (team == TEAM_ALLIANCE)
746 return spellId == 56617;
747 break;
748 }
749 case 57940: // Essence of Wintergrasp - Northrend
750 case 58045: // Essence of Wintergrasp - Wintergrasp
751 {
752 if (!player)
753 return false;
754
755 if (Battlefield* battlefieldWG = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG))
756 return battlefieldWG->IsEnabled() && (player->GetTeamId() == battlefieldWG->GetDefenderTeam()) && !battlefieldWG->IsWarTime();
757 break;
758 }
759 case 74411: // Battleground - Dampening
760 {
761 if (!player)
762 return false;
763
764 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId()))
765 return bf->IsWarTime();
766 break;
767 }
768
769 }
770
771 return true;
772}
773
775{
776 for (SpellChainMap::iterator itr = mSpellChains.begin(); itr != mSpellChains.end(); ++itr)
777 mSpellInfoMap[itr->first]->ChainEntry = nullptr;
778
779 mSpellChains.clear();
780}
781
783{
784 // cleanup core data before reload - remove reference to ChainNode from SpellInfo
786
787 for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
788 {
789 TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
790 if (!talentInfo)
791 continue;
792
793 SpellInfo const* lastSpell = nullptr;
794 for (uint8 rank = MAX_TALENT_RANK - 1; rank > 0; --rank)
795 {
796 if (talentInfo->SpellRank[rank])
797 {
798 lastSpell = GetSpellInfo(talentInfo->SpellRank[rank]);
799 break;
800 }
801 }
802
803 if (!lastSpell)
804 continue;
805
806 SpellInfo const* firstSpell = GetSpellInfo(talentInfo->SpellRank[0]);
807 if (!firstSpell)
808 {
809 TC_LOG_ERROR("spells", "SpellMgr::LoadSpellTalentRanks: First Rank Spell {} for TalentEntry {} does not exist.", talentInfo->SpellRank[0], i);
810 continue;
811 }
812
813 SpellInfo const* prevSpell = nullptr;
814 for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank)
815 {
816 uint32 spellId = talentInfo->SpellRank[rank];
817 if (!spellId)
818 break;
819
820 SpellInfo const* currentSpell = GetSpellInfo(spellId);
821 if (!currentSpell)
822 {
823 TC_LOG_ERROR("spells", "SpellMgr::LoadSpellTalentRanks: Spell {} (Rank: {}) for TalentEntry {} does not exist.", spellId, rank + 1, i);
824 break;
825 }
826
827 SpellChainNode node;
828 node.first = firstSpell;
829 node.last = lastSpell;
830 node.rank = rank + 1;
831
832 node.prev = prevSpell;
833 node.next = node.rank < MAX_TALENT_RANK ? GetSpellInfo(talentInfo->SpellRank[node.rank]) : nullptr;
834
835 mSpellChains[spellId] = node;
836 mSpellInfoMap[spellId]->ChainEntry = &mSpellChains[spellId];
837
838 prevSpell = currentSpell;
839 }
840 }
841}
842
844{
845 // cleanup data and load spell ranks for talents from dbc
847
848 uint32 oldMSTime = getMSTime();
849
850 // 0 1 2
851 QueryResult result = WorldDatabase.Query("SELECT first_spell_id, spell_id, `rank` from spell_ranks ORDER BY first_spell_id, `rank`");
852
853 if (!result)
854 {
855 TC_LOG_INFO("server.loading", ">> Loaded 0 spell rank records. DB table `spell_ranks` is empty.");
856 return;
857 }
858
859 uint32 count = 0;
860 bool finished = false;
861
862 do
863 {
864 // spellid, rank
865 std::list < std::pair < int32, int32 > > rankChain;
866 int32 currentSpell = -1;
867 int32 lastSpell = -1;
868
869 // fill one chain
870 while (currentSpell == lastSpell && !finished)
871 {
872 Field* fields = result->Fetch();
873
874 currentSpell = fields[0].GetUInt32();
875 if (lastSpell == -1)
876 lastSpell = currentSpell;
877 uint32 spell_id = fields[1].GetUInt32();
878 uint32 rank = fields[2].GetUInt8();
879
880 // don't drop the row if we're moving to the next rank
881 if (currentSpell == lastSpell)
882 {
883 rankChain.push_back(std::make_pair(spell_id, rank));
884 if (!result->NextRow())
885 finished = true;
886 }
887 else
888 break;
889 }
890 // check if chain is made with valid first spell
891 SpellInfo const* first = GetSpellInfo(lastSpell);
892 if (!first)
893 {
894 TC_LOG_ERROR("sql.sql", "The spell rank identifier(first_spell_id) {} listed in `spell_ranks` does not exist!", lastSpell);
895 continue;
896 }
897 // check if chain is long enough
898 if (rankChain.size() < 2)
899 {
900 TC_LOG_ERROR("sql.sql", "There is only 1 spell rank for identifier(first_spell_id) {} in `spell_ranks`, entry is not needed!", lastSpell);
901 continue;
902 }
903 int32 curRank = 0;
904 bool valid = true;
905 // check spells in chain
906 for (std::list<std::pair<int32, int32> >::iterator itr = rankChain.begin(); itr!= rankChain.end(); ++itr)
907 {
908 SpellInfo const* spell = GetSpellInfo(itr->first);
909 if (!spell)
910 {
911 TC_LOG_ERROR("sql.sql", "The spell {} (rank {}) listed in `spell_ranks` for chain {} does not exist!", itr->first, itr->second, lastSpell);
912 valid = false;
913 break;
914 }
915 ++curRank;
916 if (itr->second != curRank)
917 {
918 TC_LOG_ERROR("sql.sql", "The spell {} (rank {}) listed in `spell_ranks` for chain {} does not have a proper rank value (should be {})!", itr->first, itr->second, lastSpell, curRank);
919 valid = false;
920 break;
921 }
922 }
923 if (!valid)
924 continue;
925 int32 prevRank = 0;
926 // insert the chain
927 std::list<std::pair<int32, int32> >::iterator itr = rankChain.begin();
928 do
929 {
930 ++count;
931 int32 addedSpell = itr->first;
932
933 if (mSpellInfoMap[addedSpell]->ChainEntry)
934 TC_LOG_ERROR("sql.sql", "The spell {} (rank: {}, first: {}) listed in `spell_ranks` already has ChainEntry from dbc.", addedSpell, itr->second, lastSpell);
935
936 mSpellChains[addedSpell].first = GetSpellInfo(lastSpell);
937 mSpellChains[addedSpell].last = GetSpellInfo(rankChain.back().first);
938 mSpellChains[addedSpell].rank = itr->second;
939 mSpellChains[addedSpell].prev = GetSpellInfo(prevRank);
940 mSpellInfoMap[addedSpell]->ChainEntry = &mSpellChains[addedSpell];
941 prevRank = addedSpell;
942 ++itr;
943
944 if (itr == rankChain.end())
945 {
946 mSpellChains[addedSpell].next = nullptr;
947 break;
948 }
949 else
950 mSpellChains[addedSpell].next = GetSpellInfo(itr->first);
951 }
952 while (true);
953 }
954 while (!finished);
955
956 TC_LOG_INFO("server.loading", ">> Loaded {} spell rank records in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
957}
958
960{
961 uint32 oldMSTime = getMSTime();
962
963 mSpellsReqSpell.clear(); // need for reload case
964 mSpellReq.clear(); // need for reload case
965
966 // 0 1
967 QueryResult result = WorldDatabase.Query("SELECT spell_id, req_spell from spell_required");
968
969 if (!result)
970 {
971 TC_LOG_INFO("server.loading", ">> Loaded 0 spell required records. DB table `spell_required` is empty.");
972
973 return;
974 }
975
976 uint32 count = 0;
977 do
978 {
979 Field* fields = result->Fetch();
980
981 uint32 spell_id = fields[0].GetUInt32();
982 uint32 spell_req = fields[1].GetUInt32();
983
984 // check if chain is made with valid first spell
985 SpellInfo const* spell = GetSpellInfo(spell_id);
986 if (!spell)
987 {
988 TC_LOG_ERROR("sql.sql", "spell_id {} in `spell_required` table could not be found in dbc, skipped.", spell_id);
989 continue;
990 }
991
992 SpellInfo const* reqSpell = GetSpellInfo(spell_req);
993 if (!reqSpell)
994 {
995 TC_LOG_ERROR("sql.sql", "req_spell {} in `spell_required` table could not be found in dbc, skipped.", spell_req);
996 continue;
997 }
998
999 if (spell->IsRankOf(reqSpell))
1000 {
1001 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);
1002 continue;
1003 }
1004
1005 if (IsSpellRequiringSpell(spell_id, spell_req))
1006 {
1007 TC_LOG_ERROR("sql.sql", "Duplicate entry of req_spell {} and spell_id {} in `spell_required`, skipped.", spell_req, spell_id);
1008 continue;
1009 }
1010
1011 mSpellReq.insert (std::pair<uint32, uint32>(spell_id, spell_req));
1012 mSpellsReqSpell.insert (std::pair<uint32, uint32>(spell_req, spell_id));
1013 ++count;
1014 } while (result->NextRow());
1015
1016 TC_LOG_INFO("server.loading", ">> Loaded {} spell required records in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1017
1018}
1019
1021{
1022 uint32 oldMSTime = getMSTime();
1023
1024 mSpellLearnSkills.clear(); // need for reload case
1025
1026 // search auto-learned skills and add its to map also for use in unlearn spells/talents
1027 uint32 dbc_count = 0;
1028 for (SpellInfo const* entry : mSpellInfoMap)
1029 {
1030 if (!entry)
1031 continue;
1032
1033 for (SpellEffectInfo const& spellEffectInfo : entry->GetEffects())
1034 {
1035 SpellLearnSkillNode dbc_node;
1036 switch (spellEffectInfo.Effect)
1037 {
1038 case SPELL_EFFECT_SKILL:
1039 dbc_node.skill = spellEffectInfo.MiscValue;
1040 dbc_node.step = spellEffectInfo.CalcValue();
1041 if (dbc_node.skill != SKILL_RIDING)
1042 dbc_node.value = 1;
1043 else
1044 dbc_node.value = dbc_node.step * 75;
1045 dbc_node.maxvalue = dbc_node.step * 75;
1046 break;
1048 dbc_node.skill = SKILL_DUAL_WIELD;
1049 dbc_node.step = 1;
1050 dbc_node.value = 1;
1051 dbc_node.maxvalue = 1;
1052 break;
1053 default:
1054 continue;
1055 }
1056
1057 mSpellLearnSkills[entry->Id] = dbc_node;
1058 ++dbc_count;
1059 break;
1060 }
1061 }
1062
1063 TC_LOG_INFO("server.loading", ">> Loaded {} Spell Learn Skills from DBC in {} ms", dbc_count, GetMSTimeDiffToNow(oldMSTime));
1064}
1065
1067{
1068 uint32 oldMSTime = getMSTime();
1069
1070 mSpellLearnSpells.clear(); // need for reload case
1071
1072 // 0 1 2
1073 QueryResult result = WorldDatabase.Query("SELECT entry, SpellID, Active FROM spell_learn_spell");
1074 if (!result)
1075 {
1076 TC_LOG_INFO("server.loading", ">> Loaded 0 spell learn spells. DB table `spell_learn_spell` is empty.");
1077 return;
1078 }
1079
1080 uint32 count = 0;
1081 do
1082 {
1083 Field* fields = result->Fetch();
1084
1085 uint32 spell_id = fields[0].GetUInt32();
1086
1088 node.spell = fields[1].GetUInt32();
1089 node.active = fields[2].GetBool();
1090 node.autoLearned = false;
1091
1092 if (!GetSpellInfo(spell_id))
1093 {
1094 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_learn_spell` does not exist.", spell_id);
1095 continue;
1096 }
1097
1098 if (!GetSpellInfo(node.spell))
1099 {
1100 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_learn_spell` learning non-existing spell {}.", spell_id, node.spell);
1101 continue;
1102 }
1103
1104 if (GetTalentSpellCost(node.spell))
1105 {
1106 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_learn_spell` attempts learning talent spell {}, skipped.", spell_id, node.spell);
1107 continue;
1108 }
1109
1110 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell_id, node));
1111
1112 ++count;
1113 } while (result->NextRow());
1114
1115 // search auto-learned spells and add its to map also for use in unlearn spells/talents
1116 uint32 dbc_count = 0;
1117 for (uint32 spell = 0; spell < GetSpellInfoStoreSize(); ++spell)
1118 {
1119 SpellInfo const* entry = GetSpellInfo(spell);
1120
1121 if (!entry)
1122 continue;
1123
1124 for (SpellEffectInfo const& spellEffectInfo : entry->GetEffects())
1125 {
1126 if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL))
1127 {
1128 SpellLearnSpellNode dbc_node;
1129 dbc_node.spell = spellEffectInfo.TriggerSpell;
1130 dbc_node.active = true; // all dbc based learned spells is active (show in spell book or hide by client itself)
1131
1132 // ignore learning not existed spells (broken/outdated/or generic learnig spell 483
1133 if (!GetSpellInfo(dbc_node.spell))
1134 continue;
1135
1136 // talent or passive spells or skill-step spells auto-cast and not need dependent learning,
1137 // pet teaching spells must not be dependent learning (cast)
1138 // other required explicit dependent learning
1139 dbc_node.autoLearned = spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET || GetTalentSpellCost(spell) > 0 || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
1140
1142
1143 bool found = false;
1144 for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
1145 {
1146 if (itr->second.spell == dbc_node.spell)
1147 {
1148 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.",
1149 spell, dbc_node.spell);
1150 found = true;
1151 break;
1152 }
1153 }
1154
1155 if (!found) // add new spell-spell pair if not found
1156 {
1157 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell, dbc_node));
1158 ++dbc_count;
1159 }
1160 }
1161 }
1162 }
1163
1164 TC_LOG_INFO("server.loading", ">> Loaded {} spell learn spells + {} found in DBC in {} ms", count, dbc_count, GetMSTimeDiffToNow(oldMSTime));
1165}
1166
1168{
1169 uint32 oldMSTime = getMSTime();
1170
1171 mSpellTargetPositions.clear(); // need for reload case
1172
1173 // 0 1 2 3 4 5 6
1174 QueryResult result = WorldDatabase.Query("SELECT ID, EffectIndex, MapID, PositionX, PositionY, PositionZ, Orientation FROM spell_target_position");
1175 if (!result)
1176 {
1177 TC_LOG_INFO("server.loading", ">> Loaded 0 spell target coordinates. DB table `spell_target_position` is empty.");
1178 return;
1179 }
1180
1181 uint32 count = 0;
1182 do
1183 {
1184 Field* fields = result->Fetch();
1185
1186 uint32 Spell_ID = fields[0].GetUInt32();
1187 SpellEffIndex effIndex = SpellEffIndex(fields[1].GetUInt8());
1188
1190
1191 st.target_mapId = fields[2].GetUInt16();
1192 st.target_X = fields[3].GetFloat();
1193 st.target_Y = fields[4].GetFloat();
1194 st.target_Z = fields[5].GetFloat();
1195 st.target_Orientation = fields[6].GetFloat();
1196
1197 MapEntry const* mapEntry = sMapStore.LookupEntry(st.target_mapId);
1198 if (!mapEntry)
1199 {
1200 TC_LOG_ERROR("sql.sql", "Spell (Id: {}, effIndex: {}) target map (ID: {}) does not exist in `Map.dbc`.", Spell_ID, effIndex, st.target_mapId);
1201 continue;
1202 }
1203
1204 if (st.target_X==0 && st.target_Y==0 && st.target_Z==0)
1205 {
1206 TC_LOG_ERROR("sql.sql", "Spell (Id: {}, effIndex: {}) target coordinates not provided.", Spell_ID, effIndex);
1207 continue;
1208 }
1209
1210 SpellInfo const* spellInfo = GetSpellInfo(Spell_ID);
1211 if (!spellInfo)
1212 {
1213 TC_LOG_ERROR("sql.sql", "Spell (Id: {}) listed in `spell_target_position` does not exist.", Spell_ID);
1214 continue;
1215 }
1216
1217 if (spellInfo->GetEffect(effIndex).TargetA.GetTarget() == TARGET_DEST_DB || spellInfo->GetEffect(effIndex).TargetB.GetTarget() == TARGET_DEST_DB)
1218 {
1219 std::pair<uint32, SpellEffIndex> key = std::make_pair(Spell_ID, effIndex);
1220 mSpellTargetPositions[key] = st;
1221 ++count;
1222 }
1223 else
1224 {
1225 TC_LOG_ERROR("sql.sql", "Spell (Id: {}, effIndex: {}) listed in `spell_target_position` does not have a target TARGET_DEST_DB (17).", Spell_ID, effIndex);
1226 continue;
1227 }
1228
1229 } while (result->NextRow());
1230
1231 /*
1232 // Check all spells
1233 for (uint32 i = 1; i < GetSpellInfoStoreSize; ++i)
1234 {
1235 SpellInfo const* spellInfo = GetSpellInfo(i);
1236 if (!spellInfo)
1237 continue;
1238
1239 bool found = false;
1240 for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
1241 {
1242 switch (spellInfo->Effects[j].TargetA)
1243 {
1244 case TARGET_DEST_DB:
1245 found = true;
1246 break;
1247 }
1248 if (found)
1249 break;
1250 switch (spellInfo->Effects[j].TargetB)
1251 {
1252 case TARGET_DEST_DB:
1253 found = true;
1254 break;
1255 }
1256 if (found)
1257 break;
1258 }
1259 if (found)
1260 {
1261 if (!sSpellMgr->GetSpellTargetPosition(i))
1262 TC_LOG_DEBUG("spells", "Spell (ID: {}) does not have a record in `spell_target_position`.", i);
1263 }
1264 }*/
1265
1266 TC_LOG_INFO("server.loading", ">> Loaded {} spell teleport coordinates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1267}
1268
1270{
1271 uint32 oldMSTime = getMSTime();
1272
1273 mSpellSpellGroup.clear(); // need for reload case
1274 mSpellGroupSpell.clear();
1275
1276 // 0 1
1277 QueryResult result = WorldDatabase.Query("SELECT id, spell_id FROM spell_group");
1278 if (!result)
1279 {
1280 TC_LOG_INFO("server.loading", ">> Loaded 0 spell group definitions. DB table `spell_group` is empty.");
1281 return;
1282 }
1283
1284 std::set<uint32> groups;
1285 uint32 count = 0;
1286 do
1287 {
1288 Field* fields = result->Fetch();
1289
1290 uint32 group_id = fields[0].GetUInt32();
1291 if (group_id <= SPELL_GROUP_DB_RANGE_MIN && group_id >= SPELL_GROUP_CORE_RANGE_MAX)
1292 {
1293 TC_LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` is in core range, but is not defined in core!", group_id);
1294 continue;
1295 }
1296 int32 spell_id = fields[1].GetInt32();
1297
1298 groups.insert(group_id);
1299 mSpellGroupSpell.emplace(SpellGroup(group_id), spell_id);
1300
1301 } while (result->NextRow());
1302
1303 for (auto itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
1304 {
1305 if (itr->second < 0)
1306 {
1307 if (groups.find(abs(itr->second)) == groups.end())
1308 {
1309 TC_LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` does not exist", abs(itr->second));
1310 itr = mSpellGroupSpell.erase(itr);
1311 }
1312 else
1313 ++itr;
1314 }
1315 else
1316 {
1317 SpellInfo const* spellInfo = GetSpellInfo(itr->second);
1318 if (!spellInfo)
1319 {
1320 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_group` does not exist", itr->second);
1321 itr = mSpellGroupSpell.erase(itr);
1322 }
1323 else if (spellInfo->GetRank() > 1)
1324 {
1325 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_group` is not the first rank of the spell.", itr->second);
1326 itr = mSpellGroupSpell.erase(itr);
1327 }
1328 else
1329 ++itr;
1330 }
1331 }
1332
1333 for (auto groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
1334 {
1335 std::set<uint32> spells;
1336 GetSetOfSpellsInSpellGroup(SpellGroup(*groupItr), spells);
1337
1338 for (auto spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
1339 {
1340 ++count;
1341 mSpellSpellGroup.emplace(*spellItr, SpellGroup(*groupItr));
1342 }
1343 }
1344
1345 TC_LOG_INFO("server.loading", ">> Loaded {} spell group definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1346}
1347
1349{
1350 uint32 oldMSTime = getMSTime();
1351
1352 mSpellGroupStack.clear(); // need for reload case
1353 mSpellSameEffectStack.clear();
1354
1355 std::vector<uint32> sameEffectGroups;
1356
1357 // 0 1
1358 QueryResult result = WorldDatabase.Query("SELECT group_id, stack_rule FROM spell_group_stack_rules");
1359 if (!result)
1360 {
1361 TC_LOG_INFO("server.loading", ">> Loaded 0 spell group stack rules. DB table `spell_group_stack_rules` is empty.");
1362 return;
1363 }
1364
1365 uint32 count = 0;
1366 do
1367 {
1368 Field* fields = result->Fetch();
1369
1370 uint32 group_id = fields[0].GetUInt32();
1371 uint8 stack_rule = fields[1].GetInt8();
1372 if (stack_rule >= SPELL_GROUP_STACK_RULE_MAX)
1373 {
1374 TC_LOG_ERROR("sql.sql", "SpellGroupStackRule {} listed in `spell_group_stack_rules` does not exist.", stack_rule);
1375 continue;
1376 }
1377
1378 auto bounds = GetSpellGroupSpellMapBounds((SpellGroup)group_id);
1379 if (bounds.first == bounds.second)
1380 {
1381 TC_LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group_stack_rules` does not exist.", group_id);
1382 continue;
1383 }
1384
1385 mSpellGroupStack.emplace(SpellGroup(group_id), SpellGroupStackRule(stack_rule));
1386
1387 // different container for same effect stack rules, need to check effect types
1389 sameEffectGroups.push_back(group_id);
1390
1391 ++count;
1392 } while (result->NextRow());
1393
1394 TC_LOG_INFO("server.loading", ">> Loaded {} spell group stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1395
1396 count = 0;
1397 oldMSTime = getMSTime();
1398 TC_LOG_INFO("server.loading", ">> Parsing SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules...");
1399
1400 for (uint32 group_id : sameEffectGroups)
1401 {
1402 std::set<uint32> spellIds;
1403 GetSetOfSpellsInSpellGroup(SpellGroup(group_id), spellIds);
1404
1405 std::unordered_set<uint32> auraTypes;
1406
1407 // we have to 'guess' what effect this group corresponds to
1408 {
1409 std::unordered_multiset<uint32 /*auraName*/> frequencyContainer;
1410
1411 // only waylay for the moment (shared group)
1412 std::vector<std::vector<uint32 /*auraName*/>> const SubGroups =
1413 {
1415 };
1416
1417 for (uint32 spellId : spellIds)
1418 {
1419 SpellInfo const* spellInfo = AssertSpellInfo(spellId);
1420 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1421 {
1422 if (!spellEffectInfo.IsAura())
1423 continue;
1424
1425 uint32 auraName = spellEffectInfo.ApplyAuraName;
1426 for (std::vector<uint32> const& subGroup : SubGroups)
1427 {
1428 if (std::find(subGroup.begin(), subGroup.end(), auraName) != subGroup.end())
1429 {
1430 // count as first aura
1431 auraName = subGroup.front();
1432 break;
1433 }
1434 }
1435
1436 frequencyContainer.insert(auraName);
1437 }
1438 }
1439
1440 uint32 auraType = 0;
1441 size_t auraTypeCount = 0;
1442 for (uint32 auraName : frequencyContainer)
1443 {
1444 size_t currentCount = frequencyContainer.count(auraName);
1445 if (currentCount > auraTypeCount)
1446 {
1447 auraType = auraName;
1448 auraTypeCount = currentCount;
1449 }
1450 }
1451
1452 for (std::vector<uint32> const& subGroup : SubGroups)
1453 {
1454 if (auraType == subGroup.front())
1455 {
1456 auraTypes.insert(subGroup.begin(), subGroup.end());
1457 break;
1458 }
1459 }
1460
1461 if (auraTypes.empty())
1462 auraTypes.insert(auraType);
1463 }
1464
1465 // re-check spells against guessed group
1466 for (uint32 spellId : spellIds)
1467 {
1468 SpellInfo const* spellInfo = AssertSpellInfo(spellId);
1469
1470 bool found = false;
1471 while (spellInfo)
1472 {
1473 for (uint32 auraType : auraTypes)
1474 {
1475 if (spellInfo->HasAura(AuraType(auraType)))
1476 {
1477 found = true;
1478 break;
1479 }
1480 }
1481
1482 if (found)
1483 break;
1484
1485 spellInfo = spellInfo->GetNextRankSpell();
1486 }
1487
1488 // not found either, log error
1489 if (!found)
1490 TC_LOG_ERROR("sql.sql", "SpellId {} listed in `spell_group` with stack rule 3 does not share aura assigned for group {}", spellId, group_id);
1491 }
1492
1493 mSpellSameEffectStack[SpellGroup(group_id)] = auraTypes;
1494 ++count;
1495 }
1496
1497 TC_LOG_INFO("server.loading", ">> Parsed {} SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1498}
1499
1501{
1502 uint32 oldMSTime = getMSTime();
1503
1504 mSpellProcMap.clear(); // need for reload case
1505
1506 // 0 1 2 3 4 5
1507 QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, "
1508 // 6 7 8 9 10 11 12 13 14 15
1509 "ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, DisableEffectsMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
1510
1511 uint32 count = 0;
1512 if (result)
1513 {
1514 do
1515 {
1516 Field* fields = result->Fetch();
1517
1518 int32 spellId = fields[0].GetInt32();
1519
1520 bool allRanks = false;
1521 if (spellId < 0)
1522 {
1523 allRanks = true;
1524 spellId = -spellId;
1525 }
1526
1527 SpellInfo const* spellInfo = GetSpellInfo(spellId);
1528 if (!spellInfo)
1529 {
1530 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` does not exist", spellId);
1531 continue;
1532 }
1533
1534 if (allRanks)
1535 {
1536 if (!spellInfo->IsRanked())
1537 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` with all ranks, but spell has no ranks.", spellId);
1538
1539 if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
1540 {
1541 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` is not the first rank of the spell.", spellId);
1542 continue;
1543 }
1544 }
1545
1546 SpellProcEntry baseProcEntry;
1547
1548 baseProcEntry.SchoolMask = fields[1].GetInt8();
1549 baseProcEntry.SpellFamilyName = fields[2].GetUInt16();
1550 baseProcEntry.SpellFamilyMask[0] = fields[3].GetUInt32();
1551 baseProcEntry.SpellFamilyMask[1] = fields[4].GetUInt32();
1552 baseProcEntry.SpellFamilyMask[2] = fields[5].GetUInt32();
1553 baseProcEntry.ProcFlags = fields[6].GetUInt32();
1554 baseProcEntry.SpellTypeMask = fields[7].GetUInt32();
1555 baseProcEntry.SpellPhaseMask = fields[8].GetUInt32();
1556 baseProcEntry.HitMask = fields[9].GetUInt32();
1557 baseProcEntry.AttributesMask = fields[10].GetUInt32();
1558 baseProcEntry.DisableEffectsMask = fields[11].GetUInt32();
1559 baseProcEntry.ProcsPerMinute = fields[12].GetFloat();
1560 baseProcEntry.Chance = fields[13].GetFloat();
1561 baseProcEntry.Cooldown = Milliseconds(fields[14].GetUInt32());
1562 baseProcEntry.Charges = fields[15].GetUInt8();
1563
1564 while (spellInfo)
1565 {
1566 if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
1567 {
1568 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` already has its first rank in the table.", spellInfo->Id);
1569 break;
1570 }
1571
1572 SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
1573
1574 // take defaults from dbcs
1575 if (!procEntry.ProcFlags)
1576 procEntry.ProcFlags = spellInfo->ProcFlags;
1577 if (!procEntry.Charges)
1578 procEntry.Charges = spellInfo->ProcCharges;
1579 if (!procEntry.Chance && !procEntry.ProcsPerMinute)
1580 procEntry.Chance = float(spellInfo->ProcChance);
1581
1582 // validate data
1583 if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL)
1584 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `SchoolMask` set: {}", spellInfo->Id, procEntry.SchoolMask);
1585 if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < SPELLFAMILY_MAGE || procEntry.SpellFamilyName > SPELLFAMILY_PET || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16))
1586 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `SpellFamilyName` set: {}", spellInfo->Id, procEntry.SpellFamilyName);
1587 if (procEntry.Chance < 0)
1588 {
1589 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in the `Chance` field", spellInfo->Id);
1590 procEntry.Chance = 0;
1591 }
1592 if (procEntry.ProcsPerMinute < 0)
1593 {
1594 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in the `ProcsPerMinute` field", spellInfo->Id);
1595 procEntry.ProcsPerMinute = 0;
1596 }
1597 if (!procEntry.ProcFlags)
1598 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);
1599 if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
1600 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `SpellTypeMask` set: {}", spellInfo->Id, procEntry.SpellTypeMask);
1601 if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & SPELL_PROC_FLAG_MASK))
1602 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);
1603 if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
1604 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);
1606 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has wrong `SpellPhaseMask` set: {}", spellInfo->Id, procEntry.SpellPhaseMask);
1607 if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
1608 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);
1609 if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
1610 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has wrong `HitMask` set: {}", spellInfo->Id, procEntry.HitMask);
1611 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)))))
1612 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);
1613 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1614 if ((procEntry.DisableEffectsMask & (1u << spellEffectInfo.EffectIndex)) && !spellEffectInfo.IsAura())
1615 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));
1616 if (procEntry.AttributesMask & PROC_ATTR_REQ_SPELLMOD)
1617 {
1618 bool found = false;
1619 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1620 {
1621 if (!spellEffectInfo.IsAura())
1622 continue;
1623
1624 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_ADD_PCT_MODIFIER || spellEffectInfo.ApplyAuraName == SPELL_AURA_ADD_FLAT_MODIFIER)
1625 {
1626 found = true;
1627 break;
1628 }
1629 }
1630
1631 if (!found)
1632 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);
1633 }
1634
1635 mSpellProcMap[spellInfo->Id] = procEntry;
1636
1637 if (allRanks)
1638 spellInfo = spellInfo->GetNextRankSpell();
1639 else
1640 break;
1641 }
1642 ++count;
1643 } while (result->NextRow());
1644 }
1645 else
1646 TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty.");
1647
1648 TC_LOG_INFO("server.loading", ">> Loaded {} spell proc conditions and data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1649
1650 // Define can trigger auras
1651 bool isTriggerAura[TOTAL_AURAS];
1652 // Triggered always, even from triggered spells
1653 bool isAlwaysTriggeredAura[TOTAL_AURAS];
1654 // SpellTypeMask to add to the proc
1655 uint32 spellTypeMask[TOTAL_AURAS];
1656
1657 // List of auras that CAN trigger but may not exist in spell_proc
1658 // in most cases needed to drop charges
1659
1660 // some aura types need additional checks (eg SPELL_AURA_MECHANIC_IMMUNITY needs mechanic check)
1661 // see AuraEffect::CheckEffectProc
1662 for (uint16 i = 0; i < TOTAL_AURAS; ++i)
1663 {
1664 isTriggerAura[i] = false;
1665 isAlwaysTriggeredAura[i] = false;
1666 spellTypeMask[i] = PROC_SPELL_TYPE_MASK_ALL;
1667 }
1668
1669 isTriggerAura[SPELL_AURA_DUMMY] = true; // Most dummy auras should require scripting, but there are some exceptions (ie 12311)
1670 isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; // "Any direct damaging attack will revive targets"
1671 isTriggerAura[SPELL_AURA_MOD_THREAT] = true; // Only one spell: 28762 part of Mage T3 8p bonus
1672 isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger
1673 isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
1674 isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
1675 isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
1676 isTriggerAura[SPELL_AURA_MOD_STEALTH] = true;
1677 isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger
1678 isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
1679 isTriggerAura[SPELL_AURA_TRANSFORM] = true;
1680 isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
1681 isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
1682 isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
1683 isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
1684 isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true;
1685 isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
1686 isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
1687 isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
1688 isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
1689 isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
1690 isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true;
1691 isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
1692 isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true;
1693 isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true;
1694 isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true;
1695 isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true;
1696 isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
1697 isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
1698 isTriggerAura[SPELL_AURA_ADD_FLAT_MODIFIER] = true;
1699 isTriggerAura[SPELL_AURA_ADD_PCT_MODIFIER] = true;
1700 isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true;
1701 isTriggerAura[SPELL_AURA_MOD_INVISIBILITY] = true;
1702 isTriggerAura[SPELL_AURA_FORCE_REACTION] = true;
1703 isTriggerAura[SPELL_AURA_MOD_TAUNT] = true;
1704 isTriggerAura[SPELL_AURA_MOD_DETAUNT] = true;
1705 isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_DONE] = true;
1706 isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER_PCT] = true;
1707 isTriggerAura[SPELL_AURA_MOD_HIT_CHANCE] = true;
1708 isTriggerAura[SPELL_AURA_MOD_WEAPON_CRIT_PERCENT] = true;
1709 isTriggerAura[SPELL_AURA_MOD_BLOCK_PERCENT] = true;
1710
1711 isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
1712 isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
1713 isAlwaysTriggeredAura[SPELL_AURA_MOD_CONFUSE] = true;
1714 isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true;
1715 isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true;
1716 isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true;
1717 isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true;
1718 isAlwaysTriggeredAura[SPELL_AURA_MOD_INVISIBILITY] = true;
1719
1727
1728 // This generates default procs to retain compatibility with previous proc system
1729 TC_LOG_INFO("server.loading", "Generating spell proc data from SpellMap...");
1730 count = 0;
1731 oldMSTime = getMSTime();
1732
1733 for (SpellInfo const* spellInfo : mSpellInfoMap)
1734 {
1735 if (!spellInfo)
1736 continue;
1737
1738 // Data already present in DB, overwrites default proc
1739 if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
1740 continue;
1741
1742 // Nothing to do if no flags set
1743 if (!spellInfo->ProcFlags)
1744 continue;
1745
1746 bool addTriggerFlag = false;
1747 uint32 procSpellTypeMask = PROC_SPELL_TYPE_NONE;
1748 uint32 nonProcMask = 0;
1749 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1750 {
1751 if (!spellEffectInfo.IsEffect())
1752 continue;
1753
1754 uint32 auraName = spellEffectInfo.ApplyAuraName;
1755 if (!auraName)
1756 continue;
1757
1758 if (!isTriggerAura[auraName])
1759 {
1760 // explicitly disable non proccing auras to avoid losing charges on self proc
1761 nonProcMask |= 1 << spellEffectInfo.EffectIndex;
1762 continue;
1763 }
1764
1765 procSpellTypeMask |= spellTypeMask[auraName];
1766 if (isAlwaysTriggeredAura[auraName])
1767 addTriggerFlag = true;
1768
1769 // many proc auras with taken procFlag mask don't have attribute "can proc with triggered"
1770 // they should proc nevertheless (example mage armor spells with judgement)
1771 if (!addTriggerFlag && (spellInfo->ProcFlags & TAKEN_HIT_PROC_FLAG_MASK) != 0)
1772 {
1773 switch (auraName)
1774 {
1777 addTriggerFlag = true;
1778 break;
1779 default:
1780 break;
1781 }
1782 }
1783 }
1784
1785 if (!procSpellTypeMask)
1786 {
1787 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1788 {
1789 if (spellEffectInfo.IsAura())
1790 {
1791 TC_LOG_ERROR("sql.sql", "Spell Id {} has DBC ProcFlags {}, but it's of non-proc aura type, it probably needs an entry in `spell_proc` table to be handled correctly.", spellInfo->Id, spellInfo->ProcFlags);
1792 break;
1793 }
1794 }
1795
1796 continue;
1797 }
1798
1799 SpellProcEntry procEntry;
1800 procEntry.SchoolMask = 0;
1801 procEntry.ProcFlags = spellInfo->ProcFlags;
1802 procEntry.SpellFamilyName = 0;
1803 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1804 if (spellEffectInfo.IsEffect() && isTriggerAura[spellEffectInfo.ApplyAuraName])
1805 procEntry.SpellFamilyMask |= spellEffectInfo.SpellClassMask;
1806
1807 if (procEntry.SpellFamilyMask)
1808 procEntry.SpellFamilyName = spellInfo->SpellFamilyName;
1809
1810 procEntry.SpellTypeMask = procSpellTypeMask;
1812 procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent
1813
1814 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1815 {
1816 if (!spellEffectInfo.IsAura())
1817 continue;
1818
1819 switch (spellEffectInfo.ApplyAuraName)
1820 {
1821 // Reflect auras should only proc off reflects
1824 procEntry.HitMask = PROC_HIT_REFLECT;
1825 break;
1826 // Only drop charge on crit
1828 procEntry.HitMask = PROC_HIT_CRITICAL;
1829 break;
1830 // Only drop charge on block
1832 procEntry.HitMask = PROC_HIT_BLOCK;
1833 break;
1834 // proc auras with another aura reducing hit chance (eg 63767) only proc on missed attack
1836 if (spellEffectInfo.CalcValue() <= -100)
1837 procEntry.HitMask = PROC_HIT_MISS;
1838 break;
1839 default:
1840 continue;
1841 }
1842 break;
1843 }
1844
1845 procEntry.AttributesMask = 0;
1846 procEntry.DisableEffectsMask = nonProcMask;
1847 if (spellInfo->ProcFlags & PROC_FLAG_KILL)
1849 if (addTriggerFlag)
1851
1852 procEntry.ProcsPerMinute = 0;
1853 procEntry.Chance = spellInfo->ProcChance;
1854 procEntry.Cooldown = Milliseconds::zero();
1855 procEntry.Charges = spellInfo->ProcCharges;
1856
1857 mSpellProcMap[spellInfo->Id] = procEntry;
1858 ++count;
1859 }
1860
1861 TC_LOG_INFO("server.loading", ">> Generated spell proc data for {} spells in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1862}
1863
1865{
1866 uint32 oldMSTime = getMSTime();
1867
1868 mSpellBonusMap.clear(); // need for reload case
1869
1870 // 0 1 2 3 4
1871 QueryResult result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus, ap_dot_bonus FROM spell_bonus_data");
1872 if (!result)
1873 {
1874 TC_LOG_INFO("server.loading", ">> Loaded 0 spell bonus data. DB table `spell_bonus_data` is empty.");
1875 return;
1876 }
1877
1878 uint32 count = 0;
1879 do
1880 {
1881 Field* fields = result->Fetch();
1882 uint32 entry = fields[0].GetUInt32();
1883
1884 SpellInfo const* spell = GetSpellInfo(entry);
1885 if (!spell)
1886 {
1887 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_bonus_data` does not exist.", entry);
1888 continue;
1889 }
1890
1891 SpellBonusEntry& sbe = mSpellBonusMap[entry];
1892 sbe.direct_damage = fields[1].GetFloat();
1893 sbe.dot_damage = fields[2].GetFloat();
1894 sbe.ap_bonus = fields[3].GetFloat();
1895 sbe.ap_dot_bonus = fields[4].GetFloat();
1896
1897 ++count;
1898 } while (result->NextRow());
1899
1900 TC_LOG_INFO("server.loading", ">> Loaded {} extra spell bonus data 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))
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 // Don't autolearn secondary variant of Seal of Righteousness - it is learned together with Judgement of Light
1961 if (SkillLineAbilityEntry* sealOfRighteousnessR2 = const_cast<SkillLineAbilityEntry*>(sSkillLineAbilityStore.LookupEntry(11957)))
1962 sealOfRighteousnessR2->AcquireMethod = 0;
1963
1964 TC_LOG_INFO("server.loading", ">> Loaded {} SkillLineAbility MultiMap Data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1965}
1966
1968{
1969 uint32 oldMSTime = getMSTime();
1970
1971 mSpellPetAuraMap.clear(); // need for reload case
1972
1973 // 0 1 2 3
1974 QueryResult result = WorldDatabase.Query("SELECT spell, effectId, pet, aura FROM spell_pet_auras");
1975 if (!result)
1976 {
1977 TC_LOG_INFO("server.loading", ">> Loaded 0 spell pet auras. DB table `spell_pet_auras` is empty.");
1978 return;
1979 }
1980
1981 uint32 count = 0;
1982 do
1983 {
1984 Field* fields = result->Fetch();
1985
1986 uint32 spell = fields[0].GetUInt32();
1987 SpellEffIndex eff = SpellEffIndex(fields[1].GetUInt8());
1988 uint32 pet = fields[2].GetUInt32();
1989 uint32 aura = fields[3].GetUInt32();
1990
1991 SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find((spell << 8) + eff);
1992 if (itr != mSpellPetAuraMap.end())
1993 itr->second.AddAura(pet, aura);
1994 else
1995 {
1996 SpellInfo const* spellInfo = GetSpellInfo(spell);
1997 if (!spellInfo)
1998 {
1999 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_pet_auras` does not exist.", spell);
2000 continue;
2001 }
2002 if (spellInfo->GetEffect(eff).Effect != SPELL_EFFECT_DUMMY &&
2003 (spellInfo->GetEffect(eff).Effect != SPELL_EFFECT_APPLY_AURA ||
2004 spellInfo->GetEffect(eff).ApplyAuraName != SPELL_AURA_DUMMY))
2005 {
2006 TC_LOG_ERROR("spells", "The spell {} listed in `spell_pet_auras` does not have any dummy aura or dummy effect.", spell);
2007 continue;
2008 }
2009
2010 SpellInfo const* spellInfo2 = GetSpellInfo(aura);
2011 if (!spellInfo2)
2012 {
2013 TC_LOG_ERROR("sql.sql", "The aura {} listed in `spell_pet_auras` does not exist.", aura);
2014 continue;
2015 }
2016
2017 PetAura pa(pet, aura, spellInfo->GetEffect(eff).TargetA.GetTarget() == TARGET_UNIT_PET, spellInfo->GetEffect(eff).CalcValue());
2018 mSpellPetAuraMap[(spell<<8) + eff] = pa;
2019 }
2020
2021 ++count;
2022 } while (result->NextRow());
2023
2024 TC_LOG_INFO("server.loading", ">> Loaded {} spell pet auras in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2025}
2026
2027// Fill custom data about enchancments
2029{
2030 uint32 oldMSTime = getMSTime();
2031
2032 uint32 size = sSpellItemEnchantmentStore.GetNumRows();
2033 mEnchantCustomAttr.resize(size, false);
2034
2035 uint32 count = 0;
2036 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2037 {
2038 SpellInfo const* spellInfo = GetSpellInfo(i);
2039 if (!spellInfo)
2040 continue;
2041
2044 continue;
2045
2046 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2047 {
2048 if (spellEffectInfo.Effect == SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY)
2049 {
2050 uint32 enchId = spellEffectInfo.MiscValue;
2051 SpellItemEnchantmentEntry const* ench = sSpellItemEnchantmentStore.LookupEntry(enchId);
2052 if (!ench)
2053 continue;
2054 mEnchantCustomAttr[enchId] = true;
2055 ++count;
2056 break;
2057 }
2058 }
2059 }
2060
2061 TC_LOG_INFO("server.loading", ">> Loaded {} custom enchant attributes in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2062}
2063
2065{
2066 uint32 oldMSTime = getMSTime();
2067
2068 mSpellEnchantProcEventMap.clear(); // need for reload case
2069
2070 // 0 1 2 3 4
2071 QueryResult result = WorldDatabase.Query("SELECT EnchantID, Chance, ProcsPerMinute, HitMask, AttributesMask FROM spell_enchant_proc_data");
2072 if (!result)
2073 {
2074 TC_LOG_INFO("server.loading", ">> Loaded 0 spell enchant proc event conditions. DB table `spell_enchant_proc_data` is empty.");
2075 return;
2076 }
2077
2078 uint32 count = 0;
2079 do
2080 {
2081 Field* fields = result->Fetch();
2082
2083 uint32 enchantId = fields[0].GetUInt32();
2084
2085 SpellItemEnchantmentEntry const* ench = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2086 if (!ench)
2087 {
2088 TC_LOG_ERROR("sql.sql", "The enchancment {} listed in `spell_enchant_proc_data` does not exist.", enchantId);
2089 continue;
2090 }
2091
2093 spe.Chance = fields[1].GetFloat();
2094 spe.ProcsPerMinute = fields[2].GetFloat();
2095 spe.HitMask = fields[3].GetUInt32();
2096 spe.AttributesMask = fields[4].GetUInt32();
2097
2098 mSpellEnchantProcEventMap[enchantId] = spe;
2099
2100 ++count;
2101 } while (result->NextRow());
2102
2103 TC_LOG_INFO("server.loading", ">> Loaded {} enchant proc data definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2104}
2105
2107{
2108 uint32 oldMSTime = getMSTime();
2109
2110 mSpellLinkedMap.clear(); // need for reload case
2111
2112 // 0 1 2
2113 QueryResult result = WorldDatabase.Query("SELECT spell_trigger, spell_effect, type FROM spell_linked_spell");
2114 if (!result)
2115 {
2116 TC_LOG_INFO("server.loading", ">> Loaded 0 linked spells. DB table `spell_linked_spell` is empty.");
2117 return;
2118 }
2119
2120 uint32 count = 0;
2121 do
2122 {
2123 Field* fields = result->Fetch();
2124
2125 int32 trigger = fields[0].GetInt32();
2126 int32 effect = fields[1].GetInt32();
2127 int32 type = fields[2].GetUInt8();
2128
2129 SpellInfo const* spellInfo = GetSpellInfo(abs(trigger));
2130 if (!spellInfo)
2131 {
2132 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_linked_spell` does not exist.", abs(trigger));
2133 continue;
2134 }
2135
2136 if (effect >= 0)
2137 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2138 {
2139 if (spellEffectInfo.CalcValue() == abs(effect))
2140 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));
2141 }
2142
2143 spellInfo = GetSpellInfo(abs(effect));
2144 if (!spellInfo)
2145 {
2146 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_linked_spell` does not exist.", abs(effect));
2147 continue;
2148 }
2149
2150 if (type) //we will find a better way when more types are needed
2151 {
2152 if (trigger > 0)
2153 trigger += SPELL_LINKED_MAX_SPELLS * type;
2154 else
2155 trigger -= SPELL_LINKED_MAX_SPELLS * type;
2156 }
2157 mSpellLinkedMap[trigger].push_back(effect);
2158
2159 ++count;
2160 } while (result->NextRow());
2161
2162 TC_LOG_INFO("server.loading", ">> Loaded {} linked spells in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2163}
2164
2166{
2167 uint32 oldMSTime = getMSTime();
2168
2169 mPetLevelupSpellMap.clear(); // need for reload case
2170
2171 uint32 count = 0;
2172 uint32 family_count = 0;
2173
2174 for (uint32 i = 0; i < sCreatureFamilyStore.GetNumRows(); ++i)
2175 {
2176 CreatureFamilyEntry const* creatureFamily = sCreatureFamilyStore.LookupEntry(i);
2177 if (!creatureFamily) // not exist
2178 continue;
2179
2180 for (uint8 j = 0; j < 2; ++j)
2181 {
2182 if (!creatureFamily->SkillLine[j])
2183 continue;
2184
2185 std::vector<SkillLineAbilityEntry const*> const* skillLineAbilities = GetSkillLineAbilitiesBySkill(creatureFamily->SkillLine[j]);
2186 if (!skillLineAbilities)
2187 continue;
2188
2189 for (SkillLineAbilityEntry const* skillLine : *skillLineAbilities)
2190 {
2191 if (skillLine->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN)
2192 continue;
2193
2194 SpellInfo const* spell = GetSpellInfo(skillLine->Spell);
2195 if (!spell) // not exist or triggered or talent
2196 continue;
2197
2198 if (!spell->SpellLevel)
2199 continue;
2200
2201 PetLevelupSpellSet& spellSet = mPetLevelupSpellMap[creatureFamily->ID];
2202 if (spellSet.empty())
2203 ++family_count;
2204
2205 spellSet.insert(PetLevelupSpellSet::value_type(spell->SpellLevel, spell->Id));
2206 ++count;
2207 }
2208 }
2209 }
2210
2211 TC_LOG_INFO("server.loading", ">> Loaded {} pet levelup and default spells for {} families in {} ms", count, family_count, GetMSTimeDiffToNow(oldMSTime));
2212}
2213
2215{
2216 // skip empty list;
2217 bool have_spell = false;
2218 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2219 {
2220 if (petDefSpells.spellid[j])
2221 {
2222 have_spell = true;
2223 break;
2224 }
2225 }
2226 if (!have_spell)
2227 return false;
2228
2229 // remove duplicates with levelupSpells if any
2230 if (PetLevelupSpellSet const* levelupSpells = cInfo->family ? sSpellMgr->GetPetLevelupSpellList(cInfo->family) : nullptr)
2231 {
2232 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2233 {
2234 if (!petDefSpells.spellid[j])
2235 continue;
2236
2237 for (PetLevelupSpellSet::const_iterator itr = levelupSpells->begin(); itr != levelupSpells->end(); ++itr)
2238 {
2239 if (itr->second == petDefSpells.spellid[j])
2240 {
2241 petDefSpells.spellid[j] = 0;
2242 break;
2243 }
2244 }
2245 }
2246 }
2247
2248 // skip empty list;
2249 have_spell = false;
2250 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2251 {
2252 if (petDefSpells.spellid[j])
2253 {
2254 have_spell = true;
2255 break;
2256 }
2257 }
2258
2259 return have_spell;
2260}
2261
2263{
2264 uint32 oldMSTime = getMSTime();
2265
2266 mPetDefaultSpellsMap.clear();
2267
2268 uint32 countCreature = 0;
2269 uint32 countData = 0;
2270
2271 CreatureTemplateContainer const& ctc = sObjectMgr->GetCreatureTemplates();
2272 for (auto const& creatureTemplatePair : ctc)
2273 {
2274 if (!creatureTemplatePair.second.PetSpellDataId)
2275 continue;
2276
2277 // for creature with PetSpellDataId get default pet spells from dbc
2278 CreatureSpellDataEntry const* spellDataEntry = sCreatureSpellDataStore.LookupEntry(creatureTemplatePair.second.PetSpellDataId);
2279 if (!spellDataEntry)
2280 continue;
2281
2282 int32 petSpellsId = -int32(creatureTemplatePair.second.PetSpellDataId);
2283 PetDefaultSpellsEntry petDefSpells;
2284 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2285 petDefSpells.spellid[j] = spellDataEntry->Spells[j];
2286
2287 if (LoadPetDefaultSpells_helper(&creatureTemplatePair.second, petDefSpells))
2288 {
2289 mPetDefaultSpellsMap[petSpellsId] = petDefSpells;
2290 ++countData;
2291 }
2292 }
2293
2294 TC_LOG_INFO("server.loading", ">> Loaded addition spells for {} pet spell data entries in {} ms", countData, GetMSTimeDiffToNow(oldMSTime));
2295
2296 TC_LOG_INFO("server.loading", "Loading summonable creature templates...");
2297 oldMSTime = getMSTime();
2298
2299 // different summon spells
2300 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2301 {
2302 SpellInfo const* spellEntry = GetSpellInfo(i);
2303 if (!spellEntry)
2304 continue;
2305
2306 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
2307 {
2308 if (spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON) || spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON_PET))
2309 {
2310 uint32 creature_id = spellEffectInfo.MiscValue;
2311 CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(creature_id);
2312 if (!cInfo)
2313 continue;
2314
2315 // already loaded
2316 if (cInfo->PetSpellDataId)
2317 continue;
2318
2319 // for creature without PetSpellDataId get default pet spells from creature_template
2320 int32 petSpellsId = cInfo->Entry;
2321 if (mPetDefaultSpellsMap.find(cInfo->Entry) != mPetDefaultSpellsMap.end())
2322 continue;
2323
2324 PetDefaultSpellsEntry petDefSpells;
2325 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2326 petDefSpells.spellid[j] = cInfo->spells[j];
2327
2328 if (LoadPetDefaultSpells_helper(cInfo, petDefSpells))
2329 {
2330 mPetDefaultSpellsMap[petSpellsId] = petDefSpells;
2331 ++countCreature;
2332 }
2333 }
2334 }
2335 }
2336
2337 TC_LOG_INFO("server.loading", ">> Loaded {} summonable creature templates in {} ms", countCreature, GetMSTimeDiffToNow(oldMSTime));
2338}
2339
2341{
2342 uint32 oldMSTime = getMSTime();
2343
2344 mSpellAreaMap.clear(); // need for reload case
2345 mSpellAreaForAreaMap.clear();
2346 mSpellAreaForQuestMap.clear();
2348 mSpellAreaForAuraMap.clear();
2349
2350 // 0 1 2 3 4 5 6 7 8 9
2351 QueryResult result = WorldDatabase.Query("SELECT spell, area, quest_start, quest_start_status, quest_end_status, quest_end, aura_spell, racemask, gender, autocast FROM spell_area");
2352 if (!result)
2353 {
2354 TC_LOG_INFO("server.loading", ">> Loaded 0 spell area requirements. DB table `spell_area` is empty.");
2355
2356 return;
2357 }
2358
2359 uint32 count = 0;
2360 do
2361 {
2362 Field* fields = result->Fetch();
2363
2364 uint32 spell = fields[0].GetUInt32();
2365 SpellArea spellArea;
2366 spellArea.spellId = spell;
2367 spellArea.areaId = fields[1].GetUInt32();
2368 spellArea.questStart = fields[2].GetUInt32();
2369 spellArea.questStartStatus = fields[3].GetUInt32();
2370 spellArea.questEndStatus = fields[4].GetUInt32();
2371 spellArea.questEnd = fields[5].GetUInt32();
2372 spellArea.auraSpell = fields[6].GetInt32();
2373 spellArea.raceMask = fields[7].GetUInt32();
2374 spellArea.gender = Gender(fields[8].GetUInt8());
2375 spellArea.autocast = fields[9].GetBool();
2376
2377 if (SpellInfo const* spellInfo = GetSpellInfo(spell))
2378 {
2379 if (spellArea.autocast)
2380 const_cast<SpellInfo*>(spellInfo)->Attributes |= SPELL_ATTR0_CANT_CANCEL;
2381 }
2382 else
2383 {
2384 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` does not exist", spell);
2385 continue;
2386 }
2387
2388 {
2389 bool ok = true;
2390 SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds(spellArea.spellId);
2391 for (SpellAreaMap::const_iterator itr = sa_bounds.first; itr != sa_bounds.second; ++itr)
2392 {
2393 if (spellArea.spellId != itr->second.spellId)
2394 continue;
2395 if (spellArea.areaId != itr->second.areaId)
2396 continue;
2397 if (spellArea.questStart != itr->second.questStart)
2398 continue;
2399 if (spellArea.auraSpell != itr->second.auraSpell)
2400 continue;
2401 if ((spellArea.raceMask & itr->second.raceMask) == 0)
2402 continue;
2403 if (spellArea.gender != itr->second.gender)
2404 continue;
2405
2406 // duplicate by requirements
2407 ok = false;
2408 break;
2409 }
2410
2411 if (!ok)
2412 {
2413 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` is already listed with similar requirements.", spell);
2414 continue;
2415 }
2416 }
2417
2418 if (spellArea.areaId && !sAreaTableStore.LookupEntry(spellArea.areaId))
2419 {
2420 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has a wrong area ({}) requirement.", spell, spellArea.areaId);
2421 continue;
2422 }
2423
2424 if (spellArea.questStart && !sObjectMgr->GetQuestTemplate(spellArea.questStart))
2425 {
2426 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has a wrong start quest ({}) requirement.", spell, spellArea.questStart);
2427 continue;
2428 }
2429
2430 if (spellArea.questEnd)
2431 {
2432 if (!sObjectMgr->GetQuestTemplate(spellArea.questEnd))
2433 {
2434 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has a wrong ending quest ({}) requirement.", spell, spellArea.questEnd);
2435 continue;
2436 }
2437 }
2438
2439 if (spellArea.auraSpell)
2440 {
2441 SpellInfo const* spellInfo = GetSpellInfo(abs(spellArea.auraSpell));
2442 if (!spellInfo)
2443 {
2444 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has wrong aura spell ({}) requirement", spell, abs(spellArea.auraSpell));
2445 continue;
2446 }
2447
2448 if (uint32(abs(spellArea.auraSpell)) == spellArea.spellId)
2449 {
2450 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has aura spell ({}) requirement for itself", spell, abs(spellArea.auraSpell));
2451 continue;
2452 }
2453
2454 // not allow autocast chains by auraSpell field (but allow use as alternative if not present)
2455 if (spellArea.autocast && spellArea.auraSpell > 0)
2456 {
2457 bool chain = false;
2459 for (SpellAreaForAuraMap::const_iterator itr = saBound.first; itr != saBound.second; ++itr)
2460 {
2461 if (itr->second->autocast && itr->second->auraSpell > 0)
2462 {
2463 chain = true;
2464 break;
2465 }
2466 }
2467
2468 if (chain)
2469 {
2470 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);
2471 continue;
2472 }
2473
2475 for (SpellAreaMap::const_iterator itr2 = saBound2.first; itr2 != saBound2.second; ++itr2)
2476 {
2477 if (itr2->second.autocast && itr2->second.auraSpell > 0)
2478 {
2479 chain = true;
2480 break;
2481 }
2482 }
2483
2484 if (chain)
2485 {
2486 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);
2487 continue;
2488 }
2489 }
2490 }
2491
2492 if (spellArea.raceMask && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE) == 0)
2493 {
2494 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has wrong race mask ({}) requirement.", spell, spellArea.raceMask);
2495 continue;
2496 }
2497
2498 if (spellArea.gender != GENDER_NONE && spellArea.gender != GENDER_FEMALE && spellArea.gender != GENDER_MALE)
2499 {
2500 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has wrong gender ({}) requirement.", spell, spellArea.gender);
2501 continue;
2502 }
2503
2504 SpellArea const* sa = &mSpellAreaMap.insert(SpellAreaMap::value_type(spell, spellArea))->second;
2505
2506 // for search by current zone/subzone at zone/subzone change
2507 if (spellArea.areaId)
2508 mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(spellArea.areaId, sa));
2509
2510 // for search at quest update checks
2511 if (spellArea.questStart || spellArea.questEnd)
2512 {
2513 if (spellArea.questStart == spellArea.questEnd)
2514 mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa));
2515 else
2516 {
2517 if (spellArea.questStart)
2518 mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa));
2519 if (spellArea.questEnd)
2520 mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd, sa));
2521 }
2522 }
2523
2524 // for search at quest start/reward
2525 if (spellArea.questEnd)
2526 mSpellAreaForQuestEndMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd, sa));
2527
2528 // for search at aura apply
2529 if (spellArea.auraSpell)
2530 mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(abs(spellArea.auraSpell), sa));
2531
2532 ++count;
2533 } while (result->NextRow());
2534
2535 TC_LOG_INFO("server.loading", ">> Loaded {} spell area requirements in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2536}
2537
2539{
2540 uint32 oldMSTime = getMSTime();
2541
2543 mSpellInfoMap.resize(sSpellStore.GetNumRows(), nullptr);
2544
2545 for (SpellEntry const* spellEntry : sSpellStore)
2546 mSpellInfoMap[spellEntry->ID] = new SpellInfo(spellEntry);
2547
2548 for (uint32 spellIndex = 0; spellIndex < GetSpellInfoStoreSize(); ++spellIndex)
2549 {
2550 if (!mSpellInfoMap[spellIndex])
2551 continue;
2552
2553 for (SpellEffectInfo const& spellEffectInfo : mSpellInfoMap[spellIndex]->GetEffects())
2554 {
2555 //ASSERT(effect.EffectIndex < MAX_SPELL_EFFECTS, "MAX_SPELL_EFFECTS must be at least %u", effect.EffectIndex + 1);
2556 ASSERT(spellEffectInfo.Effect < TOTAL_SPELL_EFFECTS, "TOTAL_SPELL_EFFECTS must be at least %u", spellEffectInfo.Effect + 1);
2557 ASSERT(spellEffectInfo.ApplyAuraName < TOTAL_AURAS, "TOTAL_AURAS must be at least %u", spellEffectInfo.ApplyAuraName + 1);
2558 ASSERT(spellEffectInfo.TargetA.GetTarget() < TOTAL_SPELL_TARGETS, "TOTAL_SPELL_TARGETS must be at least %u", spellEffectInfo.TargetA.GetTarget() + 1);
2559 ASSERT(spellEffectInfo.TargetB.GetTarget() < TOTAL_SPELL_TARGETS, "TOTAL_SPELL_TARGETS must be at least %u", spellEffectInfo.TargetB.GetTarget() + 1);
2560 }
2561 }
2562
2563 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo store in {} ms", GetMSTimeDiffToNow(oldMSTime));
2564}
2565
2567{
2568 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2569 delete mSpellInfoMap[i];
2570
2571 mSpellInfoMap.clear();
2572}
2573
2575{
2576 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2577 if (mSpellInfoMap[i])
2578 mSpellInfoMap[i]->_UnloadImplicitTargetConditionLists();
2579}
2580
2582{
2583 uint32 oldMSTime = getMSTime();
2584 uint32 oldMSTime2 = oldMSTime;
2585
2586 QueryResult result = WorldDatabase.Query("SELECT entry, attributes FROM spell_custom_attr");
2587
2588 if (!result)
2589 TC_LOG_INFO("server.loading", ">> Loaded 0 spell custom attributes from DB. DB table `spell_custom_attr` is empty.");
2590 else
2591 {
2592 uint32 count = 0;
2593 do
2594 {
2595 Field* fields = result->Fetch();
2596
2597 uint32 spellId = fields[0].GetUInt32();
2598 uint32 attributes = fields[1].GetUInt32();
2599
2600 SpellInfo* spellInfo = _GetSpellInfo(spellId);
2601 if (!spellInfo)
2602 {
2603 TC_LOG_ERROR("sql.sql", "Table `spell_custom_attr` has wrong spell (entry: {}), ignored.", spellId);
2604 continue;
2605 }
2606
2607 if ((attributes & SPELL_ATTR0_CU_NEGATIVE) != 0)
2608 {
2609 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2610 {
2611 if (spellEffectInfo.IsEffect())
2612 continue;
2613
2614 if ((attributes & (SPELL_ATTR0_CU_NEGATIVE_EFF0 << spellEffectInfo.EffectIndex)) != 0)
2615 {
2616 TC_LOG_ERROR("sql.sql", "Table `spell_custom_attr` has attribute SPELL_ATTR0_CU_NEGATIVE_EFF{} for spell {} with no EFFECT_{}", uint32(spellEffectInfo.EffectIndex), spellId, uint32(spellEffectInfo.EffectIndex));
2617 continue;
2618 }
2619 }
2620 }
2621
2622 spellInfo->AttributesCu |= attributes;
2623 ++count;
2624 } while (result->NextRow());
2625
2626 TC_LOG_INFO("server.loading", ">> Loaded {} spell custom attributes from DB in {} ms", count, GetMSTimeDiffToNow(oldMSTime2));
2627 }
2628
2629 for (SpellInfo* spellInfo : mSpellInfoMap)
2630 {
2631 if (!spellInfo)
2632 continue;
2633
2634 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2635 {
2636 // all bleed effects and spells ignore armor
2637 if (spellInfo->GetEffectMechanicMask(spellEffectInfo.EffectIndex) & (1 << MECHANIC_BLEED))
2638 spellInfo->AttributesCu |= SPELL_ATTR0_CU_IGNORE_ARMOR;
2639
2640 switch (spellEffectInfo.ApplyAuraName)
2641 {
2648 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
2649 break;
2650 default:
2651 break;
2652 }
2653
2654 switch (spellEffectInfo.ApplyAuraName)
2655 {
2656 case SPELL_AURA_CONVERT_RUNE: // Can't be saved - aura handler relies on calculated amount and changes it
2657 case SPELL_AURA_OPEN_STABLE: // No point in saving this, since the stable dialog can't be open on aura load anyway.
2658 // Auras that require both caster & target to be in world cannot be saved
2665 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CANNOT_BE_SAVED;
2666 break;
2667 default:
2668 break;
2669 }
2670
2671 switch (spellEffectInfo.Effect)
2672 {
2675 case SPELL_EFFECT_HEAL:
2683 spellInfo->AttributesCu |= SPELL_ATTR0_CU_CAN_CRIT;
2684 break;
2685 default:
2686 break;
2687 }
2688
2689 switch (spellEffectInfo.Effect)
2690 {
2696 case SPELL_EFFECT_HEAL:
2697 spellInfo->AttributesCu |= SPELL_ATTR0_CU_DIRECT_DAMAGE;
2698 break;
2707 spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
2708 break;
2711 case SPELL_EFFECT_JUMP:
2714 spellInfo->AttributesCu |= SPELL_ATTR0_CU_CHARGE;
2715 break;
2717 spellInfo->AttributesCu |= SPELL_ATTR0_CU_PICKPOCKET;
2718 break;
2723 {
2724 // only enchanting profession enchantments procs can stack
2725 if (IsPartOfSkillLine(SKILL_ENCHANTING, spellInfo->Id))
2726 {
2727 uint32 enchantId = spellEffectInfo.MiscValue;
2728 SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2729 if (!enchant)
2730 break;
2731
2732 for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
2733 {
2734 if (enchant->Effect[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
2735 continue;
2736
2737 SpellInfo* procInfo = _GetSpellInfo(enchant->EffectArg[s]);
2738 if (!procInfo)
2739 continue;
2740
2741 // if proced directly from enchantment, not via proc aura
2742 // NOTE: Enchant Weapon - Blade Ward also has proc aura spell and is proced directly
2743 // however its not expected to stack so this check is good
2745 continue;
2746
2748 }
2749 }
2750 break;
2751 }
2752 default:
2753 break;
2754 }
2755 }
2756
2757 // spells ignoring hit result should not be binary
2758 if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
2759 {
2760 bool setFlag = false;
2761 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2762 {
2763 if (spellEffectInfo.IsEffect())
2764 {
2765 switch (spellEffectInfo.Effect)
2766 {
2774 break;
2783 {
2784 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE ||
2785 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE_PERCENT ||
2786 spellEffectInfo.ApplyAuraName == SPELL_AURA_DUMMY ||
2787 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_LEECH ||
2788 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_HEALTH_FUNNEL ||
2789 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_DUMMY)
2790 break;
2791 [[fallthrough]];
2792 }
2793 default:
2794 {
2795 // No value and not interrupt cast or crowd control without SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY flag
2796 if (!spellEffectInfo.CalcValue() && !((spellEffectInfo.Effect == SPELL_EFFECT_INTERRUPT_CAST || spellInfo->HasAttribute(SPELL_ATTR0_CU_AURA_CC)) && !spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)))
2797 break;
2798
2799 // Sindragosa Frost Breath
2800 if (spellInfo->Id == 69649 || spellInfo->Id == 71056 || spellInfo->Id == 71057 || spellInfo->Id == 71058 || spellInfo->Id == 73061 || spellInfo->Id == 73062 || spellInfo->Id == 73063 || spellInfo->Id == 73064)
2801 break;
2802
2803 // Frostbolt
2804 if (spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfo->SpellFamilyFlags[0] & 0x20))
2805 break;
2806
2807 // Frost Fever
2808 if (spellInfo->Id == 55095)
2809 break;
2810
2811 // Haunt
2812 if (spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && (spellInfo->SpellFamilyFlags[1] & 0x40000))
2813 break;
2814
2815 setFlag = true;
2816 break;
2817 }
2818 }
2819
2820 if (setFlag)
2821 {
2822 spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY_SPELL;
2823 break;
2824 }
2825 }
2826 }
2827 }
2828
2829 // Remove normal school mask to properly calculate damage
2830 if ((spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) && (spellInfo->SchoolMask & SPELL_SCHOOL_MASK_MAGIC))
2831 {
2832 spellInfo->SchoolMask &= ~SPELL_SCHOOL_MASK_NORMAL;
2833 spellInfo->AttributesCu |= SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC;
2834 }
2835
2836 spellInfo->_InitializeSpellPositivity();
2837
2838 if (spellInfo->SpellVisual[0] == 3879)
2839 spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_BACK;
2840
2841 switch (spellInfo->SpellFamilyName)
2842 {
2844 // Shout / Piercing Howl
2845 if (spellInfo->SpellFamilyFlags[0] & 0x20000/* || spellInfo->SpellFamilyFlags[1] & 0x20*/)
2846 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
2847 break;
2848 case SPELLFAMILY_DRUID:
2849 // Roar
2850 if (spellInfo->SpellFamilyFlags[0] & 0x8)
2851 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
2852 break;
2854 // Stoneclaw Totem effect
2855 if (spellInfo->Id == 5729)
2856 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
2857 break;
2858 default:
2859 break;
2860 }
2861
2862 spellInfo->_InitializeExplicitTargetMask();
2863
2864 if (spellInfo->Speed > 0.0f)
2865 if (SpellVisualEntry const* spellVisual = sSpellVisualStore.LookupEntry(spellInfo->SpellVisual[0]))
2866 if (spellVisual->HasMissile)
2867 if (spellVisual->MissileModel == -4 || spellVisual->MissileModel == -5)
2868 spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEEDS_AMMO_DATA;
2869
2870 }
2871
2872 // addition for binary spells, omit spells triggering other spells
2873 for (SpellInfo* spellInfo : mSpellInfoMap)
2874 {
2875 if (!spellInfo)
2876 continue;
2877
2878 if (spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
2879 continue;
2880
2881 bool allNonBinary = true;
2882 bool overrideAttr = false;
2883 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2884 {
2885 if (spellEffectInfo.IsAura() && spellEffectInfo.TriggerSpell)
2886 {
2887 switch (spellEffectInfo.ApplyAuraName)
2888 {
2892 if (SpellInfo const* triggerSpell = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell))
2893 {
2894 overrideAttr = true;
2895 if (triggerSpell->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
2896 allNonBinary = false;
2897 }
2898 break;
2899 default:
2900 break;
2901 }
2902 }
2903 }
2904
2905 if (overrideAttr && allNonBinary)
2906 spellInfo->AttributesCu &= ~SPELL_ATTR0_CU_BINARY_SPELL;
2907 }
2908
2909 // remove attribute from spells that can't crit
2910 for (SpellInfo* spellInfo : mSpellInfoMap)
2911 {
2912 if (!spellInfo)
2913 continue;
2914
2915 if (spellInfo->HasAttribute(SPELL_ATTR2_CANT_CRIT))
2916 spellInfo->AttributesCu &= ~SPELL_ATTR0_CU_CAN_CRIT;
2917 }
2918
2919 // add custom attribute to liquid auras
2920 for (LiquidTypeEntry const* liquid : sLiquidTypeStore)
2921 {
2922 if (uint32 spellId = liquid->SpellID)
2923 if (SpellInfo* spellInfo = _GetSpellInfo(spellId))
2924 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CANNOT_BE_SAVED;
2925 }
2926
2927 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo custom attributes in {} ms", GetMSTimeDiffToNow(oldMSTime));
2928}
2929
2930inline void ApplySpellFix(std::initializer_list<uint32> spellIds, void(*fix)(SpellInfo*))
2931{
2932 for (uint32 spellId : spellIds)
2933 {
2934 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
2935 if (!spellInfo)
2936 {
2937 TC_LOG_ERROR("server.loading", "Spell info correction specified for non-existing spell {}", spellId);
2938 continue;
2939 }
2940
2941 fix(const_cast<SpellInfo*>(spellInfo));
2942 }
2943}
2944
2946{
2947 uint32 oldMSTime = getMSTime();
2948
2949 // Some spells have no amplitude set
2950 {
2952 6727, // Poison Mushroom
2953 7288, // Immolate Cumulative (TEST) (Rank 1)
2954 7291, // Food (TEST)
2955 7331, // Healing Aura (TEST) (Rank 1)
2956 /*
2957 30400, // Nether Beam - Perseverance
2958 Blizzlike to have it disabled? DBC says:
2959 "This is currently turned off to increase performance. Enable this to make it fire more frequently."
2960 */
2961 34589, // Dangerous Water
2962 52562, // Arthas Zombie Catcher
2963 57550, // Tirion Aggro
2964 65755
2965 }, [](SpellInfo* spellInfo)
2966 {
2967 spellInfo->_GetEffect(EFFECT_0).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2968 });
2969
2971 24707, // Food
2972 26263, // Dim Sum
2973 29055, // Refreshing Red Apple
2974 37504 // Karazhan - Chess NPC AI, action timer
2975 }, [](SpellInfo* spellInfo)
2976 {
2977 // first effect has correct amplitude
2978 spellInfo->_GetEffect(EFFECT_1).ApplyAuraPeriod = spellInfo->GetEffect(EFFECT_0).ApplyAuraPeriod;
2979 });
2980
2981 // Vomit
2982 ApplySpellFix({ 43327 }, [](SpellInfo* spellInfo)
2983 {
2984 spellInfo->_GetEffect(EFFECT_1).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2985 });
2986
2987 // Strider Presence
2988 ApplySpellFix({ 4312 }, [](SpellInfo* spellInfo)
2989 {
2990 spellInfo->_GetEffect(EFFECT_0).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2991 spellInfo->_GetEffect(EFFECT_1).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2992 });
2993
2994 // Food
2995 ApplySpellFix({ 64345 }, [](SpellInfo* spellInfo)
2996 {
2997 spellInfo->_GetEffect(EFFECT_0).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2998 spellInfo->_GetEffect(EFFECT_2).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2999 });
3000 }
3001
3002 // specific code for cases with no trigger spell provided in field
3003 {
3004 // Brood Affliction: Bronze
3005 ApplySpellFix({ 23170 }, [](SpellInfo* spellInfo)
3006 {
3007 spellInfo->_GetEffect(EFFECT_0).TriggerSpell = 23171;
3008 });
3009
3010 // Feed Captured Animal
3011 ApplySpellFix({ 29917 }, [](SpellInfo* spellInfo)
3012 {
3013 spellInfo->_GetEffect(EFFECT_0).TriggerSpell = 29916;
3014 });
3015
3016 // Eye of Grillok
3017 ApplySpellFix({ 38495 }, [](SpellInfo* spellInfo)
3018 {
3019 spellInfo->_GetEffect(EFFECT_0).TriggerSpell = 38530;
3020 });
3021
3022 // Tear of Azzinoth Summon Channel - it's not really supposed to do anything, and this only prevents the console spam
3023 ApplySpellFix({ 39857 }, [](SpellInfo* spellInfo)
3024 {
3025 spellInfo->_GetEffect(EFFECT_0).TriggerSpell = 39856;
3026 });
3027
3028 // Personalized Weather
3029 ApplySpellFix({ 46736 }, [](SpellInfo* spellInfo)
3030 {
3031 spellInfo->_GetEffect(EFFECT_1).TriggerSpell = 46737;
3032 });
3033 }
3034
3035 // this one is here because we have no SP bonus for dmgclass none spell
3036 // but this one should since it's DBC data
3038 52042, // Healing Stream Totem
3039 }, [](SpellInfo* spellInfo)
3040 {
3041 // We need more spells to find a general way (if there is any)
3042 spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC;
3043 });
3044
3045 // Spell Reflection
3046 ApplySpellFix({ 57643 }, [](SpellInfo* spellInfo)
3047 {
3048 spellInfo->EquippedItemClass = -1;
3049 });
3050
3052 63026, // Force Cast (HACK: Target shouldn't be changed)
3053 63137 // Force Cast (HACK: Target shouldn't be changed; summon position should be untied from spell destination)
3054 }, [](SpellInfo* spellInfo)
3055 {
3056 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
3057 });
3058
3059 // Immolate
3061 348,
3062 707,
3063 1094,
3064 2941,
3065 11665,
3066 11667,
3067 11668,
3068 25309,
3069 27215,
3070 47810,
3071 47811
3072 }, [](SpellInfo* spellInfo)
3073 {
3074 // copy SP scaling data from direct damage to DoT
3075 spellInfo->_GetEffect(EFFECT_0).BonusCoefficient = spellInfo->GetEffect(EFFECT_1).BonusCoefficient;
3076 });
3077
3078 // Detect Undead
3079 ApplySpellFix({ 11389 }, [](SpellInfo* spellInfo)
3080 {
3081 spellInfo->PowerType = POWER_MANA;
3082 spellInfo->ManaCost = 0;
3083 spellInfo->ManaPerSecond = 0;
3084 });
3085
3086 // Drink! (Brewfest)
3087 ApplySpellFix({ 42436 }, [](SpellInfo* spellInfo)
3088 {
3089 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY);
3090 });
3091
3092 // Warsong Gulch Anti-Stall Debuffs
3094 46392, // Focused Assault
3095 46393, // Brutal Assault
3096 }, [](SpellInfo* spellInfo)
3097 {
3098 // due to discrepancies between ranks
3099 spellInfo->Attributes |= SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY;
3100 });
3101
3102 // Summon Skeletons
3103 ApplySpellFix({ 52611, 52612 }, [](SpellInfo* spellInfo)
3104 {
3105 spellInfo->_GetEffect(EFFECT_0).MiscValueB = 64;
3106 });
3107
3108 // Battlegear of Eternal Justice
3110 26135, // Battlegear of Eternal Justice
3111 37557 // Mark of Light
3112 }, [](SpellInfo* spellInfo)
3113 {
3114 spellInfo->SpellFamilyFlags = flag96();
3115 });
3116
3118 40244, // Simon Game Visual
3119 40245, // Simon Game Visual
3120 40246, // Simon Game Visual
3121 40247, // Simon Game Visual
3122 42835 // Spout, remove damage effect, only anim is needed
3123 }, [](SpellInfo* spellInfo)
3124 {
3125 spellInfo->_GetEffect(EFFECT_0).Effect = SPELL_EFFECT_NONE;
3126 });
3127
3129 63665, // Charge (Argent Tournament emote on riders)
3130 51904, // Summon Ghouls On Scarlet Crusade (this should use conditions table, script for this spell needs to be fixed)
3131 2895, // Wrath of Air Totem rank 1 (Aura)
3132 68933, // Wrath of Air Totem rank 2 (Aura)
3133 29200, // Purify Helboar Meat
3134 10872, // Abolish Disease Effect
3135 3137 // Abolish Poison Effect
3136 }, [](SpellInfo* spellInfo)
3137 {
3138 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3139 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo();
3140 });
3141
3143 56690, // Thrust Spear
3144 60586, // Mighty Spear Thrust
3145 60776, // Claw Swipe
3146 60881, // Fatal Strike
3147 60864 // Jaws of Death
3148 }, [](SpellInfo* spellInfo)
3149 {
3150 spellInfo->AttributesEx4 |= SPELL_ATTR4_FIXED_DAMAGE;
3151 });
3152
3153 // Missile Barrage
3154 ApplySpellFix({ 44401 }, [](SpellInfo* spellInfo)
3155 {
3156 // should be consumed before Clearcasting
3157 spellInfo->Priority = 100;
3158 });
3159
3161 42818, // Headless Horseman - Wisp Flight Port
3162 42821, // Headless Horseman - Wisp Flight Missile
3163 17678, // Despawn Spectral Combatants
3164 720, // Entangle
3165 731 // Entangle
3166 }, [](SpellInfo* spellInfo)
3167 {
3168 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100 yards
3169 });
3170
3171 // They Must Burn Bomb Aura (self)
3172 ApplySpellFix({ 36350 }, [](SpellInfo* spellInfo)
3173 {
3174 spellInfo->_GetEffect(EFFECT_0).TriggerSpell = 36325; // They Must Burn Bomb Drop (DND)
3175 });
3176
3178 61407, // Energize Cores
3179 62136, // Energize Cores
3180 54069, // Energize Cores
3181 56251 // Energize Cores
3182 }, [](SpellInfo* spellInfo)
3183 {
3184 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENTRY);
3185 });
3186
3188 50785, // Energize Cores
3189 59372 // Energize Cores
3190 }, [](SpellInfo* spellInfo)
3191 {
3192 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENEMY);
3193 });
3194
3195 // Mana Shield (rank 2)
3196 ApplySpellFix({ 8494 }, [](SpellInfo* spellInfo)
3197 {
3198 // because of bug in dbc
3199 spellInfo->ProcChance = 0;
3200 });
3201
3202 // Maelstrom Weapon
3204 51528, // (Rank 1)
3205 51529, // (Rank 2)
3206 51530, // (Rank 3)
3207 51531, // (Rank 4)
3208 51532 // (Rank 5)
3209 }, [](SpellInfo* spellInfo)
3210 {
3211 // due to discrepancies between ranks
3212 spellInfo->EquippedItemSubClassMask = 0x0000FC33;
3213 spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_FROM_PROCS;
3214 });
3215
3217 20335, // Heart of the Crusader
3218 20336,
3219 20337,
3220 53228, // Rapid Killing (Rank 1)
3221 53232, // Rapid Killing (Rank 2)
3222 63320 // Glyph of Life Tap
3223 }, [](SpellInfo* spellInfo)
3224 {
3225 // Entries were not updated after spell effect change, we have to do that manually :/
3226 spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_FROM_PROCS;
3227 });
3228
3230 51627, // Turn the Tables (Rank 1)
3231 51628, // Turn the Tables (Rank 2)
3232 51629 // Turn the Tables (Rank 3)
3233 }, [](SpellInfo* spellInfo)
3234 {
3235 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
3236 });
3237
3239 52910, // Turn the Tables
3240 52914, // Turn the Tables
3241 52915 // Turn the Tables
3242 }, [](SpellInfo* spellInfo)
3243 {
3244 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3245 });
3246
3247 // Magic Absorption
3249 29441, // (Rank 1)
3250 29444 // (Rank 2)
3251 }, [](SpellInfo* spellInfo)
3252 {
3253 // Caused off by 1 calculation (ie 79 resistance at level 80)
3254 spellInfo->SpellLevel = 0;
3255 });
3256
3257 // Execute
3259 5308, // (Rank 1)
3260 20658, // (Rank 2)
3261 20660, // (Rank 3)
3262 20661, // (Rank 4)
3263 20662, // (Rank 5)
3264 25234, // (Rank 6)
3265 25236, // (Rank 7)
3266 47470, // (Rank 8)
3267 47471 // (Rank 9)
3268 }, [](SpellInfo* spellInfo)
3269 {
3270 spellInfo->AttributesEx3 |= SPELL_ATTR3_CANT_TRIGGER_PROC;
3271 });
3272
3273 // Improved Spell Reflection - aoe aura
3274 ApplySpellFix({ 59725 }, [](SpellInfo* spellInfo)
3275 {
3276 // Target entry seems to be wrong for this spell :/
3277 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER_AREA_PARTY);
3278 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_20_YARDS);
3279 });
3280
3282 44978, // Wild Magic
3283 45001, // Wild Magic
3284 45002, // Wild Magic
3285 45004, // Wild Magic
3286 45006, // Wild Magic
3287 45010, // Wild Magic
3288 41635, // Prayer of Mending
3289 44869, // Spectral Blast
3290 45027, // Revitalize
3291 45976, // Muru Portal Channel
3292 39365, // Thundering Storm
3293 41071, // Raise Dead (HACK)
3294 52124, // Sky Darkener Assault
3295 42442, // Vengeance Landing Cannonfire
3296 45863, // Cosmetic - Incinerate to Random Target
3297 25425, // Shoot
3298 45761, // Shoot
3299 42611, // Shoot
3300 61588, // Blazing Harpoon
3301 52479, // Gift of the Harvester
3302 48246, // Ball of Flame
3303 36327, // Shoot Arcane Explosion Arrow
3304 55479, // Force Obedience
3305 28560, // Summon Blizzard (Sapphiron)
3306 53096, // Quetz'lun's Judgment
3307 70743, // AoD Special
3308 70614, // AoD Special - Vegard
3309 4020, // Safirdrang's Chill
3310 52438, // Summon Skittering Swarmer (Force Cast)
3311 52449, // Summon Skittering Infector (Force Cast)
3312 53609, // Summon Anub'ar Assassin (Force Cast)
3313 53457, // Summon Impale Trigger (AoE)
3314 45907, // Torch Target Picker
3315 52953, // Torch
3316 58121, // Torch
3317 43109, // Throw Torch
3318 58552, // Return to Orgrimmar
3319 58533, // Return to Stormwind
3320 21855, // Challenge Flag
3321 38762, // Force of Neltharaku
3322 51122, // Fierce Lightning Stike
3323 71848, // Toxic Wasteling Find Target
3324 36146, // Chains of Naberius
3325 33711, // Murmur's Touch
3326 38794 // Murmur's Touch
3327 }, [](SpellInfo* spellInfo)
3328 {
3329 spellInfo->MaxAffectedTargets = 1;
3330 });
3331
3333 36384, // Skartax Purple Beam
3334 47731 // Critter
3335 }, [](SpellInfo* spellInfo)
3336 {
3337 spellInfo->MaxAffectedTargets = 2;
3338 });
3339
3341 41376, // Spite
3342 39992, // Needle Spine
3343 29576, // Multi-Shot
3344 40816, // Saber Lash
3345 37790, // Spread Shot
3346 46771, // Flame Sear
3347 45248, // Shadow Blades
3348 41303, // Soul Drain
3349 54172, // Divine Storm (heal)
3350 29213, // Curse of the Plaguebringer - Noth
3351 28542, // Life Drain - Sapphiron
3352 66588, // Flaming Spear
3353 54171 // Divine Storm
3354 }, [](SpellInfo* spellInfo)
3355 {
3356 spellInfo->MaxAffectedTargets = 3;
3357 });
3358
3360 38310, // Multi-Shot
3361 53385 // Divine Storm (Damage)
3362 }, [](SpellInfo* spellInfo)
3363 {
3364 spellInfo->MaxAffectedTargets = 4;
3365 });
3366
3368 42005, // Bloodboil
3369 38296, // Spitfire Totem
3370 37676, // Insidious Whisper
3371 46008, // Negative Energy
3372 45641, // Fire Bloom
3373 55665, // Life Drain - Sapphiron (H)
3374 28796, // Poison Bolt Volly - Faerlina
3375 37135 // Domination
3376 }, [](SpellInfo* spellInfo)
3377 {
3378 spellInfo->MaxAffectedTargets = 5;
3379 });
3380
3382 40827, // Sinful Beam
3383 40859, // Sinister Beam
3384 40860, // Vile Beam
3385 40861, // Wicked Beam
3386 54098, // Poison Bolt Volly - Faerlina (H)
3387 54835 // Curse of the Plaguebringer - Noth (H)
3388 }, [](SpellInfo* spellInfo)
3389 {
3390 spellInfo->MaxAffectedTargets = 10;
3391 });
3392
3394 50312 // Unholy Frenzy
3395 }, [](SpellInfo* spellInfo)
3396 {
3397 spellInfo->MaxAffectedTargets = 15;
3398 });
3399
3401 47977, // Magic Broom
3402 48025, // Headless Horseman's Mount
3403 54729, // Winged Steed of the Ebon Blade
3404 58983, // Big Blizzard Bear
3405 65917, // Magic Rooster
3406 71342, // Big Love Rocket
3407 72286, // Invincible
3408 74856, // Blazing Hippogryph
3409 75614, // Celestial Steed
3410 75973 // X-53 Touring Rocket
3411 }, [](SpellInfo* spellInfo)
3412 {
3413 // First two effects apply auras, which shouldn't be there
3414 // due to NO_TARGET applying aura on current caster (core bug)
3415 // Just wipe effect data, to mimic blizz-behavior
3416 spellInfo->_GetEffect(EFFECT_0).Effect = SPELL_EFFECT_NONE;
3417 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_NONE;
3418 });
3419
3420 // Lock and Load (Rank 1)
3421 ApplySpellFix({ 56342 }, [](SpellInfo* spellInfo)
3422 {
3423 // @workaround: Delete dummy effect from rank 1
3424 // effect apply aura has NO_TARGET but core still applies it to caster (same as above)
3425 spellInfo->_GetEffect(EFFECT_2).Effect = SPELL_EFFECT_NONE;
3426 });
3427
3428 // Roar of Sacrifice
3429 ApplySpellFix({ 53480 }, [](SpellInfo* spellInfo)
3430 {
3431 // missing spell effect 2 data, taken from 4.3.4
3432 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_APPLY_AURA;
3433 spellInfo->_GetEffect(EFFECT_1).ApplyAuraName = SPELL_AURA_DUMMY;
3434 spellInfo->_GetEffect(EFFECT_1).MiscValue = 127;
3435 spellInfo->_GetEffect(EFFECT_1).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ALLY);
3436 });
3437
3438 // Fingers of Frost
3439 ApplySpellFix({ 44544 }, [](SpellInfo* spellInfo)
3440 {
3441 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(685904631, 1151048, 0);
3442 });
3443
3444 // Magic Suppression - DK
3445 ApplySpellFix({ 49224, 49610, 49611 }, [](SpellInfo* spellInfo)
3446 {
3447 spellInfo->ProcCharges = 0;
3448 });
3449
3450 // Death and Decay
3451 ApplySpellFix({ 52212 }, [](SpellInfo* spellInfo)
3452 {
3453 spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE;
3454 });
3455
3456 // Oscillation Field
3457 ApplySpellFix({ 37408 }, [](SpellInfo* spellInfo)
3458 {
3459 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
3460 });
3461
3462 // Everlasting Affliction
3463 ApplySpellFix({ 47201, 47202, 47203, 47204, 47205 }, [](SpellInfo* spellInfo)
3464 {
3465 // add corruption to affected spells
3466 spellInfo->_GetEffect(EFFECT_1).SpellClassMask[0] |= 2;
3467 });
3468
3469 // Renewed Hope
3471 57470, // (Rank 1)
3472 57472 // (Rank 2)
3473 }, [](SpellInfo* spellInfo)
3474 {
3475 // should also affect Flash Heal
3476 spellInfo->_GetEffect(EFFECT_0).SpellClassMask[0] |= 0x800;
3477 });
3478
3479 // Crafty's Ultra-Advanced Proto-Typical Shortening Blaster
3480 ApplySpellFix({ 51912 }, [](SpellInfo* spellInfo)
3481 {
3482 spellInfo->_GetEffect(EFFECT_0).ApplyAuraPeriod = 3000;
3483 });
3484
3485 // Desecration Arm - 36 instead of 37 - typo? :/
3486 ApplySpellFix({ 29809 }, [](SpellInfo* spellInfo)
3487 {
3488 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_7_YARDS);
3489 });
3490
3491 // In sniff caster hits multiple targets
3493 73725, // [DND] Test Cheer
3494 73835, // [DND] Test Salute
3495 73836 // [DND] Test Roar
3496 }, [](SpellInfo* spellInfo)
3497 {
3498 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50_YARDS); // 50yd
3499 });
3500
3501 // In sniff caster hits multiple targets
3503 73837, // [DND] Test Dance
3504 73886 // [DND] Test Stop Dance
3505 }, [](SpellInfo* spellInfo)
3506 {
3507 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_150_YARDS); // 150yd
3508 });
3509
3510 // Radius in DBC is not enough
3512 36854, // Channel
3513 36856 // Channel
3514 }, [](SpellInfo* spellInfo)
3515 {
3516 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(5); // 40yd
3517 });
3518
3519 // Master Shapeshifter: missing stance data for forms other than bear - bear version has correct data
3520 // To prevent aura staying on target after talent unlearned
3521 ApplySpellFix({ 48420 }, [](SpellInfo* spellInfo)
3522 {
3523 spellInfo->Stances = UI64LIT(1) << (FORM_CAT - 1);
3524 });
3525
3526 ApplySpellFix({ 48421 }, [](SpellInfo* spellInfo)
3527 {
3528 spellInfo->Stances = UI64LIT(1) << (FORM_MOONKIN - 1);
3529 });
3530
3531 ApplySpellFix({ 48422 }, [](SpellInfo* spellInfo)
3532 {
3533 spellInfo->Stances = UI64LIT(1) << (FORM_TREE - 1);
3534 });
3535
3536 // Improved Shadowform (Rank 1)
3537 ApplySpellFix({ 47569 }, [](SpellInfo* spellInfo)
3538 {
3539 // with this spell atrribute aura can be stacked several times
3540 spellInfo->Attributes &= ~SPELL_ATTR0_NOT_SHAPESHIFT;
3541 });
3542
3543 // Hymn of Hope
3544 ApplySpellFix({ 64904 }, [](SpellInfo* spellInfo)
3545 {
3546 spellInfo->_GetEffect(EFFECT_1).ApplyAuraName = SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT;
3547 });
3548
3549 // Improved Stings (Rank 2)
3550 ApplySpellFix({ 19465 }, [](SpellInfo* spellInfo)
3551 {
3552 spellInfo->_GetEffect(EFFECT_2).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3553 });
3554
3555 // Nether Portal - Perseverence
3556 ApplySpellFix({ 30421 }, [](SpellInfo* spellInfo)
3557 {
3558 spellInfo->_GetEffect(EFFECT_2).BasePoints += 30000;
3559 });
3560
3561 // Natural shapeshifter
3562 ApplySpellFix({ 16834, 16835 }, [](SpellInfo* spellInfo)
3563 {
3564 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(21);
3565 });
3566
3567 // Ebon Plague
3568 ApplySpellFix({ 65142 }, [](SpellInfo* spellInfo)
3569 {
3570 spellInfo->AttributesEx3 &= ~SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
3571 });
3572
3573 // Ebon Plague
3574 ApplySpellFix({ 51735, 51734, 51726 }, [](SpellInfo* spellInfo)
3575 {
3576 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
3577 spellInfo->SpellFamilyFlags[2] = 0x10;
3578 spellInfo->_GetEffect(EFFECT_1).ApplyAuraName = SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN;
3579 });
3580
3581 // Parasitic Shadowfiend Passive
3582 ApplySpellFix({ 41913 }, [](SpellInfo* spellInfo)
3583 {
3584 // proc debuff, and summon infinite fiends
3585 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_DUMMY;
3586 });
3587
3589 27892, // To Anchor 1
3590 27928, // To Anchor 1
3591 27935, // To Anchor 1
3592 27915, // Anchor to Skulls
3593 27931, // Anchor to Skulls
3594 27937, // Anchor to Skulls
3595 16177, // Ancestral Fortitude (Rank 1)
3596 16236, // Ancestral Fortitude (Rank 2)
3597 16237, // Ancestral Fortitude (Rank 3)
3598 47930, // Grace
3599 45145, // Snake Trap Effect (Rank 1)
3600 13812, // Explosive Trap Effect (Rank 1)
3601 14314, // Explosive Trap Effect (Rank 2)
3602 14315, // Explosive Trap Effect (Rank 3)
3603 27026, // Explosive Trap Effect (Rank 4)
3604 49064, // Explosive Trap Effect (Rank 5)
3605 49065, // Explosive Trap Effect (Rank 6)
3606 43446, // Explosive Trap Effect (Hexlord Malacrass)
3607 50661, // Weakened Resolve
3608 68979, // Unleashed Souls
3609 48714, // Compelled
3610 7853 // The Art of Being a Water Terror: Force Cast on Player
3611 }, [](SpellInfo* spellInfo)
3612 {
3613 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13);
3614 });
3615
3616 // Wrath of the Plaguebringer
3617 ApplySpellFix({ 29214, 54836 }, [](SpellInfo* spellInfo)
3618 {
3619 // target allys instead of enemies, target A is src_caster, spells with effect like that have ally target
3620 // this is the only known exception, probably just wrong data
3621 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
3622 spellInfo->_GetEffect(EFFECT_1).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
3623 });
3624
3625 // Wind Shear
3626 ApplySpellFix({ 57994 }, [](SpellInfo* spellInfo)
3627 {
3628 // improper data for EFFECT_1 in 3.3.5 DBC, but is correct in 4.x
3629 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_MODIFY_THREAT_PERCENT;
3630 spellInfo->_GetEffect(EFFECT_1).BasePoints = -6; // -5%
3631 });
3632
3634 50526, // Wandering Plague
3635 15290 // Vampiric Embrace
3636 }, [](SpellInfo* spellInfo)
3637 {
3638 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO;
3639 });
3640
3641 // Vampiric Touch (dispel effect)
3642 ApplySpellFix({ 64085 }, [](SpellInfo* spellInfo)
3643 {
3644 // copy from similar effect of Unstable Affliction (31117)
3645 spellInfo->AttributesEx4 |= SPELL_ATTR4_FIXED_DAMAGE;
3646 spellInfo->AttributesEx6 |= SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS;
3647 });
3648
3649 // Improved Devouring Plague
3650 ApplySpellFix({ 63675 }, [](SpellInfo* spellInfo)
3651 {
3652 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
3653 });
3654
3655 // Deep Wounds
3656 ApplySpellFix({ 12721 }, [](SpellInfo* spellInfo)
3657 {
3658 // shouldnt ignore resillience or damage taken auras because its damage is not based off a spell.
3659 spellInfo->AttributesEx4 &= ~SPELL_ATTR4_FIXED_DAMAGE;
3660 });
3661
3662 // Tremor Totem (instant pulse)
3663 ApplySpellFix({ 8145 }, [](SpellInfo* spellInfo)
3664 {
3665 spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
3666 spellInfo->AttributesEx5 |= SPELL_ATTR5_START_PERIODIC_AT_APPLY;
3667 });
3668
3669 // Earthbind Totem (instant pulse)
3670 ApplySpellFix({ 6474 }, [](SpellInfo* spellInfo)
3671 {
3672 spellInfo->AttributesEx5 |= SPELL_ATTR5_START_PERIODIC_AT_APPLY;
3673 });
3674
3675 // Flametongue Totem (Aura)
3677 52109, // rank 1
3678 52110, // rank 2
3679 52111, // rank 3
3680 52112, // rank 4
3681 52113, // rank 5
3682 58651, // rank 6
3683 58654, // rank 7
3684 58655 // rank 8
3685 }, [](SpellInfo* spellInfo)
3686 {
3687 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3688 spellInfo->_GetEffect(EFFECT_1).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3689 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo();
3690 spellInfo->_GetEffect(EFFECT_1).TargetB = SpellImplicitTargetInfo();
3691 });
3692
3693 // Marked for Death
3695 53241, // (Rank 1)
3696 53243, // (Rank 2)
3697 53244, // (Rank 3)
3698 53245, // (Rank 4)
3699 53246 // (Rank 5)
3700 }, [](SpellInfo* spellInfo)
3701 {
3702 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(0x00067801, 0x10820001, 0x00000801);
3703 });
3704
3706 70728, // Exploit Weakness (needs target selection script)
3707 70840 // Devious Minds (needs target selection script)
3708 }, [](SpellInfo* spellInfo)
3709 {
3710 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3711 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_PET);
3712 });
3713
3714 // Culling The Herd (needs target selection script)
3715 ApplySpellFix({ 70893 }, [](SpellInfo* spellInfo)
3716 {
3717 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3718 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_MASTER);
3719 });
3720
3721 // Sigil of the Frozen Conscience
3722 ApplySpellFix({ 54800 }, [](SpellInfo* spellInfo)
3723 {
3724 // change class mask to custom extended flags of Icy Touch
3725 // this is done because another spell also uses the same SpellFamilyFlags as Icy Touch
3726 // SpellFamilyFlags[0] & 0x00000040 in SPELLFAMILY_DEATHKNIGHT is currently unused (3.3.5a)
3727 // this needs research on modifier applying rules, does not seem to be in Attributes fields
3728 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(0x00000040, 0x00000000, 0x00000000);
3729 });
3730
3731 // Idol of the Flourishing Life
3732 ApplySpellFix({ 64949 }, [](SpellInfo* spellInfo)
3733 {
3734 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(0x00000000, 0x02000000, 0x00000000);
3735 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER;
3736 });
3737
3739 34231, // Libram of the Lightbringer
3740 60792, // Libram of Tolerance
3741 64956 // Libram of the Resolute
3742 }, [](SpellInfo* spellInfo)
3743 {
3744 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(0x80000000, 0x00000000, 0x00000000);
3745 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER;
3746 });
3747
3749 28851, // Libram of Light
3750 28853, // Libram of Divinity
3751 32403 // Blessed Book of Nagrand
3752 }, [](SpellInfo* spellInfo)
3753 {
3754 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(0x40000000, 0x00000000, 0x00000000);
3755 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER;
3756 });
3757
3758 // Ride Carpet
3759 ApplySpellFix({ 45602 }, [](SpellInfo* spellInfo)
3760 {
3761 // force seat 0, vehicle doesn't have the required seat flags for "no seat specified (-1)"
3762 spellInfo->_GetEffect(EFFECT_0).BasePoints = 0;
3763 });
3764
3766 64745, // Item - Death Knight T8 Tank 4P Bonus
3767 64936 // Item - Warrior T8 Protection 4P Bonus
3768 }, [](SpellInfo* spellInfo)
3769 {
3770 // 100% chance of procc'ing, not -10% (chance calculated in PrepareTriggersExecutedOnHit)
3771 spellInfo->_GetEffect(EFFECT_0).BasePoints = 100;
3772 });
3773
3774 // Entangling Roots -- Nature's Grasp Proc
3776 19970, // (Rank 6)
3777 19971, // (Rank 5)
3778 19972, // (Rank 4)
3779 19973, // (Rank 3)
3780 19974, // (Rank 2)
3781 19975, // (Rank 1)
3782 27010, // (Rank 7)
3783 53313 // (Rank 8)
3784 }, [](SpellInfo* spellInfo)
3785 {
3786 spellInfo->CastTimeEntry = sSpellCastTimesStore.LookupEntry(1);
3787 });
3788
3789 // Easter Lay Noblegarden Egg Aura
3790 ApplySpellFix({ 61719 }, [](SpellInfo* spellInfo)
3791 {
3792 // Interrupt flags copied from aura which this aura is linked with
3793 spellInfo->AuraInterruptFlags = AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE;
3794 });
3795
3796 // Death Knight T10 Tank 2P Bonus
3797 ApplySpellFix({ 70650 }, [](SpellInfo* spellInfo)
3798 {
3799 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_ADD_PCT_MODIFIER;
3800 });
3801
3803 6789, // Warlock - Death Coil (Rank 1)
3804 17925, // Warlock - Death Coil (Rank 2)
3805 17926, // Warlock - Death Coil (Rank 3)
3806 27223, // Warlock - Death Coil (Rank 4)
3807 47859, // Warlock - Death Coil (Rank 5)
3808 47860, // Warlock - Death Coil (Rank 6)
3809 71838, // Drain Life - Bryntroll Normal
3810 71839 // Drain Life - Bryntroll Heroic
3811 }, [](SpellInfo* spellInfo)
3812 {
3813 spellInfo->AttributesEx2 |= SPELL_ATTR2_CANT_CRIT;
3814 });
3815
3817 51597, // Summon Scourged Captive
3818 56606, // Ride Jokkum
3819 61791 // Ride Vehicle (Yogg-Saron)
3820 }, [](SpellInfo* spellInfo)
3821 {
3823 spellInfo->_GetEffect(EFFECT_0).BasePoints = 1;
3824 });
3825
3826 // Summon Scourged Captive
3827 ApplySpellFix({ 51597 }, [](SpellInfo* spellInfo)
3828 {
3829 spellInfo->_GetEffect(EFFECT_0).DieSides = 0;
3830 });
3831
3832 // Black Magic
3833 ApplySpellFix({ 59630 }, [](SpellInfo* spellInfo)
3834 {
3835 spellInfo->Attributes |= SPELL_ATTR0_PASSIVE;
3836 });
3837
3839 17364, // Stormstrike
3840 48278, // Paralyze
3841 53651 // Light's Beacon
3842 }, [](SpellInfo* spellInfo)
3843 {
3844 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
3845 });
3846
3848 51798, // Brewfest - Relay Race - Intro - Quest Complete
3849 47134 // Quest Complete
3850 }, [](SpellInfo* spellInfo)
3851 {
3853 spellInfo->_GetEffect(EFFECT_0).Effect = SPELL_EFFECT_NONE;
3854 });
3855
3857 47476, // Deathknight - Strangulate
3858 15487, // Priest - Silence
3859 5211, // Druid - Bash - R1
3860 6798, // Druid - Bash - R2
3861 8983 // Druid - Bash - R3
3862 }, [](SpellInfo* spellInfo)
3863 {
3864 spellInfo->AttributesEx7 |= SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER;
3865 });
3866
3867 // Guardian Spirit
3868 ApplySpellFix({ 47788 }, [](SpellInfo* spellInfo)
3869 {
3870 spellInfo->ExcludeTargetAuraSpell = 72232; // Weakened Spirit
3871 });
3872
3874 15538, // Gout of Flame
3875 42490, // Energized!
3876 42492, // Cast Energized
3877 43115 // Plague Vial
3878 }, [](SpellInfo* spellInfo)
3879 {
3880 spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT;
3881 });
3882
3884 46842, // Flame Ring
3885 46836 // Flame Patch
3886 }, [](SpellInfo* spellInfo)
3887 {
3888 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo();
3889 });
3890
3891 // Test Ribbon Pole Channel
3892 ApplySpellFix({ 29726 }, [](SpellInfo* spellInfo)
3893 {
3894 spellInfo->InterruptFlags &= ~AURA_INTERRUPT_FLAG_CAST;
3895 });
3896
3898 42767, // Sic'em
3899 43092 // Stop the Ascension!: Halfdan's Soul Destruction
3900 }, [](SpellInfo* spellInfo)
3901 {
3902 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_NEARBY_ENTRY);
3903 });
3904
3905 // Polymorph (Six Demon Bag)
3906 ApplySpellFix({ 14621 }, [](SpellInfo* spellInfo)
3907 {
3908 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(4); // Medium Range
3909 });
3910
3911 // Concussive Barrage
3912 ApplySpellFix({ 35101 }, [](SpellInfo* spellInfo)
3913 {
3914 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(155); // Hunter Range (Long)
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
3926 51675, // Rogue - Unfair Advantage (Rank 1)
3927 51677 // Rogue - Unfair Advantage (Rank 2)
3928 }, [](SpellInfo* spellInfo)
3929 {
3930 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(2); // 5 yards
3931 });
3932
3934 55741, // Desecration (Rank 1)
3935 68766, // Desecration (Rank 2)
3936 57842 // Killing Spree (Off hand damage)
3937 }, [](SpellInfo* spellInfo)
3938 {
3939 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(2); // Melee Range
3940 });
3941
3942 // Safeguard
3944 46946, // (Rank 1)
3945 46947 // (Rank 2)
3946 }, [](SpellInfo* spellInfo)
3947 {
3948 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(34); // Twenty-Five yards
3949 });
3950
3951 // Summon Corpse Scarabs
3952 ApplySpellFix({ 28864, 29105 }, [](SpellInfo* spellInfo)
3953 {
3954 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS);
3955 });
3956
3958 37851, // Tag Greater Felfire Diemetradon
3959 37918 // Arcano-pince
3960 }, [](SpellInfo* spellInfo)
3961 {
3962 spellInfo->RecoveryTime = 3000;
3963 });
3964
3965 // Jormungar Strike
3966 ApplySpellFix({ 56513 }, [](SpellInfo* spellInfo)
3967 {
3968 spellInfo->RecoveryTime = 2000;
3969 });
3970
3972 54997, // Cast Net (tooltip says 10s but sniffs say 6s)
3973 56524 // Acid Breath
3974 }, [](SpellInfo* spellInfo)
3975 {
3976 spellInfo->RecoveryTime = 6000;
3977 });
3978
3980 47911, // EMP
3981 48620, // Wing Buffet
3982 51752 // Stampy's Stompy-Stomp
3983 }, [](SpellInfo* spellInfo)
3984 {
3985 spellInfo->RecoveryTime = 10000;
3986 });
3987
3989 37727, // Touch of Darkness
3990 54996 // Ice Slick (tooltip says 20s but sniffs say 12s)
3991 }, [](SpellInfo* spellInfo)
3992 {
3993 spellInfo->RecoveryTime = 12000;
3994 });
3995
3996 // Signal Helmet to Attack
3997 ApplySpellFix({ 51748 }, [](SpellInfo* spellInfo)
3998 {
3999 spellInfo->RecoveryTime = 15000;
4000 });
4001
4003 51756, // Charge
4004 37919, //Arcano-dismantle
4005 37917 //Arcano-Cloak
4006 }, [](SpellInfo* spellInfo)
4007 {
4008 spellInfo->RecoveryTime = 20000;
4009 });
4010
4011 // Summon Frigid Bones
4012 ApplySpellFix({ 53525 }, [](SpellInfo* spellInfo)
4013 {
4014 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(4); // 2 minutes
4015 });
4016
4017 // Dark Conclave Ritualist Channel
4018 ApplySpellFix({ 38469 }, [](SpellInfo* spellInfo)
4019 {
4020 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100yd
4021 });
4022
4023 //
4024 // VIOLET HOLD SPELLS
4025 //
4026 // Water Globule (Ichoron)
4027 ApplySpellFix({ 54258, 54264, 54265, 54266, 54267 }, [](SpellInfo* spellInfo)
4028 {
4029 // in 3.3.5 there is only one radius in dbc which is 0 yards in this
4030 // use max radius from 4.3.4
4031 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS);
4032 });
4033 // ENDOF VIOLET HOLD
4034
4035 //
4036 // ULDUAR SPELLS
4037 //
4038 // Pursued (Flame Leviathan)
4039 ApplySpellFix({ 62374 }, [](SpellInfo* spellInfo)
4040 {
4041 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4042 });
4043
4044 // Focused Eyebeam Summon Trigger (Kologarn)
4045 ApplySpellFix({ 63342 }, [](SpellInfo* spellInfo)
4046 {
4047 spellInfo->MaxAffectedTargets = 1;
4048 });
4049
4051 62716, // Growth of Nature (Freya)
4052 65584, // Growth of Nature (Freya)
4053 64381 // Strength of the Pack (Auriaya)
4054 }, [](SpellInfo* spellInfo)
4055 {
4056 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
4057 });
4058
4060 63018, // Searing Light (XT-002)
4061 65121, // Searing Light (25m) (XT-002)
4062 63024, // Gravity Bomb (XT-002)
4063 64234 // Gravity Bomb (25m) (XT-002)
4064 }, [](SpellInfo* spellInfo)
4065 {
4066 spellInfo->MaxAffectedTargets = 1;
4067 });
4068
4070 64386, // Terrifying Screech (Auriaya)
4071 64389, // Sentinel Blast (Auriaya)
4072 64678 // Sentinel Blast (Auriaya)
4073 }, [](SpellInfo* spellInfo)
4074 {
4075 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(28); // 5 seconds, wrong DBC data?
4076 });
4077
4078 // Summon Swarming Guardian (Auriaya)
4079 ApplySpellFix({ 64397 }, [](SpellInfo* spellInfo)
4080 {
4081 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(137); // 8y, Based in BFA effect radius
4082 });
4083
4084 // Potent Pheromones (Freya)
4085 ApplySpellFix({ 64321 }, [](SpellInfo* spellInfo)
4086 {
4087 // spell should dispel area aura, but doesn't have the attribute
4088 // may be db data bug, or blizz may keep reapplying area auras every update with checking immunity
4089 // that will be clear if we get more spells with problem like this
4090 spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY;
4091 });
4092
4093 // Blizzard (Thorim)
4094 ApplySpellFix({ 62576, 62602 }, [](SpellInfo* spellInfo)
4095 {
4096 // DBC data is wrong for EFFECT_0, it's a different dynobject target than EFFECT_1
4097 // Both effects should be shared by the same DynObject
4098 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_DEST_CASTER_LEFT);
4099 });
4100
4101 // Spinning Up (Mimiron)
4102 ApplySpellFix({ 63414 }, [](SpellInfo* spellInfo)
4103 {
4104 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
4105 spellInfo->ChannelInterruptFlags = 0;
4106 });
4107
4108 // Rocket Strike (Mimiron)
4109 ApplySpellFix({ 63036 }, [](SpellInfo* spellInfo)
4110 {
4111 spellInfo->Speed = 0;
4112 });
4113
4114 // Magnetic Field (Mimiron)
4115 ApplySpellFix({ 64668 }, [](SpellInfo* spellInfo)
4116 {
4117 spellInfo->Mechanic = MECHANIC_NONE;
4118 });
4119
4120 // Empowering Shadows (Yogg-Saron)
4121 ApplySpellFix({ 64468, 64486 }, [](SpellInfo* spellInfo)
4122 {
4123 spellInfo->MaxAffectedTargets = 3; // same for both modes?
4124 });
4125
4126 // Cosmic Smash (Algalon the Observer)
4127 ApplySpellFix({ 62301 }, [](SpellInfo* spellInfo)
4128 {
4129 spellInfo->MaxAffectedTargets = 1;
4130 });
4131
4132 // Cosmic Smash (Algalon the Observer)
4133 ApplySpellFix({ 64598 }, [](SpellInfo* spellInfo)
4134 {
4135 spellInfo->MaxAffectedTargets = 3;
4136 });
4137
4138 // Cosmic Smash (Algalon the Observer)
4139 ApplySpellFix({ 62293 }, [](SpellInfo* spellInfo)
4140 {
4141 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_DEST_CASTER);
4142 });
4143
4144 // Cosmic Smash (Algalon the Observer)
4145 ApplySpellFix({ 62311, 64596 }, [](SpellInfo* spellInfo)
4146 {
4147 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100yd
4148 });
4149
4151 64014, // Expedition Base Camp Teleport
4152 64024, // Conservatory Teleport
4153 64025, // Halls of Invention Teleport
4154 64028, // Colossal Forge Teleport
4155 64029, // Shattered Walkway Teleport
4156 64030, // Antechamber Teleport
4157 64031, // Scrapyard Teleport
4158 64032, // Formation Grounds Teleport
4159 65042 // Prison of Yogg-Saron Teleport
4160 }, [](SpellInfo* spellInfo)
4161 {
4162 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
4163 });
4164 // ENDOF ULDUAR SPELLS
4165
4166 //
4167 // TRIAL OF THE CRUSADER SPELLS
4168 //
4169 // Infernal Eruption
4170 ApplySpellFix({ 66258, 67901 }, [](SpellInfo* spellInfo)
4171 {
4172 // increase duration from 15 to 18 seconds because caster is already
4173 // unsummoned when spell missile hits the ground so nothing happen in result
4174 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(85);
4175 });
4176 // ENDOF TRIAL OF THE CRUSADER SPELLS
4177
4178 //
4179 // HALLS OF REFLECTION SPELLS
4180 //
4182 72435, // Defiling Horror
4183 72452 // Defiling Horror
4184 }, [](SpellInfo* spellInfo)
4185 {
4186 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_60_YARDS); // 60yd
4187 });
4188
4189 // Achievement Check
4190 ApplySpellFix({ 72830 }, [](SpellInfo* spellInfo)
4191 {
4192 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4193 });
4194
4195 // Start Halls of Reflection Quest AE
4196 ApplySpellFix({ 72900 }, [](SpellInfo* spellInfo)
4197 {
4198 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4199 });
4200 // ENDOF HALLS OF REFLECTION SPELLS
4201
4202 //
4203 // ICECROWN CITADEL SPELLS
4204 //
4206 // THESE SPELLS ARE WORKING CORRECTLY EVEN WITHOUT THIS HACK
4207 // THE ONLY REASON ITS HERE IS THAT CURRENT GRID SYSTEM
4208 // DOES NOT ALLOW FAR OBJECT SELECTION (dist > 333)
4209 70781, // Light's Hammer Teleport
4210 70856, // Oratory of the Damned Teleport
4211 70857, // Rampart of Skulls Teleport
4212 70858, // Deathbringer's Rise Teleport
4213 70859, // Upper Spire Teleport
4214 70860, // Frozen Throne Teleport
4215 70861 // Sindragosa's Lair Teleport
4216 }, [](SpellInfo* spellInfo)
4217 {
4218 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
4219 });
4220
4221 // Bone Slice (Lord Marrowgar)
4222 ApplySpellFix({ 69055, 70814 }, [](SpellInfo* spellInfo)
4223 {
4224 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_5_YARDS); // 5yd
4225 });
4226
4228 69075, // Bone Storm (Lord Marrowgar)
4229 70834, // Bone Storm (Lord Marrowgar)
4230 70835, // Bone Storm (Lord Marrowgar)
4231 70836, // Bone Storm (Lord Marrowgar)
4232 71160, // Plague Stench (Stinky)
4233 71161, // Plague Stench (Stinky)
4234 71123 // Decimate (Stinky & Precious)
4235 }, [](SpellInfo* spellInfo)
4236 {
4237 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yd
4238 });
4239
4240 // Coldflame (Lord Marrowgar)
4241 ApplySpellFix({ 69146, 70823, 70824, 70825 }, [](SpellInfo* spellInfo)
4242 {
4243 spellInfo->AttributesEx4 &= ~SPELL_ATTR4_IGNORE_RESISTANCES;
4244 });
4245
4246 // Shadow's Fate
4247 ApplySpellFix({ 71169 }, [](SpellInfo* spellInfo)
4248 {
4249 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
4250 });
4251
4252 // Lock Players and Tap Chest
4253 ApplySpellFix({ 72347 }, [](SpellInfo* spellInfo)
4254 {
4255 spellInfo->AttributesEx3 &= ~SPELL_ATTR3_NO_INITIAL_AGGRO;
4256 });
4257
4258 // Award Reputation - Boss Kill
4259 ApplySpellFix({ 73843, 73844, 73845, 73846 }, [](SpellInfo* spellInfo)
4260 {
4261 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4262 });
4263
4265 72378, // Blood Nova (Deathbringer Saurfang)
4266 73058, // Blood Nova (Deathbringer Saurfang)
4267 72769 // Scent of Blood (Deathbringer Saurfang)
4268 }, [](SpellInfo* spellInfo)
4269 {
4270 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS);
4271 });
4272
4273 // Scent of Blood (Deathbringer Saurfang)
4274 ApplySpellFix({ 72771 }, [](SpellInfo* spellInfo)
4275 {
4276 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS);
4277 });
4278
4279 // Resistant Skin (Deathbringer Saurfang adds)
4280 ApplySpellFix({ 72723 }, [](SpellInfo* spellInfo)
4281 {
4282 // this spell initially granted Shadow damage immunity, however it was removed but the data was left in client
4283 spellInfo->_GetEffect(EFFECT_2).Effect = SPELL_EFFECT_NONE;
4284 });
4285
4286 // Coldflame Jets (Traps after Saurfang)
4287 ApplySpellFix({ 70460 }, [](SpellInfo* spellInfo)
4288 {
4289 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(1); // 10 seconds
4290 });
4291
4293 71412, // Green Ooze Summon (Professor Putricide)
4294 71415 // Orange Ooze Summon (Professor Putricide)
4295 }, [](SpellInfo* spellInfo)
4296 {
4297 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY);
4298 });
4299
4300 // Ooze flood
4301 ApplySpellFix({ 69783, 69797, 69799, 69802 }, [](SpellInfo* spellInfo)
4302 {
4303 // Those spells are cast on creatures with same entry as caster while they have TARGET_UNIT_NEARBY_ENTRY.
4304 spellInfo->AttributesEx |= SPELL_ATTR1_CANT_TARGET_SELF;
4305 });
4306
4307 // Awaken Plagued Zombies
4308 ApplySpellFix({ 71159 }, [](SpellInfo* spellInfo)
4309 {
4310 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(21);
4311 });
4312
4313 // Volatile Ooze Beam Protection (Professor Putricide)
4314 ApplySpellFix({ 70530 }, [](SpellInfo* spellInfo)
4315 {
4316 spellInfo->_GetEffect(EFFECT_0).Effect = SPELL_EFFECT_APPLY_AURA; // for an unknown reason this was SPELL_EFFECT_APPLY_AREA_AURA_RAID
4317 });
4318
4319 // Mutated Strength (Professor Putricide)
4320 ApplySpellFix({ 71604, 72673, 72674, 72675 }, [](SpellInfo* spellInfo)
4321 {
4322 // THIS IS HERE BECAUSE COOLDOWN ON CREATURE PROCS WERE NOT IMPLEMENTED WHEN THE SCRIPT WAS WRITTEN
4323 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_NONE;
4324 });
4325
4326 // Mutated Plague (Professor Putricide)
4327 ApplySpellFix({ 72454, 72464, 72506, 72507 }, [](SpellInfo* spellInfo)
4328 {
4329 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4330 });
4331
4332 // Unbound Plague (Professor Putricide) (needs target selection script)
4333 ApplySpellFix({ 70911, 72854, 72855, 72856 }, [](SpellInfo* spellInfo)
4334 {
4335 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ENEMY);
4336 });
4337
4339 71518, // Unholy Infusion Quest Credit (Professor Putricide)
4340 72934, // Blood Infusion Quest Credit (Blood-Queen Lana'thel)
4341 72289 // Frost Infusion Quest Credit (Sindragosa)
4342 }, [](SpellInfo* spellInfo)
4343 {
4344 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // another missing radius
4345 });
4346
4347 // Empowered Flare (Blood Prince Council)
4348 ApplySpellFix({ 71708, 72785, 72786, 72787 }, [](SpellInfo* spellInfo)
4349 {
4350 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
4351 });
4352
4353 // Swarming Shadows
4354 ApplySpellFix({ 71266, 72890 }, [](SpellInfo* spellInfo)
4355 {
4356 spellInfo->RequiredAreasID = 0; // originally, these require area 4522, which is... outside of Icecrown Citadel
4357 });
4358
4359 // Corruption
4360 ApplySpellFix({ 70602 }, [](SpellInfo* spellInfo)
4361 {
4362 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
4363 });
4364
4365 // Column of Frost (visual marker)
4366 ApplySpellFix({ 70715 }, [](SpellInfo* spellInfo)
4367 {
4368 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(32); // 6 seconds (missing)
4369 });
4370
4371 // Mana Void (periodic aura)
4372 ApplySpellFix({ 71085 }, [](SpellInfo* spellInfo)
4373 {
4374 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(9); // 30 seconds (missing)
4375 });
4376
4377 // Frostbolt Volley (only heroic)
4378 ApplySpellFix({ 72015, 72016 }, [](SpellInfo* spellInfo)
4379 {
4380 spellInfo->_GetEffect(EFFECT_2).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_40_YARDS);
4381 });
4382
4383 // Summon Suppressor (needs target selection script)
4384 ApplySpellFix({ 70936 }, [](SpellInfo* spellInfo)
4385 {
4386 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY);
4387 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo();
4388 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(157); // 90yd
4389 });
4390
4392 72706, // Achievement Check (Valithria Dreamwalker)
4393 71357 // Order Whelp
4394 }, [](SpellInfo* spellInfo)
4395 {
4396 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4397 });
4398
4399 // Sindragosa's Fury
4400 ApplySpellFix({ 70598 }, [](SpellInfo* spellInfo)
4401 {
4402 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_DEST_DEST);
4403 });
4404
4405 // Frost Bomb
4406 ApplySpellFix({ 69846 }, [](SpellInfo* spellInfo)
4407 {
4408 spellInfo->Speed = 0.0f; // This spell's summon happens instantly
4409 });
4410
4411 // Chilled to the Bone
4412 ApplySpellFix({ 70106 }, [](SpellInfo* spellInfo)
4413 {
4414 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
4415 spellInfo->AttributesEx6 |= SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS;
4416 });
4417
4418 // Ice Lock
4419 ApplySpellFix({ 71614 }, [](SpellInfo* spellInfo)
4420 {
4421 spellInfo->Mechanic = MECHANIC_STUN;
4422 });
4423
4424 // Defile
4425 ApplySpellFix({ 72762 }, [](SpellInfo* spellInfo)
4426 {
4427 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(559); // 53 seconds
4428 });
4429
4430 // Defile
4431 ApplySpellFix({ 72743 }, [](SpellInfo* spellInfo)
4432 {
4433 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(22); // 45 seconds
4434 });
4435
4436 // Defile
4437 ApplySpellFix({ 72754, 73708, 73709, 73710 }, [](SpellInfo* spellInfo)
4438 {
4439 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4440 });
4441
4442 // Val'kyr Target Search
4443 ApplySpellFix({ 69030 }, [](SpellInfo* spellInfo)
4444 {
4445 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4446 spellInfo->Attributes |= SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY;
4447 });
4448
4449 // Raging Spirit Visual
4450 ApplySpellFix({ 69198 }, [](SpellInfo* spellInfo)
4451 {
4452 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
4453 });
4454
4455 // Harvest Souls
4456 ApplySpellFix({ 73654, 74295, 74296, 74297 }, [](SpellInfo* spellInfo)
4457 {
4458 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4459 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4460 spellInfo->_GetEffect(EFFECT_2).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4461 });
4462
4463 // Harvest Soul
4464 ApplySpellFix({ 73655 }, [](SpellInfo* spellInfo)
4465 {
4466 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
4467 });
4468
4469 // Summon Shadow Trap
4470 ApplySpellFix({ 73540 }, [](SpellInfo* spellInfo)
4471 {
4472 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(3); // 60 seconds
4473 });
4474
4475 // Shadow Trap (visual)
4476 ApplySpellFix({ 73530 }, [](SpellInfo* spellInfo)
4477 {
4478 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(27); // 3 seconds
4479 });
4480
4481 // Shadow Trap
4482 ApplySpellFix({ 73529 }, [](SpellInfo* spellInfo)
4483 {
4484 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS); // 10yd
4485 });
4486
4487 // Shadow Trap (searcher)
4488 ApplySpellFix({ 74282 }, [](SpellInfo* spellInfo)
4489 {
4490 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_5_YARDS); // 5yd
4491 });
4492
4493 // Restore Soul
4494 ApplySpellFix({ 72595, 73650 }, [](SpellInfo* spellInfo)
4495 {
4496 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4497 });
4498
4499 // Destroy Soul
4500 ApplySpellFix({ 74086 }, [](SpellInfo* spellInfo)
4501 {
4502 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4503 });
4504
4505 // Summon Spirit Bomb
4506 ApplySpellFix({ 74302, 74342 }, [](SpellInfo* spellInfo)
4507 {
4508 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4509 spellInfo->MaxAffectedTargets = 1;
4510 });
4511
4512 // Summon Spirit Bomb
4513 ApplySpellFix({ 74341, 74343 }, [](SpellInfo* spellInfo)
4514 {
4515 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4516 spellInfo->MaxAffectedTargets = 3;
4517 });
4518
4519 // Summon Spirit Bomb
4520 ApplySpellFix({ 73579 }, [](SpellInfo* spellInfo)
4521 {
4522 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS); // 25yd
4523 });
4524
4525 // Fury of Frostmourne
4526 ApplySpellFix({ 72350 }, [](SpellInfo* spellInfo)
4527 {
4528 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4529 });
4530
4532 {
4533 75127, // Kill Frostmourne Players
4534 72351, // Fury of Frostmourne
4535 72431, // Jump (removes Fury of Frostmourne debuff)
4536 72429, // Mass Resurrection
4537 73159, // Play Movie
4538 73582 // Trigger Vile Spirit (Inside, Heroic)
4539 }, [](SpellInfo* spellInfo)
4540 {
4541 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4542 });
4543
4544 // Raise Dead
4545 ApplySpellFix({ 72376 }, [](SpellInfo* spellInfo)
4546 {
4547 spellInfo->MaxAffectedTargets = 3;
4548 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4549 });
4550
4551 // Jump
4552 ApplySpellFix({ 71809 }, [](SpellInfo* spellInfo)
4553 {
4554 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(5); // 40yd
4555 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS); // 10yd
4556 spellInfo->_GetEffect(EFFECT_0).MiscValue = 190;
4557 });
4558
4559 // Broken Frostmourne
4560 ApplySpellFix({ 72405 }, [](SpellInfo* spellInfo)
4561 {
4562 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_20_YARDS); // 20yd
4563 spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT;
4564 });
4565 // ENDOF ICECROWN CITADEL SPELLS
4566
4567 //
4568 // RUBY SANCTUM SPELLS
4569 //
4570 // Soul Consumption
4571 ApplySpellFix({ 74799 }, [](SpellInfo* spellInfo)
4572 {
4573 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_12_YARDS);
4574 });
4575
4576 // Twilight Cutter
4577 ApplySpellFix({ 74769, 77844, 77845, 77846 }, [](SpellInfo* spellInfo)
4578 {
4579 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yd
4580 });
4581
4582 // Twilight Mending
4583 ApplySpellFix({ 75509 }, [](SpellInfo* spellInfo)
4584 {
4585 spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE;
4586 spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
4587 });
4588
4589 // Combustion and Consumption Heroic versions lacks radius data
4590 ApplySpellFix({ 75875 }, [](SpellInfo* spellInfo)
4591 {
4592 spellInfo->_GetEffect(EFFECT_0).Mechanic = MECHANIC_NONE;
4593 spellInfo->_GetEffect(EFFECT_1).Mechanic = MECHANIC_SNARE;
4594 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_6_YARDS);
4595 });
4596
4597 ApplySpellFix({ 75884 }, [](SpellInfo* spellInfo)
4598 {
4599 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_6_YARDS);
4600 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_6_YARDS);
4601 });
4602
4603 ApplySpellFix({ 75883, 75876 }, [](SpellInfo* spellInfo)
4604 {
4605 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_6_YARDS);
4606 });
4607 // ENDOF RUBY SANCTUM SPELLS
4608
4609 //
4610 // EYE OF ETERNITY SPELLS
4611 //
4613 // All spells below work even without these changes. The LOS attribute is due to problem
4614 // from collision between maps & gos with active destroyed state.
4615 57473, // Arcane Storm bonus explicit visual spell
4616 57431, // Summon Static Field
4617 56091, // Flame Spike (Wyrmrest Skytalon)
4618 56092, // Engulf in Flames (Wyrmrest Skytalon)
4619 57090, // Revivify (Wyrmrest Skytalon)
4620 57143 // Life Burst (Wyrmrest Skytalon)
4621 }, [](SpellInfo* spellInfo)
4622 {
4623 spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
4624 });
4625
4626 // Arcane Barrage (cast by players and NONMELEEDAMAGELOG with caster Scion of Eternity (original caster)).
4627 ApplySpellFix({ 63934 }, [](SpellInfo* spellInfo)
4628 {
4629 // This would never crit on retail and it has attribute for SPELL_ATTR3_NO_DONE_BONUS because is handled from player,
4630 // until someone figures how to make scions not critting without hack and without making them main casters this should stay here.
4631 spellInfo->AttributesEx2 |= SPELL_ATTR2_CANT_CRIT;
4632 });
4633 // ENDOF EYE OF ETERNITY SPELLS
4634
4635 //
4636 // OCULUS SPELLS
4637 //
4639 // The spells below are here because their effect 1 is giving warning due to
4640 // triggered spell not found in any dbc and is missing from encounter source* of data.
4641 // Even judged as clientside these spells can't be guessed for* now.
4642 49462, // Call Ruby Drake
4643 49461, // Call Amber Drake
4644 49345 // Call Emerald Drake
4645 }, [](SpellInfo* spellInfo)
4646 {
4647 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_NONE;
4648 });
4649 // ENDOF OCULUS SPELLS
4650
4651 // Introspection
4652 ApplySpellFix({ 40055, 40165, 40166, 40167 }, [](SpellInfo* spellInfo)
4653 {
4654 spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1;
4655 });
4656
4657 // Chains of Ice
4658 ApplySpellFix({ 45524 }, [](SpellInfo* spellInfo)
4659 {
4660 spellInfo->_GetEffect(EFFECT_2).TargetA = SpellImplicitTargetInfo();
4661 });
4662
4663 // Minor Fortitude
4664 ApplySpellFix({ 2378 }, [](SpellInfo* spellInfo)
4665 {
4666 spellInfo->ManaCost = 0;
4667 spellInfo->ManaPerSecond = 0;
4668 });
4669
4670 // Threatening Gaze
4671 ApplySpellFix({ 24314 }, [](SpellInfo* spellInfo)
4672 {
4674 });
4675
4676 //
4677 // ISLE OF CONQUEST SPELLS
4678 //
4679 // Teleport
4680 ApplySpellFix({ 66551 }, [](SpellInfo* spellInfo)
4681 {
4682 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
4683 });
4684 // ENDOF ISLE OF CONQUEST SPELLS
4685
4686 // Aura of Fear
4687 ApplySpellFix({ 40453 }, [](SpellInfo* spellInfo)
4688 {
4689 // Bad DBC data? Copying 25820 here due to spell description
4690 // either is a periodic with chance on tick, or a proc
4691
4692 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_PROC_TRIGGER_SPELL;
4693 spellInfo->_GetEffect(EFFECT_0).ApplyAuraPeriod = 0;
4694 spellInfo->ProcChance = 10;
4695 });
4696
4697 // Survey Sinkholes
4698 ApplySpellFix({ 45853 }, [](SpellInfo* spellInfo)
4699 {
4700 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(5); // 40 yards
4701 });
4702
4704 41485, // Deadly Poison - Black Temple
4705 41487 // Envenom - Black Temple
4706 }, [](SpellInfo* spellInfo)
4707 {
4708 spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE;
4709 });
4710
4712 // Proc attribute correction
4713 // Remove procflags from test/debug/deprecated spells to avoid DB Errors
4714 2479, // Honorless Target
4715 3232, // Gouge Stun Test
4716 3409, // Crippling Poison
4717 4312, // Strider Presence
4718 5707, // Lifestone Regeneration
4719 5760, // Mind-numbing Poison
4720 6727, // Poison Mushroom
4721 6940, // Hand of Sacrifice (handled remove in split hook)
4722 6984, // Frost Shot (Rank 2)
4723 7164, // Defensive Stance
4724 7288, // Immolate Cumulative (TEST) (Rank 1)
4725 7291, // Food (TEST)
4726 7331, // Healing Aura (TEST) (Rank 1)
4727 7366, // Berserker Stance
4728 7824, // Blacksmithing Skill +10
4729 12551, // Frost Shot
4730 13218, // Wound Poison (Rank 1)
4731 13222, // Wound Poison II (Rank 2)
4732 13223, // Wound Poison III (Rank 3)
4733 13224, // Wound Poison IV (Rank 4)
4734 14795, // Venomhide Poison
4735 16610, // Razorhide
4736 18099, // Chill Nova
4737 18499, // Berserker Rage (extra rage implemented in Unit::RewardRage)
4738 18802, // Frost Shot
4739 20000, // Alexander's Test Periodic Aura
4740 21163, // Polished Armor (Rank 1)
4741 22818, // Mol'dar's Moxie
4742 22820, // Slip'kik's Savvy
4743 23333, // Warsong Flag
4744 23335, // Silverwing Flag
4745 25160, // Sand Storm
4746 27189, // Wound Poison V (Rank 5)
4747 28313, // Aura of Fear
4748 28726, // Nightmare Seed
4749 28754, // Fury of the Ashbringer
4750 30802, // Unleashed Rage (Rank 1)
4751 31481, // Lung Burst
4752 32430, // Battle Standard
4753 32431, // Battle Standard
4754 32447, // Travel Form
4755 33370, // Spell Haste
4756 33807, // Abacus of Violent Odds
4757 33891, // Tree of Life (Shapeshift)
4758 34132, // Gladiator's Totem of the Third Wind
4759 34135, // Libram of Justice
4760 34666, // Tamed Pet Passive 08 (DND)
4761 34667, // Tamed Pet Passive 09 (DND)
4762 34775, // Dragonspine Flurry
4763 34889, // Fire Breath (Rank 1)
4764 34976, // Netherstorm Flag
4765 35131, // Bladestorm
4766 35244, // Choking Vines
4767 35323, // Fire Breath (Rank 2)
4768 35336, // Energizing Spores
4769 36148, // Chill Nova
4770 36613, // Aspect of the Spirit Hunter
4771 36786, // Soul Chill
4772 37174, // Perceived Weakness
4773 37482, // Exploited Weakness
4774 37526, // Battle Rush
4775 37588, // Dive
4776 37985, // Fire Breath
4777 38317, // Forgotten Knowledge
4778 38843, // Soul Chill
4779 39015, // Atrophic Blow
4780 40396, // Fel Infusion
4781 40603, // Taunt Gurtogg
4782 40803, // Ron's Test Buff
4783 40879, // Prismatic Shield (no longer used since patch 2.2/adaptive prismatic shield)
4784 41341, // Balance of Power (implemented by hooking absorb)
4785 41435, // The Twin Blades of Azzinoth
4786 42369, // Merciless Libram of Justice
4787 42371, // Merciless Gladiator's Totem of the Third Wind
4788 42636, // Birmingham Tools Test 3
4789 43727, // Vengeful Libram of Justice
4790 43729, // Vengeful Gladiator's Totem of the Third Wind
4791 43817, // Focused Assault
4792 44305, // You're a ...! (Effects2)
4793 44586, // Prayer of Mending (unknown, unused aura type)
4794 45384, // Birmingham Tools Test 4
4795 45433, // Birmingham Tools Test 5
4796 46093, // Brutal Libram of Justice
4797 46099, // Brutal Gladiator's Totem of the Third Wind
4798 46705, // Honorless Target
4799 49145, // Spell Deflection (Rank 1) (implemented by hooking absorb)
4800 49883, // Flames
4801 50365, // Improved Blood Presence (Rank 1)
4802 50371, // Improved Blood Presence (Rank 2)
4803 50462, // Anti-Magic Zone (implemented by hooking absorb)
4804
4805 50498, // Savage Rend (Rank 1) - proc from Savage Rend moved from attack itself to autolearn aura 50871
4806 53578, // Savage Rend (Rank 2)
4807 53579, // Savage Rend (Rank 3)
4808 53580, // Savage Rend (Rank 4)
4809 53581, // Savage Rend (Rank 5)
4810 53582, // Savage Rend (Rank 6)
4811
4812 50655, // Frost Cut
4813 50995, // Empowered Blood Presence (Rank 1)
4814 51809, // First Aid
4815 53032, // Flurry of Claws
4816 55482, // Fire Breath (Rank 3)
4817 55483, // Fire Breath (Rank 4)
4818 55484, // Fire Breath (Rank 5)
4819 55485, // Fire Breath (Rank 6)
4820 57974, // Wound Poison VI (Rank 6)
4821 57975, // Wound Poison VII (Rank 7)
4822 60062, // Essence of Life
4823 60302, // Meteorite Whetstone
4824 60437, // Grim Toll
4825 60492, // Embrace of the Spider
4826 62142, // Improved Chains of Ice (Rank 3)
4827 63024, // Gravity Bomb
4828 64205, // Divine Sacrifice (handled remove in split hook)
4829 64772, // Comet's Trail
4830 65004, // Alacrity of the Elements
4831 65019, // Mjolnir Runestone
4832 65024, // Implosion
4833
4834 66334, // Mistress' Kiss - currently not used in script, need implement?
4835 67905, // Mistress' Kiss
4836 67906, // Mistress' Kiss
4837 67907, // Mistress' Kiss
4838
4839 71003, // Vegard's Touch
4840
4841 72151, // Frenzied Bloodthirst - currently not used in script, need implement?
4842 72648, // Frenzied Bloodthirst
4843 72649, // Frenzied Bloodthirst
4844 72650, // Frenzied Bloodthirst
4845
4846 72559, // Birmingham Tools Test 3
4847 72560, // Birmingham Tools Test 3
4848 72561, // Birmingham Tools Test 5
4849 72980 // Shadow Resonance
4850 }, [](SpellInfo* spellInfo)
4851 {
4852 spellInfo->ProcFlags = 0;
4853 });
4854
4855 // Feral Charge - Cat
4856 ApplySpellFix({ 49376 }, [](SpellInfo* spellInfo)
4857 {
4858 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_3_YARDS); // 3yd
4859 });
4860
4861 // Baron Rivendare (Stratholme) - Unholy Aura
4862 ApplySpellFix({ 17466, 17467 }, [](SpellInfo* spellInfo)
4863 {
4864 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO;
4865 });
4866
4867 // Spore - Spore Visual
4868 ApplySpellFix({ 42525 }, [](SpellInfo* spellInfo)
4869 {
4870 spellInfo->AttributesEx3 |= SPELL_ATTR3_DEATH_PERSISTENT;
4871 spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_DEAD;
4872 });
4873
4874 // Death's Embrace
4875 ApplySpellFix({ 47198, 47199, 47200 }, [](SpellInfo* spellInfo)
4876 {
4877 spellInfo->_GetEffect(EFFECT_1).SpellClassMask[0] |= 0x00004000; // Drain soul
4878 });
4879
4880 // Soul Sickness (Forge of Souls)
4881 ApplySpellFix({ 69131 }, [](SpellInfo* spellInfo)
4882 {
4883 spellInfo->_GetEffect(EFFECT_1).ApplyAuraName = SPELL_AURA_MOD_DECREASE_SPEED;
4884 });
4885
4886 // Headless Horseman Climax - Return Head (Hallow End)
4887 // Headless Horseman Climax - Body Regen (confuse only - removed on death)
4888 // Headless Horseman Climax - Head Is Dead
4889 ApplySpellFix({ 42401, 43105, 42428 }, [](SpellInfo* spellInfo)
4890 {
4891 spellInfo->Attributes |= SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY;
4892 });
4893
4894 // Sacred Cleansing
4895 ApplySpellFix({ 53659 }, [](SpellInfo* spellInfo)
4896 {
4897 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(5); // 40yd
4898 });
4899
4900 // Pilgrim's Bounty - Candied Sweet Potato
4901 ApplySpellFix({ 65418 }, [](SpellInfo* spellInfo)
4902 {
4903 spellInfo->_GetEffect(EFFECT_2).TriggerSpell = 65410;
4904 });
4905
4906 // Pilgrim's Bounty - Spice Bread Stuffing
4907 ApplySpellFix({ 65419 }, [](SpellInfo* spellInfo)
4908 {
4909 spellInfo->_GetEffect(EFFECT_2).TriggerSpell = 65416;
4910 });
4911
4912 // Pilgrim's Bounty - Cranberry Chutney
4913 ApplySpellFix({ 65420 }, [](SpellInfo* spellInfo)
4914 {
4915 spellInfo->_GetEffect(EFFECT_2).TriggerSpell = 65412;
4916 });
4917
4918 // Pilgrim's Bounty - Pumpkin Pie
4919 ApplySpellFix({ 65421 }, [](SpellInfo* spellInfo)
4920 {
4921 spellInfo->_GetEffect(EFFECT_2).TriggerSpell = 65415;
4922 });
4923
4924 // Pilgrim's Bounty - Slow-Roasted Turkey
4925 ApplySpellFix({ 65422 }, [](SpellInfo* spellInfo)
4926 {
4927 spellInfo->_GetEffect(EFFECT_2).TriggerSpell = 65414;
4928 });
4929
4931 24869, // Bobbing Apple, Bread of the Dead, Winter Veil Cookie
4932 61874, // Noblegarden Chocolate
4933 71068, // Sweet Surprise
4934 71071, // Very Berry Cream
4935 71073, // Dark Desire
4936 71074 // Buttermilk Delight
4937 }, [](SpellInfo* spellInfo)
4938 {
4939 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_APPLY_AURA;
4940 spellInfo->_GetEffect(EFFECT_1).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
4941 spellInfo->_GetEffect(EFFECT_1).ApplyAuraName = SPELL_AURA_PERIODIC_TRIGGER_SPELL;
4942 spellInfo->_GetEffect(EFFECT_1).ApplyAuraPeriod = 10 * IN_MILLISECONDS;
4943 spellInfo->_GetEffect(EFFECT_1).TriggerSpell = 24870;
4944 });
4945
4946 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
4947 {
4948 SpellInfo* spellInfo = mSpellInfoMap[i];
4949 if (!spellInfo)
4950 continue;
4951
4952 // Fix range for trajectory triggered spell
4953 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4954 {
4955 if (spellEffectInfo.IsEffect() && (spellEffectInfo.TargetA.GetTarget() == TARGET_DEST_TRAJ || spellEffectInfo.TargetB.GetTarget() == TARGET_DEST_TRAJ))
4956 {
4957 // Get triggered spell if any
4958 if (SpellInfo* spellInfoTrigger = const_cast<SpellInfo*>(GetSpellInfo(spellEffectInfo.TriggerSpell)))
4959 {
4960 float maxRangeMain = spellInfo->RangeEntry ? spellInfo->RangeEntry->RangeMax[0] : 0.0f;
4961 float maxRangeTrigger = spellInfoTrigger->RangeEntry ? spellInfoTrigger->RangeEntry->RangeMax[0] : 0.0f;
4962
4963 // check if triggered spell has enough max range to cover trajectory
4964 if (maxRangeTrigger < maxRangeMain)
4965 spellInfoTrigger->RangeEntry = spellInfo->RangeEntry;
4966 }
4967 }
4968 }
4969
4970 for (SpellEffectInfo& spellEffectInfo : spellInfo->_GetEffects())
4971 {
4972 switch (spellEffectInfo.Effect)
4973 {
4976 case SPELL_EFFECT_JUMP:
4979 if (!spellInfo->Speed && !spellInfo->SpellFamilyName)
4980 spellInfo->Speed = SPEED_CHARGE;
4981 break;
4983 // special aura updates each 30 seconds
4984 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR)
4985 spellEffectInfo.ApplyAuraPeriod = 30 * IN_MILLISECONDS;
4986 break;
4987 default:
4988 break;
4989 }
4990
4991 // Passive talent auras cannot target pets
4992 if (spellInfo->IsPassive() && GetTalentSpellCost(i))
4993 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
4994 spellEffectInfo.TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
4995
4996 // Area auras may not target area (they're self cast)
4997 if (spellEffectInfo.IsAreaAuraEffect() && spellEffectInfo.IsTargetingArea())
4998 {
4999 spellEffectInfo.TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
5000 spellEffectInfo.TargetB = SpellImplicitTargetInfo(0);
5001 }
5002 }
5003
5004 // disable proc for magnet auras, they're handled differently
5005 if (spellInfo->HasAura(SPELL_AURA_SPELL_MAGNET))
5006 spellInfo->ProcFlags = 0;
5007
5008 // due to the way spell system works, unit would change orientation in Spell::_cast
5009 if (spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
5011
5012 if (spellInfo->ActiveIconID == 2158) // flight
5013 spellInfo->Attributes |= SPELL_ATTR0_PASSIVE;
5014
5015 switch (spellInfo->SpellFamilyName)
5016 {
5018 // Seals of the Pure should affect Seal of Righteousness
5019 if (spellInfo->SpellIconID == 25 && spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE))
5020 spellInfo->_GetEffect(EFFECT_0).SpellClassMask[1] |= 0x20000000;
5021 break;
5023 // Icy Touch - extend FamilyFlags (unused value) for Sigil of the Frozen Conscience to use
5024 if (spellInfo->SpellIconID == 2721 && spellInfo->SpellFamilyFlags[0] & 0x2)
5025 spellInfo->SpellFamilyFlags[0] |= 0x40;
5026 break;
5027 }
5028 }
5029
5030 if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(121)))
5031 properties->Title = SUMMON_TYPE_TOTEM;
5032 if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(647))) // 52893
5033 properties->Title = SUMMON_TYPE_TOTEM;
5034 if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(628))) // Hungry Plaguehound
5035 properties->Control = SUMMON_CATEGORY_PET;
5036
5037 if (LockEntry* entry = const_cast<LockEntry*>(sLockStore.LookupEntry(36))) // 3366 Opening, allows to open without proper key
5038 entry->Type[2] = LOCK_KEY_NONE;
5039
5040 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo corrections in {} ms", GetMSTimeDiffToNow(oldMSTime));
5041}
5042
5044{
5045 uint32 oldMSTime = getMSTime();
5046
5047 for (SpellInfo* spellInfo : mSpellInfoMap)
5048 {
5049 if (!spellInfo)
5050 continue;
5051
5052 // AuraState depends on SpellSpecific
5053 spellInfo->_LoadSpellSpecific();
5054 spellInfo->_LoadAuraState();
5055 }
5056
5057 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo SpellSpecific and AuraState in {} ms", GetMSTimeDiffToNow(oldMSTime));
5058}
5059
5061{
5062 uint32 oldMSTime = getMSTime();
5063
5064 for (SpellInfo* spellInfo : mSpellInfoMap)
5065 {
5066 if (!spellInfo)
5067 continue;
5068
5069 spellInfo->_LoadSpellDiminishInfo();
5070 }
5071
5072 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo diminishing infos in {} ms", GetMSTimeDiffToNow(oldMSTime));
5073}
5074
5076{
5077 uint32 oldMSTime = getMSTime();
5078
5079 for (SpellInfo* spellInfo : mSpellInfoMap)
5080 {
5081 if (!spellInfo)
5082 continue;
5083
5084 spellInfo->_LoadImmunityInfo();
5085 }
5086
5087 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo immunity infos in {} ms", GetMSTimeDiffToNow(oldMSTime));
5088}
#define sBattlefieldMgr
@ BATTLEFIELD_WG
Definition Battlefield.h:28
@ BATTLEFIELD_BATTLEID_WG
Definition Battlefield.h:34
@ IN_MILLISECONDS
Definition Common.h:35
@ ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL
Definition DBCEnums.h:356
@ DUNGEON_DIFFICULTY_HEROIC
Definition DBCEnums.h:283
#define MAX_DIFFICULTY
Definition DBCEnums.h:296
#define MAX_SPELL_REAGENTS
Definition DBCEnums.h:390
#define MAX_TALENT_RANK
Definition DBCEnums.h:432
@ SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN
Definition DBCEnums.h:350
@ AREA_FLAG_NO_FLY_ZONE
Definition DBCEnums.h:275
DBCStorage< SpellItemEnchantmentEntry > sSpellItemEnchantmentStore(SpellItemEnchantmentfmt)
DBCStorage< SpellRadiusEntry > sSpellRadiusStore(SpellRadiusfmt)
DBCStorage< SummonPropertiesEntry > sSummonPropertiesStore(SummonPropertiesfmt)
std::vector< SkillLineAbilityEntry const * > const * GetSkillLineAbilitiesBySkill(uint32 skillLine)
DBCStorage< LockEntry > sLockStore(LockEntryfmt)
DBCStorage< CreatureSpellDataEntry > sCreatureSpellDataStore(CreatureSpellDatafmt)
DBCStorage< SpellCastTimesEntry > sSpellCastTimesStore(SpellCastTimefmt)
DBCStorage< SpellRangeEntry > sSpellRangeStore(SpellRangefmt)
uint32 GetTalentSpellCost(uint32 spellId)
DBCStorage< SpellDifficultyEntry > sSpellDifficultyStore(SpellDifficultyfmt)
DBCStorage< SpellVisualEntry > sSpellVisualStore(SpellVisualfmt)
DBCStorage< SpellEntry > sSpellStore(SpellEntryfmt)
DBCStorage< SkillLineEntry > sSkillLineStore(SkillLinefmt)
DBCStorage< CreatureFamilyEntry > sCreatureFamilyStore(CreatureFamilyfmt)
DBCStorage< TalentEntry > sTalentStore(TalentEntryfmt)
DBCStorage< SpellDurationEntry > sSpellDurationStore(SpellDurationfmt)
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
DBCStorage< AreaTableEntry > sAreaTableStore(AreaTableEntryfmt)
DBCStorage< SkillLineAbilityEntry > sSkillLineAbilityStore(SkillLineAbilityfmt)
DBCStorage< LiquidTypeEntry > sLiquidTypeStore(LiquidTypefmt)
#define MAX_ITEM_ENCHANTMENT_EFFECTS
std::shared_ptr< ResultSet > QueryResult
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
#define UI64LIT(N)
Definition Define.h:118
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
#define ASSERT
Definition Errors.h:68
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#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:1721
std::unordered_map< uint32, CreatureTemplate > CreatureTemplateContainer
Definition ObjectMgr.h:535
SpellEffIndex
@ EFFECT_1
@ EFFECT_0
@ EFFECT_2
@ SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER
@ 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_ENCHANT_HELD_ITEM
@ SPELL_EFFECT_ENCHANT_ITEM
@ SPELL_EFFECT_HEALTH_LEECH
@ SPELL_EFFECT_SKILL
@ SPELL_EFFECT_WEAPON_DAMAGE
@ SPELL_EFFECT_HEAL
@ SPELL_EFFECT_NORMALIZED_WEAPON_DMG
@ SPELL_EFFECT_TRIGGER_SPELL
@ SPELL_EFFECT_HEAL_MAX_HEALTH
@ SPELL_EFFECT_APPLY_AREA_AURA_PET
@ SPELL_EFFECT_NONE
@ SPELL_EFFECT_JUMP_DEST
@ SPELL_EFFECT_PICKPOCKET
@ SPELL_EFFECT_HEAL_MECHANICAL
@ SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
@ SPELL_EFFECT_MODIFY_THREAT_PERCENT
@ SPELL_EFFECT_APPLY_AREA_AURA_RAID
@ SPELL_EFFECT_CREATE_ITEM_2
@ 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_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
@ SKILL_CATEGORY_PROFESSION
Gender
@ GENDER_MALE
@ GENDER_FEMALE
@ GENDER_NONE
@ SPELL_ATTR5_DONT_TURN_DURING_CAST
@ SPELL_ATTR5_START_PERIODIC_AT_APPLY
@ TARGET_DEST_CASTER_LEFT
@ TARGET_DEST_DB
@ TARGET_UNIT_CASTER_AREA_PARTY
@ TARGET_UNIT_SRC_AREA_ENTRY
@ TARGET_UNIT_SRC_AREA_ALLY
@ TARGET_UNIT_TARGET_ALLY
@ TARGET_UNIT_TARGET_ANY
@ TARGET_DEST_DEST
@ TARGET_UNIT_SRC_AREA_ENEMY
@ TARGET_UNIT_PET
@ TARGET_UNIT_TARGET_ENEMY
@ TARGET_UNIT_MASTER
@ 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_CAN_TARGET_DEAD
@ SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA
@ SPELL_ATTR2_CANT_CRIT
@ SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS
@ SPELL_ATTR1_NO_THREAT
@ SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY
@ SPELL_ATTR1_CANT_TARGET_SELF
@ SPELL_ATTR3_STACK_FOR_DIFF_CASTERS
@ SPELL_ATTR3_DEATH_PERSISTENT
@ SPELL_ATTR3_NO_DONE_BONUS
@ SPELL_ATTR3_NO_INITIAL_AGGRO
@ SPELL_ATTR3_CAN_PROC_FROM_PROCS
@ SPELL_ATTR3_CANT_TRIGGER_PROC
@ SPELL_ATTR3_IGNORE_HIT_RESULT
@ SPELL_DAMAGE_CLASS_MAGIC
@ TEAM_ALLIANCE
@ TEAM_HORDE
@ LOCK_KEY_NONE
@ SUMMON_TYPE_TOTEM
#define MAX_CREATURE_SPELL_DATA_SLOT
@ MECHANIC_NONE
@ MECHANIC_STUN
@ MECHANIC_BLEED
@ MECHANIC_SNARE
@ SPELLFAMILY_WARLOCK
@ SPELLFAMILY_MAGE
@ SPELLFAMILY_GENERIC
@ SPELLFAMILY_WARRIOR
@ SPELLFAMILY_PALADIN
@ SPELLFAMILY_DRUID
@ SPELLFAMILY_PET
@ SPELLFAMILY_DEATHKNIGHT
@ POWER_MANA
@ SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY
@ SPELL_ATTR0_NEGATIVE_1
@ SPELL_ATTR0_PASSIVE
@ SPELL_ATTR0_CANT_CANCEL
@ SPELL_ATTR0_NOT_SHAPESHIFT
#define RACEMASK_ALL_PLAYABLE
@ SPELL_ATTR4_FIXED_DAMAGE
@ SUMMON_CATEGORY_PET
@ SKILL_DUAL_WIELD
@ SKILL_RIDING
@ SKILL_ENCHANTING
@ SPELL_ATTR6_CAN_TARGET_INVISIBLE
@ SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS
@ SPELL_AURA_MOD_ATTACK_POWER
@ SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_ABILITY_IGNORE_AURASTATE
@ SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE
@ 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_PROC_TRIGGER_SPELL
@ SPELL_AURA_CONVERT_RUNE
@ SPELL_AURA_MOD_FEAR
@ SPELL_AURA_ADD_CASTER_HIT_TRIGGER
@ SPELL_AURA_ADD_FLAT_MODIFIER
@ SPELL_AURA_REFLECT_SPELLS
@ SPELL_AURA_CONTROL_VEHICLE
@ SPELL_AURA_MOD_MELEE_HASTE
@ 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_MOD_DAMAGE_PERCENT_DONE
@ SPELL_AURA_MOD_CHARM
@ SPELL_AURA_MOD_ROOT
@ SPELL_AURA_MOD_RANGED_HASTE
@ SPELL_AURA_MOD_POWER_COST_SCHOOL
@ SPELL_AURA_RAID_PROC_FROM_CHARGE
@ SPELL_AURA_MOD_DAMAGE_TAKEN
@ SPELL_AURA_MOD_TAUNT
@ SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT
@ SPELL_AURA_AOE_CHARM
@ SPELL_AURA_MOD_DECREASE_SPEED
@ SPELL_AURA_TRANSFORM
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL_WITH_VALUE
@ SPELL_AURA_MOD_WEAPON_CRIT_PERCENT
@ SPELL_AURA_SPELL_MAGNET
@ SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR
@ SPELL_AURA_PERIODIC_LEECH
@ SPELL_AURA_PROC_TRIGGER_DAMAGE
@ 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_PERIODIC_TRIGGER_SPELL_FROM_CLIENT
@ SPELL_AURA_MOD_STEALTH
@ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
@ SPELL_AURA_OVERRIDE_CLASS_SCRIPTS
@ 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_MOD_BLOCK_PERCENT
@ SPELL_AURA_MOD_STUN
@ SPELL_AURA_BIND_SIGHT
@ FORM_MOONKIN
@ FORM_CAT
@ FORM_TREE
@ AURA_INTERRUPT_FLAG_TAKE_DAMAGE
@ AURA_INTERRUPT_FLAG_CAST
@ AURA_INTERRUPT_FLAG_HITBYSPELL
@ AURA_INTERRUPT_FLAG_MOVE
@ AURA_INTERRUPT_FLAG_JUMP
@ SPELL_ATTR0_CU_IGNORE_ARMOR
Definition SpellInfo.h:156
@ SPELL_ATTR0_CU_ENCHANT_PROC
Definition SpellInfo.h:141
@ SPELL_ATTR0_CU_DIRECT_DAMAGE
Definition SpellInfo.h:149
@ SPELL_ATTR0_CU_CAN_CRIT
Definition SpellInfo.h:148
@ SPELL_ATTR0_CU_CONE_BACK
Definition SpellInfo.h:142
@ SPELL_ATTR0_CU_AURA_CANNOT_BE_SAVED
Definition SpellInfo.h:165
@ SPELL_ATTR0_CU_AURA_CC
Definition SpellInfo.h:146
@ SPELL_ATTR0_CU_CHARGE
Definition SpellInfo.h:150
@ SPELL_ATTR0_CU_NEGATIVE
Definition SpellInfo.h:168
@ SPELL_ATTR0_CU_NEEDS_AMMO_DATA
Definition SpellInfo.h:160
@ SPELL_ATTR0_CU_NEGATIVE_EFF0
Definition SpellInfo.h:153
@ SPELL_ATTR0_CU_BINARY_SPELL
Definition SpellInfo.h:161
@ SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC
Definition SpellInfo.h:162
@ SPELL_ATTR0_CU_PICKPOCKET
Definition SpellInfo.h:151
@ SPELL_ATTR0_CU_NO_INITIAL_THREAT
Definition SpellInfo.h:145
bool IsPrimaryProfessionSkill(uint32 skill)
Definition SpellMgr.cpp:35
bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
Definition SpellMgr.cpp:47
bool LoadPetDefaultSpells_helper(CreatureTemplate const *cInfo, PetDefaultSpellsEntry &petDefSpells)
void ApplySpellFix(std::initializer_list< uint32 > spellIds, void(*fix)(SpellInfo *))
bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
Definition SpellMgr.cpp:47
@ PROC_HIT_BLOCK
Definition SpellMgr.h:226
@ PROC_HIT_MISS
Definition SpellMgr.h:222
@ PROC_HIT_NONE
Definition SpellMgr.h:219
@ PROC_HIT_ABSORB
Definition SpellMgr.h:230
@ PROC_HIT_MASK_ALL
Definition SpellMgr.h:234
@ PROC_HIT_CRITICAL
Definition SpellMgr.h:221
@ PROC_HIT_NORMAL
Definition SpellMgr.h:220
@ PROC_HIT_REFLECT
Definition SpellMgr.h:231
std::pair< SpellsRequiringSpellMap::const_iterator, SpellsRequiringSpellMap::const_iterator > SpellsRequiringSpellMapBounds
Definition SpellMgr.h:513
std::pair< SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator > SpellSpellGroupMapBounds
Definition SpellMgr.h:318
std::pair< SpellAreaMap::const_iterator, SpellAreaMap::const_iterator > SpellAreaMapBounds
Definition SpellMgr.h:490
SpellGroup
Definition SpellMgr.h:293
@ SPELL_GROUP_CORE_RANGE_MAX
Definition SpellMgr.h:299
std::pair< SpellAreaForAreaMap::const_iterator, SpellAreaForAreaMap::const_iterator > SpellAreaForAreaMapBounds
Definition SpellMgr.h:493
@ PROC_ATTR_REQ_MANA_COST
Definition SpellMgr.h:241
@ PROC_ATTR_REQ_EXP_OR_HONOR
Definition SpellMgr.h:239
@ PROC_ATTR_TRIGGERED_CAN_PROC
Definition SpellMgr.h:240
@ PROC_ATTR_REQ_SPELLMOD
Definition SpellMgr.h:242
SpellGroupStackRule
Definition SpellMgr.h:325
@ SPELL_GROUP_STACK_RULE_DEFAULT
Definition SpellMgr.h:326
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition SpellMgr.h:329
@ SPELL_GROUP_STACK_RULE_MAX
Definition SpellMgr.h:331
#define sSpellMgr
Definition SpellMgr.h:738
std::pair< SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_iterator > SpellGroupSpellMapBounds
Definition SpellMgr.h:322
std::pair< SpellAreaForAuraMap::const_iterator, SpellAreaForAuraMap::const_iterator > SpellAreaForAuraMapBounds
Definition SpellMgr.h:492
std::pair< SkillLineAbilityMap::const_iterator, SkillLineAbilityMap::const_iterator > SkillLineAbilityMapBounds
Definition SpellMgr.h:537
@ PROC_SPELL_TYPE_NONE
Definition SpellMgr.h:201
@ PROC_SPELL_TYPE_MASK_ALL
Definition SpellMgr.h:205
@ PROC_SPELL_TYPE_DAMAGE
Definition SpellMgr.h:202
@ PROC_SPELL_TYPE_NO_DMG_HEAL
Definition SpellMgr.h:204
@ EFFECT_RADIUS_7_YARDS
Definition SpellMgr.h:391
@ EFFECT_RADIUS_100_YARDS
Definition SpellMgr.h:367
@ EFFECT_RADIUS_20_YARDS
Definition SpellMgr.h:364
@ EFFECT_RADIUS_60_YARDS
Definition SpellMgr.h:402
@ EFFECT_RADIUS_25_YARDS
Definition SpellMgr.h:375
@ EFFECT_RADIUS_5_YARDS
Definition SpellMgr.h:363
@ EFFECT_RADIUS_40_YARDS
Definition SpellMgr.h:378
@ EFFECT_RADIUS_3_YARDS
Definition SpellMgr.h:370
@ EFFECT_RADIUS_50_YARDS
Definition SpellMgr.h:382
@ EFFECT_RADIUS_50000_YARDS
Definition SpellMgr.h:383
@ EFFECT_RADIUS_200_YARDS
Definition SpellMgr.h:377
@ EFFECT_RADIUS_12_YARDS
Definition SpellMgr.h:387
@ EFFECT_RADIUS_10_YARDS
Definition SpellMgr.h:368
@ EFFECT_RADIUS_150_YARDS
Definition SpellMgr.h:395
@ EFFECT_RADIUS_6_YARDS
Definition SpellMgr.h:384
@ PROC_SPELL_PHASE_FINISH
Definition SpellMgr.h:213
@ PROC_SPELL_PHASE_CAST
Definition SpellMgr.h:211
@ PROC_SPELL_PHASE_HIT
Definition SpellMgr.h:212
@ PROC_SPELL_PHASE_MASK_ALL
Definition SpellMgr.h:214
@ TAKEN_HIT_PROC_FLAG_MASK
Definition SpellMgr.h:181
@ PROC_FLAG_KILLED
Definition SpellMgr.h:115
@ PROC_FLAG_DEATH
Definition SpellMgr.h:151
@ REQ_SPELL_PHASE_PROC_FLAG_MASK
Definition SpellMgr.h:187
@ PROC_FLAG_KILL
Definition SpellMgr.h:116
@ SPELL_PROC_FLAG_MASK
Definition SpellMgr.h:164
@ DONE_HIT_PROC_FLAG_MASK
Definition SpellMgr.h:174
std::pair< SpellAreaForQuestMap::const_iterator, SpellAreaForQuestMap::const_iterator > SpellAreaForQuestMapBounds
Definition SpellMgr.h:491
std::pair< SpellLearnSpellMap::const_iterator, SpellLearnSpellMap::const_iterator > SpellLearnSpellMapBounds
Definition SpellMgr.h:534
#define SPELL_LINKED_MAX_SPELLS
Definition SpellMgr.h:100
std::multimap< uint32, uint32 > PetLevelupSpellSet
Definition SpellMgr.h:539
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
bool CanFlyIn()
Return if we can use mount in battlefield.
virtual uint32 GetData(uint32 dataId) const override
uint32 GetTypeId() const
void PSendSysMessage(char const *fmt, Args &&... args)
Definition Chat.h:69
Class used to access individual fields of database query result.
Definition Field.h:92
uint8 GetUInt8() const
Definition Field.cpp:29
int8 GetInt8() const
Definition Field.cpp:37
uint16 GetUInt16() const
Definition Field.cpp:45
float GetFloat() const
Definition Field.cpp:93
bool GetBool() const
Definition Field.h:100
uint32 GetUInt32() const
Definition Field.cpp:61
int32 GetInt32() const
Definition Field.cpp:69
bool IsDungeon() const
Definition Map.cpp:4236
uint8 GetSpawnMode() const
Definition Map.h:388
bool IsBattleground() const
Definition Map.cpp:4267
static Player * ToPlayer(Object *o)
Definition Object.h:180
Gender GetNativeGender() const override
Definition Player.h:1039
WorldSession * GetSession() const
Definition Player.h:1719
TeamId GetTeamId() const
Definition Player.h:1833
Battleground * GetBattleground() const
Definition Player.cpp:23049
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition Player.cpp:15642
uint32 GetHitMask() const
Definition Unit.h:514
SpellSchoolMask GetSchoolMask() const
Definition Unit.cpp:279
Unit * GetActionTarget() const
Definition Unit.h:509
uint32 GetSpellTypeMask() const
Definition Unit.h:512
uint32 GetTypeMask() const
Definition Unit.h:511
SpellInfo const * GetSpellInfo() const
Definition Unit.cpp:268
Unit * GetActor()
Definition Unit.h:508
uint32 GetSpellPhaseMask() const
Definition Unit.h:513
AuraType ApplyAuraName
Definition SpellInfo.h:211
SpellEffects Effect
Definition SpellInfo.h:210
flag96 SpellClassMask
Definition SpellInfo.h:229
int32 CalcValue(WorldObject const *caster=nullptr, int32 const *basePoints=nullptr) const
SpellImplicitTargetInfo TargetA
Definition SpellInfo.h:223
SpellImplicitTargetInfo TargetB
Definition SpellInfo.h:224
Targets GetTarget() const
uint32 SpellLevel
Definition SpellInfo.h:329
bool IsRankOf(SpellInfo const *spellInfo) const
std::array< int32, MAX_SPELL_REAGENTS > Reagent
Definition SpellInfo.h:342
SpellInfo const * GetFirstRankSpell() const
flag96 SpellFamilyFlags
Definition SpellInfo.h:357
uint32 AttributesCu
Definition SpellInfo.h:301
SpellEffectInfo & _GetEffect(SpellEffIndex index)
Definition SpellInfo.h:510
bool IsPassive() const
uint32 Id
Definition SpellInfo.h:289
uint8 GetRank() const
SpellRangeEntry const * RangeEntry
Definition SpellInfo.h:338
uint32 ProcCharges
Definition SpellInfo.h:326
bool IsLootCrafting() const
bool IsRanked() const
uint32 ActiveIconID
Definition SpellInfo.h:350
float Speed
Definition SpellInfo.h:339
std::array< SpellEffectInfo, MAX_SPELL_EFFECTS > & _GetEffects()
Definition SpellInfo.h:509
uint32 ProcFlags
Definition SpellInfo.h:324
bool HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:375
uint32 Attributes
Definition SpellInfo.h:293
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition SpellInfo.h:483
uint32 SpellIconID
Definition SpellInfo.h:349
SpellInfo const * GetNextRankSpell() const
bool HasEffect(SpellEffects effect) const
uint32 ProcChance
Definition SpellInfo.h:325
uint32 AttributesEx5
Definition SpellInfo.h:298
bool HasAura(AuraType aura) const
std::array< SpellEffectInfo, MAX_SPELL_EFFECTS > const & GetEffects() const
Definition SpellInfo.h:482
uint32 SpellFamilyName
Definition SpellInfo.h:356
SpellRequiredMap mSpellReq
Definition SpellMgr.h:710
static bool CanSpellTriggerProcOnEvent(SpellProcEntry const &procEntry, ProcEventInfo &eventInfo)
Definition SpellMgr.cpp:501
SpellLinkedMap mSpellLinkedMap
Definition SpellMgr.h:722
SpellInfo const * AssertSpellInfo(uint32 spellId) const
Definition SpellMgr.h:661
SpellGroupStackRule GetSpellGroupStackRule(SpellGroup groupid) const
Definition SpellMgr.cpp:484
void LoadSpellLinked()
SkillLineAbilityMap mSkillLineAbilityMap
Definition SpellMgr.h:730
SpellAreaMapBounds GetSpellAreaMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:647
EnchantCustomAttribute mEnchantCustomAttr
Definition SpellMgr.h:724
void SetSpellDifficultyId(uint32 spellId, uint32 id)
Definition SpellMgr.cpp:168
SpellLearnSpellMapBounds GetSpellLearnSpellMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:327
PetLevelupSpellSet const * GetPetLevelupSpellList(uint32 petFamily) const
Definition SpellMgr.cpp:630
void LoadSpellInfoStore()
void LoadSpellBonuses()
SpellAreaForQuestMapBounds GetSpellAreaForQuestEndMapBounds(uint32 quest_id) const
Definition SpellMgr.cpp:657
SpellAreaForAuraMap mSpellAreaForAuraMap
Definition SpellMgr.h:728
SpellChainMap mSpellChains
Definition SpellMgr.h:708
void LoadEnchantCustomAttr()
void UnloadSpellInfoStore()
void LoadSpellAreas()
uint32 GetNextSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:259
static SpellMgr * instance()
Definition SpellMgr.cpp:64
SpellPetAuraMap mSpellPetAuraMap
Definition SpellMgr.h:721
SpellLearnSkillMap mSpellLearnSkills
Definition SpellMgr.h:711
SpellInfo const * GetSpellForDifficultyFromSpell(SpellInfo const *spell, WorldObject const *caster) const
Definition SpellMgr.cpp:217
SpellAreaForQuestMapBounds GetSpellAreaForQuestMapBounds(uint32 quest_id) const
Definition SpellMgr.cpp:652
SpellBonusEntry const * GetSpellBonusData(uint32 spellId) const
Definition SpellMgr.cpp:567
void LoadSkillLineAbilityMap()
SkillLineAbilityMapBounds GetSkillLineAbilityMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:598
SpellAreaForQuestMap mSpellAreaForQuestEndMap
Definition SpellMgr.h:727
SpellGroupSpellMapBounds GetSpellGroupSpellMapBounds(SpellGroup group_id) const
Definition SpellMgr.cpp:371
PetDefaultSpellsMap mPetDefaultSpellsMap
Definition SpellMgr.h:732
uint32 GetSpellWithRank(uint32 spell_id, uint32 rank, bool strict=false) const
Definition SpellMgr.cpp:285
SpellLearnSkillNode const * GetSpellLearnSkill(uint32 spell_id) const
Definition SpellMgr.cpp:318
void LoadSpellInfoCustomAttributes()
SpellInfo const * GetSpellInfo(uint32 spellId) const
Definition SpellMgr.h:659
uint32 GetPrevSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:268
bool IsSpellRequiringSpell(uint32 spellid, uint32 req_spellid) const
Definition SpellMgr.cpp:307
void LoadSpellThreats()
bool IsSpellLearnToSpell(uint32 spell_id1, uint32 spell_id2) const
Definition SpellMgr.cpp:337
SpellAreaForAuraMapBounds GetSpellAreaForAuraMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:662
void LoadSpellInfoDiminishing()
void LoadSpellRequired()
Definition SpellMgr.cpp:959
void LoadSpellTargetPositions()
SpellDifficultySearcherMap mSpellDifficultySearcherMap
Definition SpellMgr.h:707
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set< uint32 > &foundSpells) const
Definition SpellMgr.cpp:376
void LoadSpellInfoImmunities()
void LoadSpellLearnSkills()
uint32 GetLastSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:251
void LoadSpellTalentRanks()
Definition SpellMgr.cpp:782
bool IsSpellLearnSpell(uint32 spell_id) const
Definition SpellMgr.cpp:332
SpellThreatEntry const * GetSpellThreatEntry(uint32 spellID) const
Definition SpellMgr.cpp:583
void LoadSpellGroupStackRules()
SpellGroupStackMap mSpellGroupStack
Definition SpellMgr.h:716
uint32 GetSpellIdForDifficulty(uint32 spellId, WorldObject const *caster) const
Definition SpellMgr.cpp:175
uint32 GetFirstSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:243
SpellEnchantProcEventMap mSpellEnchantProcEventMap
Definition SpellMgr.h:723
void LoadPetDefaultSpells()
PetLevelupSpellMap mPetLevelupSpellMap
Definition SpellMgr.h:731
void LoadSpellLearnSpells()
Trinity::IteratorPair< SpellRequiredMap::const_iterator > GetSpellsRequiredForSpellBounds(uint32 spell_id) const
Definition SpellMgr.cpp:297
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const *spellInfo1, SpellInfo const *spellInfo2) const
Definition SpellMgr.cpp:437
SpellProcMap mSpellProcMap
Definition SpellMgr.h:718
SpellsRequiringSpellMap mSpellsReqSpell
Definition SpellMgr.h:709
void LoadSpellInfoCorrections()
SpellTargetPositionMap mSpellTargetPositions
Definition SpellMgr.h:713
SpellProcEntry const * GetSpellProcEntry(uint32 spellId) const
Definition SpellMgr.cpp:493
SpellGroupSpellMap mSpellGroupSpell
Definition SpellMgr.h:715
PetDefaultSpellsEntry const * GetPetDefaultSpellsEntry(int32 id) const
Definition SpellMgr.cpp:639
SpellTargetPosition const * GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const
Definition SpellMgr.cpp:346
SameEffectStackMap mSpellSameEffectStack
Definition SpellMgr.h:717
std::vector< int32 > const * GetSpellLinked(int32 spell_id) const
Definition SpellMgr.cpp:625
SpellEnchantProcEntry const * GetSpellEnchantProcEvent(uint32 enchId) const
Definition SpellMgr.cpp:612
SpellAreaForAreaMap mSpellAreaForAreaMap
Definition SpellMgr.h:729
uint32 GetSpellDifficultyId(uint32 spellId) const
Definition SpellMgr.cpp:162
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:71
uint8 GetSpellRank(uint32 spell_id) const
Definition SpellMgr.cpp:277
void LoadSpellPetAuras()
void UnloadSpellInfoImplicitTargetConditionLists()
SpellSpellGroupMapBounds GetSpellSpellGroupMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:354
SpellAreaMap mSpellAreaMap
Definition SpellMgr.h:725
void LoadSpellEnchantProcData()
uint32 GetSpellInfoStoreSize() const
Definition SpellMgr.h:668
SpellBonusMap mSpellBonusMap
Definition SpellMgr.h:719
SpellChainNode const * GetSpellChainNode(uint32 spell_id) const
Definition SpellMgr.cpp:234
SpellsRequiringSpellMapBounds GetSpellsRequiringSpellBounds(uint32 spell_id) const
Definition SpellMgr.cpp:302
void LoadSpellRanks()
Definition SpellMgr.cpp:843
bool AddSameEffectStackRuleSpellGroups(SpellInfo const *spellInfo, uint32 auraType, int32 amount, std::map< SpellGroup, int32 > &groups) const
Definition SpellMgr.cpp:403
void LoadSpellGroups()
void LoadPetLevelupSpellMap()
SpellLearnSpellMap mSpellLearnSpells
Definition SpellMgr.h:712
void LoadSpellInfoSpellSpecificAndAuraState()
SpellSpellGroupMap mSpellSpellGroup
Definition SpellMgr.h:714
PetAura const * GetPetAura(uint32 spell_id, uint8 eff) const
Definition SpellMgr.cpp:603
SpellAreaForAreaMapBounds GetSpellAreaForAreaMapBounds(uint32 area_id) const
Definition SpellMgr.cpp:667
bool IsArenaAllowedEnchancment(uint32 ench_id) const
Definition SpellMgr.cpp:620
SpellThreatMap mSpellThreatMap
Definition SpellMgr.h:720
SpellAreaForQuestMap mSpellAreaForQuestMap
Definition SpellMgr.h:726
SpellInfoMap mSpellInfoMap
Definition SpellMgr.h:733
void LoadSpellProcs()
SpellInfo * _GetSpellInfo(uint32 spellId)
Definition SpellMgr.h:671
void UnloadSpellInfoChains()
Definition SpellMgr.cpp:774
bool IsSpellMemberOfSpellGroup(uint32 spellid, SpellGroup groupid) const
Definition SpellMgr.cpp:360
Utility class to enable range for loop syntax for multimap.equal_range uses.
uint32 GetRaceMask() const
Definition Unit.h:894
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4535
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4542
Map * GetMap() const
Definition Object.h:449
uint32 GetAreaId() const
Definition Object.h:374
uint32 GetZoneId() const
Definition Object.h:373
Definition Util.h:412
auto MapEqualRange(M &map, typename M::key_type const &key)
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition MapUtils.h:29
uint32 Spells[MAX_CREATURE_SPELL_DATA_SLOT]
CreatureFamily family
uint32 spells[MAX_CREATURE_SPELLS]
uint32 spellid[MAX_CREATURE_SPELL_DATA_SLOT]
Definition SpellMgr.h:546
uint32 questEnd
Definition SpellMgr.h:474
bool autocast
Definition SpellMgr.h:480
uint32 raceMask
Definition SpellMgr.h:476
uint32 questStartStatus
Definition SpellMgr.h:478
uint32 spellId
Definition SpellMgr.h:471
uint32 questEndStatus
Definition SpellMgr.h:479
int32 auraSpell
Definition SpellMgr.h:475
bool IsFitToRequirements(Player const *player, uint32 newZone, uint32 newArea) const
Definition SpellMgr.cpp:672
Gender gender
Definition SpellMgr.h:477
uint32 areaId
Definition SpellMgr.h:472
uint32 questStart
Definition SpellMgr.h:473
float ap_dot_bonus
Definition SpellMgr.h:287
float direct_damage
Definition SpellMgr.h:284
SpellInfo const * last
Definition SpellMgr.h:501
SpellInfo const * next
Definition SpellMgr.h:499
SpellInfo const * first
Definition SpellMgr.h:500
SpellInfo const * prev
Definition SpellMgr.h:498
int32 DifficultySpellID[MAX_DIFFICULTY]
uint32 Effect[MAX_ITEM_ENCHANTMENT_EFFECTS]
uint32 EffectArg[MAX_ITEM_ENCHANTMENT_EFFECTS]
uint32 SpellFamilyName
Definition SpellMgr.h:250
float ProcsPerMinute
Definition SpellMgr.h:258
Milliseconds Cooldown
Definition SpellMgr.h:260
uint32 Charges
Definition SpellMgr.h:261
uint32 AttributesMask
Definition SpellMgr.h:256
flag96 SpellFamilyMask
Definition SpellMgr.h:251
uint32 HitMask
Definition SpellMgr.h:255
uint32 SpellTypeMask
Definition SpellMgr.h:253
uint32 ProcFlags
Definition SpellMgr.h:252
uint32 SpellPhaseMask
Definition SpellMgr.h:254
uint32 SchoolMask
Definition SpellMgr.h:249
uint32 DisableEffectsMask
Definition SpellMgr.h:257
std::array< uint32, MAX_TALENT_RANK > SpellRank