Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
SpellMgr.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "BattlefieldMgr.h"
7#include "BattlefieldWG.h"
8#include "BattlegroundMgr.h"
9#include "Chat.h"
10#include "DBCStores.h"
11#include "MapManager.h"
12#include "ObjectMgr.h"
13#include "Player.h"
14#include "SharedDefines.h"
15#include "Spell.h"
16#include "SpellAuraDefines.h"
17#include "SpellAuras.h"
18#include "SpellInfo.h"
19#include "SpellMgr.h"
20#include "SpellValidation.h"
21#include "World.h"
22
24{
25 SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(skill);
26 return pSkill && pSkill->categoryId == SKILL_CATEGORY_PROFESSION;
27}
28
30{
31 SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(skill);
32 return pSkill && pSkill->categoryId == SKILL_CATEGORY_WEAPON;
33}
34
35bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
36{
37 SkillLineAbilityMapBounds skillBounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
38 for (SkillLineAbilityMap::const_iterator itr = skillBounds.first; itr != skillBounds.second; ++itr)
39 if (itr->second->skillId == skillId)
40 return true;
41
42 return false;
43}
44
46{
47 if (spellproto->IsPositive())
49
50 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
51 {
52 if (spellproto->Effects[i].ApplyAuraName == SPELL_AURA_MOD_TAUNT)
54 }
55
56 // Explicit Diminishing Groups
57 switch (spellproto->SpellFamilyName)
58 {
60 {
61 // Pet charge effects (Infernal Awakening, Demon Charge)
62 if (spellproto->SpellVisual[0] == 2816 && spellproto->SpellIconID == 15)
64 // Frost Tomb
65 else if (spellproto->Id == 48400)
67 // Gnaw
68 else if (spellproto->Id == 47481)
70 // ToC Icehowl Arctic Breath
71 else if (spellproto->SpellVisual[0] == 14153)
73 // Black Plague
74 else if (spellproto->Id == 64155)
76 break;
77 }
78 // Event spells
82 {
83 // Deep Freeze
84 if (spellproto->SpellIconID == 2939 && spellproto->SpellVisual[0] == 9963)
86 // Frost Nova / Freeze (Water Elemental)
87 else if (spellproto->SpellIconID == 193)
89 // Dragon's Breath
90 else if (spellproto->SpellFamilyFlags[0] & 0x800000)
92 break;
93 }
95 {
96 // Hamstring - limit duration to 10s in PvP
97 if (spellproto->SpellFamilyFlags[0] & 0x2)
99 // Charge Stun (own diminishing)
100 else if (spellproto->SpellFamilyFlags[0] & 0x01000000)
102 break;
103 }
105 {
106 // Curses/etc
107 if ((spellproto->SpellFamilyFlags[0] & 0x80000000) || (spellproto->SpellFamilyFlags[1] & 0x200))
109 // Seduction
110 else if (spellproto->SpellFamilyFlags[1] & 0x10000000)
112 // Sin and Punishment (Priest spell, don't ask)
113 else if (spellproto->SpellIconID == 1869)
115 break;
116 }
118 {
119 // Pounce
120 if (spellproto->SpellFamilyFlags[0] & 0x20000)
122 // Cyclone
123 else if (spellproto->SpellFamilyFlags[1] & 0x20)
125 // Entangling Roots
126 else if (spellproto->SpellFamilyFlags[0] & 0x00000200)
128 // Faerie Fire
129 else if (spellproto->SpellFamilyFlags[0] & 0x400)
131 break;
132 }
134 {
135 // Gouge
136 if (spellproto->SpellFamilyFlags[0] & 0x8)
138 // Blind
139 else if (spellproto->SpellFamilyFlags[0] & 0x1000000)
141 // Cheap Shot
142 else if (spellproto->SpellFamilyFlags[0] & 0x400)
144 // Crippling poison - Limit to 10 seconds in PvP (No SpellFamilyFlags)
145 else if (spellproto->SpellIconID == 163)
147 break;
148 }
150 {
151 // Hunter's Mark
152 if ((spellproto->SpellFamilyFlags[0] & 0x400) && spellproto->SpellIconID == 538)
154 // Scatter Shot (own diminishing)
155 else if ((spellproto->SpellFamilyFlags[0] & 0x40000) && spellproto->SpellIconID == 132)
157 // Entrapment (own diminishing)
158 else if (spellproto->SpellVisual[0] == 7484 && spellproto->SpellIconID == 20)
160 // Wyvern Sting mechanic is MECHANIC_SLEEP but the diminishing is DIMINISHING_DISORIENT
161 else if ((spellproto->SpellFamilyFlags[1] & 0x1000) && spellproto->SpellIconID == 1721)
163 break;
164 }
166 {
167 // Turn Evil
168 if ((spellproto->SpellFamilyFlags[1] & 0x804000) && spellproto->SpellIconID == 309)
170 break;
171 }
172 default:
173 break;
174 }
175
176 // Lastly - Set diminishing depending on mechanic
177 uint32 mechanic = spellproto->GetAllEffectsMechanicMask();
186 // Mechanic Knockout, except Blast Wave
187 if (Skyfire::Spells::HasMechanic(mechanic, MECHANIC_KNOCKOUT) && spellproto->SpellIconID != 292)
201
203}
204
223
234
236{
238 return 0;
239
240 // Explicit diminishing duration
241 switch (spellproto->SpellFamilyName)
242 {
244 {
245 // Faerie Fire - limit to 40 seconds in PvP (3.1)
246 if (spellproto->SpellFamilyFlags[0] & 0x400)
247 return 40 * IN_MILLISECONDS;
248 break;
249 }
251 {
252 // Wyvern Sting
253 if (spellproto->SpellFamilyFlags[1] & 0x1000)
254 return 6 * IN_MILLISECONDS;
255 // Hunter's Mark
256 if (spellproto->SpellFamilyFlags[0] & 0x400)
257 return 30 * IN_MILLISECONDS;
258 break;
259 }
261 {
262 // Repentance - limit to 6 seconds in PvP
263 if (spellproto->SpellFamilyFlags[0] & 0x4)
264 return 6 * IN_MILLISECONDS;
265 break;
266 }
268 {
269 // Banish - limit to 6 seconds in PvP
270 if (spellproto->SpellFamilyFlags[1] & 0x8000000)
271 return 6 * IN_MILLISECONDS;
272 // Curse of Tongues - limit to 12 seconds in PvP
273 else if (spellproto->SpellFamilyFlags[2] & 0x800)
274 return 12 * IN_MILLISECONDS;
275 // Curse of Elements - limit to 120 seconds in PvP
276 else if (spellproto->SpellFamilyFlags[1] & 0x200)
277 return 120 * IN_MILLISECONDS;
278 break;
279 }
280 default:
281 break;
282 }
283
284 return 8 * IN_MILLISECONDS;
285}
286
310
312
317
319bool SpellMgr::IsSpellValid(SpellInfo const* spellInfo, Player* player, bool msg)
320{
321 // not exist
322 if (!spellInfo)
323 return false;
324
325 bool needCheckReagents = false;
326
327 // check effects
328 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
329 {
330 switch (spellInfo->Effects[i].Effect)
331 {
332 case 0:
333 continue;
334
335 // craft spell for crafting non-existed item (break client recipes list show)
338 {
339 if (spellInfo->Effects[i].ItemType == 0)
340 {
341 // skip auto-loot crafting spells, its not need explicit item info (but have special fake items sometime)
342 if (!spellInfo->IsLootCrafting())
343 {
344 if (msg)
345 {
346 if (player)
347 ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u not have create item entry.", spellInfo->Id);
348 else
349 SF_LOG_ERROR("sql.sql", "Craft spell %u not have create item entry.", spellInfo->Id);
350 }
351 return false;
352 }
353 }
354 // also possible IsLootCrafting case but fake item must exist anyway
355 else if (!sObjectMgr->GetItemTemplate(spellInfo->Effects[i].ItemType))
356 {
357 if (msg)
358 {
359 if (player)
360 ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u create not-exist in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Effects[i].ItemType);
361 else
362 SF_LOG_ERROR("sql.sql", "Craft spell %u create not-exist in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Effects[i].ItemType);
363 }
364 return false;
365 }
366
367 needCheckReagents = true;
368 break;
369 }
371 {
372 SpellInfo const* spellInfo2 = sSpellMgr->GetSpellInfo(spellInfo->Effects[i].TriggerSpell);
373 if (!IsSpellValid(spellInfo2, player, msg))
374 {
375 if (msg)
376 {
377 if (player)
378 ChatHandler(player->GetSession()).PSendSysMessage("Spell %u learn to broken spell %u, and then...", spellInfo->Id, spellInfo->Effects[i].TriggerSpell);
379 else
380 SF_LOG_ERROR("sql.sql", "Spell %u learn to invalid spell %u, and then...", spellInfo->Id, spellInfo->Effects[i].TriggerSpell);
381 }
382 return false;
383 }
384 break;
385 }
386 }
387 }
388
389 if (needCheckReagents)
390 {
391 for (uint8 j = 0; j < MAX_SPELL_REAGENTS; ++j)
392 {
393 if (spellInfo->Reagent[j] > 0 && !sObjectMgr->GetItemTemplate(spellInfo->Reagent[j]))
394 {
395 if (msg)
396 {
397 if (player)
398 ChatHandler(player->GetSession()).PSendSysMessage("Craft spell %u have not-exist reagent in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Reagent[j]);
399 else
400 SF_LOG_ERROR("sql.sql", "Craft spell %u have not-exist reagent in DB item (Entry: %u) and then...", spellInfo->Id, spellInfo->Reagent[j]);
401 }
402 return false;
403 }
404 }
405 }
406
407 return true;
408}
409
411{
412 SpellDifficultySearcherMap::const_iterator i = mSpellDifficultySearcherMap.find(spellId);
413 return i == mSpellDifficultySearcherMap.end() ? 0 : i->second;
414}
415
417{
418 mSpellDifficultySearcherMap[spellId] = id;
419}
420
422{
423 if (!GetSpellInfo(spellId))
424 return spellId;
425
426 if (!caster || !caster->GetMap() || !caster->GetMap()->IsInstance())
427 return spellId;
428
429 uint32 mode = uint32(caster->GetMap()->GetSpawnMode());
430 if (mode >= 14)
431 {
432 SF_LOG_ERROR("spells", "SpellMgr::GetSpellIdForDifficulty: Incorrect DifficultyID for spell %u.", spellId);
433 return spellId; //return source spell
434 }
435
436 uint32 difficultyId = GetSpellDifficultyId(spellId);
437 if (!difficultyId)
438 return spellId; //return source spell, it has only REGULAR_DIFFICULTY
439
440 SpellDifficultyEntry const* difficultyEntry = sSpellDifficultyStore.LookupEntry(difficultyId);
441 if (!difficultyEntry)
442 {
443 SF_LOG_DEBUG("spells", "SpellMgr::GetSpellIdForDifficulty: SpellDifficultyEntry not found for spell %u. This should never happen.", spellId);
444 return spellId; //return source spell
445 }
446
447 if (difficultyEntry->SpellID[mode] <= 0 && mode > DIFFICULTY_HEROIC)
448 {
449 SF_LOG_DEBUG("spells", "SpellMgr::GetSpellIdForDifficulty: spell %u mode %u spell is NULL, using mode %u", spellId, mode, mode - 2);
450 mode -= 2;
451 }
452
453 if (difficultyEntry->SpellID[mode] <= 0)
454 {
455 SF_LOG_ERROR("sql.sql", "SpellMgr::GetSpellIdForDifficulty: spell %u mode %u spell is 0. Check spelldifficulty_dbc!", spellId, mode);
456 return spellId;
457 }
458
459 SF_LOG_DEBUG("spells", "SpellMgr::GetSpellIdForDifficulty: spellid for spell %u in mode %u is %d", spellId, mode, difficultyEntry->SpellID[mode]);
460 return uint32(difficultyEntry->SpellID[mode]);
461}
462
463SpellInfo const* SpellMgr::GetSpellForDifficultyFromSpell(SpellInfo const* spell, Unit const* caster) const
464{
465 if (!spell)
466 return NULL;
467
468 uint32 newSpellId = GetSpellIdForDifficulty(spell->Id, caster);
469 SpellInfo const* newSpell = GetSpellInfo(newSpellId);
470 if (!newSpell)
471 {
472 SF_LOG_DEBUG("spells", "SpellMgr::GetSpellForDifficultyFromSpell: spell %u not found. Check spelldifficulty_dbc!", newSpellId);
473 return spell;
474 }
475
476 SF_LOG_DEBUG("spells", "SpellMgr::GetSpellForDifficultyFromSpell: Spell id for instance mode is %u (original %u)", newSpell->Id, spell->Id);
477 return newSpell;
478}
479
481{
482 SpellChainMap::const_iterator itr = mSpellChains.find(spell_id);
483 if (itr == mSpellChains.end())
484 return NULL;
485
486 return &itr->second;
487}
488
490{
491 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
492 return node->first->Id;
493
494 return spell_id;
495}
496
498{
499 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
500 return node->last->Id;
501
502 return spell_id;
503}
504
506{
507 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
508 if (node->next)
509 return node->next->Id;
510
511 return 0;
512}
513
515{
516 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
517 if (node->prev)
518 return node->prev->Id;
519
520 return 0;
521}
522
524{
525 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
526 return node->rank;
527
528 return 0;
529}
530
531uint32 SpellMgr::GetSpellWithRank(uint32 spell_id, uint32 rank, bool strict) const
532{
533 if (SpellChainNode const* node = GetSpellChainNode(spell_id))
534 {
535 if (rank != node->rank)
536 return GetSpellWithRank(node->rank < rank ? node->next->Id : node->prev->Id, rank, strict);
537 }
538 else if (strict && rank > 1)
539 return 0;
540 return spell_id;
541}
542
544{
545 return mSpellReq.equal_range(spell_id);
546}
547
549{
550 return mSpellsReqSpell.equal_range(spell_id);
551}
552
553bool SpellMgr::IsSpellRequiringSpell(uint32 spellid, uint32 req_spellid) const
554{
555 SpellsRequiringSpellMapBounds spellsRequiringSpell = GetSpellsRequiringSpellBounds(req_spellid);
556 for (SpellsRequiringSpellMap::const_iterator itr = spellsRequiringSpell.first; itr != spellsRequiringSpell.second; ++itr)
557 {
558 if (itr->second == spellid)
559 return true;
560 }
561 return false;
562}
563
565{
566 SpellLearnSkillMap::const_iterator itr = mSpellLearnSkills.find(spell_id);
567 if (itr != mSpellLearnSkills.end())
568 return &itr->second;
569 else
570 return NULL;
571}
572
574{
575 return mSpellLearnSpells.equal_range(spell_id);
576}
577
579{
580 return mSpellLearnSpells.find(spell_id) != mSpellLearnSpells.end();
581}
582
583bool SpellMgr::IsSpellLearnToSpell(uint32 spell_id1, uint32 spell_id2) const
584{
586 for (SpellLearnSpellMap::const_iterator i = bounds.first; i != bounds.second; ++i)
587 if (i->second.spell == spell_id2)
588 return true;
589 return false;
590}
591
593{
594 SpellTargetPositionMap::const_iterator itr = mSpellTargetPositions.find(std::make_pair(spell_id, effIndex));
595 if (itr != mSpellTargetPositions.end())
596 return &itr->second;
597 return NULL;
598}
599
601{
602 spell_id = GetFirstSpellInChain(spell_id);
603 return mSpellSpellGroup.equal_range(spell_id);
604}
605
607{
609 for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second; ++itr)
610 {
611 if (itr->second == groupid)
612 return true;
613 }
614 return false;
615}
616
618{
619 return mSpellGroupSpell.equal_range(group_id);
620}
621
622void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells) const
623{
624 std::set<SpellGroup> usedGroups;
625 GetSetOfSpellsInSpellGroup(group_id, foundSpells, usedGroups);
626}
627
628void SpellMgr::GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set<uint32>& foundSpells, std::set<SpellGroup>& usedGroups) const
629{
630 if (usedGroups.find(group_id) != usedGroups.end())
631 return;
632 usedGroups.insert(group_id);
633
635 for (SpellGroupSpellMap::const_iterator itr = groupSpell.first; itr != groupSpell.second; ++itr)
636 {
637 if (itr->second < 0)
638 {
639 SpellGroup currGroup = (SpellGroup)abs(itr->second);
640 GetSetOfSpellsInSpellGroup(currGroup, foundSpells, usedGroups);
641 }
642 else
643 {
644 foundSpells.insert(itr->second);
645 }
646 }
647}
648
649bool SpellMgr::AddSameEffectStackRuleSpellGroups(SpellInfo const* spellInfo, int32 amount, std::map<SpellGroup, int32>& groups) const
650{
651 uint32 spellId = spellInfo->GetFirstRankSpell()->Id;
653 // Find group with SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT if it belongs to one
654 for (SpellSpellGroupMap::const_iterator itr = spellGroup.first; itr != spellGroup.second; ++itr)
655 {
656 SpellGroup group = itr->second;
657 SpellGroupStackMap::const_iterator found = mSpellGroupStack.find(group);
658 if (found != mSpellGroupStack.end())
659 {
661 {
662 // Put the highest amount in the map
663 if (groups.find(group) == groups.end())
664 groups[group] = amount;
665 else
666 {
667 int32 curr_amount = groups[group];
668 // Take absolute value because this also counts for the highest negative aura
669 if (abs(curr_amount) < abs(amount))
670 groups[group] = amount;
671 }
672 // return because a spell should be in only one SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group
673 return true;
674 }
675 }
676 }
677 // Not in a SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT group, so return false
678 return false;
679}
680
682{
683 uint32 spellid_1 = spellInfo1->GetFirstRankSpell()->Id;
684 uint32 spellid_2 = spellInfo2->GetFirstRankSpell()->Id;
685 if (spellid_1 == spellid_2)
687 // find SpellGroups which are common for both spells
689 std::set<SpellGroup> groups;
690 for (SpellSpellGroupMap::const_iterator itr = spellGroup1.first; itr != spellGroup1.second; ++itr)
691 {
692 if (IsSpellMemberOfSpellGroup(spellid_2, itr->second))
693 {
694 bool add = true;
696 for (SpellGroupSpellMap::const_iterator itr2 = groupSpell.first; itr2 != groupSpell.second; ++itr2)
697 {
698 if (itr2->second < 0)
699 {
700 SpellGroup currGroup = (SpellGroup)abs(itr2->second);
701 if (IsSpellMemberOfSpellGroup(spellid_1, currGroup) && IsSpellMemberOfSpellGroup(spellid_2, currGroup))
702 {
703 add = false;
704 break;
705 }
706 }
707 }
708 if (add)
709 groups.insert(itr->second);
710 }
711 }
712
714
715 for (std::set<SpellGroup>::iterator itr = groups.begin(); itr != groups.end(); ++itr)
716 {
717 SpellGroupStackMap::const_iterator found = mSpellGroupStack.find(*itr);
718 if (found != mSpellGroupStack.end())
719 rule = found->second;
720 if (rule)
721 break;
722 }
723 return rule;
724}
725
727{
728 SpellProcEventMap::const_iterator itr = mSpellProcEventMap.find(spellId);
729 if (itr != mSpellProcEventMap.end())
730 return &itr->second;
731 return NULL;
732}
733
734bool SpellMgr::IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const* spellProcEvent, uint32 EventProcFlag, SpellInfo const* procSpell, uint32 procFlags, uint32 procExtra, bool active) const
735{
736 // No extra req need
737 uint32 procEvent_procEx = PROC_EX_NONE;
738
739 // check prockFlags for condition
740 if ((procFlags & EventProcFlag) == 0)
741 return false;
742
743 bool hasFamilyMask = false;
744
745 /* Check Periodic Auras
746
747 *Dots can trigger if spell has no PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL
748 nor PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL
749
750 *Only Hots can trigger if spell has PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL
751
752 *Only dots can trigger if spell has both positivity flags or PROC_FLAG_SUCCESSFUL_NEGATIVE_MAGIC_SPELL
753
754 *Aura has to have PROC_FLAG_TAKEN_POSITIVE_MAGIC_SPELL or spellfamily specified to trigger from Hot
755
756 */
757
758 if (procFlags & PROC_FLAG_DONE_PERIODIC)
759 {
761 {
762 if (!(procExtra & PROC_EX_INTERNAL_DOT))
763 return false;
764 }
765 else if (procExtra & PROC_EX_INTERNAL_HOT)
766 procExtra |= PROC_EX_INTERNAL_REQ_FAMILY;
767 else if (EventProcFlag & PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS)
768 return false;
769 }
770
771 if (procFlags & PROC_FLAG_TAKEN_PERIODIC)
772 {
774 {
775 if (!(procExtra & PROC_EX_INTERNAL_DOT))
776 return false;
777 }
778 else if (procExtra & PROC_EX_INTERNAL_HOT)
779 procExtra |= PROC_EX_INTERNAL_REQ_FAMILY;
780 else if (EventProcFlag & PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS)
781 return false;
782 }
783 // Trap casts are active by default
784 if (procFlags & PROC_FLAG_DONE_TRAP_ACTIVATION)
785 active = true;
786
787 // Always trigger for this
788 if (procFlags & (PROC_FLAG_KILLED | PROC_FLAG_KILL | PROC_FLAG_DEATH))
789 return true;
790
791 if (spellProcEvent) // Exist event data
792 {
793 // Store extra req
794 procEvent_procEx = spellProcEvent->procEx;
795
796 // For melee triggers
797 if (procSpell == NULL)
798 {
799 // Check (if set) for school (melee attack have Normal school)
800 if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & SPELL_SCHOOL_MASK_NORMAL) == 0)
801 return false;
802 }
803 else // For spells need check school/spell family/family mask
804 {
805 // Check (if set) for school
806 if (spellProcEvent->schoolMask && (spellProcEvent->schoolMask & procSpell->SchoolMask) == 0)
807 return false;
808
809 // Check (if set) for spellFamilyName
810 if (spellProcEvent->spellFamilyName && (spellProcEvent->spellFamilyName != procSpell->SpellFamilyName))
811 return false;
812
813 // spellFamilyName is Ok need check for spellFamilyMask if present
814 if (spellProcEvent->spellFamilyMask)
815 {
816 if (!(spellProcEvent->spellFamilyMask & procSpell->SpellFamilyFlags))
817 return false;
818 hasFamilyMask = true;
819 // Some spells are not considered as active even with have spellfamilyflags
820 if (!(procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL))
821 active = true;
822 }
823 }
824 }
825
826 if (procExtra & (PROC_EX_INTERNAL_REQ_FAMILY))
827 {
828 if (!hasFamilyMask)
829 return false;
830 }
831
832 // Check for extra req (if none) and hit/crit
833 if (procEvent_procEx == PROC_EX_NONE)
834 {
835 // No extra req, so can trigger only for hit/crit - spell has to be active
836 if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && active)
837 return true;
838 }
839 else // Passive spells hits here only if resist/reflect/immune/evade
840 {
841 if (procExtra & AURA_SPELL_PROC_EX_MASK)
842 {
843 // if spell marked as procing only from not active spells
844 if (active && procEvent_procEx & PROC_EX_NOT_ACTIVE_SPELL)
845 return false;
846 // if spell marked as procing only from active spells
847 if (!active && procEvent_procEx & PROC_EX_ONLY_ACTIVE_SPELL)
848 return false;
849 // Exist req for PROC_EX_EX_TRIGGER_ALWAYS
850 if (procEvent_procEx & PROC_EX_EX_TRIGGER_ALWAYS)
851 return true;
852 // PROC_EX_NOT_ACTIVE_SPELL and PROC_EX_ONLY_ACTIVE_SPELL flags handle: if passed checks before
853 if ((procExtra & (PROC_EX_NORMAL_HIT | PROC_EX_CRITICAL_HIT)) && ((procEvent_procEx & (AURA_SPELL_PROC_EX_MASK)) == 0))
854 return true;
855 }
856 // Check Extra Requirement like (hit/crit/miss/resist/parry/dodge/block/immune/reflect/absorb and other)
857 if (procEvent_procEx & procExtra)
858 return true;
859 }
860 return false;
861}
862
864{
865 SpellProcMap::const_iterator itr = mSpellProcMap.find(spellId);
866 if (itr != mSpellProcMap.end())
867 return &itr->second;
868 return NULL;
869}
870
872{
873 // proc type doesn't match
874 if (!(eventInfo.GetTypeMask() & procEntry.typeMask))
875 return false;
876
877 // check XP or honor target requirement
879 if (Player* actor = eventInfo.GetActor()->ToPlayer())
880 if (eventInfo.GetActionTarget() && !actor->isHonorOrXPTarget(eventInfo.GetActionTarget()))
881 return false;
882
883 // always trigger for these types
885 return true;
886
887 // check school mask (if set) for other trigger types
888 if (procEntry.schoolMask && !(eventInfo.GetSchoolMask() & procEntry.schoolMask))
889 return false;
890
891 // check spell family name/flags (if set) for spells
893 {
894 if (procEntry.spellFamilyName && (procEntry.spellFamilyName != eventInfo.GetSpellInfo()->SpellFamilyName))
895 return false;
896
897 if (procEntry.spellFamilyMask && !(procEntry.spellFamilyMask & eventInfo.GetSpellInfo()->SpellFamilyFlags))
898 return false;
899 }
900
901 // check spell type mask (if set)
903 {
904 if (procEntry.spellTypeMask && !(eventInfo.GetSpellTypeMask() & procEntry.spellTypeMask))
905 return false;
906 }
907
908 // check spell phase mask
910 {
911 if (!(eventInfo.GetSpellPhaseMask() & procEntry.spellPhaseMask))
912 return false;
913 }
914
915 // check hit mask (on taken hit or on done hit, but not on spell cast phase)
916 if ((eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK) || ((eventInfo.GetTypeMask() & DONE_HIT_PROC_FLAG_MASK) && !(eventInfo.GetSpellPhaseMask() & PROC_SPELL_PHASE_CAST)))
917 {
918 uint32 hitMask = procEntry.hitMask;
919 // get default values if hit mask not set
920 if (!hitMask)
921 {
922 // for taken procs allow normal + critical hits by default
923 if (eventInfo.GetTypeMask() & TAKEN_HIT_PROC_FLAG_MASK)
925 // for done procs allow normal + critical + absorbs by default
926 else
928 }
929 if (!(eventInfo.GetHitMask() & hitMask))
930 return false;
931 }
932
933 return true;
934}
935
937{
938 // Lookup data
939 SpellBonusMap::const_iterator itr = mSpellBonusMap.find(spellId);
940 if (itr != mSpellBonusMap.end())
941 return &itr->second;
942 // Not found, try lookup for 1 spell rank if exist
943 if (uint32 rank_1 = GetFirstSpellInChain(spellId))
944 {
945 SpellBonusMap::const_iterator itr2 = mSpellBonusMap.find(rank_1);
946 if (itr2 != mSpellBonusMap.end())
947 return &itr2->second;
948 }
949 return NULL;
950}
951
953{
954 SpellThreatMap::const_iterator itr = mSpellThreatMap.find(spellID);
955 if (itr != mSpellThreatMap.end())
956 return &itr->second;
957 else
958 {
959 uint32 firstSpell = GetFirstSpellInChain(spellID);
960 itr = mSpellThreatMap.find(firstSpell);
961 if (itr != mSpellThreatMap.end())
962 return &itr->second;
963 }
964 return NULL;
965}
966
968{
969 return mSkillLineAbilityMap.equal_range(spell_id);
970}
971
972PetAura const* SpellMgr::GetPetAura(uint32 spell_id, uint8 eff) const
973{
974 SpellPetAuraMap::const_iterator itr = mSpellPetAuraMap.find((spell_id << 8) + eff);
975 if (itr != mSpellPetAuraMap.end())
976 return &itr->second;
977 else
978 return NULL;
979}
980
982{
983 SpellEnchantProcEventMap::const_iterator itr = mSpellEnchantProcEventMap.find(enchId);
984 if (itr != mSpellEnchantProcEventMap.end())
985 return &itr->second;
986 return NULL;
987}
988
990{
991 return mEnchantCustomAttr[ench_id];
992}
993
994const std::vector<int32>* SpellMgr::GetSpellLinked(int32 spell_id) const
995{
996 SpellLinkedMap::const_iterator itr = mSpellLinkedMap.find(spell_id);
997 return itr != mSpellLinkedMap.end() ? &(itr->second) : NULL;
998}
999
1001{
1002 PetLevelupSpellMap::const_iterator itr = mPetLevelupSpellMap.find(petFamily);
1003 if (itr != mPetLevelupSpellMap.end())
1004 return &itr->second;
1005 else
1006 return NULL;
1007}
1008
1010{
1011 PetDefaultSpellsMap::const_iterator itr = mPetDefaultSpellsMap.find(id);
1012 if (itr != mPetDefaultSpellsMap.end())
1013 return &itr->second;
1014 return NULL;
1015}
1016
1018{
1019 return mSpellAreaMap.equal_range(spell_id);
1020}
1021
1023{
1024 return mSpellAreaForQuestMap.equal_range(quest_id);
1025}
1026
1031
1033{
1034 return mSpellAreaForAuraMap.equal_range(spell_id);
1035}
1036
1038{
1039 return mSpellAreaForAreaMap.equal_range(area_id);
1040}
1041
1042bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32 newArea) const
1043{
1044 if (gender != GENDER_NONE) // not in expected gender
1045 if (!player || gender != player->getGender())
1046 return false;
1047
1048 if (raceMask) // not in expected race
1049 if (!player || !(raceMask & player->getRaceMask()))
1050 return false;
1051
1052 if (areaId) // not in expected zone
1053 if (newZone != areaId && newArea != areaId)
1054 return false;
1055
1056 if (questStart) // not in expected required quest state
1057 if (!player || (((1 << player->GetQuestStatus(questStart)) & questStartStatus) == 0))
1058 return false;
1059
1060 if (questEnd) // not in expected forbidden quest state
1061 if (!player || (((1 << player->GetQuestStatus(questEnd)) & questEndStatus) == 0))
1062 return false;
1063
1064 if (auraSpell) // not have expected aura
1065 if (!player || (auraSpell > 0 && !player->HasAura(auraSpell)) || (auraSpell < 0 && player->HasAura(-auraSpell)))
1066 return false;
1067
1068 if (player)
1069 {
1070 if (Battleground* bg = player->GetBattleground())
1071 return bg->IsSpellAllowed(spellId, player);
1072 }
1073
1074 // Extra conditions
1075 switch (spellId)
1076 {
1077 case 91604: // No fly Zone - Wintergrasp
1078 {
1079 if (!player)
1080 return false;
1081
1082 Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId());
1084 return false;
1085 break;
1086 }
1087 case 56618: // Horde Controls Factory Phase Shift
1088 case 56617: // Alliance Controls Factory Phase Shift
1089 {
1090 if (!player)
1091 return false;
1092
1093 Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId());
1094
1095 if (!bf || bf->GetTypeId() != BATTLEFIELD_WG)
1096 return false;
1097
1098 // team that controls the workshop in the specified area
1099 uint32 team = bf->GetData(newArea);
1100
1101 if (team == TEAM_HORDE)
1102 return spellId == 56618;
1103 else if (team == TEAM_ALLIANCE)
1104 return spellId == 56617;
1105 break;
1106 }
1107 case 57940: // Essence of Wintergrasp - Northrend
1108 case 58045: // Essence of Wintergrasp - Wintergrasp
1109 {
1110 if (!player)
1111 return false;
1112
1113 if (Battlefield* battlefieldWG = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG))
1114 return battlefieldWG->IsEnabled() && (player->GetTeamId() == battlefieldWG->GetDefenderTeam()) && !battlefieldWG->IsWarTime();
1115 break;
1116 }
1117 case 74411: // Battleground - Dampening
1118 {
1119 if (!player)
1120 return false;
1121
1122 if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId()))
1123 return bf->IsWarTime();
1124 break;
1125 }
1126 }
1127
1128 return true;
1129}
1130
1132{
1133 for (SpellChainMap::iterator itr = mSpellChains.begin(); itr != mSpellChains.end(); ++itr)
1134 mSpellInfoMap[itr->first]->ChainEntry = NULL;
1135
1136 mSpellChains.clear();
1137}
1138
1140{
1141 // Remove Me
1142}
1143
1145{
1146 // cleanup data and load spell ranks for talents from dbc
1148
1149 uint32 oldMSTime = getMSTime();
1150
1151 // 0 1 2
1152 QueryResult result = WorldDatabase.Query("SELECT first_spell_id, spell_id, spell_rank from spell_ranks ORDER BY first_spell_id, spell_rank");
1153
1154 if (!result)
1155 {
1156 SF_LOG_INFO("server.loading", ">> Loaded 0 spell rank records. DB table `spell_ranks` is empty.");
1157 return;
1158 }
1159
1160 uint32 count = 0;
1161 bool finished = false;
1162
1163 do
1164 {
1165 // spellid, rank
1166 std::list < std::pair < int32, int32 > > rankChain;
1167 int32 currentSpell = -1;
1168 int32 lastSpell = -1;
1169
1170 // fill one chain
1171 while (currentSpell == lastSpell && !finished)
1172 {
1173 Field* fields = result->Fetch();
1174
1175 currentSpell = fields[0].GetUInt32();
1176 if (lastSpell == -1)
1177 lastSpell = currentSpell;
1178 uint32 spell_id = fields[1].GetUInt32();
1179 uint32 rank = fields[2].GetUInt8();
1180
1181 // don't drop the row if we're moving to the next rank
1182 if (currentSpell == lastSpell)
1183 {
1184 rankChain.push_back(std::make_pair(spell_id, rank));
1185 if (!result->NextRow())
1186 finished = true;
1187 }
1188 else
1189 break;
1190 }
1191 // check if chain is made with valid first spell
1192 SpellInfo const* first = GetSpellInfo(lastSpell);
1193 if (!first)
1194 {
1195 SF_LOG_ERROR("sql.sql", "Spell rank identifier(first_spell_id) %u listed in `spell_ranks` does not exist!", lastSpell);
1196 continue;
1197 }
1198 // check if chain is long enough
1199 if (rankChain.size() < 2)
1200 {
1201 SF_LOG_ERROR("sql.sql", "There is only 1 spell rank for identifier(first_spell_id) %u in `spell_ranks`, entry is not needed!", lastSpell);
1202 continue;
1203 }
1204 int32 curRank = 0;
1205 bool valid = true;
1206 // check spells in chain
1207 for (std::list<std::pair<int32, int32> >::iterator itr = rankChain.begin(); itr != rankChain.end(); ++itr)
1208 {
1209 SpellInfo const* spell = GetSpellInfo(itr->first);
1210 if (!spell)
1211 {
1212 SF_LOG_ERROR("sql.sql", "Spell %u (rank %u) listed in `spell_ranks` for chain %u does not exist!", itr->first, itr->second, lastSpell);
1213 valid = false;
1214 break;
1215 }
1216 ++curRank;
1217 if (itr->second != curRank)
1218 {
1219 SF_LOG_ERROR("sql.sql", "Spell %u (rank %u) listed in `spell_ranks` for chain %u does not have proper rank value(should be %u)!", itr->first, itr->second, lastSpell, curRank);
1220 valid = false;
1221 break;
1222 }
1223 }
1224 if (!valid)
1225 continue;
1226 int32 prevRank = 0;
1227 // insert the chain
1228 std::list<std::pair<int32, int32> >::iterator itr = rankChain.begin();
1229 do
1230 {
1231 ++count;
1232 int32 addedSpell = itr->first;
1233
1234 if (mSpellInfoMap[addedSpell]->ChainEntry)
1235 SF_LOG_ERROR("sql.sql", "Spell %u (rank: %u, first: %u) listed in `spell_ranks` has already ChainEntry from dbc.", addedSpell, itr->second, lastSpell);
1236
1237 mSpellChains[addedSpell].first = GetSpellInfo(lastSpell);
1238 mSpellChains[addedSpell].last = GetSpellInfo(rankChain.back().first);
1239 mSpellChains[addedSpell].rank = itr->second;
1240 mSpellChains[addedSpell].prev = GetSpellInfo(prevRank);
1241 mSpellInfoMap[addedSpell]->ChainEntry = &mSpellChains[addedSpell];
1242 prevRank = addedSpell;
1243 ++itr;
1244
1245 if (itr == rankChain.end())
1246 {
1247 mSpellChains[addedSpell].next = NULL;
1248 break;
1249 }
1250 else
1251 mSpellChains[addedSpell].next = GetSpellInfo(itr->first);
1252 } while (true);
1253 } while (!finished);
1254
1255 SF_LOG_INFO("server.loading", ">> Loaded %u spell rank records in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1256}
1257
1259{
1260 uint32 oldMSTime = getMSTime();
1261
1262 mSpellsReqSpell.clear(); // need for reload case
1263 mSpellReq.clear(); // need for reload case
1264
1265 // 0 1
1266 QueryResult result = WorldDatabase.Query("SELECT spell_id, req_spell from spell_required");
1267
1268 if (!result)
1269 {
1270 SF_LOG_INFO("server.loading", ">> Loaded 0 spell required records. DB table `spell_required` is empty.");
1271
1272 return;
1273 }
1274
1275 uint32 count = 0;
1276 do
1277 {
1278 Field* fields = result->Fetch();
1279
1280 uint32 spell_id = fields[0].GetUInt32();
1281 uint32 spell_req = fields[1].GetUInt32();
1282
1283 // check if chain is made with valid first spell
1284 SpellInfo const* spell = GetSpellInfo(spell_id);
1285 if (!spell)
1286 {
1287 SF_LOG_ERROR("sql.sql", "spell_id %u in `spell_required` table is not found in dbcs, skipped", spell_id);
1288 continue;
1289 }
1290
1291 SpellInfo const* reqSpell = GetSpellInfo(spell_req);
1292 if (!reqSpell)
1293 {
1294 SF_LOG_ERROR("sql.sql", "req_spell %u in `spell_required` table is not found in dbcs, skipped", spell_req);
1295 continue;
1296 }
1297
1298 if (spell->IsRankOf(reqSpell))
1299 {
1300 SF_LOG_ERROR("sql.sql", "req_spell %u and spell_id %u in `spell_required` table are ranks of the same spell, entry not needed, skipped", spell_req, spell_id);
1301 continue;
1302 }
1303
1304 if (IsSpellRequiringSpell(spell_id, spell_req))
1305 {
1306 SF_LOG_ERROR("sql.sql", "duplicated entry of req_spell %u and spell_id %u in `spell_required`, skipped", spell_req, spell_id);
1307 continue;
1308 }
1309
1310 mSpellReq.insert(std::pair<uint32, uint32>(spell_id, spell_req));
1311 mSpellsReqSpell.insert(std::pair<uint32, uint32>(spell_req, spell_id));
1312 ++count;
1313 } while (result->NextRow());
1314
1315 SF_LOG_INFO("server.loading", ">> Loaded %u spell required records in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1316}
1317
1319{
1320 uint32 oldMSTime = getMSTime();
1321
1322 mSpellLearnSkills.clear(); // need for reload case
1323
1324 // search auto-learned skills and add its to map also for use in unlearn spells/talents
1325 uint32 dbc_count = 0;
1326 for (uint32 spell = 0; spell < GetSpellInfoStoreSize(); ++spell)
1327 {
1328 SpellInfo const* entry = GetSpellInfo(spell);
1329
1330 if (!entry)
1331 continue;
1332
1333 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
1334 {
1335 if (entry->Effects[i].Effect == SPELL_EFFECT_SKILL)
1336 {
1337 SpellLearnSkillNode dbc_node;
1338 dbc_node.skill = entry->Effects[i].MiscValue;
1339 dbc_node.step = entry->Effects[i].CalcValue();
1340 if (dbc_node.skill != SKILL_RIDING)
1341 dbc_node.value = 1;
1342 else
1343 dbc_node.value = dbc_node.step * 75;
1344 dbc_node.maxvalue = dbc_node.step * 75;
1345 mSpellLearnSkills[spell] = dbc_node;
1346 ++dbc_count;
1347 break;
1348 }
1349 }
1350 }
1351
1352 SF_LOG_INFO("server.loading", ">> Loaded %u Spell Learn Skills from DBC in %u ms", dbc_count, GetMSTimeDiffToNow(oldMSTime));
1353}
1354
1356{
1357 uint32 oldMSTime = getMSTime();
1358
1359 mSpellLearnSpells.clear(); // need for reload case
1360
1361 // 0 1 2
1362 QueryResult result = WorldDatabase.Query("SELECT entry, SpellID, Active FROM spell_learn_spell");
1363 if (!result)
1364 {
1365 SF_LOG_INFO("server.loading", ">> Loaded 0 spell learn spells. DB table `spell_learn_spell` is empty.");
1366 return;
1367 }
1368
1369 uint32 count = 0;
1370 do
1371 {
1372 Field* fields = result->Fetch();
1373
1374 uint32 spell_id = fields[0].GetUInt32();
1375
1377 node.spell = fields[1].GetUInt32();
1378 node.active = fields[2].GetBool();
1379 node.autoLearned = false;
1380
1381 if (!GetSpellInfo(spell_id))
1382 {
1383 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` does not exist", spell_id);
1384 continue;
1385 }
1386
1387 if (!GetSpellInfo(node.spell))
1388 {
1389 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` learning not existed spell %u", spell_id, node.spell);
1390 continue;
1391 }
1392
1393 if (GetTalentSpellCost(node.spell))
1394 {
1395 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped", spell_id, node.spell);
1396 continue;
1397 }
1398
1399 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell_id, node));
1400
1401 ++count;
1402 } while (result->NextRow());
1403
1404 // copy state loaded from db
1405 SpellLearnSpellMap dbSpellLearnSpells = mSpellLearnSpells;
1406
1407 // search auto-learned spells and add its to map also for use in unlearn spells/talents
1408 uint32 dbc_count = 0;
1409 for (uint32 spell = 0; spell < GetSpellInfoStoreSize(); ++spell)
1410 {
1411 SpellInfo const* entry = GetSpellInfo(spell);
1412
1413 if (!entry)
1414 continue;
1415
1416 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
1417 {
1418 if (entry->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL)
1419 {
1420 SpellLearnSpellNode dbc_node;
1421 dbc_node.spell = entry->Effects[i].TriggerSpell;
1422 dbc_node.active = true; // all dbc based learned spells is active (show in spell book or hide by client itself)
1423
1424 // ignore learning not existed spells (broken/outdated/or generic learnig spell 483
1425 if (!GetSpellInfo(dbc_node.spell))
1426 continue;
1427
1428 // talent or passive spells or skill-step spells auto-casted and not need dependent learning,
1429 // pet teaching spells must not be dependent learning (casted)
1430 // other required explicit dependent learning
1431 dbc_node.autoLearned = entry->Effects[i].TargetA.GetTarget() == TARGET_UNIT_PET || GetTalentSpellCost(spell) > 0 || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
1432
1433 SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(spell);
1434
1435 bool found = false;
1436 for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
1437 {
1438 if (itr->second.spell == dbc_node.spell)
1439 {
1440 SF_LOG_ERROR("sql.sql", "Spell %u auto-learn spell %u in spell.dbc then the record in `spell_learn_spell` is redundant, please fix DB.",
1441 spell, dbc_node.spell);
1442 found = true;
1443 break;
1444 }
1445 }
1446
1447 if (!found) // add new spell-spell pair if not found
1448 {
1449 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(spell, dbc_node));
1450 ++dbc_count;
1451 }
1452 }
1453 }
1454 }
1455 /*
1456 uint32 mastery_count = 0;
1457 for (uint32 i = 0; i < sTalentTabStore.GetNumRows(); ++i)
1458 {
1459 TalentTabEntry const* talentTab = sTalentTabStore.LookupEntry(i);
1460 if (!talentTab)
1461 continue;
1462
1463 for (uint32 c = CLASS_WARRIOR; c < MAX_CLASSES; ++c)
1464 {
1465 if (!(talentTab->ClassMask & (1 << (c - 1))))
1466 continue;
1467
1468 uint32 masteryMainSpell = MasterySpells[c];
1469
1470 for (uint32 m = 0; m < MAX_MASTERY_SPELLS; ++m)
1471 {
1472 uint32 mastery = talentTab->MasterySpellId[m];
1473 if (!mastery)
1474 continue;
1475
1476 SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(masteryMainSpell);
1477 bool found = false;
1478 for (SpellLearnSpellMap::const_iterator itr = db_node_bounds.first; itr != db_node_bounds.second; ++itr)
1479 {
1480 if (itr->second.spell == mastery)
1481 {
1482 SF_LOG_ERROR("sql.sql", "Found redundant record (entry: %u, SpellID: %u) in `spell_learn_spell`, spell added automatically as mastery learned spell from TalentTab.dbc", masteryMainSpell, mastery);
1483 found = true;
1484 break;
1485 }
1486 }
1487
1488 if (found)
1489 continue;
1490
1491 // Check if it is already found in Spell.dbc, ignore silently if yes
1492 SpellLearnSpellMapBounds dbc_node_bounds = GetSpellLearnSpellMapBounds(masteryMainSpell);
1493 found = false;
1494 for (SpellLearnSpellMap::const_iterator itr = dbc_node_bounds.first; itr != dbc_node_bounds.second; ++itr)
1495 {
1496 if (itr->second.spell == mastery)
1497 {
1498 found = true;
1499 break;
1500 }
1501 }
1502
1503 if (found)
1504 continue;
1505
1506 SpellLearnSpellNode masteryNode;
1507 masteryNode.spell = mastery;
1508 masteryNode.active = true;
1509 masteryNode.autoLearned = false;
1510
1511 mSpellLearnSpells.insert(SpellLearnSpellMap::value_type(masteryMainSpell, masteryNode));
1512 ++mastery_count;
1513 }
1514 }
1515 }
1516 */
1517 SF_LOG_INFO("server.loading", ">> Loaded %u spell learn spells, %u found in Spell.dbc and %u from TalentTab.dbc in %u ms", count, dbc_count, 0, GetMSTimeDiffToNow(oldMSTime));
1518}
1519
1521{
1522 uint32 oldMSTime = getMSTime();
1523
1524 mSpellTargetPositions.clear(); // need for reload case
1525
1526 // 0 1 2 3 4 5 6
1527 QueryResult result = WorldDatabase.Query("SELECT id, effIndex, target_map, target_position_x, target_position_y, target_position_z, target_orientation FROM spell_target_position");
1528 if (!result)
1529 {
1530 SF_LOG_INFO("server.loading", ">> Loaded 0 spell target coordinates. DB table `spell_target_position` is empty.");
1531 return;
1532 }
1533
1534 uint32 count = 0;
1535 do
1536 {
1537 Field* fields = result->Fetch();
1538
1539 uint32 Spell_ID = fields[0].GetUInt32();
1540 SpellEffIndex effIndex = SpellEffIndex(fields[1].GetUInt8());
1541
1543
1544 st.target_mapId = fields[2].GetUInt16();
1545 st.target_X = fields[3].GetFloat();
1546 st.target_Y = fields[4].GetFloat();
1547 st.target_Z = fields[5].GetFloat();
1548 st.target_Orientation = fields[6].GetFloat();
1549
1550 MapEntry const* mapEntry = sMapStore.LookupEntry(st.target_mapId);
1551 if (!mapEntry)
1552 {
1553 SF_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) target map (ID: %u) does not exist in `Map.dbc`.", Spell_ID, effIndex, st.target_mapId);
1554 continue;
1555 }
1556
1557 if (st.target_X == 0 && st.target_Y == 0 && st.target_Z == 0)
1558 {
1559 SF_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) target coordinates not provided.", Spell_ID, effIndex);
1560 continue;
1561 }
1562
1563 SpellInfo const* spellInfo = GetSpellInfo(Spell_ID);
1564 if (!spellInfo)
1565 {
1566 SF_LOG_ERROR("sql.sql", "Spell (Id: %u) listed in `spell_target_position` does not exist.", Spell_ID);
1567 continue;
1568 }
1569
1570 if (spellInfo->Effects[effIndex].TargetA.GetTarget() == TARGET_DEST_DB || spellInfo->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DB)
1571 {
1572 std::pair<uint32, SpellEffIndex> key = std::make_pair(Spell_ID, effIndex);
1573 mSpellTargetPositions[key] = st;
1574 ++count;
1575 }
1576 else
1577 {
1578 SF_LOG_ERROR("sql.sql", "Spell (Id: %u, effIndex: %u) listed in `spell_target_position` does not have target TARGET_DEST_DB (17).", Spell_ID, effIndex);
1579 continue;
1580 }
1581 } while (result->NextRow());
1582
1583 /*
1584 // Check all spells
1585 for (uint32 i = 1; i < GetSpellInfoStoreSize; ++i)
1586 {
1587 SpellInfo const* spellInfo = GetSpellInfo(i);
1588 if (!spellInfo)
1589 continue;
1590
1591 bool found = false;
1592 for (int j = 0; j < MAX_SPELL_EFFECTS; ++j)
1593 {
1594 switch (spellInfo->Effects[j].TargetA)
1595 {
1596 case TARGET_DEST_DB:
1597 found = true;
1598 break;
1599 }
1600 if (found)
1601 break;
1602 switch (spellInfo->Effects[j].TargetB)
1603 {
1604 case TARGET_DEST_DB:
1605 found = true;
1606 break;
1607 }
1608 if (found)
1609 break;
1610 }
1611 if (found)
1612 {
1613 if (!sSpellMgr->GetSpellTargetPosition(i))
1614 SF_LOG_DEBUG("spells", "Spell (ID: %u) does not have record in `spell_target_position`", i);
1615 }
1616 }*/
1617
1618 SF_LOG_INFO("server.loading", ">> Loaded %u spell teleport coordinates in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1619}
1620
1622{
1623 uint32 oldMSTime = getMSTime();
1624
1625 mSpellSpellGroup.clear(); // need for reload case
1626 mSpellGroupSpell.clear();
1627
1628 // 0 1
1629 QueryResult result = WorldDatabase.Query("SELECT id, spell_id FROM spell_group");
1630 if (!result)
1631 {
1632 SF_LOG_INFO("server.loading", ">> Loaded 0 spell group definitions. DB table `spell_group` is empty.");
1633 return;
1634 }
1635
1636 std::set<uint32> groups;
1637 uint32 count = 0;
1638 do
1639 {
1640 Field* fields = result->Fetch();
1641
1642 uint32 group_id = fields[0].GetUInt32();
1643 if (group_id <= SPELL_GROUP_DB_RANGE_MIN && group_id >= SPELL_GROUP_CORE_RANGE_MAX)
1644 {
1645 SF_LOG_ERROR("sql.sql", "SpellGroup id %u listed in `spell_group` is in core range, but is not defined in core!", group_id);
1646 continue;
1647 }
1648 int32 spell_id = fields[1].GetInt32();
1649
1650 groups.insert(std::set<uint32>::value_type(group_id));
1651 mSpellGroupSpell.insert(SpellGroupSpellMap::value_type((SpellGroup)group_id, spell_id));
1652 } while (result->NextRow());
1653
1654 for (SpellGroupSpellMap::iterator itr = mSpellGroupSpell.begin(); itr != mSpellGroupSpell.end();)
1655 {
1656 if (itr->second < 0)
1657 {
1658 if (groups.find(abs(itr->second)) == groups.end())
1659 {
1660 SF_LOG_ERROR("sql.sql", "SpellGroup id %u listed in `spell_group` does not exist", abs(itr->second));
1661 mSpellGroupSpell.erase(itr++);
1662 }
1663 else
1664 ++itr;
1665 }
1666 else
1667 {
1668 SpellInfo const* spellInfo = GetSpellInfo(itr->second);
1669
1670 if (!spellInfo)
1671 {
1672 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_group` does not exist", itr->second);
1673 mSpellGroupSpell.erase(itr++);
1674 }
1675 else if (spellInfo->GetRank() > 1)
1676 {
1677 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_group` is not first rank of spell", itr->second);
1678 mSpellGroupSpell.erase(itr++);
1679 }
1680 else
1681 ++itr;
1682 }
1683 }
1684
1685 for (std::set<uint32>::iterator groupItr = groups.begin(); groupItr != groups.end(); ++groupItr)
1686 {
1687 std::set<uint32> spells;
1688 GetSetOfSpellsInSpellGroup(SpellGroup(*groupItr), spells);
1689
1690 for (std::set<uint32>::iterator spellItr = spells.begin(); spellItr != spells.end(); ++spellItr)
1691 {
1692 ++count;
1693 mSpellSpellGroup.insert(SpellSpellGroupMap::value_type(*spellItr, SpellGroup(*groupItr)));
1694 }
1695 }
1696
1697 SF_LOG_INFO("server.loading", ">> Loaded %u spell group definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1698}
1699
1701{
1702 uint32 oldMSTime = getMSTime();
1703
1704 mSpellGroupStack.clear(); // need for reload case
1705
1706 // 0 1
1707 QueryResult result = WorldDatabase.Query("SELECT group_id, stack_rule FROM spell_group_stack_rules");
1708 if (!result)
1709 {
1710 SF_LOG_INFO("server.loading", ">> Loaded 0 spell group stack rules. DB table `spell_group_stack_rules` is empty.");
1711 return;
1712 }
1713
1714 uint32 count = 0;
1715 do
1716 {
1717 Field* fields = result->Fetch();
1718
1719 uint32 group_id = fields[0].GetUInt32();
1720 uint8 stack_rule = fields[1].GetInt8();
1721 if (stack_rule >= SPELL_GROUP_STACK_RULE_MAX)
1722 {
1723 SF_LOG_ERROR("sql.sql", "SpellGroupStackRule %u listed in `spell_group_stack_rules` does not exist", stack_rule);
1724 continue;
1725 }
1726
1728
1729 if (spellGroup.first == spellGroup.second)
1730 {
1731 SF_LOG_ERROR("sql.sql", "SpellGroup id %u listed in `spell_group_stack_rules` does not exist", group_id);
1732 continue;
1733 }
1734
1735 mSpellGroupStack[(SpellGroup)group_id] = (SpellGroupStackRule)stack_rule;
1736
1737 ++count;
1738 } while (result->NextRow());
1739
1740 SF_LOG_INFO("server.loading", ">> Loaded %u spell group stack rules in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1741}
1742
1744{
1745 uint32 oldMSTime = getMSTime();
1746
1747 mSpellProcEventMap.clear(); // need for reload case
1748
1749 // 0 1 2 3 4 5 6 7 8 9 10 11
1750 QueryResult result = WorldDatabase.Query("SELECT entry, SchoolMask, SpellFamilyName, SpellFamilyMask0, SpellFamilyMask1, SpellFamilyMask2, SpellFamilyMask3, procFlags, procEx, ppmRate, CustomChance, Cooldown FROM spell_proc_event");
1751 if (!result)
1752 {
1753 SF_LOG_INFO("server.loading", ">> Loaded 0 spell proc event conditions. DB table `spell_proc_event` is empty.");
1754 return;
1755 }
1756
1757 uint32 count = 0;
1758
1759 do
1760 {
1761 Field* fields = result->Fetch();
1762 int i = 0;
1763
1764 int32 spellId = fields[i++].GetInt32();
1765
1766 bool allRanks = false;
1767 if (spellId < 0)
1768 {
1769 allRanks = true;
1770 spellId = -spellId;
1771 }
1772
1773 SpellInfo const* spellInfo = GetSpellInfo(spellId);
1774 if (!spellInfo)
1775 {
1776 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc_event` does not exist", spellId);
1777 continue;
1778 }
1779
1780 if (allRanks)
1781 {
1782 if (!spellInfo->IsRanked())
1783 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc_event` with all ranks, but spell has no ranks.", spellId);
1784
1785 if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
1786 {
1787 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc_event` is not first rank of spell.", spellId);
1788 continue;
1789 }
1790 }
1791
1792 SpellProcEventEntry spellProcEvent;
1793
1794 spellProcEvent.schoolMask = fields[i++].GetInt8();
1795 spellProcEvent.spellFamilyName = fields[i++].GetUInt16();
1796 spellProcEvent.spellFamilyMask[0] = fields[i++].GetUInt32();
1797 spellProcEvent.spellFamilyMask[1] = fields[i++].GetUInt32();
1798 spellProcEvent.spellFamilyMask[2] = fields[i++].GetUInt32();
1799 spellProcEvent.spellFamilyMask[3] = fields[i++].GetUInt32();
1800 spellProcEvent.procFlags = fields[i++].GetUInt32();
1801 spellProcEvent.procEx = fields[i++].GetUInt32();
1802 spellProcEvent.ppmRate = fields[i++].GetFloat();
1803 spellProcEvent.customChance = fields[i++].GetFloat();
1804 spellProcEvent.cooldown = fields[i++].GetUInt32();
1805
1806 while (spellInfo)
1807 {
1808 if (mSpellProcEventMap.find(spellInfo->Id) != mSpellProcEventMap.end())
1809 {
1810 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc_event` already has its first rank in table.", spellInfo->Id);
1811 break;
1812 }
1813
1814 if (!spellInfo->ProcFlags && !spellProcEvent.procFlags)
1815 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc_event` probably not triggered spell", spellInfo->Id);
1816
1817 mSpellProcEventMap[spellInfo->Id] = spellProcEvent;
1818
1819 if (allRanks)
1820 spellInfo = spellInfo->GetNextRankSpell();
1821 else
1822 break;
1823 }
1824
1825 ++count;
1826 } while (result->NextRow());
1827
1828 SF_LOG_INFO("server.loading", ">> Loaded %u extra spell proc event conditions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1829}
1830
1832{
1833 uint32 oldMSTime = getMSTime();
1834
1835 mSpellProcMap.clear(); // need for reload case
1836
1837 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1838 QueryResult result = WorldDatabase.Query("SELECT spellId, schoolMask, spellFamilyName, spellFamilyMask0, spellFamilyMask1, spellFamilyMask2, typeMask, spellTypeMask, spellPhaseMask, hitMask, attributesMask, ratePerMinute, chance, cooldown, charges FROM spell_proc");
1839 if (!result)
1840 {
1841 SF_LOG_INFO("server.loading", ">> Loaded 0 spell proc conditions and data. DB table `spell_proc` is empty.");
1842 return;
1843 }
1844
1845 uint32 count = 0;
1846 do
1847 {
1848 Field* fields = result->Fetch();
1849
1850 int32 spellId = fields[0].GetInt32();
1851
1852 bool allRanks = false;
1853 if (spellId < 0)
1854 {
1855 allRanks = true;
1856 spellId = -spellId;
1857 }
1858
1859 SpellInfo const* spellInfo = GetSpellInfo(spellId);
1860 if (!spellInfo)
1861 {
1862 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc` does not exist", spellId);
1863 continue;
1864 }
1865
1866 if (allRanks)
1867 {
1868 if (!spellInfo->IsRanked())
1869 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc` with all ranks, but spell has no ranks.", spellId);
1870
1871 if (spellInfo->GetFirstRankSpell()->Id != uint32(spellId))
1872 {
1873 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc` is not first rank of spell.", spellId);
1874 continue;
1875 }
1876 }
1877
1878 SpellProcEntry baseProcEntry;
1879
1880 baseProcEntry.schoolMask = fields[1].GetInt8();
1881 baseProcEntry.spellFamilyName = fields[2].GetUInt16();
1882 baseProcEntry.spellFamilyMask[0] = fields[3].GetUInt32();
1883 baseProcEntry.spellFamilyMask[1] = fields[4].GetUInt32();
1884 baseProcEntry.spellFamilyMask[2] = fields[5].GetUInt32();
1885 baseProcEntry.typeMask = fields[6].GetUInt32();
1886 baseProcEntry.spellTypeMask = fields[7].GetUInt32();
1887 baseProcEntry.spellPhaseMask = fields[8].GetUInt32();
1888 baseProcEntry.hitMask = fields[9].GetUInt32();
1889 baseProcEntry.attributesMask = fields[10].GetUInt32();
1890 baseProcEntry.ratePerMinute = fields[11].GetFloat();
1891 baseProcEntry.chance = fields[12].GetFloat();
1892 float cooldown = fields[13].GetFloat();
1893 baseProcEntry.cooldown = uint32(cooldown);
1894 baseProcEntry.charges = fields[14].GetUInt32();
1895
1896 while (spellInfo)
1897 {
1898 if (mSpellProcMap.find(spellInfo->Id) != mSpellProcMap.end())
1899 {
1900 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_proc` already has its first rank in table.", spellInfo->Id);
1901 break;
1902 }
1903
1904 SpellProcEntry procEntry = SpellProcEntry(baseProcEntry);
1905
1906 // take defaults from dbcs
1907 if (!procEntry.typeMask)
1908 procEntry.typeMask = spellInfo->ProcFlags;
1909 if (!procEntry.charges)
1910 procEntry.charges = spellInfo->ProcCharges;
1911 if (!procEntry.chance && !procEntry.ratePerMinute)
1912 procEntry.chance = float(spellInfo->ProcChance);
1913
1914 // validate data
1915 if (procEntry.schoolMask & ~SPELL_SCHOOL_MASK_ALL)
1916 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `schoolMask` set: %u", spellInfo->Id, procEntry.schoolMask);
1917 if (procEntry.spellFamilyName && (procEntry.spellFamilyName < 3 || procEntry.spellFamilyName > 17 || procEntry.spellFamilyName == 14 || procEntry.spellFamilyName == 16))
1918 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `spellFamilyName` set: %u", spellInfo->Id, procEntry.spellFamilyName);
1919 if (procEntry.chance < 0)
1920 {
1921 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in `chance` field", spellInfo->Id);
1922 procEntry.chance = 0;
1923 }
1924 if (procEntry.ratePerMinute < 0)
1925 {
1926 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in `ratePerMinute` field", spellInfo->Id);
1927 procEntry.ratePerMinute = 0;
1928 }
1929 if (cooldown < 0)
1930 {
1931 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has negative value in `cooldown` field", spellInfo->Id);
1932 procEntry.cooldown = 0;
1933 }
1934 if (procEntry.chance == 0 && procEntry.ratePerMinute == 0)
1935 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have `chance` and `ratePerMinute` values defined, proc will not be triggered", spellInfo->Id);
1936 if (procEntry.charges > 99)
1937 {
1938 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has too big value in `charges` field", spellInfo->Id);
1939 procEntry.charges = 99;
1940 }
1941 if (!procEntry.typeMask)
1942 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have `typeMask` value defined, proc will not be triggered", spellInfo->Id);
1943 if (procEntry.spellTypeMask & ~PROC_SPELL_TYPE_MASK_ALL)
1944 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `spellTypeMask` set: %u", spellInfo->Id, procEntry.spellTypeMask);
1945 if (procEntry.spellTypeMask && !(procEntry.typeMask & (SPELL_PROC_FLAG_MASK | PERIODIC_PROC_FLAG_MASK)))
1946 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has `spellTypeMask` value defined, but it won't be used for defined `typeMask` value", spellInfo->Id);
1947 if (!procEntry.spellPhaseMask && procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK)
1948 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u doesn't have `spellPhaseMask` value defined, but it's required for defined `typeMask` value, proc will not be triggered", spellInfo->Id);
1950 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `spellPhaseMask` set: %u", spellInfo->Id, procEntry.spellPhaseMask);
1951 if (procEntry.spellPhaseMask && !(procEntry.typeMask & REQ_SPELL_PHASE_PROC_FLAG_MASK))
1952 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has `spellPhaseMask` value defined, but it won't be used for defined `typeMask` value", spellInfo->Id);
1953 if (procEntry.hitMask & ~PROC_HIT_MASK_ALL)
1954 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has wrong `hitMask` set: %u", spellInfo->Id, procEntry.hitMask);
1955 if (procEntry.hitMask && !(procEntry.typeMask & TAKEN_HIT_PROC_FLAG_MASK || (procEntry.typeMask & DONE_HIT_PROC_FLAG_MASK && (!procEntry.spellPhaseMask || procEntry.spellPhaseMask & (PROC_SPELL_PHASE_HIT | PROC_SPELL_PHASE_FINISH)))))
1956 SF_LOG_ERROR("sql.sql", "`spell_proc` table entry for spellId %u has `hitMask` value defined, but it won't be used for defined `typeMask` and `spellPhaseMask` values", spellInfo->Id);
1957
1958 mSpellProcMap[spellInfo->Id] = procEntry;
1959
1960 if (allRanks)
1961 spellInfo = spellInfo->GetNextRankSpell();
1962 else
1963 break;
1964 }
1965 ++count;
1966 } while (result->NextRow());
1967
1968 SF_LOG_INFO("server.loading", ">> Loaded %u spell proc conditions and data in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
1969}
1970
1972{
1973 uint32 oldMSTime = getMSTime();
1974
1975 mSpellBonusMap.clear(); // need for reload case
1976
1977 // 0 1 2 3 4
1978 QueryResult result = WorldDatabase.Query("SELECT entry, direct_bonus, dot_bonus, ap_bonus, ap_dot_bonus FROM spell_bonus_data");
1979 if (!result)
1980 {
1981 SF_LOG_INFO("server.loading", ">> Loaded 0 spell bonus data. DB table `spell_bonus_data` is empty.");
1982 return;
1983 }
1984
1985 uint32 count = 0;
1986 do
1987 {
1988 Field* fields = result->Fetch();
1989 uint32 entry = fields[0].GetUInt32();
1990
1991 SpellInfo const* spell = GetSpellInfo(entry);
1992 if (!spell)
1993 {
1994 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_bonus_data` does not exist", entry);
1995 continue;
1996 }
1997
1998 SpellBonusEntry& sbe = mSpellBonusMap[entry];
1999 sbe.direct_damage = fields[1].GetFloat();
2000 sbe.dot_damage = fields[2].GetFloat();
2001 sbe.ap_bonus = fields[3].GetFloat();
2002 sbe.ap_dot_bonus = fields[4].GetFloat();
2003
2004 ++count;
2005 } while (result->NextRow());
2006
2007 SF_LOG_INFO("server.loading", ">> Loaded %u extra spell bonus data in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2008}
2009
2011{
2012 uint32 oldMSTime = getMSTime();
2013
2014 mSpellThreatMap.clear(); // need for reload case
2015
2016 // 0 1 2 3
2017 QueryResult result = WorldDatabase.Query("SELECT entry, flatMod, pctMod, apPctMod FROM spell_threat");
2018 if (!result)
2019 {
2020 SF_LOG_INFO("server.loading", ">> Loaded 0 aggro generating spells. DB table `spell_threat` is empty.");
2021 return;
2022 }
2023
2024 uint32 count = 0;
2025 do
2026 {
2027 Field* fields = result->Fetch();
2028
2029 uint32 entry = fields[0].GetUInt32();
2030
2031 if (!GetSpellInfo(entry))
2032 {
2033 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_threat` does not exist", entry);
2034 continue;
2035 }
2036
2037 SpellThreatEntry ste;
2038 ste.flatMod = fields[1].GetInt32();
2039 ste.pctMod = fields[2].GetFloat();
2040 ste.apPctMod = fields[3].GetFloat();
2041
2042 mSpellThreatMap[entry] = ste;
2043 ++count;
2044 } while (result->NextRow());
2045
2046 SF_LOG_INFO("server.loading", ">> Loaded %u SpellThreatEntries in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2047}
2048
2050{
2051 uint32 oldMSTime = getMSTime();
2052
2053 mSkillLineAbilityMap.clear();
2054
2055 uint32 count = 0;
2056
2057 for (uint32 i = 0; i < sSkillLineAbilityStore.GetNumRows(); ++i)
2058 {
2059 SkillLineAbilityEntry const* SkillInfo = sSkillLineAbilityStore.LookupEntry(i);
2060 if (!SkillInfo)
2061 continue;
2062
2063 mSkillLineAbilityMap.insert(SkillLineAbilityMap::value_type(SkillInfo->spellId, SkillInfo));
2064 ++count;
2065 }
2066
2067 SF_LOG_INFO("server.loading", ">> Loaded %u SkillLineAbility MultiMap Data in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2068}
2069
2071{
2072 uint32 oldMSTime = getMSTime();
2073
2074 mSpellPetAuraMap.clear(); // need for reload case
2075
2076 // 0 1 2 3
2077 QueryResult result = WorldDatabase.Query("SELECT spell, effectId, pet, aura FROM spell_pet_auras");
2078 if (!result)
2079 {
2080 SF_LOG_INFO("server.loading", ">> Loaded 0 spell pet auras. DB table `spell_pet_auras` is empty.");
2081 return;
2082 }
2083
2084 uint32 count = 0;
2085 do
2086 {
2087 Field* fields = result->Fetch();
2088
2089 uint32 spell = fields[0].GetUInt32();
2090 uint8 eff = fields[1].GetUInt8();
2091 uint32 pet = fields[2].GetUInt32();
2092 uint32 aura = fields[3].GetUInt32();
2093
2094 SpellPetAuraMap::iterator itr = mSpellPetAuraMap.find((spell << 8) + eff);
2095 if (itr != mSpellPetAuraMap.end())
2096 itr->second.AddAura(pet, aura);
2097 else
2098 {
2099 SpellInfo const* spellInfo = GetSpellInfo(spell);
2100 if (!spellInfo)
2101 {
2102 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_pet_auras` does not exist", spell);
2103 continue;
2104 }
2105 if (spellInfo->Effects[eff].Effect != SPELL_EFFECT_DUMMY &&
2106 (spellInfo->Effects[eff].Effect != SPELL_EFFECT_APPLY_AURA ||
2107 spellInfo->Effects[eff].ApplyAuraName != SPELL_AURA_DUMMY))
2108 {
2109 SF_LOG_ERROR("spells", "Spell %u listed in `spell_pet_auras` does not have dummy aura or dummy effect", spell);
2110 continue;
2111 }
2112
2113 SpellInfo const* spellInfo2 = GetSpellInfo(aura);
2114 if (!spellInfo2)
2115 {
2116 SF_LOG_ERROR("sql.sql", "Aura %u listed in `spell_pet_auras` does not exist", aura);
2117 continue;
2118 }
2119
2120 PetAura pa(pet, aura, spellInfo->Effects[eff].TargetA.GetTarget() == TARGET_UNIT_PET, spellInfo->Effects[eff].CalcValue());
2121 mSpellPetAuraMap[(spell << 8) + eff] = pa;
2122 }
2123
2124 ++count;
2125 } while (result->NextRow());
2126
2127 SF_LOG_INFO("server.loading", ">> Loaded %u spell pet auras in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2128}
2129
2130// Fill custom data about enchancments
2132{
2133 uint32 oldMSTime = getMSTime();
2134
2135 uint32 size = sSpellItemEnchantmentStore.GetNumRows();
2136 mEnchantCustomAttr.resize(size);
2137
2138 for (uint32 i = 0; i < size; ++i)
2139 mEnchantCustomAttr[i] = 0;
2140
2141 uint32 count = 0;
2142 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2143 {
2144 SpellInfo const* spellInfo = GetSpellInfo(i);
2145 if (!spellInfo)
2146 continue;
2147
2150 continue;
2151
2152 for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
2153 {
2155 {
2156 uint32 enchId = spellInfo->Effects[j].MiscValue;
2157 SpellItemEnchantmentEntry const* ench = sSpellItemEnchantmentStore.LookupEntry(enchId);
2158 if (!ench)
2159 continue;
2160 mEnchantCustomAttr[enchId] = true;
2161 ++count;
2162 break;
2163 }
2164 }
2165 }
2166
2167 SF_LOG_INFO("server.loading", ">> Loaded %u custom enchant attributes in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2168}
2169
2171{
2172 uint32 oldMSTime = getMSTime();
2173
2174 mSpellEnchantProcEventMap.clear(); // need for reload case
2175
2176 // 0 1 2 3
2177 QueryResult result = WorldDatabase.Query("SELECT entry, customChance, PPMChance, procEx FROM spell_enchant_proc_data");
2178 if (!result)
2179 {
2180 SF_LOG_INFO("server.loading", ">> Loaded 0 spell enchant proc event conditions. DB table `spell_enchant_proc_data` is empty.");
2181 return;
2182 }
2183
2184 uint32 count = 0;
2185 do
2186 {
2187 Field* fields = result->Fetch();
2188
2189 uint32 enchantId = fields[0].GetUInt32();
2190
2191 SpellItemEnchantmentEntry const* ench = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2192 if (!ench)
2193 {
2194 SF_LOG_ERROR("sql.sql", "Enchancment %u listed in `spell_enchant_proc_data` does not exist", enchantId);
2195 continue;
2196 }
2197
2199
2200 spe.customChance = fields[1].GetUInt32();
2201 spe.PPMChance = fields[2].GetFloat();
2202 spe.procEx = fields[3].GetUInt32();
2203
2204 mSpellEnchantProcEventMap[enchantId] = spe;
2205
2206 ++count;
2207 } while (result->NextRow());
2208
2209 SF_LOG_INFO("server.loading", ">> Loaded %u enchant proc data definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2210}
2211
2213{
2214 uint32 oldMSTime = getMSTime();
2215
2216 mSpellLinkedMap.clear(); // need for reload case
2217
2218 // 0 1 2
2219 QueryResult result = WorldDatabase.Query("SELECT spell_trigger, spell_effect, type FROM spell_linked_spell");
2220 if (!result)
2221 {
2222 SF_LOG_INFO("server.loading", ">> Loaded 0 linked spells. DB table `spell_linked_spell` is empty.");
2223 return;
2224 }
2225
2226 uint32 count = 0;
2227 do
2228 {
2229 Field* fields = result->Fetch();
2230
2231 int32 trigger = fields[0].GetInt32();
2232 int32 effect = fields[1].GetInt32();
2233 int32 type = fields[2].GetUInt8();
2234
2235 SpellInfo const* spellInfo = GetSpellInfo(abs(trigger));
2236 if (!spellInfo)
2237 {
2238 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_linked_spell` does not exist", abs(trigger));
2239 continue;
2240 }
2241 spellInfo = GetSpellInfo(abs(effect));
2242 if (!spellInfo)
2243 {
2244 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_linked_spell` does not exist", abs(effect));
2245 continue;
2246 }
2247
2248 if (type) //we will find a better way when more types are needed
2249 {
2250 if (trigger > 0)
2251 trigger += SPELL_LINKED_MAX_SPELLS * type;
2252 else
2253 trigger -= SPELL_LINKED_MAX_SPELLS * type;
2254 }
2255 mSpellLinkedMap[trigger].push_back(effect);
2256
2257 ++count;
2258 } while (result->NextRow());
2259
2260 SF_LOG_INFO("server.loading", ">> Loaded %u linked spells in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2261}
2262
2264{
2265 uint32 oldMSTime = getMSTime();
2266
2267 mPetLevelupSpellMap.clear(); // need for reload case
2268
2269 uint32 count = 0;
2270 uint32 family_count = 0;
2271
2272 for (uint32 i = 0; i < sCreatureFamilyStore.GetNumRows(); ++i)
2273 {
2274 CreatureFamilyEntry const* creatureFamily = sCreatureFamilyStore.LookupEntry(i);
2275 if (!creatureFamily) // not exist
2276 continue;
2277
2278 for (uint8 j = 0; j < 2; ++j)
2279 {
2280 if (!creatureFamily->skillLine[j])
2281 continue;
2282
2283 for (uint32 k = 0; k < sSkillLineAbilityStore.GetNumRows(); ++k)
2284 {
2285 SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(k);
2286 if (!skillLine)
2287 continue;
2288
2289 //if (skillLine->skillId != creatureFamily->skillLine[0] &&
2290 // (!creatureFamily->skillLine[1] || skillLine->skillId != creatureFamily->skillLine[1]))
2291 // continue;
2292
2293 if (skillLine->skillId != creatureFamily->skillLine[j])
2294 continue;
2295
2297 continue;
2298
2299 SpellInfo const* spell = GetSpellInfo(skillLine->spellId);
2300 if (!spell) // not exist or triggered or talent
2301 continue;
2302
2303 if (!spell->SpellLevel)
2304 continue;
2305
2306 PetLevelupSpellSet& spellSet = mPetLevelupSpellMap[creatureFamily->ID];
2307 if (spellSet.empty())
2308 ++family_count;
2309
2310 spellSet.insert(PetLevelupSpellSet::value_type(spell->SpellLevel, spell->Id));
2311 ++count;
2312 }
2313 }
2314 }
2315
2316 SF_LOG_INFO("server.loading", ">> Loaded %u pet levelup and default spells for %u families in %u ms", count, family_count, GetMSTimeDiffToNow(oldMSTime));
2317}
2318
2320{
2321 // skip empty list;
2322 bool have_spell = false;
2323 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2324 {
2325 if (petDefSpells.spellid[j])
2326 {
2327 have_spell = true;
2328 break;
2329 }
2330 }
2331 if (!have_spell)
2332 return false;
2333
2334 // remove duplicates with levelupSpells if any
2335 if (PetLevelupSpellSet const* levelupSpells = cInfo->family ? sSpellMgr->GetPetLevelupSpellList(cInfo->family) : NULL)
2336 {
2337 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2338 {
2339 if (!petDefSpells.spellid[j])
2340 continue;
2341
2342 for (PetLevelupSpellSet::const_iterator itr = levelupSpells->begin(); itr != levelupSpells->end(); ++itr)
2343 {
2344 if (itr->second == petDefSpells.spellid[j])
2345 {
2346 petDefSpells.spellid[j] = 0;
2347 break;
2348 }
2349 }
2350 }
2351 }
2352
2353 // skip empty list;
2354 have_spell = false;
2355 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2356 {
2357 if (petDefSpells.spellid[j])
2358 {
2359 have_spell = true;
2360 break;
2361 }
2362 }
2363
2364 return have_spell;
2365}
2366
2368{
2369 uint32 oldMSTime = getMSTime();
2370
2371 mPetDefaultSpellsMap.clear();
2372
2373 uint32 countCreature = 0;
2374 uint32 countData = 0;
2375
2376 CreatureTemplateContainer const* ctc = sObjectMgr->GetCreatureTemplates();
2377 for (CreatureTemplateContainer::const_iterator itr = ctc->begin(); itr != ctc->end(); ++itr)
2378 {
2379 if (!itr->second.PetSpellDataId)
2380 continue;
2381
2382 // for creature with PetSpellDataId get default pet spells from dbc
2383 CreatureSpellDataEntry const* spellDataEntry = sCreatureSpellDataStore.LookupEntry(itr->second.PetSpellDataId);
2384 if (!spellDataEntry)
2385 continue;
2386
2387 int32 petSpellsId = -int32(itr->second.PetSpellDataId);
2388 PetDefaultSpellsEntry petDefSpells;
2389 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2390 petDefSpells.spellid[j] = spellDataEntry->spellId[j];
2391
2392 if (LoadPetDefaultSpells_helper(&itr->second, petDefSpells))
2393 {
2394 mPetDefaultSpellsMap[petSpellsId] = petDefSpells;
2395 ++countData;
2396 }
2397 }
2398
2399 SF_LOG_INFO("server.loading", ">> Loaded addition spells for %u pet spell data entries in %u ms", countData, GetMSTimeDiffToNow(oldMSTime));
2400
2401 SF_LOG_INFO("server.loading", "Loading summonable creature templates...");
2402 oldMSTime = getMSTime();
2403
2404 // different summon spells
2405 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2406 {
2407 SpellInfo const* spellEntry = GetSpellInfo(i);
2408 if (!spellEntry)
2409 continue;
2410
2411 for (uint8 k = 0; k < MAX_SPELL_EFFECTS; ++k)
2412 {
2413 if (spellEntry->Effects[k].Effect == SPELL_EFFECT_SUMMON || spellEntry->Effects[k].Effect == SPELL_EFFECT_SUMMON_PET)
2414 {
2415 uint32 creature_id = spellEntry->Effects[k].MiscValue;
2416 CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(creature_id);
2417 if (!cInfo)
2418 continue;
2419
2420 // already loaded
2421 if (cInfo->PetSpellDataId)
2422 continue;
2423
2424 // for creature without PetSpellDataId get default pet spells from creature_template
2425 int32 petSpellsId = cInfo->Entry;
2426 if (mPetDefaultSpellsMap.find(cInfo->Entry) != mPetDefaultSpellsMap.end())
2427 continue;
2428
2429 PetDefaultSpellsEntry petDefSpells;
2430 for (uint8 j = 0; j < MAX_CREATURE_SPELL_DATA_SLOT; ++j)
2431 petDefSpells.spellid[j] = cInfo->spells[j];
2432
2433 if (LoadPetDefaultSpells_helper(cInfo, petDefSpells))
2434 {
2435 mPetDefaultSpellsMap[petSpellsId] = petDefSpells;
2436 ++countCreature;
2437 }
2438 }
2439 }
2440 }
2441
2442 SF_LOG_INFO("server.loading", ">> Loaded %u summonable creature templates in %u ms", countCreature, GetMSTimeDiffToNow(oldMSTime));
2443}
2444
2446{
2447 uint32 oldMSTime = getMSTime();
2448
2449 mSpellAreaMap.clear(); // need for reload case
2450 mSpellAreaForQuestMap.clear();
2452 mSpellAreaForAuraMap.clear();
2453
2454 // 0 1 2 3 4 5 6 7 8 9
2455 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");
2456 if (!result)
2457 {
2458 SF_LOG_INFO("server.loading", ">> Loaded 0 spell area requirements. DB table `spell_area` is empty.");
2459
2460 return;
2461 }
2462
2463 uint32 count = 0;
2464 do
2465 {
2466 Field* fields = result->Fetch();
2467
2468 uint32 spell = fields[0].GetUInt32();
2469 SpellArea spellArea;
2470 spellArea.spellId = spell;
2471 spellArea.areaId = fields[1].GetUInt32();
2472 spellArea.questStart = fields[2].GetUInt32();
2473 spellArea.questStartStatus = fields[3].GetUInt32();
2474 spellArea.questEndStatus = fields[4].GetUInt32();
2475 spellArea.questEnd = fields[5].GetUInt32();
2476 spellArea.auraSpell = fields[6].GetInt32();
2477 spellArea.raceMask = fields[7].GetUInt32();
2478 spellArea.gender = Gender(fields[8].GetUInt8());
2479 spellArea.autocast = fields[9].GetBool();
2480
2481 if (SpellInfo const* spellInfo = GetSpellInfo(spell))
2482 {
2483 if (spellArea.autocast)
2484 const_cast<SpellInfo*>(spellInfo)->Attributes |= SPELL_ATTR0_CANT_CANCEL;
2485 }
2486 else
2487 {
2488 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` does not exist", spell);
2489 continue;
2490 }
2491
2492 {
2493 bool ok = true;
2494 SpellAreaMapBounds sa_bounds = GetSpellAreaMapBounds(spellArea.spellId);
2495 for (SpellAreaMap::const_iterator itr = sa_bounds.first; itr != sa_bounds.second; ++itr)
2496 {
2497 if (spellArea.spellId != itr->second.spellId)
2498 continue;
2499 if (spellArea.areaId != itr->second.areaId)
2500 continue;
2501 if (spellArea.questStart != itr->second.questStart)
2502 continue;
2503 if (spellArea.auraSpell != itr->second.auraSpell)
2504 continue;
2505 if ((spellArea.raceMask & itr->second.raceMask) == 0)
2506 continue;
2507 if (spellArea.gender != itr->second.gender)
2508 continue;
2509
2510 // duplicate by requirements
2511 ok = false;
2512 break;
2513 }
2514
2515 if (!ok)
2516 {
2517 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` already listed with similar requirements.", spell);
2518 continue;
2519 }
2520 }
2521
2522 if (spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId))
2523 {
2524 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong area (%u) requirement", spell, spellArea.areaId);
2525 continue;
2526 }
2527
2528 if (spellArea.questStart && !sObjectMgr->GetQuestTemplate(spellArea.questStart))
2529 {
2530 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong start quest (%u) requirement", spell, spellArea.questStart);
2531 continue;
2532 }
2533
2534 if (spellArea.questEnd)
2535 {
2536 if (!sObjectMgr->GetQuestTemplate(spellArea.questEnd))
2537 {
2538 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong end quest (%u) requirement", spell, spellArea.questEnd);
2539 continue;
2540 }
2541 }
2542
2543 if (spellArea.auraSpell)
2544 {
2545 SpellInfo const* spellInfo = GetSpellInfo(abs(spellArea.auraSpell));
2546 if (!spellInfo)
2547 {
2548 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong aura spell (%u) requirement", spell, abs(spellArea.auraSpell));
2549 continue;
2550 }
2551
2552 if (uint32(abs(spellArea.auraSpell)) == spellArea.spellId)
2553 {
2554 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have aura spell (%u) requirement for itself", spell, abs(spellArea.auraSpell));
2555 continue;
2556 }
2557
2558 // not allow autocast chains by auraSpell field (but allow use as alternative if not present)
2559 if (spellArea.autocast && spellArea.auraSpell > 0)
2560 {
2561 bool chain = false;
2563 for (SpellAreaForAuraMap::const_iterator itr = saBound.first; itr != saBound.second; ++itr)
2564 {
2565 if (itr->second->autocast && itr->second->auraSpell > 0)
2566 {
2567 chain = true;
2568 break;
2569 }
2570 }
2571
2572 if (chain)
2573 {
2574 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell, spellArea.auraSpell);
2575 continue;
2576 }
2577
2579 for (SpellAreaMap::const_iterator itr2 = saBound2.first; itr2 != saBound2.second; ++itr2)
2580 {
2581 if (itr2->second.autocast && itr2->second.auraSpell > 0)
2582 {
2583 chain = true;
2584 break;
2585 }
2586 }
2587
2588 if (chain)
2589 {
2590 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have aura spell (%u) requirement that itself autocast from aura", spell, spellArea.auraSpell);
2591 continue;
2592 }
2593 }
2594 }
2595
2596 if (spellArea.raceMask && (spellArea.raceMask & RACEMASK_ALL_PLAYABLE) == 0)
2597 {
2598 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong race mask (%u) requirement", spell, spellArea.raceMask);
2599 continue;
2600 }
2601
2602 if (spellArea.gender != GENDER_NONE && spellArea.gender != GENDER_FEMALE && spellArea.gender != GENDER_MALE)
2603 {
2604 SF_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong gender (%u) requirement", spell, spellArea.gender);
2605 continue;
2606 }
2607
2608 SpellArea const* sa = &mSpellAreaMap.insert(SpellAreaMap::value_type(spell, spellArea))->second;
2609
2610 // for search by current zone/subzone at zone/subzone change
2611 if (spellArea.areaId)
2612 mSpellAreaForAreaMap.insert(SpellAreaForAreaMap::value_type(spellArea.areaId, sa));
2613
2614 // for search at quest start/reward
2615 if (spellArea.questStart)
2616 mSpellAreaForQuestMap.insert(SpellAreaForQuestMap::value_type(spellArea.questStart, sa));
2617
2618 // for search at quest start/reward
2619 if (spellArea.questEnd)
2620 mSpellAreaForQuestEndMap.insert(SpellAreaForQuestMap::value_type(spellArea.questEnd, sa));
2621
2622 // for search at aura apply
2623 if (spellArea.auraSpell)
2624 mSpellAreaForAuraMap.insert(SpellAreaForAuraMap::value_type(abs(spellArea.auraSpell), sa));
2625
2626 ++count;
2627 } while (result->NextRow());
2628
2629 SF_LOG_INFO("server.loading", ">> Loaded %u spell area requirements in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
2630}
2631
2632// Temporary structure to hold spell effect entries for faster loading
2634{
2636 {
2637 for (int i = 0; i < MAX_SPELL_EFFECTS; i++)
2638 effects[i] = NULL;
2639 }
2640
2642};
2643
2645{
2646 uint32 oldMSTime = getMSTime();
2647
2649 mSpellInfoMap.resize(sSpellStore.GetNumRows(), NULL);
2650
2651 std::map<uint32, SpellEffectArray> effectsBySpell;
2652
2653 for (uint32 i = 0; i < sSpellEffectStore.GetNumRows(); ++i)
2654 {
2655 SpellEffectEntry const* effect = sSpellEffectStore.LookupEntry(i);
2656 if (!effect)
2657 continue;
2658
2659 effectsBySpell[effect->EffectSpellId].effects[effect->EffectIndex] = effect;
2660 }
2661
2662 for (uint32 i = 0; i < sSpellStore.GetNumRows(); ++i)
2663 if (SpellEntry const* spellEntry = sSpellStore.LookupEntry(i))
2664 mSpellInfoMap[i] = new SpellInfo(spellEntry, effectsBySpell[i].effects);
2665
2666 SF_LOG_INFO("server.loading", ">> Loaded SpellInfo store in %u ms", GetMSTimeDiffToNow(oldMSTime));
2667}
2668
2670{
2671 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2672 delete mSpellInfoMap[i];
2673
2674 mSpellInfoMap.clear();
2675}
2676
2678{
2679 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2680 if (mSpellInfoMap[i])
2681 mSpellInfoMap[i]->_UnloadImplicitTargetConditionLists();
2682}
2683
2685{
2686 uint32 oldMSTime = getMSTime();
2687
2688 SpellInfo* spellInfo = NULL;
2689 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2690 {
2691 spellInfo = mSpellInfoMap[i];
2692 if (!spellInfo)
2693 continue;
2694
2695 for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
2696 {
2697 switch (spellInfo->Effects[j].ApplyAuraName)
2698 {
2706 break;
2718 break;
2719 }
2720
2721 switch (spellInfo->Effects[j].Effect)
2722 {
2728 case SPELL_EFFECT_HEAL:
2730 break;
2740 break;
2743 case SPELL_EFFECT_JUMP:
2746 spellInfo->AttributesCu |= SPELL_ATTR0_CU_CHARGE;
2747 break;
2750 break;
2755 {
2756 // only enchanting profession enchantments procs can stack
2758 {
2759 uint32 enchantId = spellInfo->Effects[j].MiscValue;
2760 SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId);
2761 if (!enchant)
2762 break;
2763
2764 for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
2765 {
2766 if (enchant->type[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
2767 continue;
2768
2769 SpellInfo* procInfo = _GetSpellInfo(enchant->spellid[s]);
2770 if (!procInfo)
2771 continue;
2772
2773 // if proced directly from enchantment, not via proc aura
2774 // NOTE: Enchant Weapon - Blade Ward also has proc aura spell and is proced directly
2775 // however its not expected to stack so this check is good
2777 continue;
2778
2780 }
2781 }
2782 break;
2783 }
2784 }
2785 }
2786
2787 if (!spellInfo->_IsPositiveEffect(EFFECT_0, false))
2789
2790 if (!spellInfo->_IsPositiveEffect(EFFECT_1, false))
2792
2793 if (!spellInfo->_IsPositiveEffect(EFFECT_2, false))
2795
2796 if (spellInfo->SpellVisual[0] == 3879)
2798
2799 switch (spellInfo->Id)
2800 {
2801 case 1776: // Gouge
2802 case 13579:
2803 case 24698:
2804 case 28456:
2805 case 29425:
2806 case 34940:
2807 case 36862:
2808 case 38863:
2809 case 52743: // Head Smack
2811 break;
2812 case 53: // Backstab
2813 case 5221: // Shred
2814 case 8676: // Ambush
2815 case 6785: // Ravage
2816 case 21987: // Lash of Pain
2817 case 58563: // Assassinate Restless Lookout
2819 break;
2820 case 26029: // Dark Glare
2821 case 37433: // Spout
2822 case 43140: // Flame Breath
2823 case 43215: // Flame Breath
2824 case 70461: // Coldflame Trap
2825 case 72133: // Pain and Suffering
2827 break;
2828 case 24340: // Meteor
2829 case 26558: // Meteor
2830 case 28884: // Meteor
2831 case 36837: // Meteor
2832 case 38903: // Meteor
2833 case 41276: // Meteor
2834 case 57467: // Meteor
2835 case 26789: // Shard of the Fallen Star
2836 case 31436: // Malevolent Cleave
2837 case 35181: // Dive Bomb
2838 case 40810: // Saber Lash
2839 case 43267: // Saber Lash
2840 case 43268: // Saber Lash
2841 case 42384: // Brutal Swipe
2842 case 45150: // Meteor Slash
2843 case 64688: // Sonic Screech
2844 case 72373: // Shared Suffering
2845 case 71904: // Chaos Bane
2846 case 70492: // Ooze Eruption
2847 // ONLY SPELLS WITH SPELLFAMILY_GENERIC and EFFECT_SCHOOL_DAMAGE
2849 break;
2850 case 18500: // Wing Buffet
2851 case 33086: // Wild Bite
2852 case 49749: // Piercing Blow
2853 case 52890: // Penetrating Strike
2854 case 53454: // Impale
2855 case 59446: // Impale
2856 case 62383: // Shatter
2857 case 64777: // Machine Gun
2858 case 65239: // Machine Gun
2859 case 65919: // Impale
2860 case 74439: // Machine Gun
2861 case 63278: // Mark of the Faceless (General Vezax)
2862 case 62544: // Thrust (Argent Tournament)
2863 case 64588: // Thrust (Argent Tournament)
2864 case 66479: // Thrust (Argent Tournament)
2865 case 68505: // Thrust (Argent Tournament)
2866 case 62709: // Counterattack! (Argent Tournament)
2867 case 62626: // Break-Shield (Argent Tournament, Player)
2868 case 64590: // Break-Shield (Argent Tournament, Player)
2869 case 64342: // Break-Shield (Argent Tournament, NPC)
2870 case 64686: // Break-Shield (Argent Tournament, NPC)
2871 case 65147: // Break-Shield (Argent Tournament, NPC)
2872 case 68504: // Break-Shield (Argent Tournament, NPC)
2873 case 62874: // Charge (Argent Tournament, Player)
2874 case 68498: // Charge (Argent Tournament, Player)
2875 case 64591: // Charge (Argent Tournament, Player)
2876 case 63003: // Charge (Argent Tournament, NPC)
2877 case 63010: // Charge (Argent Tournament, NPC)
2878 case 68321: // Charge (Argent Tournament, NPC)
2879 case 72255: // Mark of the Fallen Champion (Deathbringer Saurfang)
2881 break;
2882 case 64422: // Sonic Screech (Auriaya)
2885 break;
2886 case 72293: // Mark of the Fallen Champion (Deathbringer Saurfang)
2888 break;
2889 default:
2890 break;
2891 }
2892
2893 switch (spellInfo->SpellFamilyName)
2894 {
2896 // Shout
2897 if (spellInfo->SpellFamilyFlags[0] & 0x20000 || spellInfo->SpellFamilyFlags[1] & 0x20)
2899 break;
2900 case SPELLFAMILY_DRUID:
2901 // Roar
2902 if (spellInfo->SpellFamilyFlags[0] & 0x8)
2904 break;
2905 default:
2906 break;
2907 }
2908
2909 spellInfo->_InitializeExplicitTargetMask();
2910 }
2911
2912 SF_LOG_INFO("server.loading", ">> Loaded SpellInfo custom attributes in %u ms", GetMSTimeDiffToNow(oldMSTime));
2913}
2914
2916{
2917 uint32 oldMSTime = getMSTime();
2918
2919 SpellInfo* spellInfo = NULL;
2920 for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i)
2921 {
2922 spellInfo = (SpellInfo*)mSpellInfoMap[i];
2923 if (!spellInfo)
2924 continue;
2925
2926 for (uint8 j = 0; j < MAX_SPELL_EFFECTS; ++j)
2927 {
2928 switch (spellInfo->Effects[j].Effect)
2929 {
2932 case SPELL_EFFECT_JUMP:
2935 if (!spellInfo->Speed && !spellInfo->SpellFamilyName)
2936 spellInfo->Speed = SPEED_CHARGE;
2937 break;
2938 }
2939 }
2940
2941 if (spellInfo->ActiveIconID == 2158) // flight
2942 spellInfo->Attributes |= SPELL_ATTR0_PASSIVE;
2943
2944 switch (spellInfo->Id)
2945 {
2946 case 105156: // See Quest Invis 13 // Red Flame
2947 case 105157: // See Quest Invis 14 // Blue Flame
2948 case 105158: // See Quest Invis 15 // Violet Flame
2949 spellInfo->AreaGroupId = 0;
2950 break;
2951 case 42730: // Woe Strike
2952 spellInfo->Effects[EFFECT_1].TriggerSpell = 42739;
2953 break;
2954 case 59735: // Woe Strike
2955 spellInfo->Effects[EFFECT_1].TriggerSpell = 59736;
2956 break;
2957 case 52611: // Summon Skeletons
2958 case 52612: // Summon Skeletons
2959 spellInfo->Effects[EFFECT_0].MiscValueB = 64;
2960 break;
2961 case 40244: // Simon Game Visual
2962 case 40245: // Simon Game Visual
2963 case 40246: // Simon Game Visual
2964 case 40247: // Simon Game Visual
2965 case 42835: // Spout, remove damage effect, only anim is needed
2966 spellInfo->Effects[EFFECT_0].Effect = 0;
2967 break;
2968 case 30657: // Quake
2969 spellInfo->Effects[EFFECT_0].TriggerSpell = 30571;
2970 break;
2971 case 30541: // Blaze (needs conditions entry)
2974 break;
2975 case 63665: // Charge (Argent Tournament emote on riders)
2976 case 31298: // Sleep (needs target selection script)
2977 case 51904: // Summon Ghouls On Scarlet Crusade (this should use conditions table, script for this spell needs to be fixed)
2978 case 68933: // Wrath of Air Totem rank 2 (Aura)
2979 case 29200: // Purify Helboar Meat
2982 break;
2983 case 31344: // Howl of Azgalor
2984 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yards instead of 50000?!
2985 break;
2986 case 42818: // Headless Horseman - Wisp Flight Port
2987 case 42821: // Headless Horseman - Wisp Flight Missile
2988 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100 yards
2989 break;
2990 case 36350: // They Must Burn Bomb Aura (self)
2991 spellInfo->Effects[EFFECT_0].TriggerSpell = 36325; // They Must Burn Bomb Drop (DND)
2992 break;
2993 case 49838: // Stop Time
2995 break;
2996 case 61407: // Energize Cores
2997 case 62136: // Energize Cores
2998 case 54069: // Energize Cores
2999 case 56251: // Energize Cores
3001 break;
3002 case 50785: // Energize Cores
3003 case 59372: // Energize Cores
3005 break;
3006 case 63320: // Glyph of Life Tap
3007 case 53228: // Rapid Killing (Rank 1)
3008 case 53232: // Rapid Killing (Rank 2)
3009 // Entries were not updated after spell effect change, we have to do that manually :/
3011 break;
3012 case 5308: // Execute
3014 break;
3015
3016 case 31347: // Doom
3017 case 39365: // Thundering Storm
3018 case 41071: // Raise Dead (HACK)
3019 case 42442: // Vengeance Landing Cannonfire
3020 case 42611: // Shoot
3021 case 44978: // Wild Magic
3022 case 45001: // Wild Magic
3023 case 45002: // Wild Magic
3024 case 45004: // Wild Magic
3025 case 45006: // Wild Magic
3026 case 45010: // Wild Magic
3027 case 45761: // Shoot Gun
3028 case 45863: // Cosmetic - Incinerate to Random Target
3029 case 48246: // Ball of Flame
3030 case 41635: // Prayer of Mending
3031 case 44869: // Spectral Blast
3032 case 45027: // Revitalize
3033 case 45976: // Muru Portal Channel
3034 case 52124: // Sky Darkener Assault
3035 case 53096: // Quetz'lun's Judgment
3036 case 52479: // Gift of the Harvester
3037 case 61588: // Blazing Harpoon
3038 spellInfo->MaxAffectedTargets = 1;
3039 break;
3040 case 36384: // Skartax Purple Beam
3041 spellInfo->MaxAffectedTargets = 2;
3042 break;
3043 case 28542: // Life Drain - Sapphiron
3044 case 29213: // Curse of the Plaguebringer - Noth
3045 case 29576: // Multi-Shot
3046 case 37790: // Spread Shot
3047 case 39992: // Needle Spine
3048 case 40816: // Saber Lash
3049 case 41303: // Soul Drain
3050 case 41376: // Spite
3051 case 45248: // Shadow Blades
3052 case 46771: // Flame Sear
3053 case 54171: // Divine Storm
3054 case 54172: // Divine Storm (heal)
3055 case 66588: // Flaming Spear
3056 spellInfo->MaxAffectedTargets = 3;
3057 break;
3058 case 38310: // Multi-Shot
3059 case 53385: // Divine Storm (Damage)
3060 spellInfo->MaxAffectedTargets = 4;
3061 break;
3062 case 42005: // Bloodboil
3063 case 38296: // Spitfire Totem
3064 case 37676: // Insidious Whisper
3065 case 46008: // Negative Energy
3066 case 45641: // Fire Bloom
3067 case 55665: // Life Drain - Sapphiron (H)
3068 case 28796: // Poison Bolt Volly - Faerlina
3069 spellInfo->MaxAffectedTargets = 5;
3070 break;
3071 case 40827: // Sinful Beam
3072 case 40859: // Sinister Beam
3073 case 40860: // Vile Beam
3074 case 40861: // Wicked Beam
3075 case 54835: // Curse of the Plaguebringer - Noth (H)
3076 case 54098: // Poison Bolt Volly - Faerlina (H)
3077 spellInfo->MaxAffectedTargets = 10;
3078 break;
3079 case 50312: // Unholy Frenzy
3080 spellInfo->MaxAffectedTargets = 15;
3081 break;
3082 case 33711: // Murmur's Touch
3083 case 38794: // Murmur's Touch
3084 spellInfo->MaxAffectedTargets = 1;
3085 spellInfo->Effects[EFFECT_0].TriggerSpell = 33760;
3086 break;
3087 case 17941: // Shadow Trance
3088 case 22008: // Netherwind Focus
3089 case 34477: // Misdirection
3090 case 34936: // Backlash
3091 case 48107: // Heating Up
3092 case 48108: // Pyroblast!
3093 case 51124: // Killing Machine
3094 case 54741: // Firestarter
3095 case 57761: // Fireball!
3096 case 64823: // Item - Druid T8 Balance 4P Bonus
3097 case 88819: // Daybreak
3098 spellInfo->ProcCharges = 1;
3099 break;
3100 case 44544: // Fingers of Frost
3101 spellInfo->Effects[EFFECT_0].SpellClassMask = flag128(685904631, 1151048, 0, 0);
3102 break;
3103
3104 case 28200: // Ascendance (Talisman of Ascendance trinket)
3105 spellInfo->ProcCharges = 6;
3106 break;
3107 case 47201: // Everlasting Affliction (1)
3108 case 47202: // Everlasting Affliction (2)
3109 case 47203: // Everlasting Affliction (3)
3110 case 47204: // Everlasting Affliction (4)
3111 case 47205: // Everlasting Affliction (5)
3112 // add corruption to affected spells
3113 spellInfo->Effects[EFFECT_1].SpellClassMask[0] |= 2;
3114 break;
3115 case 51852: // The Eye of Acherus (no spawn in phase 2 in db)
3116 spellInfo->Effects[EFFECT_0].MiscValue |= 1;
3117 break;
3118 case 51912: // Crafty's Ultra-Advanced Proto-Typical Shortening Blaster
3119 spellInfo->Effects[EFFECT_0].ApplyAuraTickCount = 3000;
3120 break;
3121
3122 case 51466: // Elemental Oath (Rank 1)
3123 case 51470: // Elemental Oath (Rank 2)
3127 spellInfo->Effects[EFFECT_1].SpellClassMask = flag128(0x00000000, 0x00004000, 0x00000000, 0x00000000);
3128 break;
3129
3130 case 64904: // Hymn of Hope
3132 break;
3133 case 30421: // Nether Portal - Perseverence
3134 spellInfo->Effects[EFFECT_2].BasePoints += 30000;
3135 break;
3136 case 41913: // Parasitic Shadowfiend Passive
3137 spellInfo->Effects[EFFECT_0].ApplyAuraName = SPELL_AURA_DUMMY; // proc debuff, and summon infinite fiends
3138 break;
3139 case 27892: // To Anchor 1
3140 case 27928: // To Anchor 1
3141 case 27935: // To Anchor 1
3142 case 27915: // Anchor to Skulls
3143 case 27931: // Anchor to Skulls
3144 case 27937: // Anchor to Skulls
3145 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(EFFECT_RADIUS_10_YARDS);
3146 break;
3147 // target allys instead of enemies, target A is src_caster, spells with effect like that have ally target
3148 // this is the only known exception, probably just wrong data
3149 case 29214: // Wrath of the Plaguebringer
3150 case 54836: // Wrath of the Plaguebringer
3153 break;
3154
3155 case 8145: // Tremor Totem (instant pulse)
3156 case 6474: // Earthbind Totem (instant pulse)
3158 break;
3159 case 53241: // Marked for Death (Rank 1)
3160 case 53243: // Marked for Death (Rank 2)
3161 spellInfo->Effects[EFFECT_0].SpellClassMask = flag128(0x00067801, 0x10820001, 0x00000801, 0x00000000);
3162 break;
3163 case 5176: // Wrath
3164 case 2912: // Starfire
3165 case 78674: // Starsurge
3168 break;
3169 case 70728: // Exploit Weakness (needs target selection script)
3170 case 70840: // Devious Minds (needs target selection script)
3173 break;
3174 case 70893: // Culling The Herd (needs target selection script)
3177 break;
3178
3179 case 61719: // Easter Lay Noblegarden Egg Aura - Interrupt flags copied from aura which this aura is linked with
3181 break;
3182 case 71838: // Drain Life - Bryntroll Normal
3183 case 71839: // Drain Life - Bryntroll Heroic
3185 break;
3186 case 34471: // The Beast Within
3188 break;
3189 // ULDUAR SPELLS
3190 //
3191 case 62374: // Pursued (Flame Leviathan)
3192 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
3193 break;
3194 case 63342: // Focused Eyebeam Summon Trigger (Kologarn)
3195 spellInfo->MaxAffectedTargets = 1;
3196 break;
3197 case 62716: // Growth of Nature (Freya)
3198 case 65584: // Growth of Nature (Freya)
3199 case 64381: // Strength of the Pack (Auriaya)
3201 break;
3202 case 63018: // Searing Light (XT-002)
3203 case 65121: // Searing Light (25m) (XT-002)
3204 case 63024: // Gravity Bomb (XT-002)
3205 case 64234: // Gravity Bomb (25m) (XT-002)
3206 spellInfo->MaxAffectedTargets = 1;
3207 break;
3208 case 62834: // Boom (XT-002)
3209 // This hack is here because we suspect our implementation of spell effect execution on targets
3210 // is done in the wrong order. We suspect that EFFECT_0 needs to be applied on all targets,
3211 // then EFFECT_1, etc - instead of applying each effect on target1, then target2, etc.
3212 // The above situation causes the visual for this spell to be bugged, so we remove the instakill
3213 // effect and implement a script hack for that.
3214 spellInfo->Effects[EFFECT_1].Effect = 0;
3215 break;
3216 case 64386: // Terrifying Screech (Auriaya)
3217 case 64389: // Sentinel Blast (Auriaya)
3218 case 64678: // Sentinel Blast (Auriaya)
3219 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(28); // 5 seconds, wrong DBC data?
3220 break;
3221 case 64321: // Potent Pheromones (Freya)
3222 // spell should dispel area aura, but doesn't have the attribute
3223 // may be db data bug, or blizz may keep reapplying area auras every update with checking immunity
3224 // that will be clear if we get more spells with problem like this
3226 break;
3227 case 61791: // Ride Vehicle (Yogg-Saron)
3228 // TODO: remove this when basepoints of all Ride Vehicle auras are calculated correctly
3229 spellInfo->Effects[EFFECT_0].BasePoints = 1;
3230 break;
3231 case 64468: // Empowering Shadows (Yogg-Saron)
3232 case 64486: // Empowering Shadows (Yogg-Saron)
3233 spellInfo->MaxAffectedTargets = 3; // same for both modes?
3234 break;
3235 case 62301: // Cosmic Smash (Algalon the Observer)
3236 spellInfo->MaxAffectedTargets = 1;
3237 break;
3238 case 64598: // Cosmic Smash (Algalon the Observer)
3239 spellInfo->MaxAffectedTargets = 3;
3240 break;
3241 case 62293: // Cosmic Smash (Algalon the Observer)
3243 break;
3244 case 62311: // Cosmic Smash (Algalon the Observer)
3245 case 64596: // Cosmic Smash (Algalon the Observer)
3246 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(6); // 100yd
3247 break;
3248 case 64014: // Expedition Base Camp Teleport
3249 case 64024: // Conservatory Teleport
3250 case 64025: // Halls of Invention Teleport
3251 case 64028: // Colossal Forge Teleport
3252 case 64029: // Shattered Walkway Teleport
3253 case 64030: // Antechamber Teleport
3254 case 64031: // Scrapyard Teleport
3255 case 64032: // Formation Grounds Teleport
3256 case 65042: // Prison of Yogg-Saron Teleport
3258 break;
3259 // ENDOF ULDUAR SPELLS
3260 //
3261 // TRIAL OF THE CRUSADER SPELLS
3262 //
3263 case 66258: // Infernal Eruption (10N)
3264 case 67901: // Infernal Eruption (25N)
3265 // increase duration from 15 to 18 seconds because caster is already
3266 // unsummoned when spell missile hits the ground so nothing happen in result
3267 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(85);
3268 break;
3269 // ENDOF TRIAL OF THE CRUSADER SPELLS
3270 //
3271 // ICECROWN CITADEL SPELLS
3272 //
3273 // THESE SPELLS ARE WORKING CORRECTLY EVEN WITHOUT THIS HACK
3274 // THE ONLY REASON ITS HERE IS THAT CURRENT GRID SYSTEM
3275 // DOES NOT ALLOW FAR OBJECT SELECTION (dist > 333)
3276 case 70781: // Light's Hammer Teleport
3277 case 70856: // Oratory of the Damned Teleport
3278 case 70857: // Rampart of Skulls Teleport
3279 case 70858: // Deathbringer's Rise Teleport
3280 case 70859: // Upper Spire Teleport
3281 case 70860: // Frozen Throne Teleport
3282 case 70861: // Sindragosa's Lair Teleport
3284 break;
3285 case 69075: // Bone Storm (Lord Marrowgar)
3286 case 70834: // Bone Storm (Lord Marrowgar)
3287 case 70835: // Bone Storm (Lord Marrowgar)
3288 case 70836: // Bone Storm (Lord Marrowgar)
3289 case 72864: // Death Plague (Rotting Frost Giant)
3290 case 71160: // Plague Stench (Stinky)
3291 case 71161: // Plague Stench (Stinky)
3292 case 71123: // Decimate (Stinky & Precious)
3293 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yd
3294 break;
3295 case 71169: // Shadow's Fate
3297 break;
3298 case 72378: // Blood Nova (Deathbringer Saurfang)
3299 case 73058: // Blood Nova (Deathbringer Saurfang)
3302 break;
3303 case 72769: // Scent of Blood (Deathbringer Saurfang)
3305 // no break
3306 case 72771: // Scent of Blood (Deathbringer Saurfang)
3308 break;
3309 case 72723: // Resistant Skin (Deathbringer Saurfang adds)
3310 // this spell initially granted Shadow damage immunity, however it was removed but the data was left in client
3311 spellInfo->Effects[EFFECT_2].Effect = 0;
3312 break;
3313 case 70460: // Coldflame Jets (Traps after Saurfang)
3314 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(1); // 10 seconds
3315 break;
3316 case 71412: // Green Ooze Summon (Professor Putricide)
3317 case 71415: // Orange Ooze Summon (Professor Putricide)
3319 break;
3320 case 71159: // Awaken Plagued Zombies
3321 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(21);
3322 break;
3323 case 70530: // Volatile Ooze Beam Protection (Professor Putricide)
3324 spellInfo->Effects[EFFECT_0].Effect = SPELL_EFFECT_APPLY_AURA; // for an unknown reason this was SPELL_EFFECT_APPLY_AREA_AURA_RAID
3325 break;
3326 // THIS IS HERE BECAUSE COOLDOWN ON CREATURE PROCS IS NOT IMPLEMENTED
3327 case 71604: // Mutated Strength (Professor Putricide)
3328 case 72673: // Mutated Strength (Professor Putricide)
3329 case 72674: // Mutated Strength (Professor Putricide)
3330 case 72675: // Mutated Strength (Professor Putricide)
3331 spellInfo->Effects[EFFECT_1].Effect = 0;
3332 break;
3333 case 72454: // Mutated Plague (Professor Putricide)
3334 case 72464: // Mutated Plague (Professor Putricide)
3335 case 72506: // Mutated Plague (Professor Putricide)
3336 case 72507: // Mutated Plague (Professor Putricide)
3337 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
3338 break;
3339 case 70911: // Unbound Plague (Professor Putricide) (needs target selection script)
3340 case 72854: // Unbound Plague (Professor Putricide) (needs target selection script)
3341 case 72855: // Unbound Plague (Professor Putricide) (needs target selection script)
3342 case 72856: // Unbound Plague (Professor Putricide) (needs target selection script)
3344 break;
3345 case 71518: // Unholy Infusion Quest Credit (Professor Putricide)
3346 case 72934: // Blood Infusion Quest Credit (Blood-Queen Lana'thel)
3347 case 72289: // Frost Infusion Quest Credit (Sindragosa)
3348 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // another missing radius
3349 break;
3350 case 71708: // Empowered Flare (Blood Prince Council)
3351 case 72785: // Empowered Flare (Blood Prince Council)
3352 case 72786: // Empowered Flare (Blood Prince Council)
3353 case 72787: // Empowered Flare (Blood Prince Council)
3355 break;
3356 case 71266: // Swarming Shadows
3357 case 72890: // Swarming Shadows
3358 spellInfo->AreaGroupId = 0; // originally, these require area 4522, which is... outside of Icecrown Citadel
3359 break;
3360 case 70602: // Corruption
3361 case 48278: // Paralyze
3363 break;
3364 case 70715: // Column of Frost (visual marker)
3365 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(32); // 6 seconds (missing)
3366 break;
3367 case 71085: // Mana Void (periodic aura)
3368 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(9); // 30 seconds (missing)
3369 break;
3370 case 72015: // Frostbolt Volley (only heroic)
3371 case 72016: // Frostbolt Volley (only heroic)
3373 break;
3374 case 70936: // Summon Suppressor (needs target selection script)
3377 break;
3378 case 72706: // Achievement Check (Valithria Dreamwalker)
3379 case 71357: // Order Whelp
3380 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
3381 break;
3382 case 70598: // Sindragosa's Fury
3384 break;
3385 case 69846: // Frost Bomb
3386 spellInfo->Speed = 0.0f; // This spell's summon happens instantly
3387 break;
3388 case 71614: // Ice Lock
3389 spellInfo->Mechanic = MECHANIC_STUN;
3390 break;
3391 case 72762: // Defile
3392 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(559); // 53 seconds
3393 break;
3394 case 72743: // Defile
3395 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(22); // 45 seconds
3396 break;
3397 case 72754: // Defile
3398 case 73708: // Defile
3399 case 73709: // Defile
3400 case 73710: // Defile
3401 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
3402 spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
3403 break;
3404 case 69030: // Val'kyr Target Search
3405 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
3406 spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
3407 break;
3408 case 69198: // Raging Spirit Visual
3409 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
3410 break;
3411 case 73654: // Harvest Souls
3412 case 74295: // Harvest Souls
3413 case 74296: // Harvest Souls
3414 case 74297: // Harvest Souls
3415 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
3416 spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
3417 spellInfo->Effects[EFFECT_2].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
3418 break;
3419 case 73655: // Harvest Soul
3421 break;
3422 case 73540: // Summon Shadow Trap
3423 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(23); // 90 seconds
3424 break;
3425 case 73530: // Shadow Trap (visual)
3426 spellInfo->DurationEntry = sSpellDurationStore.LookupEntry(28); // 5 seconds
3427 break;
3428 case 73529: // Shadow Trap
3429 spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_10_YARDS); // 10yd
3430 break;
3431 case 74282: // Shadow Trap (searcher)
3432 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_3_YARDS); // 3yd
3433 break;
3434 case 72595: // Restore Soul
3435 case 73650: // Restore Soul
3436 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
3437 break;
3438 case 74086: // Destroy Soul
3439 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
3440 break;
3441 case 74302: // Summon Spirit Bomb
3442 case 74342: // Summon Spirit Bomb
3443 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
3444 spellInfo->MaxAffectedTargets = 1;
3445 break;
3446 case 74341: // Summon Spirit Bomb
3447 case 74343: // Summon Spirit Bomb
3448 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
3449 spellInfo->MaxAffectedTargets = 3;
3450 break;
3451 case 73579: // Summon Spirit Bomb
3452 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS); // 25yd
3453 break;
3454 case 72350: // Fury of Frostmourne
3455 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
3456 spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
3457 break;
3458 case 75127: // Kill Frostmourne Players
3459 case 72351: // Fury of Frostmourne
3460 case 72431: // Jump (removes Fury of Frostmourne debuff)
3461 case 72429: // Mass Resurrection
3462 case 73159: // Play Movie
3463 case 73582: // Trigger Vile Spirit (Inside, Heroic)
3464 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
3465 break;
3466 case 72376: // Raise Dead
3467 spellInfo->MaxAffectedTargets = 3;
3468 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_50000_YARDS); // 50000yd
3469 break;
3470 case 71809: // Jump
3471 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(3); // 20yd
3472 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_25_YARDS); // 25yd
3473 break;
3474 case 72405: // Broken Frostmourne
3475 spellInfo->Effects[EFFECT_1].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_200_YARDS); // 200yd
3476 break;
3477 // ENDOF ICECROWN CITADEL SPELLS
3478 //
3479 // RUBY SANCTUM SPELLS
3480 //
3481 case 74769: // Twilight Cutter
3482 case 77844: // Twilight Cutter
3483 case 77845: // Twilight Cutter
3484 case 77846: // Twilight Cutter
3485 spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(EFFECT_RADIUS_100_YARDS); // 100yd
3486 break;
3487 case 75509: // Twilight Mending
3490 break;
3491 case 75888: // Awaken Flames
3492 case 75889: // Awaken Flames
3494 break;
3495 // ENDOF RUBY SANCTUM SPELLS
3496 //
3497 // EYE OF ETERNITY SPELLS
3498 // All spells below work even without these changes. The LOS attribute is due to problem
3499 // from collision between maps & gos with active destroyed state.
3500 case 57473: // Arcane Storm bonus explicit visual spell
3501 case 57431: // Summon Static Field
3502 case 56091: // Flame Spike (Wyrmrest Skytalon)
3503 case 56092: // Engulf in Flames (Wyrmrest Skytalon)
3504 case 57090: // Revivify (Wyrmrest Skytalon)
3505 case 57143: // Life Burst (Wyrmrest Skytalon)
3507 break;
3508 // This would never crit on retail and it has attribute for SPELL_ATTR3_NO_DONE_BONUS because is handled from player,
3509 // until someone figures how to make scions not critting without hack and without making them main casters this should stay here.
3510 case 63934: // Arcane Barrage (casted by players and NONMELEEDAMAGELOG with caster Scion of Eternity (original caster)).
3512 break;
3513 // ENDOF EYE OF ETERNITY SPELLS
3514 //
3515 case 40055: // Introspection
3516 case 40165: // Introspection
3517 case 40166: // Introspection
3518 case 40167: // Introspection
3519 spellInfo->Attributes |= SPELL_ATTR0_NEGATIVE_1;
3520 break;
3521 //case 2378: // Minor Fortitude
3522 //spellInfo->ManaCost = 0;
3523 //spellInfo->ManaPerSecond = 0;
3524 break;
3525 // Halls Of Origination spells
3526 // Temple Guardian Anhuur
3527 case 76606: // Disable Beacon Beams L
3528 case 76608: // Disable Beacon Beams R
3529 // Little hack, Increase the radius so it can hit the Cave In Stalkers in the platform.
3531 break;
3532 case 75323: // Reverberating Hymn
3533 // Aura is refreshed at 3 seconds, and the tick should happen at the fourth.
3535 break;
3536 case 24314: // Threatening Gaze
3538 break;
3539 case 5420: // Tree of Life (Passive)
3540 spellInfo->Stances = 1 << (FORM_TREE - 1);
3541 break;
3542 case 49376: // Feral Charge (Cat Form)
3544 break;
3545 case 45257: // Using Steam Tonk Controller
3546 case 45440: // Steam Tonk Controller
3547 case 60256: // Collect Sample
3548 // Crashes client on pressing ESC
3550 break;
3551 case 96942: // Gaze of Occu'thar
3552 case 101009: // Gaze of Occu'thar
3554 break;
3555 // ISLE OF CONQUEST SPELLS
3556 //
3557 case 66551: // Teleport
3558 spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(13); // 50000yd
3559 break;
3560 // ENDOF ISLE OF CONQUEST SPELLS
3561 //
3562 case 108055: // Remove Weapon
3564 break;
3565 default:
3566 break;
3567 }
3568 }
3569
3570 if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(121)))
3571 properties->Type = SUMMON_TYPE_TOTEM;
3572 if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(647))) // 52893
3573 properties->Type = SUMMON_TYPE_TOTEM;
3574 if (SummonPropertiesEntry* properties = const_cast<SummonPropertiesEntry*>(sSummonPropertiesStore.LookupEntry(3216))) // 52893
3575 properties->Slot = 1;
3576
3577 SF_LOG_INFO("server.loading", ">> Loaded SpellInfo corrections in %u ms", GetMSTimeDiffToNow(oldMSTime));
3578}
@ BATTLEFIELD_WG
Definition Battlefield.h:20
@ BATTLEFIELD_BATTLEID_WG
Definition Battlefield.h:26
#define sBattlefieldMgr
@ IN_MILLISECONDS
Definition Common.h:125
UNORDERED_MAP< uint32, CreatureTemplate > CreatureTemplateContainer
Definition Creature.h:187
#define MAX_SPELL_REAGENTS
@ ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL
Definition DBCEnums.h:410
@ ABILITY_LEARNED_ON_GET_RACE_OR_CLASS_SKILL
Definition DBCEnums.h:404
@ DIFFICULTY_HEROIC
Definition DBCEnums.h:333
DBCStorage< SpellItemEnchantmentEntry > sSpellItemEnchantmentStore(SpellItemEnchantmentfmt)
DBCStorage< SpellRadiusEntry > sSpellRadiusStore(SpellRadiusfmt)
DBCStorage< SummonPropertiesEntry > sSummonPropertiesStore(SummonPropertiesfmt)
DBCStorage< CreatureSpellDataEntry > sCreatureSpellDataStore(CreatureSpellDatafmt)
DBCStorage< SpellRangeEntry > sSpellRangeStore(SpellRangefmt)
uint32 GetTalentSpellCost(uint32 spellId)
DBCStorage< SpellDifficultyEntry > sSpellDifficultyStore(SpellDifficultyfmt)
DBCStorage< SpellEntry > sSpellStore(SpellEntryfmt)
DBCStorage< SkillLineEntry > sSkillLineStore(SkillLinefmt)
DBCStorage< SpellEffectEntry > sSpellEffectStore(SpellEffectEntryfmt)
DBCStorage< CreatureFamilyEntry > sCreatureFamilyStore(CreatureFamilyfmt)
DBCStorage< SpellDurationEntry > sSpellDurationStore(SpellDurationfmt)
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
AreaTableEntry const * GetAreaEntryByAreaID(uint32 area_id)
DBCStorage< SkillLineAbilityEntry > sSkillLineAbilityStore(SkillLineAbilityfmt)
#define MAX_CREATURE_SPELL_DATA_SLOT
#define MAX_SPELL_EFFECTS
#define MAX_ITEM_ENCHANTMENT_EFFECTS
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
#define SF_LOG_DEBUG(filterType__,...)
Definition Log.h:134
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
#define SF_LOG_INFO(filterType__,...)
Definition Log.h:137
#define SPEED_CHARGE
#define sObjectMgr
Definition ObjectMgr.h:1617
Skyfire::AutoPtr< ResultSet, Skyfire::Mutex > QueryResult
Definition QueryResult.h:48
SpellEffIndex
@ EFFECT_1
@ EFFECT_0
@ EFFECT_2
@ SPELL_ATTR0_NEGATIVE_1
@ SPELL_ATTR0_PASSIVE
@ SPELL_ATTR0_CANT_CANCEL
@ SPELL_ATTR0_NOT_SHAPESHIFT
DiminishingGroup
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_POWER_BURN
@ SPELL_EFFECT_ENERGIZE_PCT
@ SPELL_EFFECT_SUMMON_PET
@ 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_HEAL_MAX_HEALTH
@ SPELL_EFFECT_JUMP_DEST
@ SPELL_EFFECT_PICKPOCKET
@ SPELL_EFFECT_HEAL_MECHANICAL
@ SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
@ SPELL_EFFECT_CREATE_ITEM_2
@ SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
@ SPELL_EFFECT_LEAP_BACK
@ SPELL_EFFECT_SUMMON
@ SPELL_EFFECT_ENERGIZE
@ SPELL_EFFECT_POWER_DRAIN
@ SPELL_EFFECT_CHARGE
@ SPELL_EFFECT_SCHOOL_DAMAGE
@ SPELL_EFFECT_CHARGE_DEST
@ SPELL_EFFECT_LEARN_SPELL
@ SPELL_EFFECT_JUMP
@ SPELL_EFFECT_HEAL_PCT
@ SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
@ SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
@ SPELL_EFFECT_SKILL_STEP
@ SPELL_EFFECT_CREATE_ITEM
@ SPELL_EFFECT_APPLY_AURA
@ SPELL_ATTR1_DISPEL_AURAS_ON_IMMUNITY
@ SPELL_ATTR1_CHANNELED_1
@ SPELL_ATTR1_CANT_TARGET_SELF
@ SKILL_CATEGORY_WEAPON
@ SKILL_CATEGORY_PROFESSION
Gender
@ GENDER_MALE
@ GENDER_FEMALE
@ GENDER_NONE
@ TARGET_DEST_DB
@ TARGET_UNIT_SRC_AREA_ENTRY
@ TARGET_UNIT_SRC_AREA_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_CASTER
@ TARGET_UNIT_CASTER
@ SPELL_ATTR2_PRESERVE_ENCHANT_IN_ARENA
@ SPELL_ATTR2_CANT_CRIT
@ SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS
@ TEAM_ALLIANCE
@ TEAM_HORDE
@ SPELL_ATTR4_TRIGGERED
@ SPELL_ATTR6_CAN_TARGET_INVISIBLE
@ SUMMON_TYPE_TOTEM
@ SPELL_ATTR3_STACK_FOR_DIFF_CASTERS
@ SPELL_ATTR3_NO_DONE_BONUS
@ SPELL_ATTR3_NO_INITIAL_AGGRO
@ SPELL_ATTR3_CAN_PROC_WITH_TRIGGERED
@ SPELL_ATTR3_CANT_TRIGGER_PROC
@ SPELLFAMILY_WARLOCK
@ SPELLFAMILY_MAGE
@ SPELLFAMILY_GENERIC
@ SPELLFAMILY_WARRIOR
@ SPELLFAMILY_PALADIN
@ SPELLFAMILY_HUNTER
@ SPELLFAMILY_ROGUE
@ SPELLFAMILY_DRUID
@ SPELLFAMILY_UNK1
@ SPELL_ATTR5_USABLE_WHILE_CONFUSED
@ SPELL_ATTR5_USABLE_WHILE_FEARED
@ SPELL_ATTR5_START_PERIODIC_AT_APPLY
@ SPELL_ATTR5_USABLE_WHILE_STUNNED
DiminishingLevels
@ DIMINISHING_LEVEL_IMMUNE
@ DIMINISHING_LEVEL_TAUNT_IMMUNE
DiminishingReturnsType
@ DRTYPE_NONE
@ DRTYPE_PLAYER
@ DRTYPE_ALL
@ MECHANIC_DISARM
@ MECHANIC_FEAR
@ MECHANIC_KNOCKOUT
@ MECHANIC_CHARM
@ MECHANIC_STUN
@ MECHANIC_ROOT
@ MECHANIC_SLEEP
@ MECHANIC_POLYMORPH
@ MECHANIC_BANISH
@ MECHANIC_SILENCE
@ MECHANIC_SHACKLE
@ MECHANIC_SAPPED
@ MECHANIC_HORROR
#define RACEMASK_ALL_PLAYABLE
@ SPELL_ATTR8_DONT_RESET_PERIODIC_TIMER
@ SKILL_RIDING
@ SKILL_ENCHANTING
@ SPELL_SCHOOL_MASK_NORMAL
@ SPELL_SCHOOL_MASK_ALL
@ SPELL_AURA_PERIODIC_DAMAGE
@ SPELL_AURA_OBS_MOD_HEALTH
@ SPELL_AURA_PERIODIC_HEALTH_FUNNEL
@ SPELL_AURA_PERIODIC_MANA_LEECH
@ SPELL_AURA_PROC_TRIGGER_SPELL
@ SPELL_AURA_MOD_FEAR
@ SPELL_AURA_OBS_MOD_POWER
@ SPELL_AURA_ADD_FLAT_MODIFIER
@ SPELL_AURA_PERIODIC_HEAL
@ SPELL_AURA_PERIODIC_DAMAGE_PERCENT
@ SPELL_AURA_DUMMY
@ SPELL_AURA_FLY
@ SPELL_AURA_MOD_CHARM
@ SPELL_AURA_MOD_TAUNT
@ SPELL_AURA_MOD_INCREASE_ENERGY_PERCENT
@ SPELL_AURA_AOE_CHARM
@ SPELL_AURA_PERIODIC_ENERGIZE
@ SPELL_AURA_PERIODIC_LEECH
@ SPELL_AURA_POWER_BURN
@ SPELL_AURA_MOD_CONFUSE
@ SPELL_AURA_MOD_POSSESS
@ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
@ SPELL_AURA_MOD_STUN
@ SPELL_ATTR0_CU_IGNORE_ARMOR
Definition SpellInfo.h:77
@ SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER
Definition SpellInfo.h:78
@ SPELL_ATTR0_CU_ENCHANT_PROC
Definition SpellInfo.h:65
@ SPELL_ATTR0_CU_DIRECT_DAMAGE
Definition SpellInfo.h:71
@ SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET
Definition SpellInfo.h:79
@ SPELL_ATTR0_CU_CONE_BACK
Definition SpellInfo.h:66
@ SPELL_ATTR0_CU_NEGATIVE_EFF2
Definition SpellInfo.h:76
@ SPELL_ATTR0_CU_AURA_CC
Definition SpellInfo.h:70
@ SPELL_ATTR0_CU_NEGATIVE_EFF1
Definition SpellInfo.h:75
@ SPELL_ATTR0_CU_CHARGE
Definition SpellInfo.h:72
@ SPELL_ATTR0_CU_NEGATIVE_EFF0
Definition SpellInfo.h:74
@ SPELL_ATTR0_CU_SHARE_DAMAGE
Definition SpellInfo.h:68
@ SPELL_ATTR0_CU_PICKPOCKET
Definition SpellInfo.h:73
@ SPELL_ATTR0_CU_CONE_LINE
Definition SpellInfo.h:67
@ SPELL_ATTR0_CU_NO_INITIAL_THREAT
Definition SpellInfo.h:69
bool IsPrimaryProfessionSkill(uint32 skill)
Definition SpellMgr.cpp:23
bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
Definition SpellMgr.cpp:35
bool LoadPetDefaultSpells_helper(CreatureTemplate const *cInfo, PetDefaultSpellsEntry &petDefSpells)
int32 GetDiminishingReturnsLimitDuration(DiminishingGroup group, SpellInfo const *spellproto)
Definition SpellMgr.cpp:235
DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const *spellproto, bool triggered)
Definition SpellMgr.cpp:45
bool IsDiminishingReturnsGroupDurationLimited(DiminishingGroup group)
Definition SpellMgr.cpp:287
bool IsWeaponSkill(uint32 skill)
Definition SpellMgr.cpp:29
DiminishingReturnsType GetDiminishingReturnsGroupType(DiminishingGroup group)
Definition SpellMgr.cpp:205
DiminishingLevels GetDiminishingReturnsMaxLevel(DiminishingGroup group)
Definition SpellMgr.cpp:224
std::multimap< uint32, SpellLearnSpellNode > SpellLearnSpellMap
Definition SpellMgr.h:540
bool IsPartOfSkillLine(uint32 skillId, uint32 spellId)
Definition SpellMgr.cpp:35
#define SPELL_GROUP_STACK_RULE_MAX
Definition SpellMgr.h:341
@ PROC_HIT_ABSORB
Definition SpellMgr.h:250
@ PROC_HIT_MASK_ALL
Definition SpellMgr.h:254
@ PROC_HIT_CRITICAL
Definition SpellMgr.h:241
@ PROC_HIT_NORMAL
Definition SpellMgr.h:240
std::pair< SpellsRequiringSpellMap::const_iterator, SpellsRequiringSpellMap::const_iterator > SpellsRequiringSpellMapBounds
Definition SpellMgr.h:520
#define AURA_SPELL_PROC_EX_MASK
Definition SpellMgr.h:213
std::pair< SpellSpellGroupMap::const_iterator, SpellSpellGroupMap::const_iterator > SpellSpellGroupMapBounds
Definition SpellMgr.h:327
std::pair< SpellAreaMap::const_iterator, SpellAreaMap::const_iterator > SpellAreaMapBounds
Definition SpellMgr.h:497
SpellGroup
Definition SpellMgr.h:314
@ SPELL_GROUP_CORE_RANGE_MAX
Definition SpellMgr.h:320
std::pair< SpellAreaForAreaMap::const_iterator, SpellAreaForAreaMap::const_iterator > SpellAreaForAreaMapBounds
Definition SpellMgr.h:500
@ PROC_ATTR_REQ_EXP_OR_HONOR
Definition SpellMgr.h:259
SpellGroupStackRule
Definition SpellMgr.h:334
@ SPELL_GROUP_STACK_RULE_DEFAULT
Definition SpellMgr.h:335
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition SpellMgr.h:338
std::pair< SpellRequiredMap::const_iterator, SpellRequiredMap::const_iterator > SpellRequiredMapBounds
Definition SpellMgr.h:516
#define sSpellMgr
Definition SpellMgr.h:744
std::pair< SpellGroupSpellMap::const_iterator, SpellGroupSpellMap::const_iterator > SpellGroupSpellMapBounds
Definition SpellMgr.h:331
std::pair< SpellAreaForAuraMap::const_iterator, SpellAreaForAuraMap::const_iterator > SpellAreaForAuraMapBounds
Definition SpellMgr.h:499
std::pair< SkillLineAbilityMap::const_iterator, SkillLineAbilityMap::const_iterator > SkillLineAbilityMapBounds
Definition SpellMgr.h:544
@ PROC_EX_NONE
Definition SpellMgr.h:184
@ PROC_EX_INTERNAL_DOT
Definition SpellMgr.h:207
@ PROC_EX_CRITICAL_HIT
Definition SpellMgr.h:186
@ PROC_EX_NORMAL_HIT
Definition SpellMgr.h:185
@ PROC_EX_INTERNAL_HOT
Definition SpellMgr.h:208
@ PROC_EX_ONLY_ACTIVE_SPELL
Definition SpellMgr.h:203
@ PROC_EX_EX_TRIGGER_ALWAYS
Definition SpellMgr.h:201
@ PROC_EX_NOT_ACTIVE_SPELL
Definition SpellMgr.h:200
@ PROC_EX_INTERNAL_REQ_FAMILY
Definition SpellMgr.h:210
@ PROC_SPELL_TYPE_MASK_ALL
Definition SpellMgr.h:225
@ EFFECT_RADIUS_100_YARDS
Definition SpellMgr.h:374
@ EFFECT_RADIUS_45_YARDS
Definition SpellMgr.h:373
@ EFFECT_RADIUS_25_YARDS
Definition SpellMgr.h:382
@ EFFECT_RADIUS_40_YARDS
Definition SpellMgr.h:385
@ EFFECT_RADIUS_3_YARDS
Definition SpellMgr.h:377
@ EFFECT_RADIUS_50000_YARDS
Definition SpellMgr.h:390
@ EFFECT_RADIUS_200_YARDS
Definition SpellMgr.h:384
@ EFFECT_RADIUS_10_YARDS
Definition SpellMgr.h:375
@ PROC_SPELL_PHASE_FINISH
Definition SpellMgr.h:233
@ PROC_SPELL_PHASE_CAST
Definition SpellMgr.h:231
@ PROC_SPELL_PHASE_HIT
Definition SpellMgr.h:232
@ PROC_SPELL_PHASE_MASK_ALL
Definition SpellMgr.h:234
@ PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS
Definition SpellMgr.h:119
@ PROC_FLAG_DONE_PERIODIC
Definition SpellMgr.h:125
@ TAKEN_HIT_PROC_FLAG_MASK
Definition SpellMgr.h:164
@ PERIODIC_PROC_FLAG_MASK
Definition SpellMgr.h:156
@ PROC_FLAG_KILLED
Definition SpellMgr.h:98
@ PROC_FLAG_DEATH
Definition SpellMgr.h:134
@ PROC_FLAG_TAKEN_PERIODIC
Definition SpellMgr.h:126
@ REQ_SPELL_PHASE_PROC_FLAG_MASK
Definition SpellMgr.h:170
@ PROC_FLAG_KILL
Definition SpellMgr.h:99
@ PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS
Definition SpellMgr.h:120
@ PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS
Definition SpellMgr.h:114
@ SPELL_PROC_FLAG_MASK
Definition SpellMgr.h:147
@ DONE_HIT_PROC_FLAG_MASK
Definition SpellMgr.h:158
@ PROC_FLAG_DONE_TRAP_ACTIVATION
Definition SpellMgr.h:129
@ PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG
Definition SpellMgr.h:122
std::pair< SpellAreaForQuestMap::const_iterator, SpellAreaForQuestMap::const_iterator > SpellAreaForQuestMapBounds
Definition SpellMgr.h:498
std::pair< SpellLearnSpellMap::const_iterator, SpellLearnSpellMap::const_iterator > SpellLearnSpellMapBounds
Definition SpellMgr.h:541
#define SPELL_LINKED_MAX_SPELLS
Definition SpellMgr.h:82
std::multimap< uint32, uint32 > PetLevelupSpellSet
Definition SpellMgr.h:546
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:22
uint32 getMSTime()
Definition Timer.h:12
@ AURA_INTERRUPT_FLAG_TAKE_DAMAGE
Definition Unit.h:42
@ AURA_INTERRUPT_FLAG_CAST
Definition Unit.h:43
@ AURA_INTERRUPT_FLAG_HITBYSPELL
Definition Unit.h:41
@ AURA_INTERRUPT_FLAG_MOVE
Definition Unit.h:44
@ AURA_INTERRUPT_FLAG_JUMP
Definition Unit.h:46
@ SPELLMOD_EFFECT2
Definition Unit.h:85
@ FORM_TREE
Definition Unit.h:209
virtual uint32 GetData(uint32 dataId) const
uint32 GetTypeId() const
bool CanFlyIn() const
Return if we can use mount in battlefield.
void PSendSysMessage(const char *format,...) ATTR_PRINTF(2
Definition Chat.cpp:221
Definition Field.h:16
uint8 GetUInt8() const
Definition Field.h:26
int8 GetInt8() const
Definition Field.h:44
uint16 GetUInt16() const
Definition Field.h:69
float GetFloat() const
Definition Field.h:177
bool GetBool() const
Definition Field.h:21
uint32 GetUInt32() const
Definition Field.h:105
int32 GetInt32() const
Definition Field.h:123
uint8 GetSpawnMode() const
Definition Map.h:358
bool IsInstance() const
Definition Map.h:368
Player * ToPlayer()
Definition Object.h:204
WorldSession * GetSession() const
Definition Player.h:2417
TeamId GetTeamId() const
Definition Player.h:2531
Battleground * GetBattleground() const
Definition Player.cpp:19212
QuestStatus GetQuestStatus(uint32 quest_id) const
uint32 GetHitMask() const
Definition Unit.h:979
SpellSchoolMask GetSchoolMask() const
Definition Unit.h:983
Unit * GetActionTarget() const
Definition Unit.h:973
uint32 GetSpellTypeMask() const
Definition Unit.h:977
uint32 GetTypeMask() const
Definition Unit.h:976
SpellInfo const * GetSpellInfo() const
Definition Unit.h:982
uint32 GetSpellPhaseMask() const
Definition Unit.h:978
Unit * GetActor() const
Definition Unit.h:972
uint32 TriggerSpell
Definition SpellInfo.h:108
flag128 SpellClassMask
Definition SpellInfo.h:109
uint32 ApplyAuraTickCount
Definition SpellInfo.h:91
uint32 ApplyAuraName
Definition SpellInfo.h:90
SpellRadiusEntry const * MaxRadiusEntry
Definition SpellInfo.h:105
SpellRadiusEntry const * RadiusEntry
Definition SpellInfo.h:104
SpellImplicitTargetInfo TargetA
Definition SpellInfo.h:102
int32 CalcValue(Unit const *caster=NULL, int32 const *basePoints=NULL, Unit const *target=NULL) const
SpellImplicitTargetInfo TargetB
Definition SpellInfo.h:103
SpellEffectInfo Effects[MAX_SPELL_EFFECTS]
Definition SpellInfo.h:255
uint32 SpellLevel
Definition SpellInfo.h:206
bool IsRankOf(SpellInfo const *spellInfo) const
uint32 Stances
Definition SpellInfo.h:179
uint32 SpellVisual[2]
Definition SpellInfo.h:219
SpellInfo const * GetFirstRankSpell() const
uint32 AttributesCu
Definition SpellInfo.h:178
uint32 AttributesEx8
Definition SpellInfo.h:172
bool IsPassive() const
uint32 Mechanic
Definition SpellInfo.h:163
uint32 Id
Definition SpellInfo.h:160
uint8 GetRank() const
SpellRangeEntry const * RangeEntry
Definition SpellInfo.h:209
uint32 ProcCharges
Definition SpellInfo.h:203
bool IsLootCrafting() const
bool IsRanked() const
uint32 ActiveIconID
Definition SpellInfo.h:221
float Speed
Definition SpellInfo.h:210
uint32 SchoolMask
Definition SpellInfo.h:231
uint32 ProcFlags
Definition SpellInfo.h:201
flag128 SpellFamilyFlags
Definition SpellInfo.h:227
uint32 AttributesEx3
Definition SpellInfo.h:167
bool _IsPositiveEffect(uint8 effIndex, bool deep) const
int32 AreaGroupId
Definition SpellInfo.h:230
SpellDurationEntry const * DurationEntry
Definition SpellInfo.h:207
uint32 Attributes
Definition SpellInfo.h:164
uint32 AttributesEx
Definition SpellInfo.h:165
uint32 MaxAffectedTargets
Definition SpellInfo.h:225
uint32 AttributesEx6
Definition SpellInfo.h:170
uint32 GetAllEffectsMechanicMask() const
uint32 SpellIconID
Definition SpellInfo.h:220
void _InitializeExplicitTargetMask()
SpellInfo const * GetNextRankSpell() const
bool HasEffect(SpellEffects effect) const
bool IsPositive() const
uint32 ProcChance
Definition SpellInfo.h:202
uint32 AttributesEx2
Definition SpellInfo.h:166
uint32 AttributesEx5
Definition SpellInfo.h:169
uint32 AttributesEx4
Definition SpellInfo.h:168
bool HasAura(AuraType aura) const
int32 Reagent[MAX_SPELL_REAGENTS]
Definition SpellInfo.h:213
uint32 SpellFamilyName
Definition SpellInfo.h:226
uint32 AuraInterruptFlags
Definition SpellInfo.h:199
SpellRequiredMap mSpellReq
Definition SpellMgr.h:718
SpellLinkedMap mSpellLinkedMap
Definition SpellMgr.h:730
void LoadSpellLinked()
SkillLineAbilityMap mSkillLineAbilityMap
Definition SpellMgr.h:738
SpellAreaMapBounds GetSpellAreaMapBounds(uint32 spell_id) const
EnchantCustomAttribute mEnchantCustomAttr
Definition SpellMgr.h:732
void SetSpellDifficultyId(uint32 spellId, uint32 id)
Definition SpellMgr.cpp:416
SpellLearnSpellMapBounds GetSpellLearnSpellMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:573
PetLevelupSpellSet const * GetPetLevelupSpellList(uint32 petFamily) const
void LoadSpellInfoStore()
uint32 GetSpellIdForDifficulty(uint32 spellId, Unit const *caster) const
Definition SpellMgr.cpp:421
SpellAreaForQuestMapBounds GetSpellAreaForQuestEndMapBounds(uint32 quest_id) const
SpellAreaForAuraMap mSpellAreaForAuraMap
Definition SpellMgr.h:736
SpellProcEventEntry const * GetSpellProcEvent(uint32 spellId) const
Definition SpellMgr.cpp:726
SpellChainMap mSpellChains
Definition SpellMgr.h:716
void LoadEnchantCustomAttr()
void UnloadSpellInfoStore()
void LoadSpellAreas()
uint32 GetNextSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:505
SpellPetAuraMap mSpellPetAuraMap
Definition SpellMgr.h:729
SpellLearnSkillMap mSpellLearnSkills
Definition SpellMgr.h:719
SpellAreaForQuestMapBounds GetSpellAreaForQuestMapBounds(uint32 quest_id) const
SpellBonusEntry const * GetSpellBonusData(uint32 spellId) const
Definition SpellMgr.cpp:936
void LoadSkillLineAbilityMap()
SkillLineAbilityMapBounds GetSkillLineAbilityMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:967
SpellProcEventMap mSpellProcEventMap
Definition SpellMgr.h:725
static bool IsSpellValid(SpellInfo const *spellInfo, Player *player=NULL, bool msg=true)
Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book,...
Definition SpellMgr.cpp:319
SpellAreaForQuestMap mSpellAreaForQuestEndMap
Definition SpellMgr.h:735
SpellGroupSpellMapBounds GetSpellGroupSpellMapBounds(SpellGroup group_id) const
Definition SpellMgr.cpp:617
PetDefaultSpellsMap mPetDefaultSpellsMap
Definition SpellMgr.h:740
uint32 GetSpellWithRank(uint32 spell_id, uint32 rank, bool strict=false) const
Definition SpellMgr.cpp:531
SpellLearnSkillNode const * GetSpellLearnSkill(uint32 spell_id) const
Definition SpellMgr.cpp:564
void LoadSpellInfoCustomAttributes()
const std::vector< int32 > * GetSpellLinked(int32 spell_id) const
Definition SpellMgr.cpp:994
SpellRequiredMapBounds GetSpellsRequiredForSpellBounds(uint32 spell_id) const
Definition SpellMgr.cpp:543
SpellInfo const * GetSpellInfo(uint32 spellId) const
Definition SpellMgr.h:678
uint32 GetPrevSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:514
bool IsSpellRequiringSpell(uint32 spellid, uint32 req_spellid) const
Definition SpellMgr.cpp:553
void LoadSpellThreats()
bool IsSpellLearnToSpell(uint32 spell_id1, uint32 spell_id2) const
Definition SpellMgr.cpp:583
SpellAreaForAuraMapBounds GetSpellAreaForAuraMapBounds(uint32 spell_id) const
void LoadSpellRequired()
SpellInfo const * GetSpellForDifficultyFromSpell(SpellInfo const *spell, Unit const *caster) const
Definition SpellMgr.cpp:463
void LoadSpellTargetPositions()
SpellDifficultySearcherMap mSpellDifficultySearcherMap
Definition SpellMgr.h:715
void GetSetOfSpellsInSpellGroup(SpellGroup group_id, std::set< uint32 > &foundSpells) const
Definition SpellMgr.cpp:622
void LoadSpellLearnSkills()
uint32 GetLastSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:497
bool AddSameEffectStackRuleSpellGroups(SpellInfo const *spellInfo, int32 amount, std::map< SpellGroup, int32 > &groups) const
Definition SpellMgr.cpp:649
void LoadSpellTalentRanks()
bool IsSpellLearnSpell(uint32 spell_id) const
Definition SpellMgr.cpp:578
void LoadSpellBonusess()
SpellThreatEntry const * GetSpellThreatEntry(uint32 spellID) const
Definition SpellMgr.cpp:952
void LoadSpellGroupStackRules()
SpellGroupStackMap mSpellGroupStack
Definition SpellMgr.h:724
uint32 GetFirstSpellInChain(uint32 spell_id) const
Definition SpellMgr.cpp:489
bool CanSpellTriggerProcOnEvent(SpellProcEntry const &procEntry, ProcEventInfo &eventInfo) const
Definition SpellMgr.cpp:871
SpellEnchantProcEventMap mSpellEnchantProcEventMap
Definition SpellMgr.h:731
void LoadPetDefaultSpells()
PetLevelupSpellMap mPetLevelupSpellMap
Definition SpellMgr.h:739
void LoadSpellLearnSpells()
SpellGroupStackRule CheckSpellGroupStackRules(SpellInfo const *spellInfo1, SpellInfo const *spellInfo2) const
Definition SpellMgr.cpp:681
SpellProcMap mSpellProcMap
Definition SpellMgr.h:726
SpellsRequiringSpellMap mSpellsReqSpell
Definition SpellMgr.h:717
void LoadSpellInfoCorrections()
SpellTargetPositionMap mSpellTargetPositions
Definition SpellMgr.h:721
SpellProcEntry const * GetSpellProcEntry(uint32 spellId) const
Definition SpellMgr.cpp:863
SpellGroupSpellMap mSpellGroupSpell
Definition SpellMgr.h:723
PetDefaultSpellsEntry const * GetPetDefaultSpellsEntry(int32 id) const
SpellTargetPosition const * GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const
Definition SpellMgr.cpp:592
SpellEnchantProcEntry const * GetSpellEnchantProcEvent(uint32 enchId) const
Definition SpellMgr.cpp:981
SpellAreaForAreaMap mSpellAreaForAreaMap
Definition SpellMgr.h:737
bool IsSpellProcEventCanTriggeredBy(SpellProcEventEntry const *spellProcEvent, uint32 EventProcFlag, SpellInfo const *procSpell, uint32 procFlags, uint32 procExtra, bool active) const
Definition SpellMgr.cpp:734
uint32 GetSpellDifficultyId(uint32 spellId) const
Definition SpellMgr.cpp:410
void LoadSpellProcEvents()
uint8 GetSpellRank(uint32 spell_id) const
Definition SpellMgr.cpp:523
void LoadSpellPetAuras()
void UnloadSpellInfoImplicitTargetConditionLists()
SpellSpellGroupMapBounds GetSpellSpellGroupMapBounds(uint32 spell_id) const
Definition SpellMgr.cpp:600
SpellAreaMap mSpellAreaMap
Definition SpellMgr.h:733
void LoadSpellEnchantProcData()
uint32 GetSpellInfoStoreSize() const
Definition SpellMgr.h:679
SpellBonusMap mSpellBonusMap
Definition SpellMgr.h:727
SpellChainNode const * GetSpellChainNode(uint32 spell_id) const
Definition SpellMgr.cpp:480
SpellsRequiringSpellMapBounds GetSpellsRequiringSpellBounds(uint32 spell_id) const
Definition SpellMgr.cpp:548
void LoadSpellRanks()
void LoadSpellGroups()
void LoadPetLevelupSpellMap()
SpellLearnSpellMap mSpellLearnSpells
Definition SpellMgr.h:720
SpellSpellGroupMap mSpellSpellGroup
Definition SpellMgr.h:722
PetAura const * GetPetAura(uint32 spell_id, uint8 eff) const
Definition SpellMgr.cpp:972
SpellAreaForAreaMapBounds GetSpellAreaForAreaMapBounds(uint32 area_id) const
bool IsArenaAllowedEnchancment(uint32 ench_id) const
Definition SpellMgr.cpp:989
SpellThreatMap mSpellThreatMap
Definition SpellMgr.h:728
SpellAreaForQuestMap mSpellAreaForQuestMap
Definition SpellMgr.h:734
SpellInfoMap mSpellInfoMap
Definition SpellMgr.h:741
void LoadSpellProcs()
SpellInfo * _GetSpellInfo(uint32 spellId)
Definition SpellMgr.h:682
void UnloadSpellInfoChains()
bool IsSpellMemberOfSpellGroup(uint32 spellid, SpellGroup groupid) const
Definition SpellMgr.cpp:606
Definition Unit.h:1367
uint8 getGender() const
Definition Unit.h:1551
bool HasAura(uint32 spellId, uint64 casterGUID=0, uint64 itemCasterGUID=0, uint32 reqEffMask=0) const
uint32 getRaceMask() const
Definition Unit.h:1539
bool HasAuraType(AuraType auraType) const
Map * GetMap() const
Definition Object.h:740
uint32 GetZoneId() const
Definition Object.cpp:1597
WorldDatabaseWorkerPool WorldDatabase
Accessor to the world database.
Definition Main.cpp:40
bool HasAnyMechanic(uint32 mask, std::initializer_list< uint32 > mechanics)
bool HasMechanic(uint32 mask, uint32 mechanic)
uint32 ID
uint32 skillLine[2]
uint32 spellId[MAX_CREATURE_SPELL_DATA_SLOT]
uint32 spells[CREATURE_MAX_SPELLS]
Definition Creature.h:111
uint32 PetSpellDataId
Definition Creature.h:112
Definition SpellMgr.h:552
uint32 spellid[MAX_CREATURE_SPELL_DATA_SLOT]
Definition SpellMgr.h:553
uint32 spellId
uint32 learnOnGetSkill
uint32 skillId
int32 categoryId
uint32 questEnd
Definition SpellMgr.h:481
bool autocast
Definition SpellMgr.h:487
uint32 raceMask
Definition SpellMgr.h:483
uint32 questStartStatus
Definition SpellMgr.h:485
uint32 spellId
Definition SpellMgr.h:478
uint32 questEndStatus
Definition SpellMgr.h:486
int32 auraSpell
Definition SpellMgr.h:482
bool IsFitToRequirements(Player const *player, uint32 newZone, uint32 newArea) const
Gender gender
Definition SpellMgr.h:484
uint32 areaId
Definition SpellMgr.h:479
uint32 questStart
Definition SpellMgr.h:480
Definition SpellMgr.h:304
float ap_dot_bonus
Definition SpellMgr.h:308
float dot_damage
Definition SpellMgr.h:306
float ap_bonus
Definition SpellMgr.h:307
float direct_damage
Definition SpellMgr.h:305
int32 SpellID[4]
SpellEffectEntry const * effects[MAX_SPELL_EFFECTS]
uint32 EffectSpellId
uint32 EffectIndex
Definition SpellMgr.h:295
uint32 procEx
Definition SpellMgr.h:298
uint32 customChance
Definition SpellMgr.h:296
float PPMChance
Definition SpellMgr.h:297
uint32 type[MAX_ITEM_ENCHANTMENT_EFFECTS]
uint32 spellid[MAX_ITEM_ENCHANTMENT_EFFECTS]
Definition SpellMgr.h:277
uint32 cooldown
Definition SpellMgr.h:288
uint32 spellTypeMask
Definition SpellMgr.h:282
flag128 spellFamilyMask
Definition SpellMgr.h:280
float chance
Definition SpellMgr.h:287
uint32 schoolMask
Definition SpellMgr.h:278
float ratePerMinute
Definition SpellMgr.h:286
uint32 spellFamilyName
Definition SpellMgr.h:279
uint32 hitMask
Definition SpellMgr.h:284
uint32 attributesMask
Definition SpellMgr.h:285
uint32 spellPhaseMask
Definition SpellMgr.h:283
uint32 typeMask
Definition SpellMgr.h:281
uint32 charges
Definition SpellMgr.h:289
Definition SpellMgr.h:263
uint32 cooldown
Definition SpellMgr.h:271
flag128 spellFamilyMask
Definition SpellMgr.h:266
uint32 spellFamilyName
Definition SpellMgr.h:265
uint32 procEx
Definition SpellMgr.h:268
float ppmRate
Definition SpellMgr.h:269
uint32 schoolMask
Definition SpellMgr.h:264
float customChance
Definition SpellMgr.h:270
uint32 procFlags
Definition SpellMgr.h:267
Definition SpellMgr.h:346
int32 flatMod
Definition SpellMgr.h:347
float apPctMod
Definition SpellMgr.h:349
float pctMod
Definition SpellMgr.h:348