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 SpellInfo const* learnedSpellInfo = GetSpellInfo(node.Spell);
1099 if (!learnedSpellInfo)
1100 {
1101 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_learn_spell` learning non-existing spell {}.", spell_id, node.Spell);
1102 continue;
1103 }
1104
1105 if (learnedSpellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT))
1106 {
1107 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_learn_spell` attempts learning talent spell {}, skipped.", spell_id, node.Spell);
1108 continue;
1109 }
1110
1111 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell_id, node));
1112
1113 ++count;
1114 } while (result->NextRow());
1115
1116 // search auto-learned spells and add its to map also for use in unlearn spells/talents
1117 uint32 dbc_count = 0;
1118 for (uint32 spell = 0; spell < GetSpellInfoStoreSize(); ++spell)
1119 {
1120 SpellInfo const* entry = GetSpellInfo(spell);
1121
1122 if (!entry)
1123 continue;
1124
1125 for (SpellEffectInfo const& spellEffectInfo : entry->GetEffects())
1126 {
1127 if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL))
1128 {
1129 SpellLearnSpellNode dbc_node;
1130 dbc_node.Spell = spellEffectInfo.TriggerSpell;
1131 dbc_node.Active = true; // all dbc based learned spells is active (show in spell book or hide by client itself)
1132
1133 // ignore learning not existed spells (broken/outdated/or generic learnig spell 483
1134 if (!GetSpellInfo(dbc_node.Spell))
1135 continue;
1136
1137 // talent or passive spells or skill-step spells auto-cast and not need dependent learning,
1138 // pet teaching spells must not be dependent learning (cast)
1139 // other required explicit dependent learning
1140 dbc_node.AutoLearned = spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET || entry->HasAttribute(SPELL_ATTR0_CU_IS_TALENT) || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
1141
1143
1144 bool found = false;
1145 for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
1146 {
1147 if (itr->second.Spell == dbc_node.Spell)
1148 {
1149 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.",
1150 spell, dbc_node.Spell);
1151 found = true;
1152 break;
1153 }
1154 }
1155
1156 if (!found) // add new spell-spell pair if not found
1157 {
1158 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell, dbc_node));
1159 ++dbc_count;
1160 }
1161 }
1162 }
1163 }
1164
1165 TC_LOG_INFO("server.loading", ">> Loaded {} spell learn spells + {} found in DBC in {} ms", count, dbc_count, GetMSTimeDiffToNow(oldMSTime));
1166}
1167
1169{
1170 uint32 oldMSTime = getMSTime();
1171
1172 mSpellTargetPositions.clear(); // need for reload case
1173
1174 // 0 1 2 3 4 5 6
1175 QueryResult result = WorldDatabase.Query("SELECT ID, EffectIndex, MapID, PositionX, PositionY, PositionZ, Orientation FROM spell_target_position");
1176 if (!result)
1177 {
1178 TC_LOG_INFO("server.loading", ">> Loaded 0 spell target coordinates. DB table `spell_target_position` is empty.");
1179 return;
1180 }
1181
1182 uint32 count = 0;
1183 do
1184 {
1185 Field* fields = result->Fetch();
1186
1187 uint32 spellId = fields[0].GetUInt32();
1188 SpellEffIndex effIndex = SpellEffIndex(fields[1].GetUInt8());
1189
1191
1192 st.target_mapId = fields[2].GetUInt16();
1193 st.target_X = fields[3].GetFloat();
1194 st.target_Y = fields[4].GetFloat();
1195 st.target_Z = fields[5].GetFloat();
1196 st.target_Orientation = fields[6].GetFloat();
1197
1198 MapEntry const* mapEntry = sMapStore.LookupEntry(st.target_mapId);
1199 if (!mapEntry)
1200 {
1201 TC_LOG_ERROR("sql.sql", "Spell (Id: {}, EffectIndex: {}) is using a non-existant MapID (ID: {}).", spellId, effIndex, st.target_mapId);
1202 continue;
1203 }
1204
1205 if (st.target_X==0 && st.target_Y==0 && st.target_Z==0)
1206 {
1207 TC_LOG_ERROR("sql.sql", "Spell (Id: {}, EffectIndex: {}): target coordinates not provided.", spellId, effIndex);
1208 continue;
1209 }
1210
1211 SpellInfo const* spellInfo = GetSpellInfo(spellId);
1212 if (!spellInfo)
1213 {
1214 TC_LOG_ERROR("sql.sql", "Spell (Id: {}) listed in `spell_target_position` does not exist.", spellId);
1215 continue;
1216 }
1217
1218 if (spellInfo->GetEffect(effIndex).TargetA.GetTarget() == TARGET_DEST_DB || spellInfo->GetEffect(effIndex).TargetB.GetTarget() == TARGET_DEST_DB)
1219 {
1220 std::pair<uint32, SpellEffIndex> key = std::make_pair(spellId, effIndex);
1221 mSpellTargetPositions[key] = st;
1222 ++count;
1223 }
1224 else
1225 {
1226 TC_LOG_ERROR("sql.sql", "Spell (Id: {}, EffectIndex: {}) listed in `spell_target_position` does not have target TARGET_DEST_DB (17).", spellId, effIndex);
1227 continue;
1228 }
1229
1230 } while (result->NextRow());
1231
1232 /*
1233 // Check all spells
1234 for (SpellInfo const* spellInfo : mSpellInfoMap)
1235 {
1236 for (SpellEffectInfo const& effect : spellInfo->GetEffects())
1237 {
1238 if (effect.TargetA.GetTarget() != TARGET_DEST_DB && effect.TargetB.GetTarget() != TARGET_DEST_DB)
1239 continue;
1240
1241 if (!GetSpellTargetPosition(spellInfo->Id, effect.EffectIndex))
1242 TC_LOG_DEBUG("spells", "Spell (Id: {}, EffectIndex: {}) does not have record in `spell_target_position`.", spellInfo.Id, effect.EffectIndex);
1243 }
1244 }
1245 */
1246
1247 TC_LOG_INFO("server.loading", ">> Loaded {} spell teleport coordinates in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1248}
1249
1251{
1252 uint32 oldMSTime = getMSTime();
1253
1254 mSpellSpellGroup.clear(); // need for reload case
1255 mSpellGroupSpell.clear();
1256
1257 // 0 1
1258 QueryResult result = WorldDatabase.Query("SELECT id, spell_id FROM spell_group");
1259 if (!result)
1260 {
1261 TC_LOG_INFO("server.loading", ">> Loaded 0 spell group definitions. DB table `spell_group` is empty.");
1262 return;
1263 }
1264
1265 std::set<uint32> groups;
1266 uint32 count = 0;
1267 do
1268 {
1269 Field* fields = result->Fetch();
1270
1271 uint32 group_id = fields[0].GetUInt32();
1272 if (group_id <= SPELL_GROUP_DB_RANGE_MIN && group_id >= SPELL_GROUP_CORE_RANGE_MAX)
1273 {
1274 TC_LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` is in core range, but is not defined in core!", group_id);
1275 continue;
1276 }
1277 int32 spell_id = fields[1].GetInt32();
1278
1279 groups.insert(group_id);
1280 mSpellGroupSpell.emplace(SpellGroup(group_id), spell_id);
1281
1282 } while (result->NextRow());
1283
1284 for (auto itr = mSpellGroupSpell.begin(); itr!= mSpellGroupSpell.end();)
1285 {
1286 if (itr->second < 0)
1287 {
1288 if (groups.find(abs(itr->second)) == groups.end())
1289 {
1290 TC_LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group` does not exist", abs(itr->second));
1291 itr = mSpellGroupSpell.erase(itr);
1292 }
1293 else
1294 ++itr;
1295 }
1296 else
1297 {
1298 SpellInfo const* spellInfo = GetSpellInfo(itr->second);
1299 if (!spellInfo)
1300 {
1301 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_group` does not exist", itr->second);
1302 itr = mSpellGroupSpell.erase(itr);
1303 }
1304 else if (spellInfo->GetRank() > 1)
1305 {
1306 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_group` is not the first rank of the spell.", itr->second);
1307 itr = mSpellGroupSpell.erase(itr);
1308 }
1309 else
1310 ++itr;
1311 }
1312 }
1313
1314 for (auto groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
1315 {
1316 std::set<uint32> spells;
1317 GetSetOfSpellsInSpellGroup(SpellGroup(*groupItr), spells);
1318
1319 for (auto spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
1320 {
1321 ++count;
1322 mSpellSpellGroup.emplace(*spellItr, SpellGroup(*groupItr));
1323 }
1324 }
1325
1326 TC_LOG_INFO("server.loading", ">> Loaded {} spell group definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1327}
1328
1330{
1331 uint32 oldMSTime = getMSTime();
1332
1333 mSpellGroupStack.clear(); // need for reload case
1334 mSpellSameEffectStack.clear();
1335
1336 std::vector<uint32> sameEffectGroups;
1337
1338 // 0 1
1339 QueryResult result = WorldDatabase.Query("SELECT group_id, stack_rule FROM spell_group_stack_rules");
1340 if (!result)
1341 {
1342 TC_LOG_INFO("server.loading", ">> Loaded 0 spell group stack rules. DB table `spell_group_stack_rules` is empty.");
1343 return;
1344 }
1345
1346 uint32 count = 0;
1347 do
1348 {
1349 Field* fields = result->Fetch();
1350
1351 uint32 group_id = fields[0].GetUInt32();
1352 uint8 stack_rule = fields[1].GetInt8();
1353 if (stack_rule >= SPELL_GROUP_STACK_RULE_MAX)
1354 {
1355 TC_LOG_ERROR("sql.sql", "SpellGroupStackRule {} listed in `spell_group_stack_rules` does not exist.", stack_rule);
1356 continue;
1357 }
1358
1359 auto bounds = GetSpellGroupSpellMapBounds((SpellGroup)group_id);
1360 if (bounds.first == bounds.second)
1361 {
1362 TC_LOG_ERROR("sql.sql", "SpellGroup id {} listed in `spell_group_stack_rules` does not exist.", group_id);
1363 continue;
1364 }
1365
1366 mSpellGroupStack.emplace(SpellGroup(group_id), SpellGroupStackRule(stack_rule));
1367
1368 // different container for same effect stack rules, need to check effect types
1370 sameEffectGroups.push_back(group_id);
1371
1372 ++count;
1373 } while (result->NextRow());
1374
1375 TC_LOG_INFO("server.loading", ">> Loaded {} spell group stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1376
1377 count = 0;
1378 oldMSTime = getMSTime();
1379 TC_LOG_INFO("server.loading", ">> Parsing SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules...");
1380
1381 for (uint32 group_id : sameEffectGroups)
1382 {
1383 std::set<uint32> spellIds;
1384 GetSetOfSpellsInSpellGroup(SpellGroup(group_id), spellIds);
1385
1386 std::unordered_set<uint32> auraTypes;
1387
1388 // we have to 'guess' what effect this group corresponds to
1389 {
1390 std::unordered_multiset<uint32 /*auraName*/> frequencyContainer;
1391
1392 // only waylay for the moment (shared group)
1393 std::vector<std::vector<uint32 /*auraName*/>> const SubGroups =
1394 {
1396 };
1397
1398 for (uint32 spellId : spellIds)
1399 {
1400 SpellInfo const* spellInfo = AssertSpellInfo(spellId);
1401 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1402 {
1403 if (!spellEffectInfo.IsAura())
1404 continue;
1405
1406 uint32 auraName = spellEffectInfo.ApplyAuraName;
1407 for (std::vector<uint32> const& subGroup : SubGroups)
1408 {
1409 if (std::find(subGroup.begin(), subGroup.end(), auraName) != subGroup.end())
1410 {
1411 // count as first aura
1412 auraName = subGroup.front();
1413 break;
1414 }
1415 }
1416
1417 frequencyContainer.insert(auraName);
1418 }
1419 }
1420
1421 uint32 auraType = 0;
1422 size_t auraTypeCount = 0;
1423 for (uint32 auraName : frequencyContainer)
1424 {
1425 size_t currentCount = frequencyContainer.count(auraName);
1426 if (currentCount > auraTypeCount)
1427 {
1428 auraType = auraName;
1429 auraTypeCount = currentCount;
1430 }
1431 }
1432
1433 for (std::vector<uint32> const& subGroup : SubGroups)
1434 {
1435 if (auraType == subGroup.front())
1436 {
1437 auraTypes.insert(subGroup.begin(), subGroup.end());
1438 break;
1439 }
1440 }
1441
1442 if (auraTypes.empty())
1443 auraTypes.insert(auraType);
1444 }
1445
1446 // re-check spells against guessed group
1447 for (uint32 spellId : spellIds)
1448 {
1449 SpellInfo const* spellInfo = AssertSpellInfo(spellId);
1450
1451 bool found = false;
1452 while (spellInfo)
1453 {
1454 for (uint32 auraType : auraTypes)
1455 {
1456 if (spellInfo->HasAura(AuraType(auraType)))
1457 {
1458 found = true;
1459 break;
1460 }
1461 }
1462
1463 if (found)
1464 break;
1465
1466 spellInfo = spellInfo->GetNextRankSpell();
1467 }
1468
1469 // not found either, log error
1470 if (!found)
1471 TC_LOG_ERROR("sql.sql", "SpellId {} listed in `spell_group` with stack rule 3 does not share aura assigned for group {}", spellId, group_id);
1472 }
1473
1474 mSpellSameEffectStack[SpellGroup(group_id)] = auraTypes;
1475 ++count;
1476 }
1477
1478 TC_LOG_INFO("server.loading", ">> Parsed {} SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT stack rules in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1479}
1480
1482{
1483 uint32 oldMSTime = getMSTime();
1484
1485 mSpellProcMap.clear(); // need for reload case
1486
1487 // 0 1 2 3 4 5
1488 QueryResult result = WorldDatabase.Query("SELECT SpellId, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, "
1489 // 6 7 8 9 10 11 12 13 14 15
1490 "ProcFlags, SpellTypeMask, SpellPhaseMask, HitMask, AttributesMask, DisableEffectsMask, ProcsPerMinute, Chance, Cooldown, Charges FROM spell_proc");
1491
1492 uint32 count = 0;
1493 if (result)
1494 {
1495 do
1496 {
1497 Field* fields = result->Fetch();
1498
1499 int32 spellId = fields[0].GetInt32();
1500
1501 bool allRanks = false;
1502 if (spellId < 0)
1503 {
1504 allRanks = true;
1505 spellId = -spellId;
1506 }
1507
1508 SpellInfo const* spellInfo = GetSpellInfo(spellId);
1509 if (!spellInfo)
1510 {
1511 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` does not exist", spellId);
1512 continue;
1513 }
1514
1515 if (allRanks)
1516 {
1517 if (!spellInfo->IsRanked())
1518 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` with all ranks, but spell has no ranks.", spellId);
1519
1520 if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
1521 {
1522 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` is not the first rank of the spell.", spellId);
1523 continue;
1524 }
1525 }
1526
1527 SpellProcEntry baseProcEntry;
1528
1529 baseProcEntry.SchoolMask = fields[1].GetInt8();
1530 baseProcEntry.SpellFamilyName = fields[2].GetUInt16();
1531 baseProcEntry.SpellFamilyMask[0] = fields[3].GetUInt32();
1532 baseProcEntry.SpellFamilyMask[1] = fields[4].GetUInt32();
1533 baseProcEntry.SpellFamilyMask[2] = fields[5].GetUInt32();
1534 baseProcEntry.ProcFlags = fields[6].GetUInt32();
1535 baseProcEntry.SpellTypeMask = fields[7].GetUInt32();
1536 baseProcEntry.SpellPhaseMask = fields[8].GetUInt32();
1537 baseProcEntry.HitMask = fields[9].GetUInt32();
1538 baseProcEntry.AttributesMask = fields[10].GetUInt32();
1539 baseProcEntry.DisableEffectsMask = fields[11].GetUInt32();
1540 baseProcEntry.ProcsPerMinute = fields[12].GetFloat();
1541 baseProcEntry.Chance = fields[13].GetFloat();
1542 baseProcEntry.Cooldown = Milliseconds(fields[14].GetUInt32());
1543 baseProcEntry.Charges = fields[15].GetUInt8();
1544
1545 while (spellInfo)
1546 {
1547 if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
1548 {
1549 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_proc` already has its first rank in the table.", spellInfo->Id);
1550 break;
1551 }
1552
1553 SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
1554
1555 // take defaults from dbcs
1556 if (!procEntry.ProcFlags)
1557 procEntry.ProcFlags = spellInfo->ProcFlags;
1558 if (!procEntry.Charges)
1559 procEntry.Charges = spellInfo->ProcCharges;
1560 if (!procEntry.Chance && !procEntry.ProcsPerMinute)
1561 procEntry.Chance = float(spellInfo->ProcChance);
1562
1563 // validate data
1564 if (procEntry.SchoolMask & ~SPELL_SCHOOL_MASK_ALL)
1565 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `SchoolMask` set: {}", spellInfo->Id, procEntry.SchoolMask);
1566 if (procEntry.SpellFamilyName && (procEntry.SpellFamilyName < SPELLFAMILY_MAGE || procEntry.SpellFamilyName > SPELLFAMILY_PET || procEntry.SpellFamilyName == 14 || procEntry.SpellFamilyName == 16))
1567 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `SpellFamilyName` set: {}", spellInfo->Id, procEntry.SpellFamilyName);
1568 if (procEntry.Chance < 0)
1569 {
1570 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in the `Chance` field", spellInfo->Id);
1571 procEntry.Chance = 0;
1572 }
1573 if (procEntry.ProcsPerMinute < 0)
1574 {
1575 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has negative value in the `ProcsPerMinute` field", spellInfo->Id);
1576 procEntry.ProcsPerMinute = 0;
1577 }
1578 if (!procEntry.ProcFlags)
1579 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);
1580 if (procEntry.SpellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
1581 TC_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId {} has wrong `SpellTypeMask` set: {}", spellInfo->Id, procEntry.SpellTypeMask);
1582 if (procEntry.SpellTypeMask && !(procEntry.ProcFlags & SPELL_PROC_FLAG_MASK))
1583 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);
1584 if (!procEntry.SpellPhaseMask && procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK)
1585 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);
1587 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has wrong `SpellPhaseMask` set: {}", spellInfo->Id, procEntry.SpellPhaseMask);
1588 if (procEntry.SpellPhaseMask && !(procEntry.ProcFlags & REQ_SPELL_PHASE_PROC_FLAG_MASK))
1589 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);
1590 if (procEntry.HitMask & ~PROC_HIT_MASK_ALL)
1591 TC_LOG_ERROR("sql.sql", "The `spell_proc` table entry for spellId {} has wrong `HitMask` set: {}", spellInfo->Id, procEntry.HitMask);
1592 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)))))
1593 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);
1594 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1595 if ((procEntry.DisableEffectsMask & (1u << spellEffectInfo.EffectIndex)) && !spellEffectInfo.IsAura())
1596 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));
1597 if (procEntry.AttributesMask & PROC_ATTR_REQ_SPELLMOD)
1598 {
1599 bool found = false;
1600 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1601 {
1602 if (!spellEffectInfo.IsAura())
1603 continue;
1604
1605 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_ADD_PCT_MODIFIER || spellEffectInfo.ApplyAuraName == SPELL_AURA_ADD_FLAT_MODIFIER)
1606 {
1607 found = true;
1608 break;
1609 }
1610 }
1611
1612 if (!found)
1613 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);
1614 }
1615
1616 mSpellProcMap[spellInfo->Id] = procEntry;
1617
1618 if (allRanks)
1619 spellInfo = spellInfo->GetNextRankSpell();
1620 else
1621 break;
1622 }
1623 ++count;
1624 } while (result->NextRow());
1625 }
1626 else
1627 TC_LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty.");
1628
1629 TC_LOG_INFO("server.loading", ">> Loaded {} spell proc conditions and data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1630
1631 // Define can trigger auras
1632 bool isTriggerAura[TOTAL_AURAS];
1633 // Triggered always, even from triggered spells
1634 bool isAlwaysTriggeredAura[TOTAL_AURAS];
1635 // SpellTypeMask to add to the proc
1636 uint32 spellTypeMask[TOTAL_AURAS];
1637
1638 // List of auras that CAN trigger but may not exist in spell_proc
1639 // in most cases needed to drop charges
1640
1641 // some aura types need additional checks (eg SPELL_AURA_MECHANIC_IMMUNITY needs mechanic check)
1642 // see AuraEffect::CheckEffectProc
1643 for (uint16 i = 0; i < TOTAL_AURAS; ++i)
1644 {
1645 isTriggerAura[i] = false;
1646 isAlwaysTriggeredAura[i] = false;
1647 spellTypeMask[i] = PROC_SPELL_TYPE_MASK_ALL;
1648 }
1649
1650 isTriggerAura[SPELL_AURA_DUMMY] = true; // Most dummy auras should require scripting, but there are some exceptions (ie 12311)
1651 isTriggerAura[SPELL_AURA_MOD_CONFUSE] = true; // "Any direct damaging attack will revive targets"
1652 isTriggerAura[SPELL_AURA_MOD_THREAT] = true; // Only one spell: 28762 part of Mage T3 8p bonus
1653 isTriggerAura[SPELL_AURA_MOD_STUN] = true; // Aura does not have charges but needs to be removed on trigger
1654 isTriggerAura[SPELL_AURA_MOD_DAMAGE_DONE] = true;
1655 isTriggerAura[SPELL_AURA_MOD_DAMAGE_TAKEN] = true;
1656 isTriggerAura[SPELL_AURA_MOD_RESISTANCE] = true;
1657 isTriggerAura[SPELL_AURA_MOD_STEALTH] = true;
1658 isTriggerAura[SPELL_AURA_MOD_FEAR] = true; // Aura does not have charges but needs to be removed on trigger
1659 isTriggerAura[SPELL_AURA_MOD_ROOT] = true;
1660 isTriggerAura[SPELL_AURA_TRANSFORM] = true;
1661 isTriggerAura[SPELL_AURA_REFLECT_SPELLS] = true;
1662 isTriggerAura[SPELL_AURA_DAMAGE_IMMUNITY] = true;
1663 isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL] = true;
1664 isTriggerAura[SPELL_AURA_PROC_TRIGGER_DAMAGE] = true;
1665 isTriggerAura[SPELL_AURA_MOD_CASTING_SPEED_NOT_STACK] = true;
1666 isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT] = true;
1667 isTriggerAura[SPELL_AURA_MOD_POWER_COST_SCHOOL] = true;
1668 isTriggerAura[SPELL_AURA_REFLECT_SPELLS_SCHOOL] = true;
1669 isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN] = true;
1670 isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER] = true;
1671 isTriggerAura[SPELL_AURA_ADD_CASTER_HIT_TRIGGER] = true;
1672 isTriggerAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
1673 isTriggerAura[SPELL_AURA_MOD_MELEE_HASTE] = true;
1674 isTriggerAura[SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE] = true;
1675 isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE] = true;
1676 isTriggerAura[SPELL_AURA_RAID_PROC_FROM_CHARGE_WITH_VALUE] = true;
1677 isTriggerAura[SPELL_AURA_PROC_TRIGGER_SPELL_WITH_VALUE] = true;
1678 isTriggerAura[SPELL_AURA_MOD_SPELL_CRIT_CHANCE] = true;
1679 isTriggerAura[SPELL_AURA_ADD_FLAT_MODIFIER] = true;
1680 isTriggerAura[SPELL_AURA_ADD_PCT_MODIFIER] = true;
1681 isTriggerAura[SPELL_AURA_ABILITY_IGNORE_AURASTATE] = true;
1682 isTriggerAura[SPELL_AURA_MOD_INVISIBILITY] = true;
1683 isTriggerAura[SPELL_AURA_FORCE_REACTION] = true;
1684 isTriggerAura[SPELL_AURA_MOD_TAUNT] = true;
1685 isTriggerAura[SPELL_AURA_MOD_DETAUNT] = true;
1686 isTriggerAura[SPELL_AURA_MOD_DAMAGE_PERCENT_DONE] = true;
1687 isTriggerAura[SPELL_AURA_MOD_ATTACK_POWER_PCT] = true;
1688 isTriggerAura[SPELL_AURA_MOD_HIT_CHANCE] = true;
1689 isTriggerAura[SPELL_AURA_MOD_WEAPON_CRIT_PERCENT] = true;
1690 isTriggerAura[SPELL_AURA_MOD_BLOCK_PERCENT] = true;
1691
1692 isAlwaysTriggeredAura[SPELL_AURA_OVERRIDE_CLASS_SCRIPTS] = true;
1693 isAlwaysTriggeredAura[SPELL_AURA_MOD_STEALTH] = true;
1694 isAlwaysTriggeredAura[SPELL_AURA_MOD_CONFUSE] = true;
1695 isAlwaysTriggeredAura[SPELL_AURA_MOD_FEAR] = true;
1696 isAlwaysTriggeredAura[SPELL_AURA_MOD_ROOT] = true;
1697 isAlwaysTriggeredAura[SPELL_AURA_MOD_STUN] = true;
1698 isAlwaysTriggeredAura[SPELL_AURA_TRANSFORM] = true;
1699 isAlwaysTriggeredAura[SPELL_AURA_MOD_INVISIBILITY] = true;
1700
1708
1709 // This generates default procs to retain compatibility with previous proc system
1710 TC_LOG_INFO("server.loading", "Generating spell proc data from SpellMap...");
1711 count = 0;
1712 oldMSTime = getMSTime();
1713
1714 for (SpellInfo const* spellInfo : mSpellInfoMap)
1715 {
1716 if (!spellInfo)
1717 continue;
1718
1719 // Data already present in DB, overwrites default proc
1720 if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
1721 continue;
1722
1723 // Nothing to do if no flags set
1724 if (!spellInfo->ProcFlags)
1725 continue;
1726
1727 bool addTriggerFlag = false;
1728 uint32 procSpellTypeMask = PROC_SPELL_TYPE_NONE;
1729 uint32 nonProcMask = 0;
1730 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1731 {
1732 if (!spellEffectInfo.IsEffect())
1733 continue;
1734
1735 uint32 auraName = spellEffectInfo.ApplyAuraName;
1736 if (!auraName)
1737 continue;
1738
1739 if (!isTriggerAura[auraName])
1740 {
1741 // explicitly disable non proccing auras to avoid losing charges on self proc
1742 nonProcMask |= 1 << spellEffectInfo.EffectIndex;
1743 continue;
1744 }
1745
1746 procSpellTypeMask |= spellTypeMask[auraName];
1747 if (isAlwaysTriggeredAura[auraName])
1748 addTriggerFlag = true;
1749
1750 // many proc auras with taken procFlag mask don't have attribute "can proc with triggered"
1751 // they should proc nevertheless (example mage armor spells with judgement)
1752 if (!addTriggerFlag && (spellInfo->ProcFlags & TAKEN_HIT_PROC_FLAG_MASK) != 0)
1753 {
1754 switch (auraName)
1755 {
1758 addTriggerFlag = true;
1759 break;
1760 default:
1761 break;
1762 }
1763 }
1764 }
1765
1766 if (!procSpellTypeMask)
1767 {
1768 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1769 {
1770 if (spellEffectInfo.IsAura())
1771 {
1772 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);
1773 break;
1774 }
1775 }
1776
1777 continue;
1778 }
1779
1780 SpellProcEntry procEntry;
1781 procEntry.SchoolMask = 0;
1782 procEntry.ProcFlags = spellInfo->ProcFlags;
1783 procEntry.SpellFamilyName = 0;
1784 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1785 if (spellEffectInfo.IsEffect() && isTriggerAura[spellEffectInfo.ApplyAuraName])
1786 procEntry.SpellFamilyMask |= spellEffectInfo.SpellClassMask;
1787
1788 if (procEntry.SpellFamilyMask)
1789 procEntry.SpellFamilyName = spellInfo->SpellFamilyName;
1790
1791 procEntry.SpellTypeMask = procSpellTypeMask;
1793 procEntry.HitMask = PROC_HIT_NONE; // uses default proc @see SpellMgr::CanSpellTriggerProcOnEvent
1794
1795 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
1796 {
1797 if (!spellEffectInfo.IsAura())
1798 continue;
1799
1800 switch (spellEffectInfo.ApplyAuraName)
1801 {
1802 // Reflect auras should only proc off reflects
1805 procEntry.HitMask = PROC_HIT_REFLECT;
1806 break;
1807 // Only drop charge on crit
1809 procEntry.HitMask = PROC_HIT_CRITICAL;
1810 break;
1811 // Only drop charge on block
1813 procEntry.HitMask = PROC_HIT_BLOCK;
1814 break;
1815 // proc auras with another aura reducing hit chance (eg 63767) only proc on missed attack
1817 if (spellEffectInfo.CalcValue() <= -100)
1818 procEntry.HitMask = PROC_HIT_MISS;
1819 break;
1820 default:
1821 continue;
1822 }
1823 break;
1824 }
1825
1826 procEntry.AttributesMask = 0;
1827 procEntry.DisableEffectsMask = nonProcMask;
1828 if (spellInfo->ProcFlags & PROC_FLAG_KILL)
1830 if (addTriggerFlag)
1832
1833 procEntry.ProcsPerMinute = 0;
1834 procEntry.Chance = spellInfo->ProcChance;
1835 procEntry.Cooldown = Milliseconds::zero();
1836 procEntry.Charges = spellInfo->ProcCharges;
1837
1838 mSpellProcMap[spellInfo->Id] = procEntry;
1839 ++count;
1840 }
1841
1842 TC_LOG_INFO("server.loading", ">> Generated spell proc data for {} spells in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1843}
1844
1846{
1847 uint32 oldMSTime = getMSTime();
1848
1849 mSpellBonusMap.clear(); // need for reload case
1850
1851 // 0 1 2 3 4
1852 QueryResult result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus, ap_dot_bonus FROM spell_bonus_data");
1853 if (!result)
1854 {
1855 TC_LOG_INFO("server.loading", ">> Loaded 0 spell bonus data. DB table `spell_bonus_data` is empty.");
1856 return;
1857 }
1858
1859 uint32 count = 0;
1860 do
1861 {
1862 Field* fields = result->Fetch();
1863 uint32 entry = fields[0].GetUInt32();
1864
1865 SpellInfo const* spell = GetSpellInfo(entry);
1866 if (!spell)
1867 {
1868 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_bonus_data` does not exist.", entry);
1869 continue;
1870 }
1871
1872 SpellBonusEntry& sbe = mSpellBonusMap[entry];
1873 sbe.direct_damage = fields[1].GetFloat();
1874 sbe.dot_damage = fields[2].GetFloat();
1875 sbe.ap_bonus = fields[3].GetFloat();
1876 sbe.ap_dot_bonus = fields[4].GetFloat();
1877
1878 ++count;
1879 } while (result->NextRow());
1880
1881 TC_LOG_INFO("server.loading", ">> Loaded {} extra spell bonus data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1882}
1883
1885{
1886 uint32 oldMSTime = getMSTime();
1887
1888 mSpellThreatMap.clear(); // need for reload case
1889
1890 // 0 1 2 3
1891 QueryResult result = WorldDatabase.Query("SELECT entry, flatMod, pctMod, apPctMod FROM spell_threat");
1892 if (!result)
1893 {
1894 TC_LOG_INFO("server.loading", ">> Loaded 0 aggro generating spells. DB table `spell_threat` is empty.");
1895 return;
1896 }
1897
1898 uint32 count = 0;
1899 do
1900 {
1901 Field* fields = result->Fetch();
1902
1903 uint32 entry = fields[0].GetUInt32();
1904
1905 if (!GetSpellInfo(entry))
1906 {
1907 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_threat` does not exist.", entry);
1908 continue;
1909 }
1910
1911 SpellThreatEntry ste;
1912 ste.flatMod = fields[1].GetInt32();
1913 ste.pctMod = fields[2].GetFloat();
1914 ste.apPctMod = fields[3].GetFloat();
1915
1916 mSpellThreatMap[entry] = ste;
1917 ++count;
1918 } while (result->NextRow());
1919
1920 TC_LOG_INFO("server.loading", ">> Loaded {} SpellThreatEntries in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1921}
1922
1924{
1925 uint32 oldMSTime = getMSTime();
1926
1927 mSkillLineAbilityMap.clear();
1928
1929 uint32 count = 0;
1930
1931 for (uint32 i = 0; i < sSkillLineAbilityStore.GetNumRows(); ++i)
1932 {
1933 SkillLineAbilityEntry const* SkillInfo = sSkillLineAbilityStore.LookupEntry(i);
1934 if (!SkillInfo)
1935 continue;
1936
1937 mSkillLineAbilityMap.insert(SkillLineAbilityMap::value_type(SkillInfo->Spell, SkillInfo));
1938 ++count;
1939 }
1940
1941 // Don't autolearn secondary variant of Seal of Righteousness - it is learned together with Judgement of Light
1942 if (SkillLineAbilityEntry* sealOfRighteousnessR2 = const_cast<SkillLineAbilityEntry*>(sSkillLineAbilityStore.LookupEntry(11957)))
1943 sealOfRighteousnessR2->AcquireMethod = 0;
1944
1945 TC_LOG_INFO("server.loading", ">> Loaded {} SkillLineAbility MultiMap Data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
1946}
1947
1949{
1950 uint32 oldMSTime = getMSTime();
1951
1952 mSpellPetAuraMap.clear(); // need for reload case
1953
1954 // 0 1 2 3
1955 QueryResult result = WorldDatabase.Query("SELECT spell, effectId, pet, aura FROM spell_pet_auras");
1956 if (!result)
1957 {
1958 TC_LOG_INFO("server.loading", ">> Loaded 0 spell pet auras. DB table `spell_pet_auras` is empty.");
1959 return;
1960 }
1961
1962 uint32 count = 0;
1963 do
1964 {
1965 Field* fields = result->Fetch();
1966
1967 uint32 spell = fields[0].GetUInt32();
1968 SpellEffIndex eff = SpellEffIndex(fields[1].GetUInt8());
1969 uint32 pet = fields[2].GetUInt32();
1970 uint32 aura = fields[3].GetUInt32();
1971
1972 SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find((spell << 8) + eff);
1973 if (itr != mSpellPetAuraMap.end())
1974 itr->second.AddAura(pet, aura);
1975 else
1976 {
1977 SpellInfo const* spellInfo = GetSpellInfo(spell);
1978 if (!spellInfo)
1979 {
1980 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_pet_auras` does not exist.", spell);
1981 continue;
1982 }
1983 if (spellInfo->GetEffect(eff).Effect != SPELL_EFFECT_DUMMY &&
1984 (spellInfo->GetEffect(eff).Effect != SPELL_EFFECT_APPLY_AURA ||
1985 spellInfo->GetEffect(eff).ApplyAuraName != SPELL_AURA_DUMMY))
1986 {
1987 TC_LOG_ERROR("spells", "The spell {} listed in `spell_pet_auras` does not have any dummy aura or dummy effect.", spell);
1988 continue;
1989 }
1990
1991 SpellInfo const* spellInfo2 = GetSpellInfo(aura);
1992 if (!spellInfo2)
1993 {
1994 TC_LOG_ERROR("sql.sql", "The aura {} listed in `spell_pet_auras` does not exist.", aura);
1995 continue;
1996 }
1997
1998 PetAura pa(pet, aura, spellInfo->GetEffect(eff).TargetA.GetTarget() == TARGET_UNIT_PET, spellInfo->GetEffect(eff).CalcValue());
1999 mSpellPetAuraMap[(spell<<8) + eff] = pa;
2000 }
2001
2002 ++count;
2003 } while (result->NextRow());
2004
2005 TC_LOG_INFO("server.loading", ">> Loaded {} spell pet auras in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2006}
2007
2008// Fill custom data about enchancments
2010{
2011 uint32 oldMSTime = getMSTime();
2012
2013 uint32 size = sSpellItemEnchantmentStore.GetNumRows();
2014 mEnchantCustomAttr.resize(size, false);
2015
2016 uint32 count = 0;
2017 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2018 {
2019 SpellInfo const* spellInfo = GetSpellInfo(i);
2020 if (!spellInfo)
2021 continue;
2022
2025 continue;
2026
2027 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2028 {
2029 if (spellEffectInfo.Effect == SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY)
2030 {
2031 uint32 enchId = spellEffectInfo.MiscValue;
2032 SpellItemEnchantmentEntry const* ench = sSpellItemEnchantmentStore.LookupEntry(enchId);
2033 if (!ench)
2034 continue;
2035 mEnchantCustomAttr[enchId] = true;
2036 ++count;
2037 break;
2038 }
2039 }
2040 }
2041
2042 TC_LOG_INFO("server.loading", ">> Loaded {} custom enchant attributes in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2043}
2044
2046{
2047 uint32 oldMSTime = getMSTime();
2048
2049 mSpellEnchantProcEventMap.clear(); // need for reload case
2050
2051 // 0 1 2 3 4
2052 QueryResult result = WorldDatabase.Query("SELECT EnchantID, Chance, ProcsPerMinute, HitMask, AttributesMask FROM spell_enchant_proc_data");
2053 if (!result)
2054 {
2055 TC_LOG_INFO("server.loading", ">> Loaded 0 spell enchant proc event conditions. DB table `spell_enchant_proc_data` is empty.");
2056 return;
2057 }
2058
2059 uint32 count = 0;
2060 do
2061 {
2062 Field* fields = result->Fetch();
2063
2064 uint32 enchantId = fields[0].GetUInt32();
2065
2066 SpellItemEnchantmentEntry const* ench = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2067 if (!ench)
2068 {
2069 TC_LOG_ERROR("sql.sql", "The enchancment {} listed in `spell_enchant_proc_data` does not exist.", enchantId);
2070 continue;
2071 }
2072
2074 spe.Chance = fields[1].GetFloat();
2075 spe.ProcsPerMinute = fields[2].GetFloat();
2076 spe.HitMask = fields[3].GetUInt32();
2077 spe.AttributesMask = fields[4].GetUInt32();
2078
2079 mSpellEnchantProcEventMap[enchantId] = spe;
2080
2081 ++count;
2082 } while (result->NextRow());
2083
2084 TC_LOG_INFO("server.loading", ">> Loaded {} enchant proc data definitions in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2085}
2086
2088{
2089 uint32 oldMSTime = getMSTime();
2090
2091 mSpellLinkedMap.clear(); // need for reload case
2092
2093 // 0 1 2
2094 QueryResult result = WorldDatabase.Query("SELECT spell_trigger, spell_effect, type FROM spell_linked_spell");
2095 if (!result)
2096 {
2097 TC_LOG_INFO("server.loading", ">> Loaded 0 linked spells. DB table `spell_linked_spell` is empty.");
2098 return;
2099 }
2100
2101 uint32 count = 0;
2102 do
2103 {
2104 Field* fields = result->Fetch();
2105
2106 int32 trigger = fields[0].GetInt32();
2107 int32 effect = fields[1].GetInt32();
2108 int32 type = fields[2].GetUInt8();
2109
2110 SpellInfo const* spellInfo = GetSpellInfo(abs(trigger));
2111 if (!spellInfo)
2112 {
2113 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_linked_spell` does not exist.", abs(trigger));
2114 continue;
2115 }
2116
2117 if (effect >= 0)
2118 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2119 {
2120 if (spellEffectInfo.CalcValue() == abs(effect))
2121 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));
2122 }
2123
2124 spellInfo = GetSpellInfo(abs(effect));
2125 if (!spellInfo)
2126 {
2127 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_linked_spell` does not exist.", abs(effect));
2128 continue;
2129 }
2130
2131 if (type) //we will find a better way when more types are needed
2132 {
2133 if (trigger > 0)
2134 trigger += SPELL_LINKED_MAX_SPELLS * type;
2135 else
2136 trigger -= SPELL_LINKED_MAX_SPELLS * type;
2137 }
2138 mSpellLinkedMap[trigger].push_back(effect);
2139
2140 ++count;
2141 } while (result->NextRow());
2142
2143 TC_LOG_INFO("server.loading", ">> Loaded {} linked spells in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2144}
2145
2147{
2148 uint32 oldMSTime = getMSTime();
2149
2150 mPetLevelupSpellMap.clear(); // need for reload case
2151
2152 uint32 count = 0;
2153 uint32 family_count = 0;
2154
2155 for (uint32 i = 0; i < sCreatureFamilyStore.GetNumRows(); ++i)
2156 {
2157 CreatureFamilyEntry const* creatureFamily = sCreatureFamilyStore.LookupEntry(i);
2158 if (!creatureFamily) // not exist
2159 continue;
2160
2161 for (uint8 j = 0; j < 2; ++j)
2162 {
2163 if (!creatureFamily->SkillLine[j])
2164 continue;
2165
2166 std::vector<SkillLineAbilityEntry const*> const* skillLineAbilities = GetSkillLineAbilitiesBySkill(creatureFamily->SkillLine[j]);
2167 if (!skillLineAbilities)
2168 continue;
2169
2170 for (SkillLineAbilityEntry const* skillLine : *skillLineAbilities)
2171 {
2172 if (skillLine->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN)
2173 continue;
2174
2175 SpellInfo const* spell = GetSpellInfo(skillLine->Spell);
2176 if (!spell) // not exist or triggered or talent
2177 continue;
2178
2179 if (!spell->SpellLevel)
2180 continue;
2181
2182 PetLevelupSpellSet& spellSet = mPetLevelupSpellMap[creatureFamily->ID];
2183 if (spellSet.empty())
2184 ++family_count;
2185
2186 spellSet.insert(PetLevelupSpellSet::value_type(spell->SpellLevel, spell->Id));
2187 ++count;
2188 }
2189 }
2190 }
2191
2192 TC_LOG_INFO("server.loading", ">> Loaded {} pet levelup and default spells for {} families in {} ms", count, family_count, GetMSTimeDiffToNow(oldMSTime));
2193}
2194
2196{
2197 // skip empty list;
2198 bool have_spell = false;
2199 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2200 {
2201 if (petDefSpells.spellid[j])
2202 {
2203 have_spell = true;
2204 break;
2205 }
2206 }
2207 if (!have_spell)
2208 return false;
2209
2210 // remove duplicates with levelupSpells if any
2211 if (PetLevelupSpellSet const* levelupSpells = cInfo->family ? sSpellMgr->GetPetLevelupSpellList(cInfo->family) : nullptr)
2212 {
2213 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2214 {
2215 if (!petDefSpells.spellid[j])
2216 continue;
2217
2218 for (PetLevelupSpellSet::const_iterator itr = levelupSpells->begin(); itr != levelupSpells->end(); ++itr)
2219 {
2220 if (itr->second == petDefSpells.spellid[j])
2221 {
2222 petDefSpells.spellid[j] = 0;
2223 break;
2224 }
2225 }
2226 }
2227 }
2228
2229 // skip empty list;
2230 have_spell = false;
2231 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2232 {
2233 if (petDefSpells.spellid[j])
2234 {
2235 have_spell = true;
2236 break;
2237 }
2238 }
2239
2240 return have_spell;
2241}
2242
2244{
2245 uint32 oldMSTime = getMSTime();
2246
2247 mPetDefaultSpellsMap.clear();
2248
2249 uint32 countCreature = 0;
2250 uint32 countData = 0;
2251
2252 CreatureTemplateContainer const& ctc = sObjectMgr->GetCreatureTemplates();
2253 for (auto const& creatureTemplatePair : ctc)
2254 {
2255 if (!creatureTemplatePair.second.PetSpellDataId)
2256 continue;
2257
2258 // for creature with PetSpellDataId get default pet spells from dbc
2259 CreatureSpellDataEntry const* spellDataEntry = sCreatureSpellDataStore.LookupEntry(creatureTemplatePair.second.PetSpellDataId);
2260 if (!spellDataEntry)
2261 continue;
2262
2263 int32 petSpellsId = -int32(creatureTemplatePair.second.PetSpellDataId);
2264 PetDefaultSpellsEntry petDefSpells;
2265 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2266 petDefSpells.spellid[j] = spellDataEntry->Spells[j];
2267
2268 if (LoadPetDefaultSpells_helper(&creatureTemplatePair.second, petDefSpells))
2269 {
2270 mPetDefaultSpellsMap[petSpellsId] = petDefSpells;
2271 ++countData;
2272 }
2273 }
2274
2275 TC_LOG_INFO("server.loading", ">> Loaded addition spells for {} pet spell data entries in {} ms", countData, GetMSTimeDiffToNow(oldMSTime));
2276
2277 TC_LOG_INFO("server.loading", "Loading summonable creature templates...");
2278 oldMSTime = getMSTime();
2279
2280 // different summon spells
2281 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2282 {
2283 SpellInfo const* spellEntry = GetSpellInfo(i);
2284 if (!spellEntry)
2285 continue;
2286
2287 for (SpellEffectInfo const& spellEffectInfo : spellEntry->GetEffects())
2288 {
2289 if (spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON) || spellEffectInfo.IsEffect(SPELL_EFFECT_SUMMON_PET))
2290 {
2291 uint32 creature_id = spellEffectInfo.MiscValue;
2292 CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(creature_id);
2293 if (!cInfo)
2294 continue;
2295
2296 // already loaded
2297 if (cInfo->PetSpellDataId)
2298 continue;
2299
2300 // for creature without PetSpellDataId get default pet spells from creature_template
2301 int32 petSpellsId = cInfo->Entry;
2302 if (mPetDefaultSpellsMap.find(cInfo->Entry) != mPetDefaultSpellsMap.end())
2303 continue;
2304
2305 PetDefaultSpellsEntry petDefSpells;
2306 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2307 petDefSpells.spellid[j] = cInfo->spells[j];
2308
2309 if (LoadPetDefaultSpells_helper(cInfo, petDefSpells))
2310 {
2311 mPetDefaultSpellsMap[petSpellsId] = petDefSpells;
2312 ++countCreature;
2313 }
2314 }
2315 }
2316 }
2317
2318 TC_LOG_INFO("server.loading", ">> Loaded {} summonable creature templates in {} ms", countCreature, GetMSTimeDiffToNow(oldMSTime));
2319}
2320
2322{
2323 uint32 oldMSTime = getMSTime();
2324
2325 mSpellAreaMap.clear(); // need for reload case
2326 mSpellAreaForAreaMap.clear();
2327 mSpellAreaForQuestMap.clear();
2329 mSpellAreaForAuraMap.clear();
2330
2331 // 0 1 2 3 4 5 6 7 8 9
2332 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");
2333 if (!result)
2334 {
2335 TC_LOG_INFO("server.loading", ">> Loaded 0 spell area requirements. DB table `spell_area` is empty.");
2336
2337 return;
2338 }
2339
2340 uint32 count = 0;
2341 do
2342 {
2343 Field* fields = result->Fetch();
2344
2345 uint32 spell = fields[0].GetUInt32();
2346 SpellArea spellArea;
2347 spellArea.spellId = spell;
2348 spellArea.areaId = fields[1].GetUInt32();
2349 spellArea.questStart = fields[2].GetUInt32();
2350 spellArea.questStartStatus = fields[3].GetUInt32();
2351 spellArea.questEndStatus = fields[4].GetUInt32();
2352 spellArea.questEnd = fields[5].GetUInt32();
2353 spellArea.auraSpell = fields[6].GetInt32();
2354 spellArea.raceMask = fields[7].GetUInt32();
2355 spellArea.gender = Gender(fields[8].GetUInt8());
2356 spellArea.autocast = fields[9].GetBool();
2357
2358 if (SpellInfo const* spellInfo = GetSpellInfo(spell))
2359 {
2360 if (spellArea.autocast)
2361 const_cast<SpellInfo*>(spellInfo)->Attributes |= SPELL_ATTR0_CANT_CANCEL;
2362 }
2363 else
2364 {
2365 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` does not exist", spell);
2366 continue;
2367 }
2368
2369 {
2370 bool ok = true;
2371 SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds(spellArea.spellId);
2372 for (SpellAreaMap::const_iterator itr = sa_bounds.first; itr != sa_bounds.second; ++itr)
2373 {
2374 if (spellArea.spellId != itr->second.spellId)
2375 continue;
2376 if (spellArea.areaId != itr->second.areaId)
2377 continue;
2378 if (spellArea.questStart != itr->second.questStart)
2379 continue;
2380 if (spellArea.auraSpell != itr->second.auraSpell)
2381 continue;
2382 if ((spellArea.raceMask & itr->second.raceMask) == 0)
2383 continue;
2384 if (spellArea.gender != itr->second.gender)
2385 continue;
2386
2387 // duplicate by requirements
2388 ok = false;
2389 break;
2390 }
2391
2392 if (!ok)
2393 {
2394 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` is already listed with similar requirements.", spell);
2395 continue;
2396 }
2397 }
2398
2399 if (spellArea.areaId && !sAreaTableStore.LookupEntry(spellArea.areaId))
2400 {
2401 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has a wrong area ({}) requirement.", spell, spellArea.areaId);
2402 continue;
2403 }
2404
2405 if (spellArea.questStart && !sObjectMgr->GetQuestTemplate(spellArea.questStart))
2406 {
2407 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has a wrong start quest ({}) requirement.", spell, spellArea.questStart);
2408 continue;
2409 }
2410
2411 if (spellArea.questEnd)
2412 {
2413 if (!sObjectMgr->GetQuestTemplate(spellArea.questEnd))
2414 {
2415 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has a wrong ending quest ({}) requirement.", spell, spellArea.questEnd);
2416 continue;
2417 }
2418 }
2419
2420 if (spellArea.auraSpell)
2421 {
2422 SpellInfo const* spellInfo = GetSpellInfo(abs(spellArea.auraSpell));
2423 if (!spellInfo)
2424 {
2425 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has wrong aura spell ({}) requirement", spell, abs(spellArea.auraSpell));
2426 continue;
2427 }
2428
2429 if (uint32(abs(spellArea.auraSpell)) == spellArea.spellId)
2430 {
2431 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has aura spell ({}) requirement for itself", spell, abs(spellArea.auraSpell));
2432 continue;
2433 }
2434
2435 // not allow autocast chains by auraSpell field (but allow use as alternative if not present)
2436 if (spellArea.autocast && spellArea.auraSpell > 0)
2437 {
2438 bool chain = false;
2440 for (SpellAreaForAuraMap::const_iterator itr = saBound.first; itr != saBound.second; ++itr)
2441 {
2442 if (itr->second->autocast && itr->second->auraSpell > 0)
2443 {
2444 chain = true;
2445 break;
2446 }
2447 }
2448
2449 if (chain)
2450 {
2451 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);
2452 continue;
2453 }
2454
2456 for (SpellAreaMap::const_iterator itr2 = saBound2.first; itr2 != saBound2.second; ++itr2)
2457 {
2458 if (itr2->second.autocast && itr2->second.auraSpell > 0)
2459 {
2460 chain = true;
2461 break;
2462 }
2463 }
2464
2465 if (chain)
2466 {
2467 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);
2468 continue;
2469 }
2470 }
2471 }
2472
2473 if (spellArea.raceMask && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE) == 0)
2474 {
2475 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has wrong race mask ({}) requirement.", spell, spellArea.raceMask);
2476 continue;
2477 }
2478
2479 if (spellArea.gender != GENDER_NONE && spellArea.gender != GENDER_FEMALE && spellArea.gender != GENDER_MALE)
2480 {
2481 TC_LOG_ERROR("sql.sql", "The spell {} listed in `spell_area` has wrong gender ({}) requirement.", spell, spellArea.gender);
2482 continue;
2483 }
2484
2485 SpellArea const* sa = &mSpellAreaMap.insert(SpellAreaMap::value_type(spell, spellArea))->second;
2486
2487 // for search by current zone/subzone at zone/subzone change
2488 if (spellArea.areaId)
2489 mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(spellArea.areaId, sa));
2490
2491 // for search at quest update checks
2492 if (spellArea.questStart || spellArea.questEnd)
2493 {
2494 if (spellArea.questStart == spellArea.questEnd)
2495 mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa));
2496 else
2497 {
2498 if (spellArea.questStart)
2499 mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa));
2500 if (spellArea.questEnd)
2501 mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd, sa));
2502 }
2503 }
2504
2505 // for search at quest start/reward
2506 if (spellArea.questEnd)
2507 mSpellAreaForQuestEndMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd, sa));
2508
2509 // for search at aura apply
2510 if (spellArea.auraSpell)
2511 mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(abs(spellArea.auraSpell), sa));
2512
2513 ++count;
2514 } while (result->NextRow());
2515
2516 TC_LOG_INFO("server.loading", ">> Loaded {} spell area requirements in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2517}
2518
2520{
2521 uint32 oldMSTime = getMSTime();
2522
2524 mSpellInfoMap.resize(sSpellStore.GetNumRows(), nullptr);
2525
2526 for (SpellEntry const* spellEntry : sSpellStore)
2527 mSpellInfoMap[spellEntry->ID] = new SpellInfo(spellEntry);
2528
2529 for (uint32 spellIndex = 0; spellIndex < GetSpellInfoStoreSize(); ++spellIndex)
2530 {
2531 if (!mSpellInfoMap[spellIndex])
2532 continue;
2533
2534 for (SpellEffectInfo const& spellEffectInfo : mSpellInfoMap[spellIndex]->GetEffects())
2535 {
2536 //ASSERT(effect.EffectIndex < MAX_SPELL_EFFECTS, "MAX_SPELL_EFFECTS must be at least %u", effect.EffectIndex + 1);
2537 ASSERT(spellEffectInfo.Effect < TOTAL_SPELL_EFFECTS, "TOTAL_SPELL_EFFECTS must be at least %u", spellEffectInfo.Effect + 1);
2538 ASSERT(spellEffectInfo.ApplyAuraName < TOTAL_AURAS, "TOTAL_AURAS must be at least %u", spellEffectInfo.ApplyAuraName + 1);
2539 ASSERT(spellEffectInfo.TargetA.GetTarget() < TOTAL_SPELL_TARGETS, "TOTAL_SPELL_TARGETS must be at least %u", spellEffectInfo.TargetA.GetTarget() + 1);
2540 ASSERT(spellEffectInfo.TargetB.GetTarget() < TOTAL_SPELL_TARGETS, "TOTAL_SPELL_TARGETS must be at least %u", spellEffectInfo.TargetB.GetTarget() + 1);
2541 }
2542 }
2543
2544 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo store in {} ms", GetMSTimeDiffToNow(oldMSTime));
2545}
2546
2548{
2549 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2550 delete mSpellInfoMap[i];
2551
2552 mSpellInfoMap.clear();
2553}
2554
2556{
2557 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2558 if (mSpellInfoMap[i])
2559 mSpellInfoMap[i]->_UnloadImplicitTargetConditionLists();
2560}
2561
2563{
2564 uint32 oldMSTime = getMSTime();
2565 uint32 oldMSTime2 = oldMSTime;
2566
2567 QueryResult result = WorldDatabase.Query("SELECT entry, attributes FROM spell_custom_attr");
2568
2569 if (!result)
2570 TC_LOG_INFO("server.loading", ">> Loaded 0 spell custom attributes from DB. DB table `spell_custom_attr` is empty.");
2571 else
2572 {
2573 uint32 count = 0;
2574 do
2575 {
2576 Field* fields = result->Fetch();
2577
2578 uint32 spellId = fields[0].GetUInt32();
2579 uint32 attributes = fields[1].GetUInt32();
2580
2581 SpellInfo* spellInfo = _GetSpellInfo(spellId);
2582 if (!spellInfo)
2583 {
2584 TC_LOG_ERROR("sql.sql", "Table `spell_custom_attr` has wrong spell (entry: {}), ignored.", spellId);
2585 continue;
2586 }
2587
2588 if ((attributes & SPELL_ATTR0_CU_NEGATIVE) != 0)
2589 {
2590 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2591 {
2592 if (spellEffectInfo.IsEffect())
2593 continue;
2594
2595 if ((attributes & (SPELL_ATTR0_CU_NEGATIVE_EFF0 << spellEffectInfo.EffectIndex)) != 0)
2596 {
2597 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));
2598 continue;
2599 }
2600 }
2601 }
2602
2603 spellInfo->AttributesCu |= attributes;
2604 ++count;
2605 } while (result->NextRow());
2606
2607 TC_LOG_INFO("server.loading", ">> Loaded {} spell custom attributes from DB in {} ms", count, GetMSTimeDiffToNow(oldMSTime2));
2608 }
2609
2610 for (SpellInfo* spellInfo : mSpellInfoMap)
2611 {
2612 if (!spellInfo)
2613 continue;
2614
2615 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2616 {
2617 // all bleed effects and spells ignore armor
2618 if (spellInfo->GetEffectMechanicMask(spellEffectInfo.EffectIndex) & (1 << MECHANIC_BLEED))
2619 spellInfo->AttributesCu |= SPELL_ATTR0_CU_IGNORE_ARMOR;
2620
2621 switch (spellEffectInfo.ApplyAuraName)
2622 {
2629 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
2630 break;
2631 default:
2632 break;
2633 }
2634
2635 switch (spellEffectInfo.ApplyAuraName)
2636 {
2637 case SPELL_AURA_CONVERT_RUNE: // Can't be saved - aura handler relies on calculated amount and changes it
2638 case SPELL_AURA_OPEN_STABLE: // No point in saving this, since the stable dialog can't be open on aura load anyway.
2639 // Auras that require both caster & target to be in world cannot be saved
2646 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CANNOT_BE_SAVED;
2647 break;
2648 default:
2649 break;
2650 }
2651
2652 switch (spellEffectInfo.Effect)
2653 {
2656 case SPELL_EFFECT_HEAL:
2664 spellInfo->AttributesCu |= SPELL_ATTR0_CU_CAN_CRIT;
2665 break;
2666 default:
2667 break;
2668 }
2669
2670 switch (spellEffectInfo.Effect)
2671 {
2677 case SPELL_EFFECT_HEAL:
2678 spellInfo->AttributesCu |= SPELL_ATTR0_CU_DIRECT_DAMAGE;
2679 break;
2688 spellInfo->AttributesCu |= SPELL_ATTR0_CU_NO_INITIAL_THREAT;
2689 break;
2692 case SPELL_EFFECT_JUMP:
2695 spellInfo->AttributesCu |= SPELL_ATTR0_CU_CHARGE;
2696 break;
2698 spellInfo->AttributesCu |= SPELL_ATTR0_CU_PICKPOCKET;
2699 break;
2704 {
2705 // only enchanting profession enchantments procs can stack
2706 if (IsPartOfSkillLine(SKILL_ENCHANTING, spellInfo->Id))
2707 {
2708 uint32 enchantId = spellEffectInfo.MiscValue;
2709 SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2710 if (!enchant)
2711 break;
2712
2713 for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
2714 {
2715 if (enchant->Effect[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
2716 continue;
2717
2718 SpellInfo* procInfo = _GetSpellInfo(enchant->EffectArg[s]);
2719 if (!procInfo)
2720 continue;
2721
2722 // if proced directly from enchantment, not via proc aura
2723 // NOTE: Enchant Weapon - Blade Ward also has proc aura spell and is proced directly
2724 // however its not expected to stack so this check is good
2726 continue;
2727
2729 }
2730 }
2731 break;
2732 }
2733 default:
2734 break;
2735 }
2736 }
2737
2738 // spells ignoring hit result should not be binary
2739 if (!spellInfo->HasAttribute(SPELL_ATTR3_IGNORE_HIT_RESULT))
2740 {
2741 bool setFlag = false;
2742 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2743 {
2744 if (spellEffectInfo.IsEffect())
2745 {
2746 switch (spellEffectInfo.Effect)
2747 {
2755 break;
2764 {
2765 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE ||
2766 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_DAMAGE_PERCENT ||
2767 spellEffectInfo.ApplyAuraName == SPELL_AURA_DUMMY ||
2768 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_LEECH ||
2769 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_HEALTH_FUNNEL ||
2770 spellEffectInfo.ApplyAuraName == SPELL_AURA_PERIODIC_DUMMY)
2771 break;
2772 [[fallthrough]];
2773 }
2774 default:
2775 {
2776 // No value and not interrupt cast or crowd control without SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY flag
2777 if (!spellEffectInfo.CalcValue() && !((spellEffectInfo.Effect == SPELL_EFFECT_INTERRUPT_CAST || spellInfo->HasAttribute(SPELL_ATTR0_CU_AURA_CC)) && !spellInfo->HasAttribute(SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)))
2778 break;
2779
2780 // Sindragosa Frost Breath
2781 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)
2782 break;
2783
2784 // Frostbolt
2785 if (spellInfo->SpellFamilyName == SPELLFAMILY_MAGE && (spellInfo->SpellFamilyFlags[0] & 0x20))
2786 break;
2787
2788 // Frost Fever
2789 if (spellInfo->Id == 55095)
2790 break;
2791
2792 // Haunt
2793 if (spellInfo->SpellFamilyName == SPELLFAMILY_WARLOCK && (spellInfo->SpellFamilyFlags[1] & 0x40000))
2794 break;
2795
2796 setFlag = true;
2797 break;
2798 }
2799 }
2800
2801 if (setFlag)
2802 {
2803 spellInfo->AttributesCu |= SPELL_ATTR0_CU_BINARY_SPELL;
2804 break;
2805 }
2806 }
2807 }
2808 }
2809
2810 // Remove normal school mask to properly calculate damage
2811 if ((spellInfo->SchoolMask & SPELL_SCHOOL_MASK_NORMAL) && (spellInfo->SchoolMask & SPELL_SCHOOL_MASK_MAGIC))
2812 {
2813 spellInfo->SchoolMask &= ~SPELL_SCHOOL_MASK_NORMAL;
2814 spellInfo->AttributesCu |= SPELL_ATTR0_CU_SCHOOLMASK_NORMAL_WITH_MAGIC;
2815 }
2816
2817 spellInfo->_InitializeSpellPositivity();
2818
2819 if (GetTalentSpellPos(spellInfo->Id))
2820 spellInfo->AttributesCu |= SPELL_ATTR0_CU_IS_TALENT;
2821
2822 if (spellInfo->SpellVisual[0] == 3879)
2823 spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_BACK;
2824
2825 switch (spellInfo->SpellFamilyName)
2826 {
2828 // Shout / Piercing Howl
2829 if (spellInfo->SpellFamilyFlags[0] & 0x20000/* || spellInfo->SpellFamilyFlags[1] & 0x20*/)
2830 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
2831 break;
2832 case SPELLFAMILY_DRUID:
2833 // Roar
2834 if (spellInfo->SpellFamilyFlags[0] & 0x8)
2835 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
2836 break;
2838 // Stoneclaw Totem effect
2839 if (spellInfo->Id == 5729)
2840 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CC;
2841 break;
2842 default:
2843 break;
2844 }
2845
2846 spellInfo->_InitializeExplicitTargetMask();
2847
2848 if (spellInfo->Speed > 0.0f)
2849 if (SpellVisualEntry const* spellVisual = sSpellVisualStore.LookupEntry(spellInfo->SpellVisual[0]))
2850 if (spellVisual->HasMissile)
2851 if (spellVisual->MissileModel == -4 || spellVisual->MissileModel == -5)
2852 spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEEDS_AMMO_DATA;
2853
2854 }
2855
2856 // addition for binary spells, omit spells triggering other spells
2857 for (SpellInfo* spellInfo : mSpellInfoMap)
2858 {
2859 if (!spellInfo)
2860 continue;
2861
2862 if (spellInfo->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
2863 continue;
2864
2865 bool allNonBinary = true;
2866 bool overrideAttr = false;
2867 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2868 {
2869 if (spellEffectInfo.IsAura() && spellEffectInfo.TriggerSpell)
2870 {
2871 switch (spellEffectInfo.ApplyAuraName)
2872 {
2876 if (SpellInfo const* triggerSpell = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell))
2877 {
2878 overrideAttr = true;
2879 if (triggerSpell->HasAttribute(SPELL_ATTR0_CU_BINARY_SPELL))
2880 allNonBinary = false;
2881 }
2882 break;
2883 default:
2884 break;
2885 }
2886 }
2887 }
2888
2889 if (overrideAttr && allNonBinary)
2890 spellInfo->AttributesCu &= ~SPELL_ATTR0_CU_BINARY_SPELL;
2891 }
2892
2893 // remove attribute from spells that can't crit
2894 for (SpellInfo* spellInfo : mSpellInfoMap)
2895 {
2896 if (!spellInfo)
2897 continue;
2898
2899 if (spellInfo->HasAttribute(SPELL_ATTR2_CANT_CRIT))
2900 spellInfo->AttributesCu &= ~SPELL_ATTR0_CU_CAN_CRIT;
2901 }
2902
2903 // add custom attribute to liquid auras
2904 for (LiquidTypeEntry const* liquid : sLiquidTypeStore)
2905 {
2906 if (uint32 spellId = liquid->SpellID)
2907 if (SpellInfo* spellInfo = _GetSpellInfo(spellId))
2908 spellInfo->AttributesCu |= SPELL_ATTR0_CU_AURA_CANNOT_BE_SAVED;
2909 }
2910
2911 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo custom attributes in {} ms", GetMSTimeDiffToNow(oldMSTime));
2912}
2913
2914inline void ApplySpellFix(std::initializer_list<uint32> spellIds, void(*fix)(SpellInfo*))
2915{
2916 for (uint32 spellId : spellIds)
2917 {
2918 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
2919 if (!spellInfo)
2920 {
2921 TC_LOG_ERROR("server.loading", "Spell info correction specified for non-existing spell {}", spellId);
2922 continue;
2923 }
2924
2925 fix(const_cast<SpellInfo*>(spellInfo));
2926 }
2927}
2928
2930{
2931 uint32 oldMSTime = getMSTime();
2932
2933 // Some spells have no amplitude set
2934 {
2936 6727, // Poison Mushroom
2937 7288, // Immolate Cumulative (TEST) (Rank 1)
2938 7291, // Food (TEST)
2939 7331, // Healing Aura (TEST) (Rank 1)
2940 /*
2941 30400, // Nether Beam - Perseverance
2942 Blizzlike to have it disabled? DBC says:
2943 "This is currently turned off to increase performance. Enable this to make it fire more frequently."
2944 */
2945 34589, // Dangerous Water
2946 52562, // Arthas Zombie Catcher
2947 57550, // Tirion Aggro
2948 65755
2949 }, [](SpellInfo* spellInfo)
2950 {
2951 spellInfo->_GetEffect(EFFECT_0).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2952 });
2953
2955 24707, // Food
2956 26263, // Dim Sum
2957 29055, // Refreshing Red Apple
2958 37504 // Karazhan - Chess NPC AI, action timer
2959 }, [](SpellInfo* spellInfo)
2960 {
2961 // first effect has correct amplitude
2962 spellInfo->_GetEffect(EFFECT_1).ApplyAuraPeriod = spellInfo->GetEffect(EFFECT_0).ApplyAuraPeriod;
2963 });
2964
2965 // Vomit
2966 ApplySpellFix({ 43327 }, [](SpellInfo* spellInfo)
2967 {
2968 spellInfo->_GetEffect(EFFECT_1).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2969 });
2970
2971 // Strider Presence
2972 ApplySpellFix({ 4312 }, [](SpellInfo* spellInfo)
2973 {
2974 spellInfo->_GetEffect(EFFECT_0).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2975 spellInfo->_GetEffect(EFFECT_1).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2976 });
2977
2978 // Food
2979 ApplySpellFix({ 64345 }, [](SpellInfo* spellInfo)
2980 {
2981 spellInfo->_GetEffect(EFFECT_0).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2982 spellInfo->_GetEffect(EFFECT_2).ApplyAuraPeriod = 1 * IN_MILLISECONDS;
2983 });
2984 }
2985
2986 // specific code for cases with no trigger spell provided in field
2987 {
2988 // Brood Affliction: Bronze
2989 ApplySpellFix({ 23170 }, [](SpellInfo* spellInfo)
2990 {
2991 spellInfo->_GetEffect(EFFECT_0).TriggerSpell = 23171;
2992 });
2993
2994 // Feed Captured Animal
2995 ApplySpellFix({ 29917 }, [](SpellInfo* spellInfo)
2996 {
2997 spellInfo->_GetEffect(EFFECT_0).TriggerSpell = 29916;
2998 });
2999
3000 // Eye of Grillok
3001 ApplySpellFix({ 38495 }, [](SpellInfo* spellInfo)
3002 {
3003 spellInfo->_GetEffect(EFFECT_0).TriggerSpell = 38530;
3004 });
3005
3006 // Tear of Azzinoth Summon Channel - it's not really supposed to do anything, and this only prevents the console spam
3007 ApplySpellFix({ 39857 }, [](SpellInfo* spellInfo)
3008 {
3009 spellInfo->_GetEffect(EFFECT_0).TriggerSpell = 39856;
3010 });
3011
3012 // Personalized Weather
3013 ApplySpellFix({ 46736 }, [](SpellInfo* spellInfo)
3014 {
3015 spellInfo->_GetEffect(EFFECT_1).TriggerSpell = 46737;
3016 });
3017 }
3018
3019 // this one is here because we have no SP bonus for dmgclass none spell
3020 // but this one should since it's DBC data
3022 52042, // Healing Stream Totem
3023 }, [](SpellInfo* spellInfo)
3024 {
3025 // We need more spells to find a general way (if there is any)
3026 spellInfo->DmgClass = SPELL_DAMAGE_CLASS_MAGIC;
3027 });
3028
3029 // Spell Reflection
3030 ApplySpellFix({ 57643 }, [](SpellInfo* spellInfo)
3031 {
3032 spellInfo->EquippedItemClass = -1;
3033 });
3034
3036 63026, // Force Cast (HACK: Target shouldn't be changed)
3037 63137 // Force Cast (HACK: Target shouldn't be changed; summon position should be untied from spell destination)
3038 }, [](SpellInfo* spellInfo)
3039 {
3040 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
3041 });
3042
3043 // Immolate
3045 348,
3046 707,
3047 1094,
3048 2941,
3049 11665,
3050 11667,
3051 11668,
3052 25309,
3053 27215,
3054 47810,
3055 47811
3056 }, [](SpellInfo* spellInfo)
3057 {
3058 // copy SP scaling data from direct damage to DoT
3059 spellInfo->_GetEffect(EFFECT_0).BonusCoefficient = spellInfo->GetEffect(EFFECT_1).BonusCoefficient;
3060 });
3061
3062 // Detect Undead
3063 ApplySpellFix({ 11389 }, [](SpellInfo* spellInfo)
3064 {
3065 spellInfo->PowerType = POWER_MANA;
3066 spellInfo->ManaCost = 0;
3067 spellInfo->ManaPerSecond = 0;
3068 });
3069
3070 // Drink! (Brewfest)
3071 ApplySpellFix({ 42436 }, [](SpellInfo* spellInfo)
3072 {
3073 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY);
3074 });
3075
3076 // Warsong Gulch Anti-Stall Debuffs
3078 46392, // Focused Assault
3079 46393, // Brutal Assault
3080 }, [](SpellInfo* spellInfo)
3081 {
3082 // due to discrepancies between ranks
3083 spellInfo->Attributes |= SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY;
3084 });
3085
3086 // Summon Skeletons
3087 ApplySpellFix({ 52611, 52612 }, [](SpellInfo* spellInfo)
3088 {
3089 spellInfo->_GetEffect(EFFECT_0).MiscValueB = 64;
3090 });
3091
3092 // Battlegear of Eternal Justice
3094 26135, // Battlegear of Eternal Justice
3095 37557 // Mark of Light
3096 }, [](SpellInfo* spellInfo)
3097 {
3098 spellInfo->SpellFamilyFlags = flag96();
3099 });
3100
3102 40244, // Simon Game Visual
3103 40245, // Simon Game Visual
3104 40246, // Simon Game Visual
3105 40247, // Simon Game Visual
3106 42835 // Spout, remove damage effect, only anim is needed
3107 }, [](SpellInfo* spellInfo)
3108 {
3109 spellInfo->_GetEffect(EFFECT_0).Effect = SPELL_EFFECT_NONE;
3110 });
3111
3113 63665, // Charge (Argent Tournament emote on riders)
3114 51904, // Summon Ghouls On Scarlet Crusade (this should use conditions table, script for this spell needs to be fixed)
3115 2895, // Wrath of Air Totem rank 1 (Aura)
3116 68933, // Wrath of Air Totem rank 2 (Aura)
3117 29200, // Purify Helboar Meat
3118 10872, // Abolish Disease Effect
3119 3137 // Abolish Poison Effect
3120 }, [](SpellInfo* spellInfo)
3121 {
3122 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3123 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo();
3124 });
3125
3127 56690, // Thrust Spear
3128 60586, // Mighty Spear Thrust
3129 60776, // Claw Swipe
3130 60881, // Fatal Strike
3131 60864 // Jaws of Death
3132 }, [](SpellInfo* spellInfo)
3133 {
3134 spellInfo->AttributesEx4 |= SPELL_ATTR4_FIXED_DAMAGE;
3135 });
3136
3137 // Missile Barrage
3138 ApplySpellFix({ 44401 }, [](SpellInfo* spellInfo)
3139 {
3140 // should be consumed before Clearcasting
3141 spellInfo->Priority = 100;
3142 });
3143
3145 42818, // Headless Horseman - Wisp Flight Port
3146 42821, // Headless Horseman - Wisp Flight Missile
3147 17678, // Despawn Spectral Combatants
3148 720, // Entangle
3149 731 // Entangle
3150 }, [](SpellInfo* spellInfo)
3151 {
3152 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100 yards
3153 });
3154
3155 // They Must Burn Bomb Aura (self)
3156 ApplySpellFix({ 36350 }, [](SpellInfo* spellInfo)
3157 {
3158 spellInfo->_GetEffect(EFFECT_0).TriggerSpell = 36325; // They Must Burn Bomb Drop (DND)
3159 });
3160
3162 61407, // Energize Cores
3163 62136, // Energize Cores
3164 54069, // Energize Cores
3165 56251 // Energize Cores
3166 }, [](SpellInfo* spellInfo)
3167 {
3168 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENTRY);
3169 });
3170
3172 50785, // Energize Cores
3173 59372 // Energize Cores
3174 }, [](SpellInfo* spellInfo)
3175 {
3176 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ENEMY);
3177 });
3178
3179 // Mana Shield (rank 2)
3180 ApplySpellFix({ 8494 }, [](SpellInfo* spellInfo)
3181 {
3182 // because of bug in dbc
3183 spellInfo->ProcChance = 0;
3184 });
3185
3186 // Maelstrom Weapon
3188 51528, // (Rank 1)
3189 51529, // (Rank 2)
3190 51530, // (Rank 3)
3191 51531, // (Rank 4)
3192 51532 // (Rank 5)
3193 }, [](SpellInfo* spellInfo)
3194 {
3195 // due to discrepancies between ranks
3196 spellInfo->EquippedItemSubClassMask = 0x0000FC33;
3197 spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_FROM_PROCS;
3198 });
3199
3201 20335, // Heart of the Crusader
3202 20336,
3203 20337,
3204 53228, // Rapid Killing (Rank 1)
3205 53232, // Rapid Killing (Rank 2)
3206 63320 // Glyph of Life Tap
3207 }, [](SpellInfo* spellInfo)
3208 {
3209 // Entries were not updated after spell effect change, we have to do that manually :/
3210 spellInfo->AttributesEx3 |= SPELL_ATTR3_CAN_PROC_FROM_PROCS;
3211 });
3212
3214 51627, // Turn the Tables (Rank 1)
3215 51628, // Turn the Tables (Rank 2)
3216 51629 // Turn the Tables (Rank 3)
3217 }, [](SpellInfo* spellInfo)
3218 {
3219 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
3220 });
3221
3223 52910, // Turn the Tables
3224 52914, // Turn the Tables
3225 52915 // Turn the Tables
3226 }, [](SpellInfo* spellInfo)
3227 {
3228 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3229 });
3230
3231 // Magic Absorption
3233 29441, // (Rank 1)
3234 29444 // (Rank 2)
3235 }, [](SpellInfo* spellInfo)
3236 {
3237 // Caused off by 1 calculation (ie 79 resistance at level 80)
3238 spellInfo->SpellLevel = 0;
3239 });
3240
3241 // Execute
3243 5308, // (Rank 1)
3244 20658, // (Rank 2)
3245 20660, // (Rank 3)
3246 20661, // (Rank 4)
3247 20662, // (Rank 5)
3248 25234, // (Rank 6)
3249 25236, // (Rank 7)
3250 47470, // (Rank 8)
3251 47471 // (Rank 9)
3252 }, [](SpellInfo* spellInfo)
3253 {
3254 spellInfo->AttributesEx3 |= SPELL_ATTR3_CANT_TRIGGER_PROC;
3255 });
3256
3257 // Improved Spell Reflection - aoe aura
3258 ApplySpellFix({ 59725 }, [](SpellInfo* spellInfo)
3259 {
3260 // Target entry seems to be wrong for this spell :/
3261 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER_AREA_PARTY);
3262 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_20_YARDS);
3263 });
3264
3266 44978, // Wild Magic
3267 45001, // Wild Magic
3268 45002, // Wild Magic
3269 45004, // Wild Magic
3270 45006, // Wild Magic
3271 45010, // Wild Magic
3272 41635, // Prayer of Mending
3273 44869, // Spectral Blast
3274 45027, // Revitalize
3275 45976, // Muru Portal Channel
3276 39365, // Thundering Storm
3277 41071, // Raise Dead (HACK)
3278 52124, // Sky Darkener Assault
3279 42442, // Vengeance Landing Cannonfire
3280 45863, // Cosmetic - Incinerate to Random Target
3281 25425, // Shoot
3282 45761, // Shoot
3283 42611, // Shoot
3284 61588, // Blazing Harpoon
3285 52479, // Gift of the Harvester
3286 48246, // Ball of Flame
3287 36327, // Shoot Arcane Explosion Arrow
3288 55479, // Force Obedience
3289 28560, // Summon Blizzard (Sapphiron)
3290 53096, // Quetz'lun's Judgment
3291 70743, // AoD Special
3292 70614, // AoD Special - Vegard
3293 4020, // Safirdrang's Chill
3294 52438, // Summon Skittering Swarmer (Force Cast)
3295 52449, // Summon Skittering Infector (Force Cast)
3296 53609, // Summon Anub'ar Assassin (Force Cast)
3297 53457, // Summon Impale Trigger (AoE)
3298 45907, // Torch Target Picker
3299 52953, // Torch
3300 58121, // Torch
3301 43109, // Throw Torch
3302 58552, // Return to Orgrimmar
3303 58533, // Return to Stormwind
3304 21855, // Challenge Flag
3305 38762, // Force of Neltharaku
3306 51122, // Fierce Lightning Stike
3307 71848, // Toxic Wasteling Find Target
3308 36146, // Chains of Naberius
3309 33711, // Murmur's Touch
3310 38794 // Murmur's Touch
3311 }, [](SpellInfo* spellInfo)
3312 {
3313 spellInfo->MaxAffectedTargets = 1;
3314 });
3315
3317 36384, // Skartax Purple Beam
3318 47731 // Critter
3319 }, [](SpellInfo* spellInfo)
3320 {
3321 spellInfo->MaxAffectedTargets = 2;
3322 });
3323
3325 41376, // Spite
3326 39992, // Needle Spine
3327 29576, // Multi-Shot
3328 40816, // Saber Lash
3329 37790, // Spread Shot
3330 46771, // Flame Sear
3331 45248, // Shadow Blades
3332 41303, // Soul Drain
3333 54172, // Divine Storm (heal)
3334 29213, // Curse of the Plaguebringer - Noth
3335 28542, // Life Drain - Sapphiron
3336 66588, // Flaming Spear
3337 54171 // Divine Storm
3338 }, [](SpellInfo* spellInfo)
3339 {
3340 spellInfo->MaxAffectedTargets = 3;
3341 });
3342
3344 38310, // Multi-Shot
3345 53385 // Divine Storm (Damage)
3346 }, [](SpellInfo* spellInfo)
3347 {
3348 spellInfo->MaxAffectedTargets = 4;
3349 });
3350
3352 42005, // Bloodboil
3353 38296, // Spitfire Totem
3354 37676, // Insidious Whisper
3355 46008, // Negative Energy
3356 45641, // Fire Bloom
3357 55665, // Life Drain - Sapphiron (H)
3358 28796, // Poison Bolt Volly - Faerlina
3359 37135 // Domination
3360 }, [](SpellInfo* spellInfo)
3361 {
3362 spellInfo->MaxAffectedTargets = 5;
3363 });
3364
3366 40827, // Sinful Beam
3367 40859, // Sinister Beam
3368 40860, // Vile Beam
3369 40861, // Wicked Beam
3370 54098, // Poison Bolt Volly - Faerlina (H)
3371 54835 // Curse of the Plaguebringer - Noth (H)
3372 }, [](SpellInfo* spellInfo)
3373 {
3374 spellInfo->MaxAffectedTargets = 10;
3375 });
3376
3378 50312 // Unholy Frenzy
3379 }, [](SpellInfo* spellInfo)
3380 {
3381 spellInfo->MaxAffectedTargets = 15;
3382 });
3383
3385 47977, // Magic Broom
3386 48025, // Headless Horseman's Mount
3387 54729, // Winged Steed of the Ebon Blade
3388 58983, // Big Blizzard Bear
3389 65917, // Magic Rooster
3390 71342, // Big Love Rocket
3391 72286, // Invincible
3392 74856, // Blazing Hippogryph
3393 75614, // Celestial Steed
3394 75973 // X-53 Touring Rocket
3395 }, [](SpellInfo* spellInfo)
3396 {
3397 // First two effects apply auras, which shouldn't be there
3398 // due to NO_TARGET applying aura on current caster (core bug)
3399 // Just wipe effect data, to mimic blizz-behavior
3400 spellInfo->_GetEffect(EFFECT_0).Effect = SPELL_EFFECT_NONE;
3401 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_NONE;
3402 });
3403
3404 // Lock and Load (Rank 1)
3405 ApplySpellFix({ 56342 }, [](SpellInfo* spellInfo)
3406 {
3407 // @workaround: Delete dummy effect from rank 1
3408 // effect apply aura has NO_TARGET but core still applies it to caster (same as above)
3409 spellInfo->_GetEffect(EFFECT_2).Effect = SPELL_EFFECT_NONE;
3410 });
3411
3412 // Roar of Sacrifice
3413 ApplySpellFix({ 53480 }, [](SpellInfo* spellInfo)
3414 {
3415 // missing spell effect 2 data, taken from 4.3.4
3416 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_APPLY_AURA;
3417 spellInfo->_GetEffect(EFFECT_1).ApplyAuraName = SPELL_AURA_DUMMY;
3418 spellInfo->_GetEffect(EFFECT_1).MiscValue = 127;
3419 spellInfo->_GetEffect(EFFECT_1).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ALLY);
3420 });
3421
3422 // Fingers of Frost
3423 ApplySpellFix({ 44544 }, [](SpellInfo* spellInfo)
3424 {
3425 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(685904631, 1151048, 0);
3426 });
3427
3428 // Magic Suppression - DK
3429 ApplySpellFix({ 49224, 49610, 49611 }, [](SpellInfo* spellInfo)
3430 {
3431 spellInfo->ProcCharges = 0;
3432 });
3433
3434 // Death and Decay
3435 ApplySpellFix({ 52212 }, [](SpellInfo* spellInfo)
3436 {
3437 spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE;
3438 });
3439
3440 // Oscillation Field
3441 ApplySpellFix({ 37408 }, [](SpellInfo* spellInfo)
3442 {
3443 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
3444 });
3445
3446 // Everlasting Affliction
3447 ApplySpellFix({ 47201, 47202, 47203, 47204, 47205 }, [](SpellInfo* spellInfo)
3448 {
3449 // add corruption to affected spells
3450 spellInfo->_GetEffect(EFFECT_1).SpellClassMask[0] |= 2;
3451 });
3452
3453 // Renewed Hope
3455 57470, // (Rank 1)
3456 57472 // (Rank 2)
3457 }, [](SpellInfo* spellInfo)
3458 {
3459 // should also affect Flash Heal
3460 spellInfo->_GetEffect(EFFECT_0).SpellClassMask[0] |= 0x800;
3461 });
3462
3463 // Crafty's Ultra-Advanced Proto-Typical Shortening Blaster
3464 ApplySpellFix({ 51912 }, [](SpellInfo* spellInfo)
3465 {
3466 spellInfo->_GetEffect(EFFECT_0).ApplyAuraPeriod = 3000;
3467 });
3468
3469 // Desecration Arm - 36 instead of 37 - typo? :/
3470 ApplySpellFix({ 29809 }, [](SpellInfo* spellInfo)
3471 {
3472 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_7_YARDS);
3473 });
3474
3475 // In sniff caster hits multiple targets
3477 73725, // [DND] Test Cheer
3478 73835, // [DND] Test Salute
3479 73836 // [DND] Test Roar
3480 }, [](SpellInfo* spellInfo)
3481 {
3482 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50_YARDS); // 50yd
3483 });
3484
3485 // In sniff caster hits multiple targets
3487 73837, // [DND] Test Dance
3488 73886 // [DND] Test Stop Dance
3489 }, [](SpellInfo* spellInfo)
3490 {
3491 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_150_YARDS); // 150yd
3492 });
3493
3494 // Radius in DBC is not enough
3496 36854, // Channel
3497 36856 // Channel
3498 }, [](SpellInfo* spellInfo)
3499 {
3500 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(5); // 40yd
3501 });
3502
3503 // Master Shapeshifter: missing stance data for forms other than bear - bear version has correct data
3504 // To prevent aura staying on target after talent unlearned
3505 ApplySpellFix({ 48420 }, [](SpellInfo* spellInfo)
3506 {
3507 spellInfo->Stances = UI64LIT(1) << (FORM_CAT - 1);
3508 });
3509
3510 ApplySpellFix({ 48421 }, [](SpellInfo* spellInfo)
3511 {
3512 spellInfo->Stances = UI64LIT(1) << (FORM_MOONKIN - 1);
3513 });
3514
3515 ApplySpellFix({ 48422 }, [](SpellInfo* spellInfo)
3516 {
3517 spellInfo->Stances = UI64LIT(1) << (FORM_TREE - 1);
3518 });
3519
3520 // Improved Shadowform (Rank 1)
3521 ApplySpellFix({ 47569 }, [](SpellInfo* spellInfo)
3522 {
3523 // with this spell atrribute aura can be stacked several times
3524 spellInfo->Attributes &= ~SPELL_ATTR0_NOT_SHAPESHIFT;
3525 });
3526
3527 // Hymn of Hope
3528 ApplySpellFix({ 64904 }, [](SpellInfo* spellInfo)
3529 {
3530 spellInfo->_GetEffect(EFFECT_1).ApplyAuraName = SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT;
3531 });
3532
3533 // Improved Stings (Rank 2)
3534 ApplySpellFix({ 19465 }, [](SpellInfo* spellInfo)
3535 {
3536 spellInfo->_GetEffect(EFFECT_2).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3537 });
3538
3539 // Nether Portal - Perseverence
3540 ApplySpellFix({ 30421 }, [](SpellInfo* spellInfo)
3541 {
3542 spellInfo->_GetEffect(EFFECT_2).BasePoints += 30000;
3543 });
3544
3545 // Natural shapeshifter
3546 ApplySpellFix({ 16834, 16835 }, [](SpellInfo* spellInfo)
3547 {
3548 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(21);
3549 });
3550
3551 // Ebon Plague
3552 ApplySpellFix({ 65142 }, [](SpellInfo* spellInfo)
3553 {
3554 spellInfo->AttributesEx3 &= ~SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
3555 });
3556
3557 // Ebon Plague
3558 ApplySpellFix({ 51735, 51734, 51726 }, [](SpellInfo* spellInfo)
3559 {
3560 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
3561 spellInfo->SpellFamilyFlags[2] = 0x10;
3562 spellInfo->_GetEffect(EFFECT_1).ApplyAuraName = SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN;
3563 });
3564
3565 // Parasitic Shadowfiend Passive
3566 ApplySpellFix({ 41913 }, [](SpellInfo* spellInfo)
3567 {
3568 // proc debuff, and summon infinite fiends
3569 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_DUMMY;
3570 });
3571
3573 27892, // To Anchor 1
3574 27928, // To Anchor 1
3575 27935, // To Anchor 1
3576 27915, // Anchor to Skulls
3577 27931, // Anchor to Skulls
3578 27937, // Anchor to Skulls
3579 16177, // Ancestral Fortitude (Rank 1)
3580 16236, // Ancestral Fortitude (Rank 2)
3581 16237, // Ancestral Fortitude (Rank 3)
3582 47930, // Grace
3583 45145, // Snake Trap Effect (Rank 1)
3584 13812, // Explosive Trap Effect (Rank 1)
3585 14314, // Explosive Trap Effect (Rank 2)
3586 14315, // Explosive Trap Effect (Rank 3)
3587 27026, // Explosive Trap Effect (Rank 4)
3588 49064, // Explosive Trap Effect (Rank 5)
3589 49065, // Explosive Trap Effect (Rank 6)
3590 43446, // Explosive Trap Effect (Hexlord Malacrass)
3591 50661, // Weakened Resolve
3592 68979, // Unleashed Souls
3593 48714, // Compelled
3594 7853 // The Art of Being a Water Terror: Force Cast on Player
3595 }, [](SpellInfo* spellInfo)
3596 {
3597 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13);
3598 });
3599
3600 // Wrath of the Plaguebringer
3601 ApplySpellFix({ 29214, 54836 }, [](SpellInfo* spellInfo)
3602 {
3603 // target allys instead of enemies, target A is src_caster, spells with effect like that have ally target
3604 // this is the only known exception, probably just wrong data
3605 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
3606 spellInfo->_GetEffect(EFFECT_1).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_SRC_AREA_ALLY);
3607 });
3608
3609 // Wind Shear
3610 ApplySpellFix({ 57994 }, [](SpellInfo* spellInfo)
3611 {
3612 // improper data for EFFECT_1 in 3.3.5 DBC, but is correct in 4.x
3613 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_MODIFY_THREAT_PERCENT;
3614 spellInfo->_GetEffect(EFFECT_1).BasePoints = -6; // -5%
3615 });
3616
3618 50526, // Wandering Plague
3619 15290 // Vampiric Embrace
3620 }, [](SpellInfo* spellInfo)
3621 {
3622 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO;
3623 });
3624
3625 // Vampiric Touch (dispel effect)
3626 ApplySpellFix({ 64085 }, [](SpellInfo* spellInfo)
3627 {
3628 // copy from similar effect of Unstable Affliction (31117)
3629 spellInfo->AttributesEx4 |= SPELL_ATTR4_FIXED_DAMAGE;
3630 spellInfo->AttributesEx6 |= SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS;
3631 });
3632
3633 // Dispersion
3634 ApplySpellFix({ 60069 }, [](SpellInfo* spellInfo)
3635 {
3636 spellInfo->_GetEffect(EFFECT_0).MiscValue = POWER_MANA;
3637 });
3638
3639 // Improved Devouring Plague
3640 ApplySpellFix({ 63675 }, [](SpellInfo* spellInfo)
3641 {
3642 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
3643 });
3644
3645 // Deep Wounds
3646 ApplySpellFix({ 12721 }, [](SpellInfo* spellInfo)
3647 {
3648 // shouldnt ignore resillience or damage taken auras because its damage is not based off a spell.
3649 spellInfo->AttributesEx4 &= ~SPELL_ATTR4_FIXED_DAMAGE;
3650 });
3651
3652 // Tremor Totem (instant pulse)
3653 ApplySpellFix({ 8145 }, [](SpellInfo* spellInfo)
3654 {
3655 spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
3656 spellInfo->AttributesEx5 |= SPELL_ATTR5_START_PERIODIC_AT_APPLY;
3657 });
3658
3659 // Earthbind Totem (instant pulse)
3660 ApplySpellFix({ 6474 }, [](SpellInfo* spellInfo)
3661 {
3662 spellInfo->AttributesEx5 |= SPELL_ATTR5_START_PERIODIC_AT_APPLY;
3663 });
3664
3665 // Flametongue Totem (Aura)
3667 52109, // rank 1
3668 52110, // rank 2
3669 52111, // rank 3
3670 52112, // rank 4
3671 52113, // rank 5
3672 58651, // rank 6
3673 58654, // rank 7
3674 58655 // rank 8
3675 }, [](SpellInfo* spellInfo)
3676 {
3677 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3678 spellInfo->_GetEffect(EFFECT_1).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3679 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo();
3680 spellInfo->_GetEffect(EFFECT_1).TargetB = SpellImplicitTargetInfo();
3681 });
3682
3683 // Marked for Death
3685 53241, // (Rank 1)
3686 53243, // (Rank 2)
3687 53244, // (Rank 3)
3688 53245, // (Rank 4)
3689 53246 // (Rank 5)
3690 }, [](SpellInfo* spellInfo)
3691 {
3692 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(0x00067801, 0x10820001, 0x00000801);
3693 });
3694
3696 70728, // Exploit Weakness (needs target selection script)
3697 70840 // Devious Minds (needs target selection script)
3698 }, [](SpellInfo* spellInfo)
3699 {
3700 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3701 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_PET);
3702 });
3703
3704 // Culling The Herd (needs target selection script)
3705 ApplySpellFix({ 70893 }, [](SpellInfo* spellInfo)
3706 {
3707 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
3708 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_MASTER);
3709 });
3710
3711 // Sigil of the Frozen Conscience
3712 ApplySpellFix({ 54800 }, [](SpellInfo* spellInfo)
3713 {
3714 // change class mask to custom extended flags of Icy Touch
3715 // this is done because another spell also uses the same SpellFamilyFlags as Icy Touch
3716 // SpellFamilyFlags[0] & 0x00000040 in SPELLFAMILY_DEATHKNIGHT is currently unused (3.3.5a)
3717 // this needs research on modifier applying rules, does not seem to be in Attributes fields
3718 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(0x00000040, 0x00000000, 0x00000000);
3719 });
3720
3721 // Idol of the Flourishing Life
3722 ApplySpellFix({ 64949 }, [](SpellInfo* spellInfo)
3723 {
3724 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(0x00000000, 0x02000000, 0x00000000);
3725 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER;
3726 });
3727
3729 34231, // Libram of the Lightbringer
3730 60792, // Libram of Tolerance
3731 64956 // Libram of the Resolute
3732 }, [](SpellInfo* spellInfo)
3733 {
3734 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(0x80000000, 0x00000000, 0x00000000);
3735 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER;
3736 });
3737
3739 28851, // Libram of Light
3740 28853, // Libram of Divinity
3741 32403 // Blessed Book of Nagrand
3742 }, [](SpellInfo* spellInfo)
3743 {
3744 spellInfo->_GetEffect(EFFECT_0).SpellClassMask = flag96(0x40000000, 0x00000000, 0x00000000);
3745 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_ADD_FLAT_MODIFIER;
3746 });
3747
3748 // Ride Carpet
3749 ApplySpellFix({ 45602 }, [](SpellInfo* spellInfo)
3750 {
3751 // force seat 0, vehicle doesn't have the required seat flags for "no seat specified (-1)"
3752 spellInfo->_GetEffect(EFFECT_0).BasePoints = 0;
3753 });
3754
3756 64745, // Item - Death Knight T8 Tank 4P Bonus
3757 64936 // Item - Warrior T8 Protection 4P Bonus
3758 }, [](SpellInfo* spellInfo)
3759 {
3760 // 100% chance of procc'ing, not -10% (chance calculated in PrepareTriggersExecutedOnHit)
3761 spellInfo->_GetEffect(EFFECT_0).BasePoints = 100;
3762 });
3763
3764 // Entangling Roots -- Nature's Grasp Proc
3766 19970, // (Rank 6)
3767 19971, // (Rank 5)
3768 19972, // (Rank 4)
3769 19973, // (Rank 3)
3770 19974, // (Rank 2)
3771 19975, // (Rank 1)
3772 27010, // (Rank 7)
3773 53313 // (Rank 8)
3774 }, [](SpellInfo* spellInfo)
3775 {
3776 spellInfo->CastTimeEntry = sSpellCastTimesStore.LookupEntry(1);
3777 });
3778
3779 // Easter Lay Noblegarden Egg Aura
3780 ApplySpellFix({ 61719 }, [](SpellInfo* spellInfo)
3781 {
3782 // Interrupt flags copied from aura which this aura is linked with
3783 spellInfo->AuraInterruptFlags = AURA_INTERRUPT_FLAG_HITBYSPELL | AURA_INTERRUPT_FLAG_TAKE_DAMAGE;
3784 });
3785
3786 // Death Knight T10 Tank 2P Bonus
3787 ApplySpellFix({ 70650 }, [](SpellInfo* spellInfo)
3788 {
3789 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_ADD_PCT_MODIFIER;
3790 });
3791
3793 6789, // Warlock - Death Coil (Rank 1)
3794 17925, // Warlock - Death Coil (Rank 2)
3795 17926, // Warlock - Death Coil (Rank 3)
3796 27223, // Warlock - Death Coil (Rank 4)
3797 47859, // Warlock - Death Coil (Rank 5)
3798 47860, // Warlock - Death Coil (Rank 6)
3799 71838, // Drain Life - Bryntroll Normal
3800 71839 // Drain Life - Bryntroll Heroic
3801 }, [](SpellInfo* spellInfo)
3802 {
3803 spellInfo->AttributesEx2 |= SPELL_ATTR2_CANT_CRIT;
3804 });
3805
3807 51597, // Summon Scourged Captive
3808 56606, // Ride Jokkum
3809 61791 // Ride Vehicle (Yogg-Saron)
3810 }, [](SpellInfo* spellInfo)
3811 {
3813 spellInfo->_GetEffect(EFFECT_0).BasePoints = 1;
3814 });
3815
3816 // Summon Scourged Captive
3817 ApplySpellFix({ 51597 }, [](SpellInfo* spellInfo)
3818 {
3819 spellInfo->_GetEffect(EFFECT_0).DieSides = 0;
3820 });
3821
3822 // Black Magic
3823 ApplySpellFix({ 59630 }, [](SpellInfo* spellInfo)
3824 {
3825 spellInfo->Attributes |= SPELL_ATTR0_PASSIVE;
3826 });
3827
3829 17364, // Stormstrike
3830 48278, // Paralyze
3831 53651 // Light's Beacon
3832 }, [](SpellInfo* spellInfo)
3833 {
3834 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
3835 });
3836
3838 51798, // Brewfest - Relay Race - Intro - Quest Complete
3839 47134 // Quest Complete
3840 }, [](SpellInfo* spellInfo)
3841 {
3843 spellInfo->_GetEffect(EFFECT_0).Effect = SPELL_EFFECT_NONE;
3844 });
3845
3847 47476, // Deathknight - Strangulate
3848 15487, // Priest - Silence
3849 5211, // Druid - Bash - R1
3850 6798, // Druid - Bash - R2
3851 8983 // Druid - Bash - R3
3852 }, [](SpellInfo* spellInfo)
3853 {
3854 spellInfo->AttributesEx7 |= SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER;
3855 });
3856
3857 // Guardian Spirit
3858 ApplySpellFix({ 47788 }, [](SpellInfo* spellInfo)
3859 {
3860 spellInfo->ExcludeTargetAuraSpell = 72232; // Weakened Spirit
3861 });
3862
3864 15538, // Gout of Flame
3865 42490, // Energized!
3866 42492, // Cast Energized
3867 43115 // Plague Vial
3868 }, [](SpellInfo* spellInfo)
3869 {
3870 spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT;
3871 });
3872
3874 46842, // Flame Ring
3875 46836 // Flame Patch
3876 }, [](SpellInfo* spellInfo)
3877 {
3878 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo();
3879 });
3880
3881 // Test Ribbon Pole Channel
3882 ApplySpellFix({ 29726 }, [](SpellInfo* spellInfo)
3883 {
3884 spellInfo->InterruptFlags &= ~AURA_INTERRUPT_FLAG_CAST;
3885 });
3886
3888 42767, // Sic'em
3889 43092 // Stop the Ascension!: Halfdan's Soul Destruction
3890 }, [](SpellInfo* spellInfo)
3891 {
3892 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_NEARBY_ENTRY);
3893 });
3894
3895 // Polymorph (Six Demon Bag)
3896 ApplySpellFix({ 14621 }, [](SpellInfo* spellInfo)
3897 {
3898 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(4); // Medium Range
3899 });
3900
3901 // Concussive Barrage
3902 ApplySpellFix({ 35101 }, [](SpellInfo* spellInfo)
3903 {
3904 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(155); // Hunter Range (Long)
3905 });
3906
3908 44327, // Trained Rock Falcon/Hawk Hunting
3909 44408 // Trained Rock Falcon/Hawk Hunting
3910 }, [](SpellInfo* spellInfo)
3911 {
3912 spellInfo->Speed = 0.f;
3913 });
3914
3916 51675, // Rogue - Unfair Advantage (Rank 1)
3917 51677 // Rogue - Unfair Advantage (Rank 2)
3918 }, [](SpellInfo* spellInfo)
3919 {
3920 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(2); // 5 yards
3921 });
3922
3924 55741, // Desecration (Rank 1)
3925 68766, // Desecration (Rank 2)
3926 57842 // Killing Spree (Off hand damage)
3927 }, [](SpellInfo* spellInfo)
3928 {
3929 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(2); // Melee Range
3930 });
3931
3932 // Safeguard
3934 46946, // (Rank 1)
3935 46947 // (Rank 2)
3936 }, [](SpellInfo* spellInfo)
3937 {
3938 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(34); // Twenty-Five yards
3939 });
3940
3941 // Summon Corpse Scarabs
3942 ApplySpellFix({ 28864, 29105 }, [](SpellInfo* spellInfo)
3943 {
3944 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS);
3945 });
3946
3947 // Without this auras 35173 and 35174 triggers no spell and are removed after first tick
3949 35158, // Reflective Magic Shield
3950 35159 // Reflective Damage Shield
3951 }, [](SpellInfo* spellInfo)
3952 {
3953 spellInfo->RecoveryTime = 0;
3954 });
3955
3957 37851, // Tag Greater Felfire Diemetradon
3958 37918 // Arcano-pince
3959 }, [](SpellInfo* spellInfo)
3960 {
3961 spellInfo->RecoveryTime = 3000;
3962 });
3963
3964 // Jormungar Strike
3965 ApplySpellFix({ 56513 }, [](SpellInfo* spellInfo)
3966 {
3967 spellInfo->RecoveryTime = 2000;
3968 });
3969
3971 54997, // Cast Net (tooltip says 10s but sniffs say 6s)
3972 56524 // Acid Breath
3973 }, [](SpellInfo* spellInfo)
3974 {
3975 spellInfo->RecoveryTime = 6000;
3976 });
3977
3979 47911, // EMP
3980 48620, // Wing Buffet
3981 51752 // Stampy's Stompy-Stomp
3982 }, [](SpellInfo* spellInfo)
3983 {
3984 spellInfo->RecoveryTime = 10000;
3985 });
3986
3988 37727, // Touch of Darkness
3989 54996 // Ice Slick (tooltip says 20s but sniffs say 12s)
3990 }, [](SpellInfo* spellInfo)
3991 {
3992 spellInfo->RecoveryTime = 12000;
3993 });
3994
3995 // Signal Helmet to Attack
3996 ApplySpellFix({ 51748 }, [](SpellInfo* spellInfo)
3997 {
3998 spellInfo->RecoveryTime = 15000;
3999 });
4000
4002 51756, // Charge
4003 37919, //Arcano-dismantle
4004 37917 //Arcano-Cloak
4005 }, [](SpellInfo* spellInfo)
4006 {
4007 spellInfo->RecoveryTime = 20000;
4008 });
4009
4010 // Summon Frigid Bones
4011 ApplySpellFix({ 53525 }, [](SpellInfo* spellInfo)
4012 {
4013 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(4); // 2 minutes
4014 });
4015
4016 // Dark Conclave Ritualist Channel
4017 ApplySpellFix({ 38469 }, [](SpellInfo* spellInfo)
4018 {
4019 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100yd
4020 });
4021
4022 //
4023 // VIOLET HOLD SPELLS
4024 //
4025 // Water Globule (Ichoron)
4026 ApplySpellFix({ 54258, 54264, 54265, 54266, 54267 }, [](SpellInfo* spellInfo)
4027 {
4028 // in 3.3.5 there is only one radius in dbc which is 0 yards in this
4029 // use max radius from 4.3.4
4030 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS);
4031 });
4032 // ENDOF VIOLET HOLD
4033
4034 //
4035 // ULDUAR SPELLS
4036 //
4037 // Pursued (Flame Leviathan)
4038 ApplySpellFix({ 62374 }, [](SpellInfo* spellInfo)
4039 {
4040 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4041 });
4042
4043 // Focused Eyebeam Summon Trigger (Kologarn)
4044 ApplySpellFix({ 63342 }, [](SpellInfo* spellInfo)
4045 {
4046 spellInfo->MaxAffectedTargets = 1;
4047 });
4048
4050 62716, // Growth of Nature (Freya)
4051 65584, // Growth of Nature (Freya)
4052 64381 // Strength of the Pack (Auriaya)
4053 }, [](SpellInfo* spellInfo)
4054 {
4055 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
4056 });
4057
4059 63018, // Searing Light (XT-002)
4060 65121, // Searing Light (25m) (XT-002)
4061 63024, // Gravity Bomb (XT-002)
4062 64234 // Gravity Bomb (25m) (XT-002)
4063 }, [](SpellInfo* spellInfo)
4064 {
4065 spellInfo->MaxAffectedTargets = 1;
4066 });
4067
4069 64386, // Terrifying Screech (Auriaya)
4070 64389, // Sentinel Blast (Auriaya)
4071 64678 // Sentinel Blast (Auriaya)
4072 }, [](SpellInfo* spellInfo)
4073 {
4074 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(28); // 5 seconds, wrong DBC data?
4075 });
4076
4077 // Summon Swarming Guardian (Auriaya)
4078 ApplySpellFix({ 64397 }, [](SpellInfo* spellInfo)
4079 {
4080 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(137); // 8y, Based in BFA effect radius
4081 });
4082
4083 // Potent Pheromones (Freya)
4084 ApplySpellFix({ 64321 }, [](SpellInfo* spellInfo)
4085 {
4086 // spell should dispel area aura, but doesn't have the attribute
4087 // may be db data bug, or blizz may keep reapplying area auras every update with checking immunity
4088 // that will be clear if we get more spells with problem like this
4089 spellInfo->AttributesEx |= SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY;
4090 });
4091
4092 // Blizzard (Thorim)
4093 ApplySpellFix({ 62576, 62602 }, [](SpellInfo* spellInfo)
4094 {
4095 // DBC data is wrong for EFFECT_0, it's a different dynobject target than EFFECT_1
4096 // Both effects should be shared by the same DynObject
4097 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_DEST_CASTER_LEFT);
4098 });
4099
4100 // Spinning Up (Mimiron)
4101 ApplySpellFix({ 63414 }, [](SpellInfo* spellInfo)
4102 {
4103 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
4104 spellInfo->ChannelInterruptFlags = 0;
4105 });
4106
4107 // Rocket Strike (Mimiron)
4108 ApplySpellFix({ 63036 }, [](SpellInfo* spellInfo)
4109 {
4110 spellInfo->Speed = 0;
4111 });
4112
4113 // Magnetic Field (Mimiron)
4114 ApplySpellFix({ 64668 }, [](SpellInfo* spellInfo)
4115 {
4116 spellInfo->Mechanic = MECHANIC_NONE;
4117 });
4118
4119 // Empowering Shadows (Yogg-Saron)
4120 ApplySpellFix({ 64468, 64486 }, [](SpellInfo* spellInfo)
4121 {
4122 spellInfo->MaxAffectedTargets = 3; // same for both modes?
4123 });
4124
4125 // Cosmic Smash (Algalon the Observer)
4126 ApplySpellFix({ 62301 }, [](SpellInfo* spellInfo)
4127 {
4128 spellInfo->MaxAffectedTargets = 1;
4129 });
4130
4131 // Cosmic Smash (Algalon the Observer)
4132 ApplySpellFix({ 64598 }, [](SpellInfo* spellInfo)
4133 {
4134 spellInfo->MaxAffectedTargets = 3;
4135 });
4136
4137 // Cosmic Smash (Algalon the Observer)
4138 ApplySpellFix({ 62293 }, [](SpellInfo* spellInfo)
4139 {
4140 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_DEST_CASTER);
4141 });
4142
4143 // Cosmic Smash (Algalon the Observer)
4144 ApplySpellFix({ 62311, 64596 }, [](SpellInfo* spellInfo)
4145 {
4146 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100yd
4147 });
4148
4150 64014, // Expedition Base Camp Teleport
4151 64024, // Conservatory Teleport
4152 64025, // Halls of Invention Teleport
4153 64028, // Colossal Forge Teleport
4154 64029, // Shattered Walkway Teleport
4155 64030, // Antechamber Teleport
4156 64031, // Scrapyard Teleport
4157 64032, // Formation Grounds Teleport
4158 65042 // Prison of Yogg-Saron Teleport
4159 }, [](SpellInfo* spellInfo)
4160 {
4161 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
4162 });
4163 // ENDOF ULDUAR SPELLS
4164
4165 //
4166 // TRIAL OF THE CRUSADER SPELLS
4167 //
4168 // Infernal Eruption
4169 ApplySpellFix({ 66258, 67901 }, [](SpellInfo* spellInfo)
4170 {
4171 // increase duration from 15 to 18 seconds because caster is already
4172 // unsummoned when spell missile hits the ground so nothing happen in result
4173 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(85);
4174 });
4175 // ENDOF TRIAL OF THE CRUSADER SPELLS
4176
4177 //
4178 // HALLS OF REFLECTION SPELLS
4179 //
4181 72435, // Defiling Horror
4182 72452 // Defiling Horror
4183 }, [](SpellInfo* spellInfo)
4184 {
4185 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_60_YARDS); // 60yd
4186 });
4187
4188 // Achievement Check
4189 ApplySpellFix({ 72830 }, [](SpellInfo* spellInfo)
4190 {
4191 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4192 });
4193
4194 // Start Halls of Reflection Quest AE
4195 ApplySpellFix({ 72900 }, [](SpellInfo* spellInfo)
4196 {
4197 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4198 });
4199 // ENDOF HALLS OF REFLECTION SPELLS
4200
4201 //
4202 // ICECROWN CITADEL SPELLS
4203 //
4205 // THESE SPELLS ARE WORKING CORRECTLY EVEN WITHOUT THIS HACK
4206 // THE ONLY REASON ITS HERE IS THAT CURRENT GRID SYSTEM
4207 // DOES NOT ALLOW FAR OBJECT SELECTION (dist > 333)
4208 70781, // Light's Hammer Teleport
4209 70856, // Oratory of the Damned Teleport
4210 70857, // Rampart of Skulls Teleport
4211 70858, // Deathbringer's Rise Teleport
4212 70859, // Upper Spire Teleport
4213 70860, // Frozen Throne Teleport
4214 70861 // Sindragosa's Lair Teleport
4215 }, [](SpellInfo* spellInfo)
4216 {
4217 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_DEST_DB);
4218 });
4219
4220 // Bone Slice (Lord Marrowgar)
4221 ApplySpellFix({ 69055, 70814 }, [](SpellInfo* spellInfo)
4222 {
4223 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_5_YARDS); // 5yd
4224 });
4225
4227 69075, // Bone Storm (Lord Marrowgar)
4228 70834, // Bone Storm (Lord Marrowgar)
4229 70835, // Bone Storm (Lord Marrowgar)
4230 70836, // Bone Storm (Lord Marrowgar)
4231 71160, // Plague Stench (Stinky)
4232 71161, // Plague Stench (Stinky)
4233 71123 // Decimate (Stinky & Precious)
4234 }, [](SpellInfo* spellInfo)
4235 {
4236 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yd
4237 });
4238
4239 // Coldflame (Lord Marrowgar)
4240 ApplySpellFix({ 69146, 70823, 70824, 70825 }, [](SpellInfo* spellInfo)
4241 {
4242 spellInfo->AttributesEx4 &= ~SPELL_ATTR4_IGNORE_RESISTANCES;
4243 });
4244
4245 // Shadow's Fate
4246 ApplySpellFix({ 71169 }, [](SpellInfo* spellInfo)
4247 {
4248 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
4249 });
4250
4251 // Lock Players and Tap Chest
4252 ApplySpellFix({ 72347 }, [](SpellInfo* spellInfo)
4253 {
4254 spellInfo->AttributesEx3 &= ~SPELL_ATTR3_NO_INITIAL_AGGRO;
4255 });
4256
4257 // Award Reputation - Boss Kill
4258 ApplySpellFix({ 73843, 73844, 73845, 73846 }, [](SpellInfo* spellInfo)
4259 {
4260 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4261 });
4262
4264 72378, // Blood Nova (Deathbringer Saurfang)
4265 73058, // Blood Nova (Deathbringer Saurfang)
4266 72769 // Scent of Blood (Deathbringer Saurfang)
4267 }, [](SpellInfo* spellInfo)
4268 {
4269 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS);
4270 });
4271
4272 // Scent of Blood (Deathbringer Saurfang)
4273 ApplySpellFix({ 72771 }, [](SpellInfo* spellInfo)
4274 {
4275 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS);
4276 });
4277
4278 // Resistant Skin (Deathbringer Saurfang adds)
4279 ApplySpellFix({ 72723 }, [](SpellInfo* spellInfo)
4280 {
4281 // this spell initially granted Shadow damage immunity, however it was removed but the data was left in client
4282 spellInfo->_GetEffect(EFFECT_2).Effect = SPELL_EFFECT_NONE;
4283 });
4284
4285 // Coldflame Jets (Traps after Saurfang)
4286 ApplySpellFix({ 70460 }, [](SpellInfo* spellInfo)
4287 {
4288 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(1); // 10 seconds
4289 });
4290
4292 71412, // Green Ooze Summon (Professor Putricide)
4293 71415 // Orange Ooze Summon (Professor Putricide)
4294 }, [](SpellInfo* spellInfo)
4295 {
4296 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY);
4297 });
4298
4299 // Ooze flood
4300 ApplySpellFix({ 69783, 69797, 69799, 69802 }, [](SpellInfo* spellInfo)
4301 {
4302 // Those spells are cast on creatures with same entry as caster while they have TARGET_UNIT_NEARBY_ENTRY.
4303 spellInfo->AttributesEx |= SPELL_ATTR1_CANT_TARGET_SELF;
4304 });
4305
4306 // Awaken Plagued Zombies
4307 ApplySpellFix({ 71159 }, [](SpellInfo* spellInfo)
4308 {
4309 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(21);
4310 });
4311
4312 // Volatile Ooze Beam Protection (Professor Putricide)
4313 ApplySpellFix({ 70530 }, [](SpellInfo* spellInfo)
4314 {
4315 spellInfo->_GetEffect(EFFECT_0).Effect = SPELL_EFFECT_APPLY_AURA; // for an unknown reason this was SPELL_EFFECT_APPLY_AREA_AURA_RAID
4316 });
4317
4318 // Mutated Strength (Professor Putricide)
4319 ApplySpellFix({ 71604, 72673, 72674, 72675 }, [](SpellInfo* spellInfo)
4320 {
4321 // THIS IS HERE BECAUSE COOLDOWN ON CREATURE PROCS WERE NOT IMPLEMENTED WHEN THE SCRIPT WAS WRITTEN
4322 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_NONE;
4323 });
4324
4325 // Mutated Plague (Professor Putricide)
4326 ApplySpellFix({ 72454, 72464, 72506, 72507 }, [](SpellInfo* spellInfo)
4327 {
4328 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4329 });
4330
4331 // Unbound Plague (Professor Putricide) (needs target selection script)
4332 ApplySpellFix({ 70911, 72854, 72855, 72856 }, [](SpellInfo* spellInfo)
4333 {
4334 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ENEMY);
4335 });
4336
4338 71518, // Unholy Infusion Quest Credit (Professor Putricide)
4339 72934, // Blood Infusion Quest Credit (Blood-Queen Lana'thel)
4340 72289 // Frost Infusion Quest Credit (Sindragosa)
4341 }, [](SpellInfo* spellInfo)
4342 {
4343 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // another missing radius
4344 });
4345
4346 // Empowered Flare (Blood Prince Council)
4347 ApplySpellFix({ 71708, 72785, 72786, 72787 }, [](SpellInfo* spellInfo)
4348 {
4349 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
4350 });
4351
4352 // Swarming Shadows
4353 ApplySpellFix({ 71266, 72890 }, [](SpellInfo* spellInfo)
4354 {
4355 spellInfo->RequiredAreasID = 0; // originally, these require area 4522, which is... outside of Icecrown Citadel
4356 });
4357
4358 // Corruption
4359 ApplySpellFix({ 70602 }, [](SpellInfo* spellInfo)
4360 {
4361 spellInfo->AttributesEx3 |= SPELL_ATTR3_STACK_FOR_DIFF_CASTERS;
4362 });
4363
4364 // Column of Frost (visual marker)
4365 ApplySpellFix({ 70715 }, [](SpellInfo* spellInfo)
4366 {
4367 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(32); // 6 seconds (missing)
4368 });
4369
4370 // Mana Void (periodic aura)
4371 ApplySpellFix({ 71085 }, [](SpellInfo* spellInfo)
4372 {
4373 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(9); // 30 seconds (missing)
4374 });
4375
4376 // Frostbolt Volley (only heroic)
4377 ApplySpellFix({ 72015, 72016 }, [](SpellInfo* spellInfo)
4378 {
4379 spellInfo->_GetEffect(EFFECT_2).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_40_YARDS);
4380 });
4381
4382 // Summon Suppressor (needs target selection script)
4383 ApplySpellFix({ 70936 }, [](SpellInfo* spellInfo)
4384 {
4385 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_TARGET_ANY);
4386 spellInfo->_GetEffect(EFFECT_0).TargetB = SpellImplicitTargetInfo();
4387 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(157); // 90yd
4388 });
4389
4391 72706, // Achievement Check (Valithria Dreamwalker)
4392 71357 // Order Whelp
4393 }, [](SpellInfo* spellInfo)
4394 {
4395 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4396 });
4397
4398 // Sindragosa's Fury
4399 ApplySpellFix({ 70598 }, [](SpellInfo* spellInfo)
4400 {
4401 spellInfo->_GetEffect(EFFECT_0).TargetA = SpellImplicitTargetInfo(TARGET_DEST_DEST);
4402 });
4403
4404 // Frost Bomb
4405 ApplySpellFix({ 69846 }, [](SpellInfo* spellInfo)
4406 {
4407 spellInfo->Speed = 0.0f; // This spell's summon happens instantly
4408 });
4409
4410 // Chilled to the Bone
4411 ApplySpellFix({ 70106 }, [](SpellInfo* spellInfo)
4412 {
4413 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
4414 spellInfo->AttributesEx6 |= SPELL_ATTR6_LIMIT_PCT_DAMAGE_MODS;
4415 });
4416
4417 // Ice Lock
4418 ApplySpellFix({ 71614 }, [](SpellInfo* spellInfo)
4419 {
4420 spellInfo->Mechanic = MECHANIC_STUN;
4421 });
4422
4423 // Defile
4424 ApplySpellFix({ 72762 }, [](SpellInfo* spellInfo)
4425 {
4426 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(559); // 53 seconds
4427 });
4428
4429 // Defile
4430 ApplySpellFix({ 72743 }, [](SpellInfo* spellInfo)
4431 {
4432 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(22); // 45 seconds
4433 });
4434
4435 // Defile
4436 ApplySpellFix({ 72754, 73708, 73709, 73710 }, [](SpellInfo* spellInfo)
4437 {
4438 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4439 });
4440
4441 // Val'kyr Target Search
4442 ApplySpellFix({ 69030 }, [](SpellInfo* spellInfo)
4443 {
4444 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4445 spellInfo->Attributes |= SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY;
4446 });
4447
4448 // Raging Spirit Visual
4449 ApplySpellFix({ 69198 }, [](SpellInfo* spellInfo)
4450 {
4451 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
4452 });
4453
4454 // Harvest Souls
4455 ApplySpellFix({ 73654, 74295, 74296, 74297 }, [](SpellInfo* spellInfo)
4456 {
4457 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4458 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4459 spellInfo->_GetEffect(EFFECT_2).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4460 });
4461
4462 // Harvest Soul
4463 ApplySpellFix({ 73655 }, [](SpellInfo* spellInfo)
4464 {
4465 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_DONE_BONUS;
4466 });
4467
4468 // Summon Shadow Trap
4469 ApplySpellFix({ 73540 }, [](SpellInfo* spellInfo)
4470 {
4471 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(3); // 60 seconds
4472 });
4473
4474 // Shadow Trap (visual)
4475 ApplySpellFix({ 73530 }, [](SpellInfo* spellInfo)
4476 {
4477 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(27); // 3 seconds
4478 });
4479
4480 // Shadow Trap
4481 ApplySpellFix({ 73529 }, [](SpellInfo* spellInfo)
4482 {
4483 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS); // 10yd
4484 });
4485
4486 // Shadow Trap (searcher)
4487 ApplySpellFix({ 74282 }, [](SpellInfo* spellInfo)
4488 {
4489 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_5_YARDS); // 5yd
4490 });
4491
4492 // Restore Soul
4493 ApplySpellFix({ 72595, 73650 }, [](SpellInfo* spellInfo)
4494 {
4495 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4496 });
4497
4498 // Destroy Soul
4499 ApplySpellFix({ 74086 }, [](SpellInfo* spellInfo)
4500 {
4501 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4502 });
4503
4504 // Summon Spirit Bomb
4505 ApplySpellFix({ 74302, 74342 }, [](SpellInfo* spellInfo)
4506 {
4507 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4508 spellInfo->MaxAffectedTargets = 1;
4509 });
4510
4511 // Summon Spirit Bomb
4512 ApplySpellFix({ 74341, 74343 }, [](SpellInfo* spellInfo)
4513 {
4514 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
4515 spellInfo->MaxAffectedTargets = 3;
4516 });
4517
4518 // Summon Spirit Bomb
4519 ApplySpellFix({ 73579 }, [](SpellInfo* spellInfo)
4520 {
4521 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS); // 25yd
4522 });
4523
4524 // Fury of Frostmourne
4525 ApplySpellFix({ 72350 }, [](SpellInfo* spellInfo)
4526 {
4527 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4528 });
4529
4531 {
4532 75127, // Kill Frostmourne Players
4533 72351, // Fury of Frostmourne
4534 72431, // Jump (removes Fury of Frostmourne debuff)
4535 72429, // Mass Resurrection
4536 73159, // Play Movie
4537 73582 // Trigger Vile Spirit (Inside, Heroic)
4538 }, [](SpellInfo* spellInfo)
4539 {
4540 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4541 });
4542
4543 // Raise Dead
4544 ApplySpellFix({ 72376 }, [](SpellInfo* spellInfo)
4545 {
4546 spellInfo->MaxAffectedTargets = 3;
4547 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
4548 });
4549
4550 // Jump
4551 ApplySpellFix({ 71809 }, [](SpellInfo* spellInfo)
4552 {
4553 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(5); // 40yd
4554 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS); // 10yd
4555 spellInfo->_GetEffect(EFFECT_0).MiscValue = 190;
4556 });
4557
4558 // Broken Frostmourne
4559 ApplySpellFix({ 72405 }, [](SpellInfo* spellInfo)
4560 {
4561 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_20_YARDS); // 20yd
4562 spellInfo->AttributesEx |= SPELL_ATTR1_NO_THREAT;
4563 });
4564 // ENDOF ICECROWN CITADEL SPELLS
4565
4566 //
4567 // RUBY SANCTUM SPELLS
4568 //
4569 // Soul Consumption
4570 ApplySpellFix({ 74799 }, [](SpellInfo* spellInfo)
4571 {
4572 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_12_YARDS);
4573 });
4574
4575 // Twilight Cutter
4576 ApplySpellFix({ 74769, 77844, 77845, 77846 }, [](SpellInfo* spellInfo)
4577 {
4578 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yd
4579 });
4580
4581 // Twilight Mending
4582 ApplySpellFix({ 75509 }, [](SpellInfo* spellInfo)
4583 {
4584 spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE;
4585 spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
4586 });
4587
4588 // Combustion and Consumption Heroic versions lacks radius data
4589 ApplySpellFix({ 75875 }, [](SpellInfo* spellInfo)
4590 {
4591 spellInfo->_GetEffect(EFFECT_0).Mechanic = MECHANIC_NONE;
4592 spellInfo->_GetEffect(EFFECT_1).Mechanic = MECHANIC_SNARE;
4593 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_6_YARDS);
4594 });
4595
4596 ApplySpellFix({ 75884 }, [](SpellInfo* spellInfo)
4597 {
4598 spellInfo->_GetEffect(EFFECT_0).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_6_YARDS);
4599 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_6_YARDS);
4600 });
4601
4602 ApplySpellFix({ 75883, 75876 }, [](SpellInfo* spellInfo)
4603 {
4604 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_6_YARDS);
4605 });
4606 // ENDOF RUBY SANCTUM SPELLS
4607
4608 //
4609 // EYE OF ETERNITY SPELLS
4610 //
4612 // All spells below work even without these changes. The LOS attribute is due to problem
4613 // from collision between maps & gos with active destroyed state.
4614 57473, // Arcane Storm bonus explicit visual spell
4615 57431, // Summon Static Field
4616 56091, // Flame Spike (Wyrmrest Skytalon)
4617 56092, // Engulf in Flames (Wyrmrest Skytalon)
4618 57090, // Revivify (Wyrmrest Skytalon)
4619 57143 // Life Burst (Wyrmrest Skytalon)
4620 }, [](SpellInfo* spellInfo)
4621 {
4622 spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS;
4623 });
4624
4625 // Arcane Barrage (cast by players and NONMELEEDAMAGELOG with caster Scion of Eternity (original caster)).
4626 ApplySpellFix({ 63934 }, [](SpellInfo* spellInfo)
4627 {
4628 // This would never crit on retail and it has attribute for SPELL_ATTR3_NO_DONE_BONUS because is handled from player,
4629 // until someone figures how to make scions not critting without hack and without making them main casters this should stay here.
4630 spellInfo->AttributesEx2 |= SPELL_ATTR2_CANT_CRIT;
4631 });
4632 // ENDOF EYE OF ETERNITY SPELLS
4633
4634 //
4635 // OCULUS SPELLS
4636 //
4638 // The spells below are here because their effect 1 is giving warning due to
4639 // triggered spell not found in any dbc and is missing from encounter source* of data.
4640 // Even judged as clientside these spells can't be guessed for* now.
4641 49462, // Call Ruby Drake
4642 49461, // Call Amber Drake
4643 49345 // Call Emerald Drake
4644 }, [](SpellInfo* spellInfo)
4645 {
4646 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_NONE;
4647 });
4648 // ENDOF OCULUS SPELLS
4649
4650 // Introspection
4651 ApplySpellFix({ 40055, 40165, 40166, 40167 }, [](SpellInfo* spellInfo)
4652 {
4653 spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1;
4654 });
4655
4656 // Chains of Ice
4657 ApplySpellFix({ 45524 }, [](SpellInfo* spellInfo)
4658 {
4659 spellInfo->_GetEffect(EFFECT_2).TargetA = SpellImplicitTargetInfo();
4660 });
4661
4662 // Minor Fortitude
4663 ApplySpellFix({ 2378 }, [](SpellInfo* spellInfo)
4664 {
4665 spellInfo->ManaCost = 0;
4666 spellInfo->ManaPerSecond = 0;
4667 });
4668
4669 // Threatening Gaze
4670 ApplySpellFix({ 24314 }, [](SpellInfo* spellInfo)
4671 {
4673 });
4674
4675 //
4676 // ISLE OF CONQUEST SPELLS
4677 //
4678 // Teleport
4679 ApplySpellFix({ 66551 }, [](SpellInfo* spellInfo)
4680 {
4681 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
4682 });
4683 // ENDOF ISLE OF CONQUEST SPELLS
4684
4685 // Aura of Fear
4686 ApplySpellFix({ 40453 }, [](SpellInfo* spellInfo)
4687 {
4688 // Bad DBC data? Copying 25820 here due to spell description
4689 // either is a periodic with chance on tick, or a proc
4690
4691 spellInfo->_GetEffect(EFFECT_0).ApplyAuraName = SPELL_AURA_PROC_TRIGGER_SPELL;
4692 spellInfo->_GetEffect(EFFECT_0).ApplyAuraPeriod = 0;
4693 spellInfo->ProcChance = 10;
4694 });
4695
4696 // Survey Sinkholes
4697 ApplySpellFix({ 45853 }, [](SpellInfo* spellInfo)
4698 {
4699 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(5); // 40 yards
4700 });
4701
4703 41485, // Deadly Poison - Black Temple
4704 41487 // Envenom - Black Temple
4705 }, [](SpellInfo* spellInfo)
4706 {
4707 spellInfo->AttributesEx6 |= SPELL_ATTR6_CAN_TARGET_INVISIBLE;
4708 });
4709
4711 // Proc attribute correction
4712 // Remove procflags from test/debug/deprecated spells to avoid DB Errors
4713 2479, // Honorless Target
4714 3232, // Gouge Stun Test
4715 3409, // Crippling Poison
4716 4312, // Strider Presence
4717 5707, // Lifestone Regeneration
4718 5760, // Mind-numbing Poison
4719 6727, // Poison Mushroom
4720 6940, // Hand of Sacrifice (handled remove in split hook)
4721 6984, // Frost Shot (Rank 2)
4722 7164, // Defensive Stance
4723 7288, // Immolate Cumulative (TEST) (Rank 1)
4724 7291, // Food (TEST)
4725 7331, // Healing Aura (TEST) (Rank 1)
4726 7366, // Berserker Stance
4727 7824, // Blacksmithing Skill +10
4728 12551, // Frost Shot
4729 13218, // Wound Poison (Rank 1)
4730 13222, // Wound Poison II (Rank 2)
4731 13223, // Wound Poison III (Rank 3)
4732 13224, // Wound Poison IV (Rank 4)
4733 14795, // Venomhide Poison
4734 16610, // Razorhide
4735 18099, // Chill Nova
4736 18499, // Berserker Rage (extra rage implemented in Unit::RewardRage)
4737 18802, // Frost Shot
4738 20000, // Alexander's Test Periodic Aura
4739 21163, // Polished Armor (Rank 1)
4740 22818, // Mol'dar's Moxie
4741 22820, // Slip'kik's Savvy
4742 23333, // Warsong Flag
4743 23335, // Silverwing Flag
4744 25160, // Sand Storm
4745 27189, // Wound Poison V (Rank 5)
4746 28313, // Aura of Fear
4747 28726, // Nightmare Seed
4748 28754, // Fury of the Ashbringer
4749 30802, // Unleashed Rage (Rank 1)
4750 31481, // Lung Burst
4751 32430, // Battle Standard
4752 32431, // Battle Standard
4753 32447, // Travel Form
4754 33370, // Spell Haste
4755 33807, // Abacus of Violent Odds
4756 33891, // Tree of Life (Shapeshift)
4757 34132, // Gladiator's Totem of the Third Wind
4758 34135, // Libram of Justice
4759 34666, // Tamed Pet Passive 08 (DND)
4760 34667, // Tamed Pet Passive 09 (DND)
4761 34775, // Dragonspine Flurry
4762 34889, // Fire Breath (Rank 1)
4763 34976, // Netherstorm Flag
4764 35131, // Bladestorm
4765 35244, // Choking Vines
4766 35323, // Fire Breath (Rank 2)
4767 35336, // Energizing Spores
4768 36148, // Chill Nova
4769 36613, // Aspect of the Spirit Hunter
4770 36786, // Soul Chill
4771 37174, // Perceived Weakness
4772 37482, // Exploited Weakness
4773 37526, // Battle Rush
4774 37588, // Dive
4775 37985, // Fire Breath
4776 38317, // Forgotten Knowledge
4777 38843, // Soul Chill
4778 39015, // Atrophic Blow
4779 40396, // Fel Infusion
4780 40603, // Taunt Gurtogg
4781 40803, // Ron's Test Buff
4782 40879, // Prismatic Shield (no longer used since patch 2.2/adaptive prismatic shield)
4783 41341, // Balance of Power (implemented by hooking absorb)
4784 41435, // The Twin Blades of Azzinoth
4785 42369, // Merciless Libram of Justice
4786 42371, // Merciless Gladiator's Totem of the Third Wind
4787 42636, // Birmingham Tools Test 3
4788 43727, // Vengeful Libram of Justice
4789 43729, // Vengeful Gladiator's Totem of the Third Wind
4790 43817, // Focused Assault
4791 44305, // You're a ...! (Effects2)
4792 44586, // Prayer of Mending (unknown, unused aura type)
4793 45384, // Birmingham Tools Test 4
4794 45433, // Birmingham Tools Test 5
4795 46093, // Brutal Libram of Justice
4796 46099, // Brutal Gladiator's Totem of the Third Wind
4797 46705, // Honorless Target
4798 49145, // Spell Deflection (Rank 1) (implemented by hooking absorb)
4799 49883, // Flames
4800 50365, // Improved Blood Presence (Rank 1)
4801 50371, // Improved Blood Presence (Rank 2)
4802 50462, // Anti-Magic Zone (implemented by hooking absorb)
4803
4804 50498, // Savage Rend (Rank 1) - proc from Savage Rend moved from attack itself to autolearn aura 50871
4805 53578, // Savage Rend (Rank 2)
4806 53579, // Savage Rend (Rank 3)
4807 53580, // Savage Rend (Rank 4)
4808 53581, // Savage Rend (Rank 5)
4809 53582, // Savage Rend (Rank 6)
4810
4811 50655, // Frost Cut
4812 50995, // Empowered Blood Presence (Rank 1)
4813 51809, // First Aid
4814 53032, // Flurry of Claws
4815 55482, // Fire Breath (Rank 3)
4816 55483, // Fire Breath (Rank 4)
4817 55484, // Fire Breath (Rank 5)
4818 55485, // Fire Breath (Rank 6)
4819 57974, // Wound Poison VI (Rank 6)
4820 57975, // Wound Poison VII (Rank 7)
4821 60062, // Essence of Life
4822 60302, // Meteorite Whetstone
4823 60437, // Grim Toll
4824 60492, // Embrace of the Spider
4825 62142, // Improved Chains of Ice (Rank 3)
4826 63024, // Gravity Bomb
4827 64205, // Divine Sacrifice (handled remove in split hook)
4828 64772, // Comet's Trail
4829 65004, // Alacrity of the Elements
4830 65019, // Mjolnir Runestone
4831 65024, // Implosion
4832
4833 66334, // Mistress' Kiss - currently not used in script, need implement?
4834 67905, // Mistress' Kiss
4835 67906, // Mistress' Kiss
4836 67907, // Mistress' Kiss
4837
4838 71003, // Vegard's Touch
4839
4840 72151, // Frenzied Bloodthirst - currently not used in script, need implement?
4841 72648, // Frenzied Bloodthirst
4842 72649, // Frenzied Bloodthirst
4843 72650, // Frenzied Bloodthirst
4844
4845 72559, // Birmingham Tools Test 3
4846 72560, // Birmingham Tools Test 3
4847 72561, // Birmingham Tools Test 5
4848 72980 // Shadow Resonance
4849 }, [](SpellInfo* spellInfo)
4850 {
4851 spellInfo->ProcFlags = 0;
4852 });
4853
4854 // Feral Charge - Cat
4855 ApplySpellFix({ 49376 }, [](SpellInfo* spellInfo)
4856 {
4857 spellInfo->_GetEffect(EFFECT_1).RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_3_YARDS); // 3yd
4858 });
4859
4860 // Baron Rivendare (Stratholme) - Unholy Aura
4861 ApplySpellFix({ 17466, 17467 }, [](SpellInfo* spellInfo)
4862 {
4863 spellInfo->AttributesEx3 |= SPELL_ATTR3_NO_INITIAL_AGGRO;
4864 });
4865
4866 // Spore - Spore Visual
4867 ApplySpellFix({ 42525 }, [](SpellInfo* spellInfo)
4868 {
4869 spellInfo->AttributesEx3 |= SPELL_ATTR3_DEATH_PERSISTENT;
4870 spellInfo->AttributesEx2 |= SPELL_ATTR2_CAN_TARGET_DEAD;
4871 });
4872
4873 // Death's Embrace
4874 ApplySpellFix({ 47198, 47199, 47200 }, [](SpellInfo* spellInfo)
4875 {
4876 spellInfo->_GetEffect(EFFECT_1).SpellClassMask[0] |= 0x00004000; // Drain soul
4877 });
4878
4879 // Soul Sickness (Forge of Souls)
4880 ApplySpellFix({ 69131 }, [](SpellInfo* spellInfo)
4881 {
4882 spellInfo->_GetEffect(EFFECT_1).ApplyAuraName = SPELL_AURA_MOD_DECREASE_SPEED;
4883 });
4884
4885 // Headless Horseman Climax - Return Head (Hallow End)
4886 // Headless Horseman Climax - Body Regen (confuse only - removed on death)
4887 // Headless Horseman Climax - Head Is Dead
4888 ApplySpellFix({ 42401, 43105, 42428 }, [](SpellInfo* spellInfo)
4889 {
4890 spellInfo->Attributes |= SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY;
4891 });
4892
4893 // Sacred Cleansing
4894 ApplySpellFix({ 53659 }, [](SpellInfo* spellInfo)
4895 {
4896 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(5); // 40yd
4897 });
4898
4899 // Pilgrim's Bounty - Candied Sweet Potato
4900 ApplySpellFix({ 65418 }, [](SpellInfo* spellInfo)
4901 {
4902 spellInfo->_GetEffect(EFFECT_2).TriggerSpell = 65410;
4903 });
4904
4905 // Pilgrim's Bounty - Spice Bread Stuffing
4906 ApplySpellFix({ 65419 }, [](SpellInfo* spellInfo)
4907 {
4908 spellInfo->_GetEffect(EFFECT_2).TriggerSpell = 65416;
4909 });
4910
4911 // Pilgrim's Bounty - Cranberry Chutney
4912 ApplySpellFix({ 65420 }, [](SpellInfo* spellInfo)
4913 {
4914 spellInfo->_GetEffect(EFFECT_2).TriggerSpell = 65412;
4915 });
4916
4917 // Pilgrim's Bounty - Pumpkin Pie
4918 ApplySpellFix({ 65421 }, [](SpellInfo* spellInfo)
4919 {
4920 spellInfo->_GetEffect(EFFECT_2).TriggerSpell = 65415;
4921 });
4922
4923 // Pilgrim's Bounty - Slow-Roasted Turkey
4924 ApplySpellFix({ 65422 }, [](SpellInfo* spellInfo)
4925 {
4926 spellInfo->_GetEffect(EFFECT_2).TriggerSpell = 65414;
4927 });
4928
4930 24869, // Bobbing Apple, Bread of the Dead, Winter Veil Cookie
4931 61874, // Noblegarden Chocolate
4932 71068, // Sweet Surprise
4933 71071, // Very Berry Cream
4934 71073, // Dark Desire
4935 71074 // Buttermilk Delight
4936 }, [](SpellInfo* spellInfo)
4937 {
4938 spellInfo->_GetEffect(EFFECT_1).Effect = SPELL_EFFECT_APPLY_AURA;
4939 spellInfo->_GetEffect(EFFECT_1).TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
4940 spellInfo->_GetEffect(EFFECT_1).ApplyAuraName = SPELL_AURA_PERIODIC_TRIGGER_SPELL;
4941 spellInfo->_GetEffect(EFFECT_1).ApplyAuraPeriod = 10 * IN_MILLISECONDS;
4942 spellInfo->_GetEffect(EFFECT_1).TriggerSpell = 24870;
4943 });
4944
4945 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
4946 {
4947 SpellInfo* spellInfo = mSpellInfoMap[i];
4948 if (!spellInfo)
4949 continue;
4950
4951 // Fix range for trajectory triggered spell
4952 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4953 {
4954 if (spellEffectInfo.IsEffect() && (spellEffectInfo.TargetA.GetTarget() == TARGET_DEST_TRAJ || spellEffectInfo.TargetB.GetTarget() == TARGET_DEST_TRAJ))
4955 {
4956 // Get triggered spell if any
4957 if (SpellInfo* spellInfoTrigger = const_cast<SpellInfo*>(GetSpellInfo(spellEffectInfo.TriggerSpell)))
4958 {
4959 float maxRangeMain = spellInfo->RangeEntry ? spellInfo->RangeEntry->RangeMax[0] : 0.0f;
4960 float maxRangeTrigger = spellInfoTrigger->RangeEntry ? spellInfoTrigger->RangeEntry->RangeMax[0] : 0.0f;
4961
4962 // check if triggered spell has enough max range to cover trajectory
4963 if (maxRangeTrigger < maxRangeMain)
4964 spellInfoTrigger->RangeEntry = spellInfo->RangeEntry;
4965 }
4966 }
4967 }
4968
4969 for (SpellEffectInfo& spellEffectInfo : spellInfo->_GetEffects())
4970 {
4971 switch (spellEffectInfo.Effect)
4972 {
4975 case SPELL_EFFECT_JUMP:
4978 if (!spellInfo->Speed && !spellInfo->SpellFamilyName)
4979 spellInfo->Speed = SPEED_CHARGE;
4980 break;
4982 // special aura updates each 30 seconds
4983 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_ATTACK_POWER_OF_ARMOR)
4984 spellEffectInfo.ApplyAuraPeriod = 30 * IN_MILLISECONDS;
4985 break;
4986 default:
4987 break;
4988 }
4989
4990 // Passive talent auras cannot target pets
4991 if (spellInfo->IsPassive() && GetTalentSpellCost(i))
4992 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
4993 spellEffectInfo.TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
4994
4995 // Area auras may not target area (they're self cast)
4996 if (spellEffectInfo.IsAreaAuraEffect() && spellEffectInfo.IsTargetingArea())
4997 {
4998 spellEffectInfo.TargetA = SpellImplicitTargetInfo(TARGET_UNIT_CASTER);
4999 spellEffectInfo.TargetB = SpellImplicitTargetInfo(0);
5000 }
5001 }
5002
5003 // disable proc for magnet auras, they're handled differently
5004 if (spellInfo->HasAura(SPELL_AURA_SPELL_MAGNET))
5005 spellInfo->ProcFlags = 0;
5006
5007 // due to the way spell system works, unit would change orientation in Spell::_cast
5008 if (spellInfo->HasAura(SPELL_AURA_CONTROL_VEHICLE))
5010
5011 if (spellInfo->ActiveIconID == 2158) // flight
5012 spellInfo->Attributes |= SPELL_ATTR0_PASSIVE;
5013
5014 switch (spellInfo->SpellFamilyName)
5015 {
5017 // Seals of the Pure should affect Seal of Righteousness
5018 if (spellInfo->SpellIconID == 25 && spellInfo->HasAttribute(SPELL_ATTR0_PASSIVE))
5019 spellInfo->_GetEffect(EFFECT_0).SpellClassMask[1] |= 0x20000000;
5020 break;
5022 // Icy Touch - extend FamilyFlags (unused value) for Sigil of the Frozen Conscience to use
5023 if (spellInfo->SpellIconID == 2721 && spellInfo->SpellFamilyFlags[0] & 0x2)
5024 spellInfo->SpellFamilyFlags[0] |= 0x40;
5025 break;
5026 }
5027 }
5028
5029 if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(121)))
5030 properties->Title = SUMMON_TYPE_TOTEM;
5031 if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(647))) // 52893
5032 properties->Title = SUMMON_TYPE_TOTEM;
5033 if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(628))) // Hungry Plaguehound
5034 properties->Control = SUMMON_CATEGORY_PET;
5035
5036 if (LockEntry* entry = const_cast<LockEntry*>(sLockStore.LookupEntry(36))) // 3366 Opening, allows to open without proper key
5037 entry->Type[2] = LOCK_KEY_NONE;
5038
5039 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo corrections in {} ms", GetMSTimeDiffToNow(oldMSTime));
5040}
5041
5043{
5044 uint32 oldMSTime = getMSTime();
5045
5046 for (SpellInfo* spellInfo : mSpellInfoMap)
5047 {
5048 if (!spellInfo)
5049 continue;
5050
5051 // AuraState depends on SpellSpecific
5052 spellInfo->_LoadSpellSpecific();
5053 spellInfo->_LoadAuraState();
5054 }
5055
5056 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo SpellSpecific and AuraState in {} ms", GetMSTimeDiffToNow(oldMSTime));
5057}
5058
5060{
5061 uint32 oldMSTime = getMSTime();
5062
5063 for (SpellInfo* spellInfo : mSpellInfoMap)
5064 {
5065 if (!spellInfo)
5066 continue;
5067
5068 spellInfo->_LoadSpellDiminishInfo();
5069 }
5070
5071 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo diminishing infos in {} ms", GetMSTimeDiffToNow(oldMSTime));
5072}
5073
5075{
5076 uint32 oldMSTime = getMSTime();
5077
5078 for (SpellInfo* spellInfo : mSpellInfoMap)
5079 {
5080 if (!spellInfo)
5081 continue;
5082
5083 spellInfo->_LoadImmunityInfo();
5084 }
5085
5086 TC_LOG_INFO("server.loading", ">> Loaded SpellInfo immunity infos in {} ms", GetMSTimeDiffToNow(oldMSTime));
5087}
#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:354
@ DUNGEON_DIFFICULTY_HEROIC
Definition DBCEnums.h:283
#define MAX_DIFFICULTY
Definition DBCEnums.h:294
#define MAX_SPELL_REAGENTS
Definition DBCEnums.h:388
#define MAX_TALENT_RANK
Definition DBCEnums.h:430
@ SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN
Definition DBCEnums.h:348
@ 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)
TalentSpellPos const * GetTalentSpellPos(uint32 spellId)
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:529
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
@ SPELL_ATTR0_CU_IS_TALENT
Definition SpellInfo.h:164
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:61
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:4231
uint8 GetSpawnMode() const
Definition Map.h:409
bool IsBattleground() const
Definition Map.cpp:4262
static Player * ToPlayer(Object *o)
Definition Object.h:183
Gender GetNativeGender() const override
Definition Player.h:1017
WorldSession * GetSession() const
Definition Player.h:1705
TeamId GetTeamId() const
Definition Player.h:1819
Battleground * GetBattleground() const
Definition Player.cpp:23024
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition Player.cpp:15655
uint32 GetHitMask() const
Definition Unit.h:528
SpellSchoolMask GetSchoolMask() const
Definition Unit.cpp:280
Unit * GetActionTarget() const
Definition Unit.h:523
uint32 GetSpellTypeMask() const
Definition Unit.h:526
uint32 GetTypeMask() const
Definition Unit.h:525
SpellInfo const * GetSpellInfo() const
Definition Unit.cpp:269
Unit * GetActor()
Definition Unit.h:522
uint32 GetSpellPhaseMask() const
Definition Unit.h:527
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:908
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4558
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4565
Map * GetMap() const
Definition Object.h:451
uint32 GetAreaId() const
Definition Object.h:376
uint32 GetZoneId() const
Definition Object.h:375
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